cojson 0.16.3 → 0.16.5
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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +20 -0
- package/dist/coValue.d.ts +1 -1
- package/dist/coValue.d.ts.map +1 -1
- package/dist/coValue.js.map +1 -1
- package/dist/coValueContentMessage.d.ts +10 -0
- package/dist/coValueContentMessage.d.ts.map +1 -0
- package/dist/coValueContentMessage.js +46 -0
- package/dist/coValueContentMessage.js.map +1 -0
- package/dist/coValueCore/coValueCore.d.ts +6 -10
- package/dist/coValueCore/coValueCore.d.ts.map +1 -1
- package/dist/coValueCore/coValueCore.js +20 -125
- package/dist/coValueCore/coValueCore.js.map +1 -1
- package/dist/coValueCore/verifiedState.d.ts +1 -0
- package/dist/coValueCore/verifiedState.d.ts.map +1 -1
- package/dist/coValueCore/verifiedState.js +14 -27
- package/dist/coValueCore/verifiedState.js.map +1 -1
- package/dist/coValues/group.d.ts +18 -10
- package/dist/coValues/group.d.ts.map +1 -1
- package/dist/coValues/group.js +237 -67
- package/dist/coValues/group.js.map +1 -1
- package/dist/ids.d.ts +3 -3
- package/dist/ids.d.ts.map +1 -1
- package/dist/ids.js.map +1 -1
- package/dist/localNode.d.ts +11 -6
- package/dist/localNode.d.ts.map +1 -1
- package/dist/localNode.js +7 -2
- package/dist/localNode.js.map +1 -1
- package/dist/queue/LocalTransactionsSyncQueue.d.ts +24 -0
- package/dist/queue/LocalTransactionsSyncQueue.d.ts.map +1 -0
- package/dist/queue/LocalTransactionsSyncQueue.js +55 -0
- package/dist/queue/LocalTransactionsSyncQueue.js.map +1 -0
- package/dist/queue/StoreQueue.d.ts +9 -6
- package/dist/queue/StoreQueue.d.ts.map +1 -1
- package/dist/queue/StoreQueue.js +10 -2
- package/dist/queue/StoreQueue.js.map +1 -1
- package/dist/storage/storageAsync.d.ts +11 -3
- package/dist/storage/storageAsync.d.ts.map +1 -1
- package/dist/storage/storageAsync.js +59 -46
- package/dist/storage/storageAsync.js.map +1 -1
- package/dist/storage/storageSync.d.ts +9 -3
- package/dist/storage/storageSync.d.ts.map +1 -1
- package/dist/storage/storageSync.js +48 -35
- package/dist/storage/storageSync.js.map +1 -1
- package/dist/storage/syncUtils.d.ts +2 -1
- package/dist/storage/syncUtils.d.ts.map +1 -1
- package/dist/storage/syncUtils.js +4 -0
- package/dist/storage/syncUtils.js.map +1 -1
- package/dist/storage/types.d.ts +3 -2
- package/dist/storage/types.d.ts.map +1 -1
- package/dist/sync.d.ts +6 -6
- package/dist/sync.d.ts.map +1 -1
- package/dist/sync.js +33 -56
- package/dist/sync.js.map +1 -1
- package/dist/tests/StorageApiAsync.test.d.ts +2 -0
- package/dist/tests/StorageApiAsync.test.d.ts.map +1 -0
- package/dist/tests/StorageApiAsync.test.js +574 -0
- package/dist/tests/StorageApiAsync.test.js.map +1 -0
- package/dist/tests/StorageApiSync.test.d.ts +2 -0
- package/dist/tests/StorageApiSync.test.d.ts.map +1 -0
- package/dist/tests/StorageApiSync.test.js +426 -0
- package/dist/tests/StorageApiSync.test.js.map +1 -0
- package/dist/tests/StoreQueue.test.js +9 -21
- package/dist/tests/StoreQueue.test.js.map +1 -1
- package/dist/tests/SyncStateManager.test.js +18 -8
- package/dist/tests/SyncStateManager.test.js.map +1 -1
- package/dist/tests/group.inheritance.test.js +274 -2
- package/dist/tests/group.inheritance.test.js.map +1 -1
- package/dist/tests/group.removeMember.test.js +152 -1
- package/dist/tests/group.removeMember.test.js.map +1 -1
- package/dist/tests/group.roleOf.test.js +2 -2
- package/dist/tests/group.roleOf.test.js.map +1 -1
- package/dist/tests/group.test.js +81 -3
- package/dist/tests/group.test.js.map +1 -1
- package/dist/tests/sync.auth.test.js +22 -10
- package/dist/tests/sync.auth.test.js.map +1 -1
- package/dist/tests/sync.load.test.js +30 -25
- package/dist/tests/sync.load.test.js.map +1 -1
- package/dist/tests/sync.mesh.test.js +12 -6
- package/dist/tests/sync.mesh.test.js.map +1 -1
- package/dist/tests/sync.peerReconciliation.test.js +6 -4
- package/dist/tests/sync.peerReconciliation.test.js.map +1 -1
- package/dist/tests/sync.storage.test.js +8 -14
- package/dist/tests/sync.storage.test.js.map +1 -1
- package/dist/tests/sync.storageAsync.test.js +31 -14
- package/dist/tests/sync.storageAsync.test.js.map +1 -1
- package/dist/tests/sync.test.js +5 -9
- package/dist/tests/sync.test.js.map +1 -1
- package/dist/tests/sync.upload.test.js +31 -1
- package/dist/tests/sync.upload.test.js.map +1 -1
- package/dist/tests/testStorage.d.ts +2 -3
- package/dist/tests/testStorage.d.ts.map +1 -1
- package/dist/tests/testStorage.js +16 -8
- package/dist/tests/testStorage.js.map +1 -1
- package/dist/tests/testUtils.d.ts +4 -0
- package/dist/tests/testUtils.d.ts.map +1 -1
- package/dist/tests/testUtils.js +22 -4
- package/dist/tests/testUtils.js.map +1 -1
- package/dist/typeUtils/accountOrAgentIDfromSessionID.d.ts +2 -2
- package/dist/typeUtils/accountOrAgentIDfromSessionID.d.ts.map +1 -1
- package/dist/typeUtils/expectGroup.d.ts.map +1 -1
- package/dist/typeUtils/expectGroup.js +6 -5
- package/dist/typeUtils/expectGroup.js.map +1 -1
- package/package.json +1 -1
- package/src/coValue.ts +1 -4
- package/src/coValueContentMessage.ts +73 -0
- package/src/coValueCore/coValueCore.ts +36 -192
- package/src/coValueCore/verifiedState.ts +28 -35
- package/src/coValues/group.ts +329 -99
- package/src/ids.ts +3 -3
- package/src/localNode.ts +15 -10
- package/src/queue/LocalTransactionsSyncQueue.ts +96 -0
- package/src/queue/StoreQueue.ts +22 -12
- package/src/storage/storageAsync.ts +78 -56
- package/src/storage/storageSync.ts +66 -45
- package/src/storage/syncUtils.ts +9 -1
- package/src/storage/types.ts +6 -5
- package/src/sync.ts +47 -67
- package/src/tests/StorageApiAsync.test.ts +829 -0
- package/src/tests/StorageApiSync.test.ts +628 -0
- package/src/tests/StoreQueue.test.ts +10 -24
- package/src/tests/SyncStateManager.test.ts +22 -21
- package/src/tests/group.inheritance.test.ts +415 -1
- package/src/tests/group.removeMember.test.ts +244 -1
- package/src/tests/group.roleOf.test.ts +2 -2
- package/src/tests/group.test.ts +105 -5
- package/src/tests/sync.auth.test.ts +22 -10
- package/src/tests/sync.load.test.ts +32 -26
- package/src/tests/sync.mesh.test.ts +12 -6
- package/src/tests/sync.peerReconciliation.test.ts +6 -4
- package/src/tests/sync.storage.test.ts +8 -14
- package/src/tests/sync.storageAsync.test.ts +39 -14
- package/src/tests/sync.test.ts +6 -14
- package/src/tests/sync.upload.test.ts +38 -1
- package/src/tests/testStorage.ts +19 -13
- package/src/tests/testUtils.ts +29 -5
- package/src/typeUtils/accountOrAgentIDfromSessionID.ts +2 -2
- package/src/typeUtils/expectGroup.ts +8 -5
|
@@ -38,14 +38,6 @@ describe("SyncStateManager", () => {
|
|
|
38
38
|
const updateSpy: GlobalSyncStateListenerCallback = vi.fn();
|
|
39
39
|
const unsubscribe = subscriptionManager.subscribeToUpdates(updateSpy);
|
|
40
40
|
|
|
41
|
-
await client.node.syncManager.syncCoValue(map.core);
|
|
42
|
-
|
|
43
|
-
expect(updateSpy).toHaveBeenCalledWith(
|
|
44
|
-
peerState.id,
|
|
45
|
-
emptyKnownState(map.core.id),
|
|
46
|
-
{ uploaded: false },
|
|
47
|
-
);
|
|
48
|
-
|
|
49
41
|
await waitFor(() => {
|
|
50
42
|
return subscriptionManager.getCurrentSyncState(peerState.id, map.core.id)
|
|
51
43
|
.uploaded;
|
|
@@ -98,13 +90,6 @@ describe("SyncStateManager", () => {
|
|
|
98
90
|
unsubscribe2();
|
|
99
91
|
});
|
|
100
92
|
|
|
101
|
-
await client.node.syncManager.syncCoValue(map.core);
|
|
102
|
-
|
|
103
|
-
expect(updateToJazzCloudSpy).toHaveBeenCalledWith(
|
|
104
|
-
emptyKnownState(map.core.id),
|
|
105
|
-
{ uploaded: false },
|
|
106
|
-
);
|
|
107
|
-
|
|
108
93
|
await waitFor(() => {
|
|
109
94
|
return subscriptionManager.getCurrentSyncState(peerState.id, map.core.id)
|
|
110
95
|
.uploaded;
|
|
@@ -117,7 +102,7 @@ describe("SyncStateManager", () => {
|
|
|
117
102
|
{ uploaded: true },
|
|
118
103
|
);
|
|
119
104
|
|
|
120
|
-
expect(updateToStorageSpy).
|
|
105
|
+
expect(updateToStorageSpy).toHaveBeenCalledWith(
|
|
121
106
|
emptyKnownState(group.core.id),
|
|
122
107
|
{ uploaded: false },
|
|
123
108
|
);
|
|
@@ -133,8 +118,6 @@ describe("SyncStateManager", () => {
|
|
|
133
118
|
const map = group.createMap();
|
|
134
119
|
map.set("key1", "value1", "trusting");
|
|
135
120
|
|
|
136
|
-
await client.node.syncManager.syncCoValue(map.core);
|
|
137
|
-
|
|
138
121
|
const subscriptionManager = client.node.syncManager.syncState;
|
|
139
122
|
|
|
140
123
|
expect(
|
|
@@ -174,8 +157,6 @@ describe("SyncStateManager", () => {
|
|
|
174
157
|
unsubscribe1();
|
|
175
158
|
unsubscribe2();
|
|
176
159
|
|
|
177
|
-
await client.node.syncManager.syncCoValue(map.core);
|
|
178
|
-
|
|
179
160
|
anyUpdateSpy.mockClear();
|
|
180
161
|
|
|
181
162
|
await waitFor(() => {
|
|
@@ -336,6 +317,26 @@ describe("SyncStateManager", () => {
|
|
|
336
317
|
|
|
337
318
|
await map.core.waitForSync();
|
|
338
319
|
|
|
339
|
-
expect(client.node.getCoValue(map.id).
|
|
320
|
+
expect(client.node.getCoValue(map.id).hasVerifiedContent()).toBe(true);
|
|
321
|
+
|
|
322
|
+
// Since only the map is subscribed, the dependencies are pushed after the client requests them
|
|
323
|
+
await waitFor(() => {
|
|
324
|
+
expect(client.node.getCoValue(map.id).isAvailable()).toBe(true);
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
expect(
|
|
328
|
+
SyncMessagesLog.getMessages({
|
|
329
|
+
Map: map.core,
|
|
330
|
+
Group: group.core,
|
|
331
|
+
}),
|
|
332
|
+
).toMatchInlineSnapshot(`
|
|
333
|
+
[
|
|
334
|
+
"server -> client | CONTENT Map header: true new: After: 0 New: 1",
|
|
335
|
+
"client -> server | LOAD Group sessions: empty",
|
|
336
|
+
"client -> server | KNOWN Map sessions: header/1",
|
|
337
|
+
"server -> client | CONTENT Group header: true new: After: 0 New: 3",
|
|
338
|
+
"client -> server | KNOWN Group sessions: header/3",
|
|
339
|
+
]
|
|
340
|
+
`);
|
|
340
341
|
});
|
|
341
342
|
});
|
|
@@ -1,10 +1,21 @@
|
|
|
1
|
-
import { describe, expect, test } from "vitest";
|
|
1
|
+
import { beforeEach, describe, expect, test } from "vitest";
|
|
2
|
+
import type { CoID, RawGroup } from "../exports";
|
|
3
|
+
import { NewContentMessage } from "../sync";
|
|
2
4
|
import {
|
|
5
|
+
SyncMessagesLog,
|
|
3
6
|
createThreeConnectedNodes,
|
|
4
7
|
createTwoConnectedNodes,
|
|
5
8
|
loadCoValueOrFail,
|
|
9
|
+
setupTestNode,
|
|
6
10
|
} from "./testUtils";
|
|
7
11
|
|
|
12
|
+
let jazzCloud: ReturnType<typeof setupTestNode>;
|
|
13
|
+
|
|
14
|
+
beforeEach(async () => {
|
|
15
|
+
SyncMessagesLog.clear();
|
|
16
|
+
jazzCloud = setupTestNode({ isSyncServer: true });
|
|
17
|
+
});
|
|
18
|
+
|
|
8
19
|
describe("extend", () => {
|
|
9
20
|
test("inherited writer roles should work correctly", async () => {
|
|
10
21
|
const { node1, node2 } = await createTwoConnectedNodes("server", "server");
|
|
@@ -87,6 +98,32 @@ describe("extend", () => {
|
|
|
87
98
|
expect(mapOnNode2.get("test")).toEqual("Written from node2");
|
|
88
99
|
});
|
|
89
100
|
|
|
101
|
+
test("inherited everyone roles should work correctly", async () => {
|
|
102
|
+
const { node1, node2 } = await createTwoConnectedNodes("server", "server");
|
|
103
|
+
|
|
104
|
+
const group = node1.node.createGroup();
|
|
105
|
+
group.addMember("everyone", "writer");
|
|
106
|
+
|
|
107
|
+
const childGroup = node1.node.createGroup();
|
|
108
|
+
childGroup.extend(group);
|
|
109
|
+
|
|
110
|
+
expect(childGroup.roleOf("everyone")).toEqual("writer");
|
|
111
|
+
|
|
112
|
+
const map = childGroup.createMap();
|
|
113
|
+
map.set("test", "Written from the admin");
|
|
114
|
+
|
|
115
|
+
await map.core.waitForSync();
|
|
116
|
+
|
|
117
|
+
const mapOnNode2 = await loadCoValueOrFail(node2.node, map.id);
|
|
118
|
+
|
|
119
|
+
// The writer role should be able to see the edits from the admin
|
|
120
|
+
expect(mapOnNode2.get("test")).toEqual("Written from the admin");
|
|
121
|
+
|
|
122
|
+
mapOnNode2.set("hello", "from node 2");
|
|
123
|
+
|
|
124
|
+
expect(mapOnNode2.get("hello")).toEqual("from node 2");
|
|
125
|
+
});
|
|
126
|
+
|
|
90
127
|
test("a user should be able to extend a group when his role on the parent group is writeOnly", async () => {
|
|
91
128
|
const { node1, node2 } = await createTwoConnectedNodes("server", "server");
|
|
92
129
|
|
|
@@ -143,6 +180,132 @@ describe("extend", () => {
|
|
|
143
180
|
expect(map.get("test")).toEqual("Hello!");
|
|
144
181
|
});
|
|
145
182
|
|
|
183
|
+
test("should not break when checking for cycles on a loaded group", async () => {
|
|
184
|
+
const clientSession1 = setupTestNode({
|
|
185
|
+
connected: true,
|
|
186
|
+
});
|
|
187
|
+
const clientSession2 = clientSession1.spawnNewSession();
|
|
188
|
+
|
|
189
|
+
const group = clientSession1.node.createGroup();
|
|
190
|
+
const childGroup = clientSession1.node.createGroup();
|
|
191
|
+
const group2 = clientSession1.node.createGroup();
|
|
192
|
+
const group3 = clientSession1.node.createGroup();
|
|
193
|
+
|
|
194
|
+
childGroup.extend(group);
|
|
195
|
+
group.extend(group2);
|
|
196
|
+
group2.extend(group3);
|
|
197
|
+
|
|
198
|
+
await group.core.waitForSync();
|
|
199
|
+
await childGroup.core.waitForSync();
|
|
200
|
+
await group2.core.waitForSync();
|
|
201
|
+
await group3.core.waitForSync();
|
|
202
|
+
|
|
203
|
+
const groupOnClientSession2 = await loadCoValueOrFail(
|
|
204
|
+
clientSession2.node,
|
|
205
|
+
group.id,
|
|
206
|
+
);
|
|
207
|
+
const group3OnClientSession2 = await loadCoValueOrFail(
|
|
208
|
+
clientSession2.node,
|
|
209
|
+
group3.id,
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
expect(group3OnClientSession2.isSelfExtension(groupOnClientSession2)).toBe(
|
|
213
|
+
true,
|
|
214
|
+
);
|
|
215
|
+
|
|
216
|
+
// Child groups are not loaded as dependencies, and we want to make sure having a missing child doesn't break the extension
|
|
217
|
+
expect(clientSession2.node.getCoValue(childGroup.id).isAvailable()).toEqual(
|
|
218
|
+
false,
|
|
219
|
+
);
|
|
220
|
+
|
|
221
|
+
group3OnClientSession2.extend(groupOnClientSession2);
|
|
222
|
+
|
|
223
|
+
expect(group3OnClientSession2.getParentGroups()).toEqual([]);
|
|
224
|
+
|
|
225
|
+
const map = group3OnClientSession2.createMap();
|
|
226
|
+
map.set("test", "Hello!");
|
|
227
|
+
|
|
228
|
+
expect(map.get("test")).toEqual("Hello!");
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
test("should extend groups when loaded from a different session", async () => {
|
|
232
|
+
const clientSession1 = setupTestNode({
|
|
233
|
+
connected: true,
|
|
234
|
+
});
|
|
235
|
+
const clientSession2 = clientSession1.spawnNewSession();
|
|
236
|
+
|
|
237
|
+
const group = clientSession1.node.createGroup();
|
|
238
|
+
const group2 = clientSession1.node.createGroup();
|
|
239
|
+
|
|
240
|
+
await group.core.waitForSync();
|
|
241
|
+
await group2.core.waitForSync();
|
|
242
|
+
|
|
243
|
+
const groupOnClientSession2 = await loadCoValueOrFail(
|
|
244
|
+
clientSession2.node,
|
|
245
|
+
group.id,
|
|
246
|
+
);
|
|
247
|
+
const group2OnClientSession2 = await loadCoValueOrFail(
|
|
248
|
+
clientSession2.node,
|
|
249
|
+
group2.id,
|
|
250
|
+
);
|
|
251
|
+
|
|
252
|
+
group2OnClientSession2.extend(groupOnClientSession2);
|
|
253
|
+
|
|
254
|
+
expect(group2OnClientSession2.getParentGroups()).toEqual([
|
|
255
|
+
groupOnClientSession2,
|
|
256
|
+
]);
|
|
257
|
+
|
|
258
|
+
const map = group2OnClientSession2.createMap();
|
|
259
|
+
map.set("test", "Hello!");
|
|
260
|
+
|
|
261
|
+
expect(map.get("test")).toEqual("Hello!");
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
test("should extend groups when there is a cycle in the parent groups", async () => {
|
|
265
|
+
const clientSession1 = setupTestNode({
|
|
266
|
+
connected: true,
|
|
267
|
+
});
|
|
268
|
+
const clientSession2 = clientSession1.spawnNewSession();
|
|
269
|
+
|
|
270
|
+
const group = clientSession1.node.createGroup();
|
|
271
|
+
const group2 = clientSession1.node.createGroup();
|
|
272
|
+
|
|
273
|
+
await group.core.waitForSync();
|
|
274
|
+
await group2.core.waitForSync();
|
|
275
|
+
|
|
276
|
+
const groupOnClientSession2 = await loadCoValueOrFail(
|
|
277
|
+
clientSession2.node,
|
|
278
|
+
group.id,
|
|
279
|
+
);
|
|
280
|
+
const group2OnClientSession2 = await loadCoValueOrFail(
|
|
281
|
+
clientSession2.node,
|
|
282
|
+
group2.id,
|
|
283
|
+
);
|
|
284
|
+
|
|
285
|
+
group.extend(group2);
|
|
286
|
+
group2OnClientSession2.extend(groupOnClientSession2);
|
|
287
|
+
|
|
288
|
+
expect(group.getParentGroups()).toEqual([group2]);
|
|
289
|
+
|
|
290
|
+
expect(group2OnClientSession2.getParentGroups()).toEqual([
|
|
291
|
+
groupOnClientSession2,
|
|
292
|
+
]);
|
|
293
|
+
|
|
294
|
+
await group.core.waitForSync();
|
|
295
|
+
await group2OnClientSession2.core.waitForSync();
|
|
296
|
+
|
|
297
|
+
const group3 = clientSession1.node.createGroup();
|
|
298
|
+
|
|
299
|
+
group3.extend(group2);
|
|
300
|
+
|
|
301
|
+
expect(group3.getParentGroups()).toEqual([group2]);
|
|
302
|
+
|
|
303
|
+
const map = group3.createMap();
|
|
304
|
+
map.set("test", "Hello!");
|
|
305
|
+
|
|
306
|
+
expect(map.get("test")).toEqual("Hello!");
|
|
307
|
+
});
|
|
308
|
+
|
|
146
309
|
test("a writerInvite role should not be inherited", async () => {
|
|
147
310
|
const { node1, node2 } = await createTwoConnectedNodes("server", "server");
|
|
148
311
|
|
|
@@ -180,6 +343,257 @@ describe("extend", () => {
|
|
|
180
343
|
|
|
181
344
|
expect(childGroup.roleOf(alice.id)).toBe("writer");
|
|
182
345
|
});
|
|
346
|
+
|
|
347
|
+
test("should be possible to extend a group after getting revoked from the parent group", async () => {
|
|
348
|
+
const { node1, node2, node3 } = await createThreeConnectedNodes(
|
|
349
|
+
"server",
|
|
350
|
+
"server",
|
|
351
|
+
"server",
|
|
352
|
+
);
|
|
353
|
+
|
|
354
|
+
const parentGroup = node1.node.createGroup();
|
|
355
|
+
|
|
356
|
+
const alice = await loadCoValueOrFail(node1.node, node3.accountID);
|
|
357
|
+
const bob = await loadCoValueOrFail(node1.node, node2.accountID);
|
|
358
|
+
parentGroup.addMember(alice, "writer");
|
|
359
|
+
parentGroup.addMember(bob, "reader");
|
|
360
|
+
parentGroup.removeMember(bob);
|
|
361
|
+
|
|
362
|
+
const parentGroupOnNode2 = await loadCoValueOrFail(
|
|
363
|
+
node2.node,
|
|
364
|
+
parentGroup.id,
|
|
365
|
+
);
|
|
366
|
+
|
|
367
|
+
const childGroup = node2.node.createGroup();
|
|
368
|
+
childGroup.extend(parentGroupOnNode2);
|
|
369
|
+
|
|
370
|
+
expect(childGroup.roleOf(alice.id)).toBe("writer");
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
test("should be possible to extend when access is everyone reader and the account is revoked from the parent group", async () => {
|
|
374
|
+
const { node1, node2, node3 } = await createThreeConnectedNodes(
|
|
375
|
+
"server",
|
|
376
|
+
"server",
|
|
377
|
+
"server",
|
|
378
|
+
);
|
|
379
|
+
|
|
380
|
+
const parentGroup = node1.node.createGroup();
|
|
381
|
+
parentGroup.addMember("everyone", "reader");
|
|
382
|
+
const alice = await loadCoValueOrFail(node1.node, node3.accountID);
|
|
383
|
+
const bob = await loadCoValueOrFail(node1.node, node2.accountID);
|
|
384
|
+
parentGroup.addMember(alice, "writer");
|
|
385
|
+
parentGroup.addMember(bob, "reader");
|
|
386
|
+
parentGroup.removeMember(bob);
|
|
387
|
+
|
|
388
|
+
const parentGroupOnNode2 = await loadCoValueOrFail(
|
|
389
|
+
node2.node,
|
|
390
|
+
parentGroup.id,
|
|
391
|
+
);
|
|
392
|
+
|
|
393
|
+
const childGroup = node2.node.createGroup();
|
|
394
|
+
childGroup.extend(parentGroupOnNode2);
|
|
395
|
+
|
|
396
|
+
expect(childGroup.roleOf(alice.id)).toBe("writer");
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
test("should be able to extend when the last read key is healed", async () => {
|
|
400
|
+
const clientWithAccess = setupTestNode({
|
|
401
|
+
secret:
|
|
402
|
+
"sealerSecret_zBTPp7U58Fzq9o7EvJpu4KEziepi8QVf2Xaxuy5xmmXFx/signerSecret_z62DuviZdXCjz4EZWofvr9vaLYFXDeTaC9KWhoQiQjzKk",
|
|
403
|
+
connected: true,
|
|
404
|
+
});
|
|
405
|
+
const clientWithoutAccess = setupTestNode({
|
|
406
|
+
connected: true,
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
const brokenGroupContent = {
|
|
410
|
+
action: "content",
|
|
411
|
+
id: "co_zW7F36Nnop9A7Er4gUzBcUXnZCK",
|
|
412
|
+
header: {
|
|
413
|
+
type: "comap",
|
|
414
|
+
ruleset: {
|
|
415
|
+
type: "group",
|
|
416
|
+
initialAdmin:
|
|
417
|
+
"sealer_z12QDazYB3ygPZtBV7sMm7iYKMRnNZ6Aaj1dfLXR7LSBm/signer_z2AskZQbc82qxo7iA3oiXoNExHLsAEXC2pHbwJzRnATWv",
|
|
418
|
+
},
|
|
419
|
+
meta: null,
|
|
420
|
+
createdAt: "2025-08-06T10:14:39.617Z",
|
|
421
|
+
uniqueness: "z3LJjnuPiPJaf5Qb9A",
|
|
422
|
+
},
|
|
423
|
+
priority: 0,
|
|
424
|
+
new: {
|
|
425
|
+
"sealer_z12QDazYB3ygPZtBV7sMm7iYKMRnNZ6Aaj1dfLXR7LSBm/signer_z2AskZQbc82qxo7iA3oiXoNExHLsAEXC2pHbwJzRnATWv_session_zYLsz2CiW9pW":
|
|
426
|
+
{
|
|
427
|
+
after: 0,
|
|
428
|
+
newTransactions: [
|
|
429
|
+
{
|
|
430
|
+
privacy: "trusting",
|
|
431
|
+
madeAt: 1754475279619,
|
|
432
|
+
changes:
|
|
433
|
+
'[{"key":"sealer_z12QDazYB3ygPZtBV7sMm7iYKMRnNZ6Aaj1dfLXR7LSBm/signer_z2AskZQbc82qxo7iA3oiXoNExHLsAEXC2pHbwJzRnATWv","op":"set","value":"admin"}]',
|
|
434
|
+
},
|
|
435
|
+
{
|
|
436
|
+
privacy: "trusting",
|
|
437
|
+
madeAt: 1754475279621,
|
|
438
|
+
changes:
|
|
439
|
+
'[{"key":"key_z5CVahfMkEWPj1B3zH_for_sealer_z12QDazYB3ygPZtBV7sMm7iYKMRnNZ6Aaj1dfLXR7LSBm/signer_z2AskZQbc82qxo7iA3oiXoNExHLsAEXC2pHbwJzRnATWv","op":"set","value":"sealed_UCg4UkytXF-W8PaIvaDffO3pZ3d9hdXUuNkQQEikPTAuOD9us92Pqb5Vgu7lx1Fpb0X8V5BJ2yxz6_D5WOzK3qjWBSsc7J1xDJA=="}]',
|
|
440
|
+
},
|
|
441
|
+
{
|
|
442
|
+
privacy: "trusting",
|
|
443
|
+
madeAt: 1754475279621,
|
|
444
|
+
changes:
|
|
445
|
+
'[{"key":"readKey","op":"set","value":"key_z5CVahfMkEWPj1B3zH"}]',
|
|
446
|
+
},
|
|
447
|
+
{
|
|
448
|
+
privacy: "trusting",
|
|
449
|
+
madeAt: 1754475279622,
|
|
450
|
+
changes: '[{"key":"everyone","op":"set","value":"reader"}]',
|
|
451
|
+
},
|
|
452
|
+
{
|
|
453
|
+
privacy: "trusting",
|
|
454
|
+
madeAt: 1754475279623,
|
|
455
|
+
changes:
|
|
456
|
+
'[{"key":"key_z5CVahfMkEWPj1B3zH_for_everyone","op":"set","value":"keySecret_z9U9gzkahQXCxDoSw7isiUnbobXwuLdcSkL9Ci6ZEEkaL"}]',
|
|
457
|
+
},
|
|
458
|
+
{
|
|
459
|
+
privacy: "trusting",
|
|
460
|
+
madeAt: 1754475279623,
|
|
461
|
+
changes:
|
|
462
|
+
'[{"key":"key_z4Fi7hZNBx7XoVAKkP_for_sealer_z12QDazYB3ygPZtBV7sMm7iYKMRnNZ6Aaj1dfLXR7LSBm/signer_z2AskZQbc82qxo7iA3oiXoNExHLsAEXC2pHbwJzRnATWv","op":"set","value":"sealed_UuCBBfZkTnRTrGraqWWlzm9JE-VFduhsfu7WaZjpCbJYOTXpPhSNOnzGeS8qVuIsG6dORbME22lc5ltLxPjRqofQdDCNGQehCeQ=="}]',
|
|
463
|
+
},
|
|
464
|
+
{
|
|
465
|
+
privacy: "trusting",
|
|
466
|
+
madeAt: 1754475279624,
|
|
467
|
+
changes:
|
|
468
|
+
'[{"key":"key_z5CVahfMkEWPj1B3zH_for_key_z4Fi7hZNBx7XoVAKkP","op":"set","value":"encrypted_USTrBuobwTCORwy5yHxy4sFZ7swfrafP6k5ZwcTf76f0MBu9Ie-JmsX3mNXad4mluI47gvGXzi8I_"}]',
|
|
469
|
+
},
|
|
470
|
+
{
|
|
471
|
+
privacy: "trusting",
|
|
472
|
+
madeAt: 1754475279624,
|
|
473
|
+
changes:
|
|
474
|
+
'[{"key":"readKey","op":"set","value":"key_z4Fi7hZNBx7XoVAKkP"}]',
|
|
475
|
+
},
|
|
476
|
+
],
|
|
477
|
+
lastSignature:
|
|
478
|
+
"signature_z3tsE7U1JaeNeUmZ4EY3Xq5uQ9jq9jDi6Rkhdt7T7b7z4NCnpMgB4bo8TwLXYVCrRdBm6PoyyPdK8fYFzHJUh5EzA",
|
|
479
|
+
},
|
|
480
|
+
},
|
|
481
|
+
} as unknown as NewContentMessage;
|
|
482
|
+
|
|
483
|
+
clientWithAccess.node.syncManager.handleNewContent(
|
|
484
|
+
brokenGroupContent,
|
|
485
|
+
"import",
|
|
486
|
+
);
|
|
487
|
+
|
|
488
|
+
// Load the CoValue to recover the key_for_everyone
|
|
489
|
+
await loadCoValueOrFail(
|
|
490
|
+
clientWithAccess.node,
|
|
491
|
+
brokenGroupContent.id as CoID<RawGroup>,
|
|
492
|
+
);
|
|
493
|
+
|
|
494
|
+
const group = await loadCoValueOrFail(
|
|
495
|
+
clientWithoutAccess.node,
|
|
496
|
+
brokenGroupContent.id as CoID<RawGroup>,
|
|
497
|
+
);
|
|
498
|
+
const childGroup = clientWithoutAccess.node.createGroup();
|
|
499
|
+
childGroup.extend(group);
|
|
500
|
+
|
|
501
|
+
expect(childGroup.getParentGroups()).toEqual([group]);
|
|
502
|
+
});
|
|
503
|
+
|
|
504
|
+
test("should be able to extend when the last read key is missing", async () => {
|
|
505
|
+
const clientWithoutAccess = setupTestNode({
|
|
506
|
+
connected: true,
|
|
507
|
+
});
|
|
508
|
+
|
|
509
|
+
const brokenGroupContent = {
|
|
510
|
+
action: "content",
|
|
511
|
+
id: "co_zW7F36Nnop9A7Er4gUzBcUXnZCK",
|
|
512
|
+
header: {
|
|
513
|
+
type: "comap",
|
|
514
|
+
ruleset: {
|
|
515
|
+
type: "group",
|
|
516
|
+
initialAdmin:
|
|
517
|
+
"sealer_z12QDazYB3ygPZtBV7sMm7iYKMRnNZ6Aaj1dfLXR7LSBm/signer_z2AskZQbc82qxo7iA3oiXoNExHLsAEXC2pHbwJzRnATWv",
|
|
518
|
+
},
|
|
519
|
+
meta: null,
|
|
520
|
+
createdAt: "2025-08-06T10:14:39.617Z",
|
|
521
|
+
uniqueness: "z3LJjnuPiPJaf5Qb9A",
|
|
522
|
+
},
|
|
523
|
+
priority: 0,
|
|
524
|
+
new: {
|
|
525
|
+
"sealer_z12QDazYB3ygPZtBV7sMm7iYKMRnNZ6Aaj1dfLXR7LSBm/signer_z2AskZQbc82qxo7iA3oiXoNExHLsAEXC2pHbwJzRnATWv_session_zYLsz2CiW9pW":
|
|
526
|
+
{
|
|
527
|
+
after: 0,
|
|
528
|
+
newTransactions: [
|
|
529
|
+
{
|
|
530
|
+
privacy: "trusting",
|
|
531
|
+
madeAt: 1754475279619,
|
|
532
|
+
changes:
|
|
533
|
+
'[{"key":"sealer_z12QDazYB3ygPZtBV7sMm7iYKMRnNZ6Aaj1dfLXR7LSBm/signer_z2AskZQbc82qxo7iA3oiXoNExHLsAEXC2pHbwJzRnATWv","op":"set","value":"admin"}]',
|
|
534
|
+
},
|
|
535
|
+
{
|
|
536
|
+
privacy: "trusting",
|
|
537
|
+
madeAt: 1754475279621,
|
|
538
|
+
changes:
|
|
539
|
+
'[{"key":"key_z5CVahfMkEWPj1B3zH_for_sealer_z12QDazYB3ygPZtBV7sMm7iYKMRnNZ6Aaj1dfLXR7LSBm/signer_z2AskZQbc82qxo7iA3oiXoNExHLsAEXC2pHbwJzRnATWv","op":"set","value":"sealed_UCg4UkytXF-W8PaIvaDffO3pZ3d9hdXUuNkQQEikPTAuOD9us92Pqb5Vgu7lx1Fpb0X8V5BJ2yxz6_D5WOzK3qjWBSsc7J1xDJA=="}]',
|
|
540
|
+
},
|
|
541
|
+
{
|
|
542
|
+
privacy: "trusting",
|
|
543
|
+
madeAt: 1754475279621,
|
|
544
|
+
changes:
|
|
545
|
+
'[{"key":"readKey","op":"set","value":"key_z5CVahfMkEWPj1B3zH"}]',
|
|
546
|
+
},
|
|
547
|
+
{
|
|
548
|
+
privacy: "trusting",
|
|
549
|
+
madeAt: 1754475279622,
|
|
550
|
+
changes: '[{"key":"everyone","op":"set","value":"reader"}]',
|
|
551
|
+
},
|
|
552
|
+
{
|
|
553
|
+
privacy: "trusting",
|
|
554
|
+
madeAt: 1754475279623,
|
|
555
|
+
changes:
|
|
556
|
+
'[{"key":"key_z5CVahfMkEWPj1B3zH_for_everyone","op":"set","value":"keySecret_z9U9gzkahQXCxDoSw7isiUnbobXwuLdcSkL9Ci6ZEEkaL"}]',
|
|
557
|
+
},
|
|
558
|
+
{
|
|
559
|
+
privacy: "trusting",
|
|
560
|
+
madeAt: 1754475279623,
|
|
561
|
+
changes:
|
|
562
|
+
'[{"key":"key_z4Fi7hZNBx7XoVAKkP_for_sealer_z12QDazYB3ygPZtBV7sMm7iYKMRnNZ6Aaj1dfLXR7LSBm/signer_z2AskZQbc82qxo7iA3oiXoNExHLsAEXC2pHbwJzRnATWv","op":"set","value":"sealed_UuCBBfZkTnRTrGraqWWlzm9JE-VFduhsfu7WaZjpCbJYOTXpPhSNOnzGeS8qVuIsG6dORbME22lc5ltLxPjRqofQdDCNGQehCeQ=="}]',
|
|
563
|
+
},
|
|
564
|
+
{
|
|
565
|
+
privacy: "trusting",
|
|
566
|
+
madeAt: 1754475279624,
|
|
567
|
+
changes:
|
|
568
|
+
'[{"key":"key_z5CVahfMkEWPj1B3zH_for_key_z4Fi7hZNBx7XoVAKkP","op":"set","value":"encrypted_USTrBuobwTCORwy5yHxy4sFZ7swfrafP6k5ZwcTf76f0MBu9Ie-JmsX3mNXad4mluI47gvGXzi8I_"}]',
|
|
569
|
+
},
|
|
570
|
+
{
|
|
571
|
+
privacy: "trusting",
|
|
572
|
+
madeAt: 1754475279624,
|
|
573
|
+
changes:
|
|
574
|
+
'[{"key":"readKey","op":"set","value":"key_z4Fi7hZNBx7XoVAKkP"}]',
|
|
575
|
+
},
|
|
576
|
+
],
|
|
577
|
+
lastSignature:
|
|
578
|
+
"signature_z3tsE7U1JaeNeUmZ4EY3Xq5uQ9jq9jDi6Rkhdt7T7b7z4NCnpMgB4bo8TwLXYVCrRdBm6PoyyPdK8fYFzHJUh5EzA",
|
|
579
|
+
},
|
|
580
|
+
},
|
|
581
|
+
} as unknown as NewContentMessage;
|
|
582
|
+
|
|
583
|
+
clientWithoutAccess.node.syncManager.handleNewContent(
|
|
584
|
+
brokenGroupContent,
|
|
585
|
+
"import",
|
|
586
|
+
);
|
|
587
|
+
|
|
588
|
+
const group = await loadCoValueOrFail(
|
|
589
|
+
clientWithoutAccess.node,
|
|
590
|
+
brokenGroupContent.id as CoID<RawGroup>,
|
|
591
|
+
);
|
|
592
|
+
const childGroup = clientWithoutAccess.node.createGroup();
|
|
593
|
+
childGroup.extend(group);
|
|
594
|
+
|
|
595
|
+
expect(childGroup.getParentGroups()).toEqual([group]);
|
|
596
|
+
});
|
|
183
597
|
});
|
|
184
598
|
|
|
185
599
|
describe("unextend", () => {
|