cojson 0.6.7 → 0.7.0-alpha.0
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/.eslintrc.cjs +1 -0
- package/.turbo/turbo-build.log +2 -2
- package/CHANGELOG.md +3 -3
- package/dist/coValue.js.map +1 -1
- package/dist/coValueCore.js.map +1 -1
- package/dist/coValues/account.js +5 -5
- package/dist/coValues/account.js.map +1 -1
- package/dist/coValues/coList.js +39 -58
- package/dist/coValues/coList.js.map +1 -1
- package/dist/coValues/coMap.js +20 -61
- package/dist/coValues/coMap.js.map +1 -1
- package/dist/coValues/coStream.js +14 -64
- package/dist/coValues/coStream.js.map +1 -1
- package/dist/coValues/group.js +57 -59
- package/dist/coValues/group.js.map +1 -1
- package/dist/coreToCoValue.js +17 -12
- package/dist/coreToCoValue.js.map +1 -1
- package/dist/index.js +8 -8
- package/dist/index.js.map +1 -1
- package/dist/localNode.js +54 -38
- package/dist/localNode.js.map +1 -1
- package/dist/permissions.js +2 -2
- package/dist/permissions.js.map +1 -1
- package/dist/tests/testUtils.js +6 -11
- package/dist/tests/testUtils.js.map +1 -1
- package/dist/typeUtils/expectGroup.js +2 -2
- package/dist/typeUtils/expectGroup.js.map +1 -1
- package/dist/typeUtils/isCoValue.js +8 -8
- package/dist/typeUtils/isCoValue.js.map +1 -1
- package/package.json +3 -4
- package/src/coValue.ts +21 -21
- package/src/coValueCore.ts +8 -8
- package/src/coValues/account.ts +14 -26
- package/src/coValues/coList.ts +58 -97
- package/src/coValues/coMap.ts +27 -129
- package/src/coValues/coStream.ts +31 -137
- package/src/coValues/group.ts +52 -46
- package/src/coreToCoValue.ts +16 -12
- package/src/index.ts +27 -36
- package/src/jsonValue.ts +1 -1
- package/src/localNode.ts +88 -75
- package/src/media.ts +4 -4
- package/src/permissions.ts +2 -2
- package/src/tests/account.test.ts +12 -12
- package/src/tests/coValue.test.ts +149 -182
- package/src/tests/coValueCore.test.ts +8 -3
- package/src/tests/crypto.test.ts +7 -0
- package/src/tests/group.test.ts +13 -6
- package/src/tests/permissions.test.ts +648 -840
- package/src/tests/sync.test.ts +44 -68
- package/src/tests/testUtils.ts +6 -11
- package/src/typeUtils/expectGroup.ts +4 -4
- package/src/typeUtils/isCoValue.ts +11 -11
package/src/tests/sync.test.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import { expect, test, beforeEach } from "vitest";
|
|
1
2
|
import { newRandomSessionID } from "../coValueCore.js";
|
|
2
3
|
import { LocalNode } from "../localNode.js";
|
|
3
4
|
import { SyncMessage } from "../sync.js";
|
|
4
5
|
import { expectMap } from "../coValue.js";
|
|
5
6
|
import { MapOpPayload } from "../coValues/coMap.js";
|
|
6
|
-
import {
|
|
7
|
+
import { RawGroup } from "../coValues/group.js";
|
|
7
8
|
import {
|
|
8
9
|
randomAnonymousAccountAndSessionID,
|
|
9
10
|
shouldNotResolve,
|
|
@@ -13,6 +14,12 @@ import { AccountID } from "../coValues/account.js";
|
|
|
13
14
|
import { cojsonReady } from "../index.js";
|
|
14
15
|
import { stableStringify } from "../jsonStringify.js";
|
|
15
16
|
|
|
17
|
+
import { webcrypto } from "node:crypto";
|
|
18
|
+
if (!("crypto" in globalThis)) {
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
20
|
+
(globalThis as any).crypto = webcrypto;
|
|
21
|
+
}
|
|
22
|
+
|
|
16
23
|
beforeEach(async () => {
|
|
17
24
|
await cojsonReady;
|
|
18
25
|
});
|
|
@@ -25,9 +32,7 @@ test("Node replies with initial tx and header to empty subscribe", async () => {
|
|
|
25
32
|
|
|
26
33
|
const map = group.createMap();
|
|
27
34
|
|
|
28
|
-
map.
|
|
29
|
-
editable.set("hello", "world", "trusting");
|
|
30
|
-
});
|
|
35
|
+
map.set("hello", "world", "trusting");
|
|
31
36
|
|
|
32
37
|
const [inRx, inTx] = newStreamPair<SyncMessage>();
|
|
33
38
|
const [outRx, outTx] = newStreamPair<SyncMessage>();
|
|
@@ -91,8 +96,8 @@ test("Node replies with initial tx and header to empty subscribe", async () => {
|
|
|
91
96
|
]),
|
|
92
97
|
},
|
|
93
98
|
],
|
|
94
|
-
lastSignature:
|
|
95
|
-
|
|
99
|
+
lastSignature: map.core.sessionLogs.get(node.currentSessionID)!
|
|
100
|
+
.lastSignature!,
|
|
96
101
|
},
|
|
97
102
|
},
|
|
98
103
|
} satisfies SyncMessage);
|
|
@@ -106,10 +111,8 @@ test("Node replies with only new tx to subscribe with some known state", async (
|
|
|
106
111
|
|
|
107
112
|
const map = group.createMap();
|
|
108
113
|
|
|
109
|
-
map.
|
|
110
|
-
|
|
111
|
-
editable.set("goodbye", "world", "trusting");
|
|
112
|
-
});
|
|
114
|
+
map.set("hello", "world", "trusting");
|
|
115
|
+
map.set("goodbye", "world", "trusting");
|
|
113
116
|
|
|
114
117
|
const [inRx, inTx] = newStreamPair<SyncMessage>();
|
|
115
118
|
const [outRx, outTx] = newStreamPair<SyncMessage>();
|
|
@@ -169,8 +172,8 @@ test("Node replies with only new tx to subscribe with some known state", async (
|
|
|
169
172
|
]),
|
|
170
173
|
},
|
|
171
174
|
],
|
|
172
|
-
lastSignature:
|
|
173
|
-
|
|
175
|
+
lastSignature: map.core.sessionLogs.get(node.currentSessionID)!
|
|
176
|
+
.lastSignature!,
|
|
174
177
|
},
|
|
175
178
|
},
|
|
176
179
|
} satisfies SyncMessage);
|
|
@@ -232,9 +235,7 @@ test("After subscribing, node sends own known state and new txs to peer", async
|
|
|
232
235
|
new: {},
|
|
233
236
|
} satisfies SyncMessage);
|
|
234
237
|
|
|
235
|
-
map.
|
|
236
|
-
editable.set("hello", "world", "trusting");
|
|
237
|
-
});
|
|
238
|
+
map.set("hello", "world", "trusting");
|
|
238
239
|
|
|
239
240
|
const mapEditMsg1 = await reader.read();
|
|
240
241
|
|
|
@@ -258,15 +259,13 @@ test("After subscribing, node sends own known state and new txs to peer", async
|
|
|
258
259
|
]),
|
|
259
260
|
},
|
|
260
261
|
],
|
|
261
|
-
lastSignature:
|
|
262
|
-
|
|
262
|
+
lastSignature: map.core.sessionLogs.get(node.currentSessionID)!
|
|
263
|
+
.lastSignature!,
|
|
263
264
|
},
|
|
264
265
|
},
|
|
265
266
|
} satisfies SyncMessage);
|
|
266
267
|
|
|
267
|
-
map.
|
|
268
|
-
editable.set("goodbye", "world", "trusting");
|
|
269
|
-
});
|
|
268
|
+
map.set("goodbye", "world", "trusting");
|
|
270
269
|
|
|
271
270
|
const mapEditMsg2 = await reader.read();
|
|
272
271
|
|
|
@@ -290,8 +289,8 @@ test("After subscribing, node sends own known state and new txs to peer", async
|
|
|
290
289
|
]),
|
|
291
290
|
},
|
|
292
291
|
],
|
|
293
|
-
lastSignature:
|
|
294
|
-
|
|
292
|
+
lastSignature: map.core.sessionLogs.get(node.currentSessionID)!
|
|
293
|
+
.lastSignature!,
|
|
295
294
|
},
|
|
296
295
|
},
|
|
297
296
|
} satisfies SyncMessage);
|
|
@@ -305,9 +304,7 @@ test("Client replies with known new content to tellKnownState from server", asyn
|
|
|
305
304
|
|
|
306
305
|
const map = group.createMap();
|
|
307
306
|
|
|
308
|
-
map.
|
|
309
|
-
editable.set("hello", "world", "trusting");
|
|
310
|
-
});
|
|
307
|
+
map.set("hello", "world", "trusting");
|
|
311
308
|
|
|
312
309
|
const [inRx, inTx] = newStreamPair<SyncMessage>();
|
|
313
310
|
const [outRx, outTx] = newStreamPair<SyncMessage>();
|
|
@@ -369,8 +366,8 @@ test("Client replies with known new content to tellKnownState from server", asyn
|
|
|
369
366
|
]),
|
|
370
367
|
},
|
|
371
368
|
],
|
|
372
|
-
lastSignature:
|
|
373
|
-
|
|
369
|
+
lastSignature: map.core.sessionLogs.get(node.currentSessionID)!
|
|
370
|
+
.lastSignature!,
|
|
374
371
|
},
|
|
375
372
|
},
|
|
376
373
|
} satisfies SyncMessage);
|
|
@@ -428,13 +425,9 @@ test("No matter the optimistic known state, node respects invalid known state me
|
|
|
428
425
|
new: {},
|
|
429
426
|
} satisfies SyncMessage);
|
|
430
427
|
|
|
431
|
-
map.
|
|
432
|
-
editable.set("hello", "world", "trusting");
|
|
433
|
-
});
|
|
428
|
+
map.set("hello", "world", "trusting");
|
|
434
429
|
|
|
435
|
-
map.
|
|
436
|
-
editable.set("goodbye", "world", "trusting");
|
|
437
|
-
});
|
|
430
|
+
map.set("goodbye", "world", "trusting");
|
|
438
431
|
|
|
439
432
|
const _mapEditMsgs = await reader.read();
|
|
440
433
|
|
|
@@ -473,8 +466,8 @@ test("No matter the optimistic known state, node respects invalid known state me
|
|
|
473
466
|
]),
|
|
474
467
|
},
|
|
475
468
|
],
|
|
476
|
-
lastSignature:
|
|
477
|
-
|
|
469
|
+
lastSignature: map.core.sessionLogs.get(node.currentSessionID)!
|
|
470
|
+
.lastSignature!,
|
|
478
471
|
},
|
|
479
472
|
},
|
|
480
473
|
} satisfies SyncMessage);
|
|
@@ -498,9 +491,7 @@ test("If we add a peer, but it never subscribes to a coValue, it won't get any m
|
|
|
498
491
|
role: "peer",
|
|
499
492
|
});
|
|
500
493
|
|
|
501
|
-
map.
|
|
502
|
-
editable.set("hello", "world", "trusting");
|
|
503
|
-
});
|
|
494
|
+
map.set("hello", "world", "trusting");
|
|
504
495
|
|
|
505
496
|
const reader = outRx.getReader();
|
|
506
497
|
|
|
@@ -546,9 +537,7 @@ test("If we add a server peer, all updates to all coValues are sent to it, even
|
|
|
546
537
|
sessions: {},
|
|
547
538
|
} satisfies SyncMessage);
|
|
548
539
|
|
|
549
|
-
map.
|
|
550
|
-
editable.set("hello", "world", "trusting");
|
|
551
|
-
});
|
|
540
|
+
map.set("hello", "world", "trusting");
|
|
552
541
|
|
|
553
542
|
// expect((await reader.read()).value).toMatchObject(admContEx(admin.id));
|
|
554
543
|
expect((await reader.read()).value).toMatchObject(groupContentEx(group));
|
|
@@ -576,8 +565,8 @@ test("If we add a server peer, all updates to all coValues are sent to it, even
|
|
|
576
565
|
]),
|
|
577
566
|
},
|
|
578
567
|
],
|
|
579
|
-
lastSignature:
|
|
580
|
-
|
|
568
|
+
lastSignature: map.core.sessionLogs.get(node.currentSessionID)!
|
|
569
|
+
.lastSignature!,
|
|
581
570
|
},
|
|
582
571
|
},
|
|
583
572
|
} satisfies SyncMessage);
|
|
@@ -769,9 +758,7 @@ test.skip("When replaying creation and transactions of a coValue as new content,
|
|
|
769
758
|
expect(groupTellKnownStateMsg.value).toMatchObject(groupStateEx(group));
|
|
770
759
|
|
|
771
760
|
expect(
|
|
772
|
-
node2.syncManager.peers["test1"]!.optimisticKnownStates[
|
|
773
|
-
group.core.id
|
|
774
|
-
]
|
|
761
|
+
node2.syncManager.peers["test1"]!.optimisticKnownStates[group.core.id]
|
|
775
762
|
).toBeDefined();
|
|
776
763
|
|
|
777
764
|
// await to1.write(adminTellKnownStateMsg.value!);
|
|
@@ -816,9 +803,7 @@ test.skip("When replaying creation and transactions of a coValue as new content,
|
|
|
816
803
|
|
|
817
804
|
await to2.write(mapNewContentMsg.value!);
|
|
818
805
|
|
|
819
|
-
map.
|
|
820
|
-
editable.set("hello", "world", "trusting");
|
|
821
|
-
});
|
|
806
|
+
map.set("hello", "world", "trusting");
|
|
822
807
|
|
|
823
808
|
const mapEditMsg = await from1.read();
|
|
824
809
|
|
|
@@ -842,9 +827,7 @@ test.skip("When loading a coValue on one node, the server node it is requested f
|
|
|
842
827
|
const group = node1.createGroup();
|
|
843
828
|
|
|
844
829
|
const map = group.createMap();
|
|
845
|
-
map.
|
|
846
|
-
editable.set("hello", "world", "trusting");
|
|
847
|
-
});
|
|
830
|
+
map.set("hello", "world", "trusting");
|
|
848
831
|
|
|
849
832
|
const node2 = new LocalNode(admin, newRandomSessionID(admin.id));
|
|
850
833
|
|
|
@@ -870,9 +853,7 @@ test("Can sync a coValue through a server to another client", async () => {
|
|
|
870
853
|
const group = client1.createGroup();
|
|
871
854
|
|
|
872
855
|
const map = group.createMap();
|
|
873
|
-
map.
|
|
874
|
-
editable.set("hello", "world", "trusting");
|
|
875
|
-
});
|
|
856
|
+
map.set("hello", "world", "trusting");
|
|
876
857
|
|
|
877
858
|
const [serverUser, serverSession] = randomAnonymousAccountAndSessionID();
|
|
878
859
|
|
|
@@ -880,7 +861,8 @@ test("Can sync a coValue through a server to another client", async () => {
|
|
|
880
861
|
|
|
881
862
|
const [serverAsPeer, client1AsPeer] = connectedPeers("server", "client1", {
|
|
882
863
|
peer1role: "server",
|
|
883
|
-
peer2role: "client",
|
|
864
|
+
peer2role: "client",
|
|
865
|
+
trace: true,
|
|
884
866
|
});
|
|
885
867
|
|
|
886
868
|
client1.syncManager.addPeer(serverAsPeer);
|
|
@@ -891,7 +873,7 @@ test("Can sync a coValue through a server to another client", async () => {
|
|
|
891
873
|
const [serverAsOtherPeer, client2AsPeer] = connectedPeers(
|
|
892
874
|
"server",
|
|
893
875
|
"client2",
|
|
894
|
-
{ peer1role: "server", peer2role: "client", trace: true
|
|
876
|
+
{ peer1role: "server", peer2role: "client", trace: true }
|
|
895
877
|
);
|
|
896
878
|
|
|
897
879
|
client2.syncManager.addPeer(serverAsOtherPeer);
|
|
@@ -915,9 +897,7 @@ test("Can sync a coValue with private transactions through a server to another c
|
|
|
915
897
|
const group = client1.createGroup();
|
|
916
898
|
|
|
917
899
|
const map = group.createMap();
|
|
918
|
-
map.
|
|
919
|
-
editable.set("hello", "world", "private");
|
|
920
|
-
});
|
|
900
|
+
map.set("hello", "world", "private");
|
|
921
901
|
|
|
922
902
|
const [serverUser, serverSession] = randomAnonymousAccountAndSessionID();
|
|
923
903
|
|
|
@@ -1057,9 +1037,7 @@ test("When a peer's outgoing/writable stream closes, we remove the peer", async
|
|
|
1057
1037
|
reader.releaseLock();
|
|
1058
1038
|
await outRx.cancel();
|
|
1059
1039
|
|
|
1060
|
-
map.
|
|
1061
|
-
editable.set("hello", "world", "trusting");
|
|
1062
|
-
});
|
|
1040
|
+
map.set("hello", "world", "trusting");
|
|
1063
1041
|
|
|
1064
1042
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
1065
1043
|
|
|
@@ -1074,9 +1052,7 @@ test("If we start loading a coValue before connecting to a peer that has it, it
|
|
|
1074
1052
|
const group = node1.createGroup();
|
|
1075
1053
|
|
|
1076
1054
|
const map = group.createMap();
|
|
1077
|
-
map.
|
|
1078
|
-
editable.set("hello", "world", "trusting");
|
|
1079
|
-
});
|
|
1055
|
+
map.set("hello", "world", "trusting");
|
|
1080
1056
|
|
|
1081
1057
|
const node2 = new LocalNode(admin, newRandomSessionID(admin.id));
|
|
1082
1058
|
|
|
@@ -1104,7 +1080,7 @@ test("If we start loading a coValue before connecting to a peer that has it, it
|
|
|
1104
1080
|
);
|
|
1105
1081
|
});
|
|
1106
1082
|
|
|
1107
|
-
function groupContentEx(group:
|
|
1083
|
+
function groupContentEx(group: RawGroup) {
|
|
1108
1084
|
return {
|
|
1109
1085
|
action: "content",
|
|
1110
1086
|
id: group.core.id,
|
|
@@ -1118,7 +1094,7 @@ function admContEx(adminID: AccountID) {
|
|
|
1118
1094
|
};
|
|
1119
1095
|
}
|
|
1120
1096
|
|
|
1121
|
-
function groupStateEx(group:
|
|
1097
|
+
function groupStateEx(group: RawGroup) {
|
|
1122
1098
|
return {
|
|
1123
1099
|
action: "known",
|
|
1124
1100
|
id: group.core.id,
|
package/src/tests/testUtils.ts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
|
+
import { expect } from "vitest";
|
|
1
2
|
import { AgentSecret, createdNowUnique, getAgentID, newRandomAgentSecret } from "../crypto.js";
|
|
2
3
|
import { newRandomSessionID } from "../coValueCore.js";
|
|
3
4
|
import { LocalNode } from "../localNode.js";
|
|
4
5
|
import { expectGroup } from "../typeUtils/expectGroup.js";
|
|
5
6
|
import { ControlledAgent } from "../coValues/account.js";
|
|
6
7
|
import { SessionID } from "../ids.js";
|
|
7
|
-
// @ts-ignore
|
|
8
|
-
import { expect } from "bun:test";
|
|
9
8
|
|
|
10
9
|
export function randomAnonymousAccountAndSessionID(): [ControlledAgent, SessionID] {
|
|
11
10
|
const agentSecret = newRandomAgentSecret();
|
|
@@ -29,10 +28,8 @@ export function newGroup() {
|
|
|
29
28
|
|
|
30
29
|
const group = expectGroup(groupCore.getCurrentContent());
|
|
31
30
|
|
|
32
|
-
group.
|
|
33
|
-
|
|
34
|
-
expect(editable.get(admin.id)).toEqual("admin");
|
|
35
|
-
});
|
|
31
|
+
group.set(admin.id, "admin", "trusting");
|
|
32
|
+
expect(group.get(admin.id)).toEqual("admin");
|
|
36
33
|
|
|
37
34
|
return { node, groupCore, admin };
|
|
38
35
|
}
|
|
@@ -44,10 +41,8 @@ export function groupWithTwoAdmins() {
|
|
|
44
41
|
|
|
45
42
|
let group = expectGroup(groupCore.getCurrentContent());
|
|
46
43
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
expect(mutable.get(otherAdmin.id)).toEqual("admin");
|
|
50
|
-
});
|
|
44
|
+
group.set(otherAdmin.id, "admin", "trusting");
|
|
45
|
+
expect(group.get(otherAdmin.id)).toEqual("admin");
|
|
51
46
|
|
|
52
47
|
if (group.type !== "comap") {
|
|
53
48
|
throw new Error("Expected map");
|
|
@@ -73,7 +68,7 @@ export function groupWithTwoAdminsHighLevel() {
|
|
|
73
68
|
|
|
74
69
|
const otherAdmin = node.createAccount("otherAdmin");
|
|
75
70
|
|
|
76
|
-
group
|
|
71
|
+
group.addMember(otherAdmin, "admin");
|
|
77
72
|
|
|
78
73
|
return { admin, node, group, otherAdmin };
|
|
79
74
|
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { expectMap, type
|
|
2
|
-
import {
|
|
1
|
+
import { expectMap, type RawCoValue } from "../coValue.js";
|
|
2
|
+
import { RawGroup } from "../coValues/group.js";
|
|
3
3
|
|
|
4
|
-
export function expectGroup(content:
|
|
4
|
+
export function expectGroup(content: RawCoValue): RawGroup {
|
|
5
5
|
const map = expectMap(content);
|
|
6
6
|
if (map.core.header.ruleset.type !== "group") {
|
|
7
7
|
throw new Error("Expected group ruleset in group");
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
if (!(map instanceof
|
|
10
|
+
if (!(map instanceof RawGroup)) {
|
|
11
11
|
throw new Error("Expected group");
|
|
12
12
|
}
|
|
13
13
|
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type RawCoValue } from "../coValue.js";
|
|
2
2
|
import type { JsonValue } from "../jsonValue.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
3
|
+
import { RawCoMap } from "../coValues/coMap.js";
|
|
4
|
+
import { RawCoList } from "../coValues/coList.js";
|
|
5
|
+
import { RawCoStream } from "../coValues/coStream.js";
|
|
6
|
+
import { RawBinaryCoStream } from "../coValues/coStream.js";
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
export function isCoValue(
|
|
10
|
-
value: JsonValue |
|
|
11
|
-
): value is
|
|
10
|
+
value: JsonValue | RawCoValue | undefined
|
|
11
|
+
): value is RawCoValue {
|
|
12
12
|
return (
|
|
13
|
-
value instanceof
|
|
14
|
-
value instanceof
|
|
15
|
-
value instanceof
|
|
16
|
-
value instanceof
|
|
13
|
+
value instanceof RawCoMap ||
|
|
14
|
+
value instanceof RawCoList ||
|
|
15
|
+
value instanceof RawCoStream ||
|
|
16
|
+
value instanceof RawBinaryCoStream
|
|
17
17
|
);
|
|
18
18
|
}
|