jazz-run 0.8.15 → 0.8.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +389 -378
- package/dist/createWorkerAccount.js +39 -17
- package/dist/createWorkerAccount.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/startSyncServer.js +4 -4
- package/dist/startSyncServer.js.map +1 -1
- package/dist/test/createWorkerAccount.test.js +17 -7
- package/dist/test/createWorkerAccount.test.js.map +1 -1
- package/package.json +9 -12
- package/src/createWorkerAccount.ts +126 -95
- package/src/index.ts +42 -46
- package/src/startSyncServer.ts +75 -77
- package/src/test/createWorkerAccount.test.ts +30 -20
- package/tsconfig.json +1 -1
- package/.eslintrc.cjs +0 -24
- package/.prettierrc.js +0 -9
@@ -1,7 +1,7 @@
|
|
1
1
|
import { createWebSocketPeer } from "cojson-transport-ws";
|
2
|
-
import { WebSocket } from "ws";
|
3
2
|
import { Account, WasmCrypto, createJazzContext, isControlledAccount, } from "jazz-tools";
|
4
3
|
import { fixedCredentialsAuth, randomSessionProvider } from "jazz-tools";
|
4
|
+
import { WebSocket } from "ws";
|
5
5
|
export const createWorkerAccount = async ({ name, peer: peerAddr, }) => {
|
6
6
|
const crypto = await WasmCrypto.create();
|
7
7
|
const peer = createWebSocketPeer({
|
@@ -24,25 +24,31 @@ export const createWorkerAccount = async ({ name, peer: peerAddr, }) => {
|
|
24
24
|
syncManager.syncCoValue(accountCoValue),
|
25
25
|
syncManager.syncCoValue(accountProfileCoValue),
|
26
26
|
]);
|
27
|
-
await Promise.
|
28
|
-
|
29
|
-
|
27
|
+
await Promise.race([
|
28
|
+
Promise.all([
|
29
|
+
waitForSync(account, peer, accountCoValue),
|
30
|
+
waitForSync(account, peer, accountProfileCoValue),
|
31
|
+
]),
|
32
|
+
failAfter(4000, "Timeout: Didn't manage to upload the account and profile"),
|
30
33
|
]);
|
31
34
|
// Spawn a second peer to double check that the account is fully synced
|
32
35
|
const peer2 = createWebSocketPeer({
|
33
|
-
id: "
|
36
|
+
id: "verifyingPeer",
|
34
37
|
websocket: new WebSocket(peerAddr),
|
35
38
|
role: "server",
|
36
39
|
});
|
37
|
-
await
|
38
|
-
|
39
|
-
|
40
|
-
|
40
|
+
await Promise.race([
|
41
|
+
createJazzContext({
|
42
|
+
auth: fixedCredentialsAuth({
|
43
|
+
accountID: account.id,
|
44
|
+
secret: account._raw.agentSecret,
|
45
|
+
}),
|
46
|
+
sessionProvider: randomSessionProvider,
|
47
|
+
peersToLoadFrom: [peer2],
|
48
|
+
crypto,
|
41
49
|
}),
|
42
|
-
|
43
|
-
|
44
|
-
crypto,
|
45
|
-
});
|
50
|
+
failAfter(4000, "Timeout: Account loading check failed"),
|
51
|
+
]);
|
46
52
|
return {
|
47
53
|
accountId: account.id,
|
48
54
|
agentSecret: account._raw.agentSecret,
|
@@ -51,13 +57,24 @@ export const createWorkerAccount = async ({ name, peer: peerAddr, }) => {
|
|
51
57
|
function waitForSync(account, peer, coValue) {
|
52
58
|
const syncManager = account._raw.core.node.syncManager;
|
53
59
|
const peerState = syncManager.peers[peer.id];
|
60
|
+
if (!peerState) {
|
61
|
+
throw new Error(`Peer state for ${peer.id} not found`);
|
62
|
+
}
|
63
|
+
const isSynced = () => {
|
64
|
+
const knownState = coValue.knownState();
|
65
|
+
if (!peerState.optimisticKnownStates.get(coValue.id)) {
|
66
|
+
return false;
|
67
|
+
}
|
68
|
+
return isEqualSession(knownState.sessions, peerState.optimisticKnownStates.get(coValue.id)?.sessions ?? {});
|
69
|
+
};
|
70
|
+
if (isSynced()) {
|
71
|
+
return Promise.resolve(true);
|
72
|
+
}
|
54
73
|
return new Promise((resolve) => {
|
55
|
-
const unsubscribe = peerState?.optimisticKnownStates.subscribe((id,
|
74
|
+
const unsubscribe = peerState?.optimisticKnownStates.subscribe((id, knownState) => {
|
56
75
|
if (id !== coValue.id)
|
57
76
|
return;
|
58
|
-
|
59
|
-
const synced = isEqualSession(knownState.sessions, peerKnownState.sessions);
|
60
|
-
if (synced) {
|
77
|
+
if (isSynced()) {
|
61
78
|
resolve(true);
|
62
79
|
unsubscribe?.();
|
63
80
|
}
|
@@ -77,4 +94,9 @@ function isEqualSession(a, b) {
|
|
77
94
|
}
|
78
95
|
return true;
|
79
96
|
}
|
97
|
+
function failAfter(ms, errorMessage) {
|
98
|
+
return new Promise((_, reject) => {
|
99
|
+
setTimeout(() => reject(new Error(errorMessage)), ms);
|
100
|
+
});
|
101
|
+
}
|
80
102
|
//# sourceMappingURL=createWorkerAccount.js.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"createWorkerAccount.js","sourceRoot":"","sources":["../src/createWorkerAccount.ts"],"names":[],"mappings":"
|
1
|
+
{"version":3,"file":"createWorkerAccount.js","sourceRoot":"","sources":["../src/createWorkerAccount.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,uCAAuC;AACvC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACzC,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAEvD,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;AAE7C,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;AACrE,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC;
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,uCAAuC;AACvC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACzC,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAEvD,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;AAE7C,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;AACrE,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC;KACpC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;KAC5B,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,wBAAwB,CAAC,CAAC,CAAC;AAEvD,MAAM,oBAAoB,GAAG,OAAO,CAAC,IAAI,CACvC,QAAQ,EACR,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,EACtC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE;IACjB,OAAO,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QACzB,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,CAC5D,mBAAmB,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CACpC,CAAC;QAEF,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,mCAAmC,IAAI;sBAC1C,SAAS;qBACV,WAAW;CAC/B,CAAC,CAAC;IACC,CAAC,CAAC,CAAC;AACL,CAAC,CACF,CAAC;AAEF,MAAM,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,CACjD,OAAO,CAAC,eAAe,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAChD,CAAC;AAEF,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC;KACpC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;KAC5B,IAAI,CACH,OAAO,CAAC,eAAe,CACrB,mEAAmE,CACpE,CACF;KACA,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC;AAErC,MAAM,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,IAAI,CACtD,OAAO,CAAC,eAAe,CAAC,gDAAgD,CAAC,CAC1E,CAAC;AAEF,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;KAChC,IAAI,CACH,OAAO,CAAC,eAAe,CACrB,+EAA+E,CAChF,CACF;KACA,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,oBAAoB,CAAC,CAAC,CAAC;AAEnD,MAAM,CAAC,MAAM,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAChD,MAAM,EACN,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,cAAc,EAAE,EAAE,EAAE,QAAQ,EAAE,EAC5D,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,EAAE,EAAE;IACzB,OAAO,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QACzB,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,eAAe,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;QAErE,OAAO,CAAC,GAAG,CAAC,kDAAkD,IAAI,EAAE,CAAC,CAAC;QAEtE,qBAAqB;QACrB,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;IACtB,CAAC,CAAC,CAAC;AACL,CAAC,CACF,CAAC;AAEF,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAC5B,OAAO,CAAC,eAAe,CAAC,CAAC,cAAc,EAAE,sBAAsB,CAAC,CAAC,CAClE,CAAC;AAEF,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE;IAC/B,IAAI,EAAE,gBAAgB;IACtB,OAAO,EAAE,SAAS;CACnB,CAAC,CAAC;AAEH,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAC1C,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC,EACjC,WAAW,CAAC,OAAO,CACpB,CAAC"}
|
package/dist/startSyncServer.js
CHANGED
@@ -1,10 +1,10 @@
|
|
1
|
+
import { createServer } from "http";
|
1
2
|
import { ControlledAgent, LocalNode, WasmCrypto } from "cojson";
|
2
3
|
import { WebSocketServer } from "ws";
|
3
|
-
import { createServer } from "http";
|
4
|
-
import { createWebSocketPeer } from "cojson-transport-ws";
|
5
|
-
import { SQLiteStorage } from "cojson-storage-sqlite";
|
6
|
-
import { dirname } from "node:path";
|
7
4
|
import { mkdir } from "node:fs/promises";
|
5
|
+
import { dirname } from "node:path";
|
6
|
+
import { SQLiteStorage } from "cojson-storage-sqlite";
|
7
|
+
import { createWebSocketPeer } from "cojson-transport-ws";
|
8
8
|
export const startSyncServer = async ({ port, inMemory, db, }) => {
|
9
9
|
const crypto = await WasmCrypto.create();
|
10
10
|
const server = createServer((req, res) => {
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"startSyncServer.js","sourceRoot":"","sources":["../src/startSyncServer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,MAAM,IAAI,CAAC;
|
1
|
+
{"version":3,"file":"startSyncServer.js","sourceRoot":"","sources":["../src/startSyncServer.ts"],"names":[],"mappings":"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"}
|
@@ -1,23 +1,33 @@
|
|
1
|
-
import { describe,
|
2
|
-
import { startSyncServer } from "../startSyncServer.js";
|
1
|
+
import { describe, expect, it, onTestFinished } from "vitest";
|
3
2
|
import { createWorkerAccount } from "../createWorkerAccount.js";
|
3
|
+
import { startSyncServer } from "../startSyncServer.js";
|
4
4
|
describe("createWorkerAccount - integration tests", () => {
|
5
5
|
it("should create a worker account using the local sync server", async () => {
|
6
6
|
// Pass port: undefined to let the server choose a random port
|
7
|
-
const server = await startSyncServer({
|
7
|
+
const server = await startSyncServer({
|
8
|
+
port: undefined,
|
9
|
+
inMemory: true,
|
10
|
+
db: "",
|
11
|
+
});
|
8
12
|
onTestFinished(() => {
|
9
13
|
server.close();
|
10
14
|
});
|
11
15
|
const address = server.address();
|
12
|
-
if (typeof address !==
|
13
|
-
throw new Error(
|
16
|
+
if (typeof address !== "object" || address === null) {
|
17
|
+
throw new Error("Server address is not an object");
|
14
18
|
}
|
15
|
-
const { accountId, agentSecret } = await createWorkerAccount({
|
19
|
+
const { accountId, agentSecret } = await createWorkerAccount({
|
20
|
+
name: "test",
|
21
|
+
peer: `ws://localhost:${address.port}`,
|
22
|
+
});
|
16
23
|
expect(accountId).toBeDefined();
|
17
24
|
expect(agentSecret).toBeDefined();
|
18
25
|
});
|
19
26
|
it("should create a worker account using the Jazz cloud", async () => {
|
20
|
-
const { accountId, agentSecret } = await createWorkerAccount({
|
27
|
+
const { accountId, agentSecret } = await createWorkerAccount({
|
28
|
+
name: "test",
|
29
|
+
peer: `wss://cloud.jazz.tools`,
|
30
|
+
});
|
21
31
|
expect(accountId).toBeDefined();
|
22
32
|
expect(agentSecret).toBeDefined();
|
23
33
|
});
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"createWorkerAccount.test.js","sourceRoot":"","sources":["../../src/test/createWorkerAccount.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,
|
1
|
+
{"version":3,"file":"createWorkerAccount.test.js","sourceRoot":"","sources":["../../src/test/createWorkerAccount.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExD,QAAQ,CAAC,yCAAyC,EAAE,GAAG,EAAE;IACvD,EAAE,CAAC,4DAA4D,EAAE,KAAK,IAAI,EAAE;QAC1E,8DAA8D;QAC9D,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC;YACnC,IAAI,EAAE,SAAS;YACf,QAAQ,EAAE,IAAI;YACd,EAAE,EAAE,EAAE;SACP,CAAC,CAAC;QAEH,cAAc,CAAC,GAAG,EAAE;YAClB,MAAM,CAAC,KAAK,EAAE,CAAC;QACjB,CAAC,CAAC,CAAC;QAEH,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;QAEjC,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;YACpD,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;QACrD,CAAC;QAED,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,GAAG,MAAM,mBAAmB,CAAC;YAC3D,IAAI,EAAE,MAAM;YACZ,IAAI,EAAE,kBAAkB,OAAO,CAAC,IAAI,EAAE;SACvC,CAAC,CAAC;QAEH,MAAM,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,CAAC;QAChC,MAAM,CAAC,WAAW,CAAC,CAAC,WAAW,EAAE,CAAC;IACpC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qDAAqD,EAAE,KAAK,IAAI,EAAE;QACnE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,GAAG,MAAM,mBAAmB,CAAC;YAC3D,IAAI,EAAE,MAAM;YACZ,IAAI,EAAE,wBAAwB;SAC/B,CAAC,CAAC;QAEH,MAAM,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,CAAC;QAChC,MAAM,CAAC,WAAW,CAAC,CAAC,WAAW,EAAE,CAAC;IACpC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
package/package.json
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
"bin": "./dist/index.js",
|
4
4
|
"type": "module",
|
5
5
|
"license": "MIT",
|
6
|
-
"version": "0.8.
|
6
|
+
"version": "0.8.16",
|
7
7
|
"dependencies": {
|
8
8
|
"@effect/cli": "^0.41.2",
|
9
9
|
"@effect/platform-node": "^0.57.2",
|
@@ -11,24 +11,21 @@
|
|
11
11
|
"@effect/printer-ansi": "^0.34.5",
|
12
12
|
"@effect/schema": "^0.71.1",
|
13
13
|
"@effect/typeclass": "^0.25.5",
|
14
|
-
"cojson": "0.8.
|
15
|
-
"cojson-storage-sqlite": "0.8.
|
16
|
-
"cojson-transport-ws": "0.8.
|
14
|
+
"cojson": "0.8.16",
|
15
|
+
"cojson-storage-sqlite": "0.8.16",
|
16
|
+
"cojson-transport-ws": "0.8.16",
|
17
17
|
"effect": "^3.6.5",
|
18
|
-
"jazz-tools": "0.8.
|
18
|
+
"jazz-tools": "0.8.16",
|
19
19
|
"ws": "^8.14.2"
|
20
20
|
},
|
21
21
|
"devDependencies": {
|
22
22
|
"@types/ws": "^8.5.5",
|
23
23
|
"typescript": "^5.3.3"
|
24
24
|
},
|
25
|
-
"lint-staged": {
|
26
|
-
"*.{ts,tsx}": "eslint --fix",
|
27
|
-
"*.{js,jsx,mdx,json}": "prettier --write"
|
28
|
-
},
|
29
25
|
"scripts": {
|
30
|
-
"lint": "
|
31
|
-
"format": "
|
32
|
-
"build": "
|
26
|
+
"format-and-lint": "biome check .",
|
27
|
+
"format-and-lint:fix": "biome check . --write",
|
28
|
+
"build": "rm -rf ./dist && tsc --sourceMap --outDir dist",
|
29
|
+
"build-and-run": "pnpm turbo build && chmod +x ./dist/index.js && ./dist/index.js sync --in-memory"
|
33
30
|
}
|
34
31
|
}
|
@@ -1,114 +1,145 @@
|
|
1
|
+
import { CoValueCore, Profile } from "cojson";
|
1
2
|
import { createWebSocketPeer } from "cojson-transport-ws";
|
2
|
-
import { WebSocket } from "ws";
|
3
3
|
import {
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
4
|
+
Account,
|
5
|
+
CoMap,
|
6
|
+
Peer,
|
7
|
+
WasmCrypto,
|
8
|
+
createJazzContext,
|
9
|
+
isControlledAccount,
|
9
10
|
} from "jazz-tools";
|
10
11
|
import { fixedCredentialsAuth, randomSessionProvider } from "jazz-tools";
|
11
|
-
import {
|
12
|
+
import { WebSocket } from "ws";
|
12
13
|
|
13
14
|
export const createWorkerAccount = async ({
|
14
|
-
|
15
|
-
|
15
|
+
name,
|
16
|
+
peer: peerAddr,
|
16
17
|
}: {
|
17
|
-
|
18
|
-
|
18
|
+
name: string;
|
19
|
+
peer: string;
|
19
20
|
}) => {
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
21
|
+
const crypto = await WasmCrypto.create();
|
22
|
+
|
23
|
+
const peer = createWebSocketPeer({
|
24
|
+
id: "upstream",
|
25
|
+
websocket: new WebSocket(peerAddr),
|
26
|
+
role: "server",
|
27
|
+
});
|
28
|
+
|
29
|
+
const account = await Account.create({
|
30
|
+
creationProps: { name },
|
31
|
+
peersToLoadFrom: [peer],
|
32
|
+
crypto,
|
33
|
+
});
|
34
|
+
|
35
|
+
if (!isControlledAccount(account)) {
|
36
|
+
throw new Error("account is not a controlled account");
|
37
|
+
}
|
38
|
+
|
39
|
+
const accountCoValue = account._raw.core;
|
40
|
+
const accountProfileCoValue = account.profile!._raw.core;
|
41
|
+
const syncManager = account._raw.core.node.syncManager;
|
42
|
+
|
43
|
+
await Promise.all([
|
44
|
+
syncManager.syncCoValue(accountCoValue),
|
45
|
+
syncManager.syncCoValue(accountProfileCoValue),
|
46
|
+
]);
|
47
|
+
|
48
|
+
await Promise.race([
|
49
|
+
Promise.all([
|
50
|
+
waitForSync(account, peer, accountCoValue),
|
51
|
+
waitForSync(account, peer, accountProfileCoValue),
|
52
|
+
]),
|
53
|
+
failAfter(
|
54
|
+
4_000,
|
55
|
+
"Timeout: Didn't manage to upload the account and profile",
|
56
|
+
),
|
57
|
+
]);
|
58
|
+
|
59
|
+
// Spawn a second peer to double check that the account is fully synced
|
60
|
+
const peer2 = createWebSocketPeer({
|
61
|
+
id: "verifyingPeer",
|
62
|
+
websocket: new WebSocket(peerAddr),
|
63
|
+
role: "server",
|
64
|
+
});
|
65
|
+
|
66
|
+
await Promise.race([
|
67
|
+
createJazzContext({
|
68
|
+
auth: fixedCredentialsAuth({
|
69
|
+
accountID: account.id,
|
70
|
+
secret: account._raw.agentSecret,
|
71
|
+
}),
|
72
|
+
sessionProvider: randomSessionProvider,
|
73
|
+
peersToLoadFrom: [peer2],
|
74
|
+
crypto,
|
75
|
+
}),
|
76
|
+
failAfter(4_000, "Timeout: Account loading check failed"),
|
77
|
+
]);
|
78
|
+
|
79
|
+
return {
|
80
|
+
accountId: account.id,
|
81
|
+
agentSecret: account._raw.agentSecret,
|
82
|
+
};
|
73
83
|
};
|
74
84
|
|
75
85
|
function waitForSync(account: Account, peer: Peer, coValue: CoValueCore) {
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
return new Promise((resolve) => {
|
80
|
-
const unsubscribe = peerState?.optimisticKnownStates.subscribe(
|
81
|
-
(id, peerKnownState) => {
|
82
|
-
if (id !== coValue.id) return;
|
83
|
-
|
84
|
-
const knownState = coValue.knownState();
|
85
|
-
|
86
|
-
const synced = isEqualSession(
|
87
|
-
knownState.sessions,
|
88
|
-
peerKnownState.sessions,
|
89
|
-
);
|
90
|
-
if (synced) {
|
91
|
-
resolve(true);
|
92
|
-
unsubscribe?.();
|
93
|
-
}
|
94
|
-
},
|
95
|
-
);
|
96
|
-
});
|
97
|
-
}
|
86
|
+
const syncManager = account._raw.core.node.syncManager;
|
87
|
+
const peerState = syncManager.peers[peer.id];
|
98
88
|
|
99
|
-
|
100
|
-
|
101
|
-
|
89
|
+
if (!peerState) {
|
90
|
+
throw new Error(`Peer state for ${peer.id} not found`);
|
91
|
+
}
|
92
|
+
|
93
|
+
const isSynced = () => {
|
94
|
+
const knownState = coValue.knownState();
|
102
95
|
|
103
|
-
if (
|
104
|
-
|
96
|
+
if (!peerState.optimisticKnownStates.get(coValue.id)) {
|
97
|
+
return false;
|
105
98
|
}
|
106
99
|
|
107
|
-
|
108
|
-
|
109
|
-
|
100
|
+
return isEqualSession(
|
101
|
+
knownState.sessions,
|
102
|
+
peerState.optimisticKnownStates.get(coValue.id)?.sessions ?? {},
|
103
|
+
);
|
104
|
+
};
|
105
|
+
|
106
|
+
if (isSynced()) {
|
107
|
+
return Promise.resolve(true);
|
108
|
+
}
|
109
|
+
|
110
|
+
return new Promise((resolve) => {
|
111
|
+
const unsubscribe = peerState?.optimisticKnownStates.subscribe(
|
112
|
+
(id, knownState) => {
|
113
|
+
if (id !== coValue.id) return;
|
114
|
+
|
115
|
+
if (isSynced()) {
|
116
|
+
resolve(true);
|
117
|
+
unsubscribe?.();
|
110
118
|
}
|
119
|
+
},
|
120
|
+
);
|
121
|
+
});
|
122
|
+
}
|
123
|
+
|
124
|
+
function isEqualSession(a: Record<string, number>, b: Record<string, number>) {
|
125
|
+
const keysA = Object.keys(a);
|
126
|
+
const keysB = Object.keys(b);
|
127
|
+
|
128
|
+
if (keysA.length !== keysB.length) {
|
129
|
+
return false;
|
130
|
+
}
|
131
|
+
|
132
|
+
for (const sessionId of keysA) {
|
133
|
+
if (a[sessionId] !== b[sessionId]) {
|
134
|
+
return false;
|
111
135
|
}
|
136
|
+
}
|
137
|
+
|
138
|
+
return true;
|
139
|
+
}
|
112
140
|
|
113
|
-
|
141
|
+
function failAfter(ms: number, errorMessage: string) {
|
142
|
+
return new Promise((_, reject) => {
|
143
|
+
setTimeout(() => reject(new Error(errorMessage)), ms);
|
144
|
+
});
|
114
145
|
}
|
package/src/index.ts
CHANGED
@@ -10,80 +10,76 @@ const jazzTools = Command.make("jazz-tools");
|
|
10
10
|
|
11
11
|
const nameOption = Options.text("name").pipe(Options.withAlias("n"));
|
12
12
|
const peerOption = Options.text("peer")
|
13
|
-
|
14
|
-
|
13
|
+
.pipe(Options.withAlias("p"))
|
14
|
+
.pipe(Options.withDefault("wss://cloud.jazz.tools"));
|
15
15
|
|
16
16
|
const createAccountCommand = Command.make(
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
17
|
+
"create",
|
18
|
+
{ name: nameOption, peer: peerOption },
|
19
|
+
({ name, peer }) => {
|
20
|
+
return Effect.gen(function* () {
|
21
|
+
const { accountId, agentSecret } = yield* Effect.promise(() =>
|
22
|
+
createWorkerAccount({ name, peer }),
|
23
|
+
);
|
24
24
|
|
25
|
-
|
25
|
+
yield* Console.log(`# Credentials for Jazz account "${name}":
|
26
26
|
JAZZ_WORKER_ACCOUNT=${accountId}
|
27
27
|
JAZZ_WORKER_SECRET=${agentSecret}
|
28
28
|
`);
|
29
|
-
|
30
|
-
|
29
|
+
});
|
30
|
+
},
|
31
31
|
);
|
32
32
|
|
33
33
|
const accountCommand = Command.make("account").pipe(
|
34
|
-
|
34
|
+
Command.withSubcommands([createAccountCommand]),
|
35
35
|
);
|
36
36
|
|
37
37
|
const portOption = Options.text("port")
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
38
|
+
.pipe(Options.withAlias("p"))
|
39
|
+
.pipe(
|
40
|
+
Options.withDescription(
|
41
|
+
"Select a different port for the WebSocket server. Default is 4200",
|
42
|
+
),
|
43
|
+
)
|
44
|
+
.pipe(Options.withDefault("4200"));
|
45
45
|
|
46
46
|
const inMemoryOption = Options.boolean("in-memory").pipe(
|
47
|
-
|
47
|
+
Options.withDescription("Use an in-memory storage instead of file-based"),
|
48
48
|
);
|
49
49
|
|
50
50
|
const dbOption = Options.file("db")
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
51
|
+
.pipe(
|
52
|
+
Options.withDescription(
|
53
|
+
"The path to the file where to store the data. Default is 'sync-db/storage.db'",
|
54
|
+
),
|
55
|
+
)
|
56
|
+
.pipe(Options.withDefault("sync-db/storage.db"));
|
57
57
|
|
58
58
|
export const startSyncServerCommand = Command.make(
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
startSyncServer({ port, inMemory, db }),
|
65
|
-
);
|
59
|
+
"sync",
|
60
|
+
{ port: portOption, inMemory: inMemoryOption, db: dbOption },
|
61
|
+
({ port, inMemory, db }) => {
|
62
|
+
return Effect.gen(function* () {
|
63
|
+
yield* Effect.promise(() => startSyncServer({ port, inMemory, db }));
|
66
64
|
|
67
|
-
|
68
|
-
`COJSON sync server listening on ws://127.0.0.1:${port}`,
|
69
|
-
);
|
65
|
+
Console.log(`COJSON sync server listening on ws://127.0.0.1:${port}`);
|
70
66
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
67
|
+
// Keep the server up
|
68
|
+
yield* Effect.never;
|
69
|
+
});
|
70
|
+
},
|
75
71
|
);
|
76
72
|
|
77
73
|
const command = jazzTools.pipe(
|
78
|
-
|
74
|
+
Command.withSubcommands([accountCommand, startSyncServerCommand]),
|
79
75
|
);
|
80
76
|
|
81
77
|
const cli = Command.run(command, {
|
82
|
-
|
83
|
-
|
78
|
+
name: "Jazz CLI Tools",
|
79
|
+
version: "v0.8.11",
|
84
80
|
});
|
85
81
|
|
86
82
|
Effect.suspend(() => cli(process.argv)).pipe(
|
87
|
-
|
88
|
-
|
83
|
+
Effect.provide(NodeContext.layer),
|
84
|
+
NodeRuntime.runMain,
|
89
85
|
);
|