Skip to content

Commit 4d826e1

Browse files
committed
Mini social network written with the Skip Framework
1 parent 2dfb28d commit 4d826e1

File tree

8 files changed

+1461
-3
lines changed

8 files changed

+1461
-3
lines changed

package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,10 @@
1919
"examples/hackernews/front-end/"
2020
],
2121
"devDependencies": {
22-
"@types/node": "^22.6.0",
2322
"@skiplabs/eslint-config": "^1.0.0",
2423
"@skiplabs/tsconfig": "^1.0.0",
24+
"@types/node": "^22.6.0",
25+
"@types/uuid": "^10.0.0",
2526
"eslint": "^9.9.0",
2627
"prettier": "^3.3.3",
2728
"typescript": "^5.6.2"
@@ -31,5 +32,8 @@
3132
"clean": "npm run clean --workspaces --if-present",
3233
"lint": "npm run lint --workspaces --if-present",
3334
"test": "npm run test --workspaces --if-present"
35+
},
36+
"dependencies": {
37+
"uuid": "^10.0.0"
3438
}
3539
}

skiplang/prelude/src/skstore/Context.sk

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -782,7 +782,13 @@ mutable class Context{
782782
| Some(child @ EagerDir _) ->
783783
this.!toReset = this.toReset.set(parentName);
784784
parentMaps = child.parents.maybeGet(parentName) match {
785-
| None() -> invariant_violation("Could not find parent")
785+
| None() ->
786+
invariant_violation(
787+
"Could not find parent: " +
788+
parentName +
789+
" for child " +
790+
childName,
791+
)
786792
| Some(f) -> f
787793
};
788794
EagerDir::update(

skipruntime-ts/client/src/client.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ export type {
2828
Creds,
2929
};
3030

31+
import WebSocket from "ws";
32+
3133
import * as Protocol from "./protocol.js";
3234

3335
export { Protocol };
Lines changed: 247 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
1+
import {
2+
type ReactiveResponse,
3+
} from "@skipruntime/api";
4+
import {
5+
fetchJSON,
6+
} from "@skipruntime/helpers/rest.js";
7+
import {
8+
parseReactiveResponse,
9+
} from "@skipruntime/helpers";
10+
import { connect, Protocol } from "@skipruntime/client";
11+
import type { TJSON } from "@skipruntime/client/protocol.js";
12+
import { newID } from "./skipsocial-utils.js";
13+
14+
/*
15+
This is the client simulator of skipsocial example
16+
*/
17+
18+
/*
19+
async function sleep(ms: number) {
20+
return new Promise((resolve) => setTimeout(resolve, ms));
21+
}
22+
*/
23+
const replication = 8081;
24+
const port = 8082;
25+
const url = `http://localhost:${port.toString()}`;
26+
const creds = await Protocol.generateCredentials();
27+
28+
const publicKey = new Uint8Array(await Protocol.exportKey(creds.publicKey));
29+
30+
const header = {
31+
"X-Reactive-Auth": Buffer.from(publicKey.buffer).toString("base64"),
32+
};
33+
const [_e, headers] = await fetchJSON<ReactiveResponse>(
34+
`${url}/auth/users`,
35+
"HEAD",
36+
header,
37+
);
38+
39+
const reactive = parseReactiveResponse(headers);
40+
41+
if (!reactive) {
42+
throw new Error("Reactive response must be supplied.");
43+
}
44+
45+
const client = await connect(`ws://localhost:${replication.toString()}`, creds);
46+
47+
client.subscribe(
48+
reactive.collection,
49+
reactive.watermark,
50+
(updates: [string, TJSON[]][], isInit: boolean) => {
51+
console.log("Update", Object.fromEntries(updates), isInit);
52+
},
53+
);
54+
55+
/*****************************************************************************/
56+
// Testing friend requests
57+
/*****************************************************************************/
58+
59+
const userID1 = "users-1";
60+
const userID2 = "users-2";
61+
const userID3 = "users-3";
62+
63+
await fetchJSON(`${url}/user/${userID1}`, "PUT", {}, { country: "FR" });
64+
65+
await fetchJSON(`${url}/user/${userID2}`, "PUT", {}, { country: "UK" });
66+
67+
await fetchJSON(`${url}/user/${userID3}`, "PUT", {}, { country: "UK" });
68+
69+
await fetchJSON(
70+
`${url}/friend-request/${newID("friendRequests")}`,
71+
"PUT",
72+
{},
73+
{ from: userID2, to: userID1 },
74+
);
75+
76+
await fetchJSON(
77+
`${url}/friend-request/${newID("friendRequests")}`,
78+
"PUT",
79+
{},
80+
{ from: userID1, to: userID2 },
81+
);
82+
83+
await fetchJSON(
84+
`${url}/friend-request/${newID("friendRequests")}`,
85+
"PUT",
86+
{},
87+
{ from: userID3, to: userID1 },
88+
);
89+
90+
await fetchJSON(
91+
`${url}/friend-request/${newID("friendRequests")}`,
92+
"PUT",
93+
{},
94+
{ from: userID1, to: userID3 },
95+
);
96+
97+
const friends2 = await fetchJSON(`${url}/friend/${userID1}`, "GET", header);
98+
const areFriends = await fetchJSON(
99+
`${url}/friend-index/${userID1}:${userID2}`,
100+
"GET",
101+
header,
102+
);
103+
104+
console.log(friends2);
105+
console.log(areFriends);
106+
107+
/*****************************************************************************/
108+
/* Testing messages */
109+
/*****************************************************************************/
110+
111+
await fetchJSON(
112+
`${url}/message/${newID("messages")}`,
113+
"PUT",
114+
{},
115+
{ from: userID3, to: userID1, content: "Hello from userID3" },
116+
);
117+
118+
await fetchJSON(
119+
`${url}/message/${newID("messages")}`,
120+
"PUT",
121+
{},
122+
{ from: userID2, to: userID1, content: "Hello from userID2" },
123+
);
124+
125+
await fetchJSON(
126+
`${url}/message/${newID("messages")}`,
127+
"PUT",
128+
{},
129+
{ from: userID2, to: userID1, content: "Another hello from userID2" },
130+
);
131+
132+
const params = new URLSearchParams({
133+
userID: userID1,
134+
});
135+
136+
console.log(
137+
await fetchJSON(`${url}/messages/${userID1}?${params}`, "GET", header),
138+
);
139+
140+
/*****************************************************************************/
141+
/* Testing groups */
142+
/*****************************************************************************/
143+
144+
/*
145+
const groupID = "groupid-1";
146+
147+
await fetchJSON(
148+
`${url}/group/${groupID}`,
149+
"PUT",
150+
{},
151+
{ name: "this is my first group!", owner: userID1 },
152+
);
153+
154+
await fetchJSON(
155+
`${url}/group-member/${groupID}`,
156+
"PUT",
157+
{},
158+
{ groupID, userID: userID2 },
159+
);
160+
161+
*/
162+
163+
/*
164+
await fetchJSON(
165+
`${url}/message/${userID1}`,
166+
"PUT",
167+
{},
168+
{ from: 'id-user-2', content: "Salut!"},
169+
);
170+
171+
console.log(await fetchJSON(
172+
`${url}/friend/${userID2}`,
173+
"GET",
174+
header,
175+
));
176+
177+
178+
console.log(await fetchJSON(
179+
`${url}/group/${groupID}`,
180+
"GET",
181+
header,
182+
));
183+
*/
184+
185+
/*
186+
const postID = "post-816"
187+
const commentID = "comment-817"
188+
189+
await fetchJSON(
190+
`${url}/post/${postID}`,
191+
"PUT",
192+
{},
193+
{ content: "First post from julien!", userID: "123" },
194+
);
195+
console.log("PUT POST DONE");
196+
197+
console.log("FETCH" + await fetchJSON(
198+
`${url}/post/${postID}`,
199+
"GET",
200+
header,
201+
));
202+
console.log("FETCH POST DONE");
203+
204+
await fetchJSON(
205+
`${url}/comment/${commentID}`,
206+
"PUT",
207+
{},
208+
{ postID, content: "First comment from julien!", userID: "123" },
209+
);
210+
211+
console.log("PUT COMMENT DONE");
212+
213+
214+
215+
await sleep(1000);
216+
217+
218+
console.log(
219+
"Get /post/" + postID,
220+
(await fetchJSON(`${url}/post/${postID}`, "GET", header))[0],
221+
);
222+
*/
223+
224+
/*
225+
226+
console.log('Set /user/123 to { name: "daniel", country: "UK" }');
227+
228+
await fetchJSON(
229+
`${url}/user/123`,
230+
"PUT",
231+
{},
232+
{ name: "daniel", country: "UK" },
233+
);
234+
235+
await sleep(1000);
236+
console.log("Delete /user/123");
237+
238+
await fetchJSON(`${url}/user/123`, "DELETE", {});
239+
240+
console.log(
241+
"Get /user/123",
242+
(await fetchJSON(`${url}/user/123`, "GET", header))[0],
243+
);
244+
245+
await sleep(1000);
246+
*/
247+
client.close();

0 commit comments

Comments
 (0)