cojson 0.13.30 → 0.13.33

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.
Files changed (46) hide show
  1. package/.turbo/turbo-build.log +5 -4
  2. package/.turbo/turbo-lint.log +4 -0
  3. package/.turbo/turbo-test.log +1001 -0
  4. package/CHANGELOG.md +13 -0
  5. package/dist/coValueCore/coValueCore.d.ts.map +1 -1
  6. package/dist/coValueCore/coValueCore.js +1 -4
  7. package/dist/coValueCore/coValueCore.js.map +1 -1
  8. package/dist/coValues/group.d.ts.map +1 -1
  9. package/dist/coValues/group.js +4 -1
  10. package/dist/coValues/group.js.map +1 -1
  11. package/dist/localNode.d.ts.map +1 -1
  12. package/dist/localNode.js +1 -1
  13. package/dist/localNode.js.map +1 -1
  14. package/dist/permissions.d.ts.map +1 -1
  15. package/dist/permissions.js +0 -12
  16. package/dist/permissions.js.map +1 -1
  17. package/dist/tests/group.inheritance.test.d.ts +2 -0
  18. package/dist/tests/group.inheritance.test.d.ts.map +1 -0
  19. package/dist/tests/group.inheritance.test.js +235 -0
  20. package/dist/tests/group.inheritance.test.js.map +1 -0
  21. package/dist/tests/group.invite.test.d.ts +2 -0
  22. package/dist/tests/group.invite.test.d.ts.map +1 -0
  23. package/dist/tests/group.invite.test.js +214 -0
  24. package/dist/tests/group.invite.test.js.map +1 -0
  25. package/dist/tests/group.removeMember.test.js +22 -0
  26. package/dist/tests/group.removeMember.test.js.map +1 -1
  27. package/dist/tests/group.roleOf.test.d.ts +2 -0
  28. package/dist/tests/group.roleOf.test.d.ts.map +1 -0
  29. package/dist/tests/group.roleOf.test.js +275 -0
  30. package/dist/tests/group.roleOf.test.js.map +1 -0
  31. package/dist/tests/group.test.js +1 -505
  32. package/dist/tests/group.test.js.map +1 -1
  33. package/dist/tests/permissions.test.js +0 -33
  34. package/dist/tests/permissions.test.js.map +1 -1
  35. package/package.json +1 -1
  36. package/src/coValueCore/coValueCore.ts +1 -6
  37. package/src/coValues/group.ts +4 -1
  38. package/src/localNode.ts +3 -1
  39. package/src/permissions.ts +0 -18
  40. package/src/tests/group.inheritance.test.ts +418 -0
  41. package/src/tests/group.invite.test.ts +354 -0
  42. package/src/tests/group.removeMember.test.ts +48 -0
  43. package/src/tests/group.roleOf.test.ts +450 -0
  44. package/src/tests/group.test.ts +0 -852
  45. package/src/tests/permissions.test.ts +0 -52
  46. package/src/tests/sync.invite.test.ts +12 -4
@@ -0,0 +1,450 @@
1
+ import { describe, expect, test } from "vitest";
2
+ import { RawAccountID } from "../exports";
3
+ import {
4
+ createThreeConnectedNodes,
5
+ createTwoConnectedNodes,
6
+ loadCoValueOrFail,
7
+ nodeWithRandomAgentAndSessionID,
8
+ randomAgentAndSessionID,
9
+ waitFor,
10
+ } from "./testUtils";
11
+
12
+ describe("roleOf", () => {
13
+ test("returns direct role assignments", () => {
14
+ const node = nodeWithRandomAgentAndSessionID();
15
+ const group = node.createGroup();
16
+ const [agent2] = randomAgentAndSessionID();
17
+
18
+ group.addMember(agent2, "writer");
19
+ expect(group.roleOfInternal(agent2.id)).toEqual("writer");
20
+ });
21
+
22
+ test("returns undefined for non-members", () => {
23
+ const node = nodeWithRandomAgentAndSessionID();
24
+ const group = node.createGroup();
25
+ const [agent2] = randomAgentAndSessionID();
26
+
27
+ expect(group.roleOfInternal(agent2.id)).toEqual(undefined);
28
+ });
29
+
30
+ test("revoked roles return undefined", () => {
31
+ const node = nodeWithRandomAgentAndSessionID();
32
+ const group = node.createGroup();
33
+ const [agent2] = randomAgentAndSessionID();
34
+
35
+ group.addMember(agent2, "writer");
36
+ group.removeMemberInternal(agent2);
37
+ expect(group.roleOfInternal(agent2.id)).toEqual(undefined);
38
+ });
39
+
40
+ test("everyone role applies to all accounts", () => {
41
+ const node = nodeWithRandomAgentAndSessionID();
42
+ const group = node.createGroup();
43
+ const [agent2, sessionID2] = randomAgentAndSessionID();
44
+
45
+ group.addMemberInternal("everyone", "reader");
46
+ expect(group.roleOfInternal(agent2.id)).toEqual("reader");
47
+ });
48
+
49
+ test("account role overrides everyone role", () => {
50
+ const node = nodeWithRandomAgentAndSessionID();
51
+ const group = node.createGroup();
52
+ const [agent2, sessionID2] = randomAgentAndSessionID();
53
+
54
+ group.addMemberInternal("everyone", "writer");
55
+ group.addMember(agent2, "reader");
56
+ expect(group.roleOfInternal(agent2.id)).toEqual("reader");
57
+ });
58
+
59
+ test("Revoking access on everyone role should not affect existing members", () => {
60
+ const node = nodeWithRandomAgentAndSessionID();
61
+ const group = node.createGroup();
62
+ const [agent2, sessionID2] = randomAgentAndSessionID();
63
+
64
+ group.addMemberInternal("everyone", "reader");
65
+ group.addMember(agent2, "writer");
66
+ group.removeMemberInternal("everyone");
67
+ expect(group.roleOfInternal(agent2.id)).toEqual("writer");
68
+ expect(group.roleOfInternal("123" as RawAccountID)).toEqual(undefined);
69
+ });
70
+
71
+ test("Everyone role is inherited following the most permissive algorithm", () => {
72
+ const node = nodeWithRandomAgentAndSessionID();
73
+ const group = node.createGroup();
74
+ const [agent2, sessionID2] = randomAgentAndSessionID();
75
+
76
+ const parentGroup = node.createGroup();
77
+ parentGroup.addMemberInternal("everyone", "writer");
78
+
79
+ group.extend(parentGroup);
80
+ group.addMember(agent2, "reader");
81
+
82
+ expect(group.roleOfInternal(agent2.id)).toEqual("writer");
83
+ });
84
+ test("roleOf should prioritize explicit account role over everyone role in same group", async () => {
85
+ const { node1, node2 } = await createTwoConnectedNodes("server", "server");
86
+
87
+ const group = node1.node.createGroup();
88
+ const account2 = await loadCoValueOrFail(node1.node, node2.accountID);
89
+
90
+ // Add both everyone and specific account
91
+ group.addMember("everyone", "reader");
92
+ group.addMember(account2, "writer");
93
+
94
+ // Should return the explicit role, not everyone's role
95
+ expect(group.roleOf(node2.accountID)).toEqual("writer");
96
+
97
+ // Change everyone's role
98
+ group.addMember("everyone", "writer");
99
+
100
+ // Should still return the explicit role
101
+ expect(group.roleOf(node2.accountID)).toEqual("writer");
102
+ });
103
+
104
+ test("roleOf should prioritize inherited everyone role over explicit account role", async () => {
105
+ const { node1, node2 } = await createTwoConnectedNodes("server", "server");
106
+
107
+ const parentGroup = node1.node.createGroup();
108
+ const childGroup = node1.node.createGroup();
109
+ const account2 = await loadCoValueOrFail(node1.node, node2.accountID);
110
+
111
+ // Set up inheritance
112
+ childGroup.extend(parentGroup);
113
+
114
+ // Add everyone to parent and account to child
115
+ parentGroup.addMember("everyone", "writer");
116
+ childGroup.addMember(account2, "reader");
117
+
118
+ // Should return the explicit role from child, not inherited everyone role
119
+ expect(childGroup.roleOf(node2.accountID)).toEqual("writer");
120
+ });
121
+
122
+ test("roleOf should use everyone role when no explicit role exists", async () => {
123
+ const { node1, node2 } = await createTwoConnectedNodes("server", "server");
124
+
125
+ const group = node1.node.createGroup();
126
+
127
+ // Add only everyone role
128
+ group.addMember("everyone", "reader");
129
+
130
+ // Should return everyone's role when no explicit role exists
131
+ expect(group.roleOf(node2.accountID)).toEqual("reader");
132
+ });
133
+
134
+ test("roleOf should inherit everyone role from parent when no explicit roles exist", async () => {
135
+ const { node1, node2 } = await createTwoConnectedNodes("server", "server");
136
+
137
+ const parentGroup = node1.node.createGroup();
138
+ const childGroup = node1.node.createGroup();
139
+
140
+ // Set up inheritance
141
+ childGroup.extend(parentGroup);
142
+
143
+ // Add everyone to parent only
144
+ parentGroup.addMember("everyone", "reader");
145
+
146
+ // Should inherit everyone's role from parent
147
+ expect(childGroup.roleOf(node2.accountID)).toEqual("reader");
148
+ });
149
+
150
+ test("roleOf should handle everyone role inheritance through multiple levels", async () => {
151
+ const { node1, node2 } = await createTwoConnectedNodes("server", "server");
152
+
153
+ const grandParentGroup = node1.node.createGroup();
154
+ const parentGroup = node1.node.createGroup();
155
+ const childGroup = node1.node.createGroup();
156
+
157
+ const childGroupOnNode2 = await loadCoValueOrFail(
158
+ node2.node,
159
+ childGroup.id,
160
+ );
161
+
162
+ const account2 = await loadCoValueOrFail(node1.node, node2.accountID);
163
+
164
+ // Set up inheritance chain
165
+ parentGroup.extend(grandParentGroup);
166
+ childGroup.extend(parentGroup);
167
+
168
+ // Add everyone to grandparent
169
+ grandParentGroup.addMember("everyone", "writer");
170
+
171
+ // Should inherit everyone's role from grandparent
172
+ expect(childGroup.roleOf(node2.accountID)).toEqual("writer");
173
+
174
+ // Add explicit role in parent
175
+ parentGroup.addMember(account2, "reader");
176
+
177
+ // Should use parent's explicit role instead of grandparent's everyone role
178
+ expect(childGroup.roleOf(node2.accountID)).toEqual("writer");
179
+
180
+ // Add explicit role in child
181
+ childGroup.addMember(account2, "admin");
182
+ await childGroup.core.waitForSync();
183
+
184
+ // Should use child's explicit role
185
+ expect(childGroup.roleOf(node2.accountID)).toEqual("admin");
186
+
187
+ // Remove child's explicit role
188
+ await childGroupOnNode2.removeMember(account2);
189
+ await childGroupOnNode2.core.waitForSync();
190
+
191
+ // Should fall back to parent's explicit role
192
+ expect(childGroup.roleOf(node2.accountID)).toEqual("writer");
193
+
194
+ // Remove parent's explicit role
195
+ await parentGroup.removeMember(account2);
196
+ await childGroup.core.waitForSync();
197
+
198
+ // Should fall back to grandparent's everyone role
199
+ expect(childGroup.roleOf(node2.accountID)).toEqual("writer");
200
+ });
201
+
202
+ describe("writeOnly can be used as a role for everyone", () => {
203
+ test("writeOnly can be used as a role for everyone", async () => {
204
+ const { node1, node2 } = await createTwoConnectedNodes(
205
+ "server",
206
+ "server",
207
+ );
208
+
209
+ const group = node1.node.createGroup();
210
+
211
+ group.addMember("everyone", "writeOnly");
212
+
213
+ const map = group.createMap();
214
+
215
+ const groupOnNode2 = await loadCoValueOrFail(node2.node, group.id);
216
+
217
+ expect(groupOnNode2.myRole()).toEqual("writeOnly");
218
+
219
+ const mapOnNode2 = await loadCoValueOrFail(node2.node, map.id);
220
+
221
+ mapOnNode2.set("test", "Written from everyone");
222
+
223
+ await waitFor(async () => {
224
+ const mapOnNode1 = await loadCoValueOrFail(node1.node, map.id);
225
+ expect(mapOnNode1.get("test")).toEqual("Written from everyone");
226
+ });
227
+ });
228
+
229
+ test("switching from everyone reader to writeOnly", async () => {
230
+ const { node1, node2 } = await createTwoConnectedNodes(
231
+ "server",
232
+ "server",
233
+ );
234
+
235
+ const group = node1.node.createGroup();
236
+
237
+ group.addMember("everyone", "reader");
238
+
239
+ group.addMember("everyone", "writeOnly");
240
+
241
+ const map = group.createMap();
242
+
243
+ map.set("test", "Written from admin");
244
+
245
+ const groupOnNode2 = await loadCoValueOrFail(node2.node, group.id);
246
+
247
+ expect(groupOnNode2.myRole()).toEqual("writeOnly");
248
+
249
+ const mapOnNode2 = await loadCoValueOrFail(node2.node, map.id);
250
+
251
+ expect(mapOnNode2.get("test")).toEqual(undefined);
252
+
253
+ mapOnNode2.set("test", "Written from everyone");
254
+
255
+ await waitFor(async () => {
256
+ const mapOnNode1 = await loadCoValueOrFail(node1.node, map.id);
257
+ expect(mapOnNode1.get("test")).toEqual("Written from everyone");
258
+ });
259
+ });
260
+
261
+ test("switching from everyone writer to writeOnly", async () => {
262
+ const { node1, node2 } = await createTwoConnectedNodes(
263
+ "server",
264
+ "server",
265
+ );
266
+
267
+ const group = node1.node.createGroup();
268
+
269
+ group.addMember("everyone", "writer");
270
+
271
+ group.addMember("everyone", "writeOnly");
272
+
273
+ const map = group.createMap();
274
+
275
+ map.set("test", "Written from admin");
276
+
277
+ const groupOnNode2 = await loadCoValueOrFail(node2.node, group.id);
278
+
279
+ expect(groupOnNode2.myRole()).toEqual("writeOnly");
280
+
281
+ const mapOnNode2 = await loadCoValueOrFail(node2.node, map.id);
282
+
283
+ expect(mapOnNode2.get("test")).toEqual(undefined);
284
+
285
+ mapOnNode2.set("test", "Written from everyone");
286
+
287
+ await waitFor(async () => {
288
+ const mapOnNode1 = await loadCoValueOrFail(node1.node, map.id);
289
+ expect(mapOnNode1.get("test")).toEqual("Written from everyone");
290
+ });
291
+ });
292
+
293
+ test("switching from everyone writeOnly to reader", async () => {
294
+ const { node1, node2 } = await createTwoConnectedNodes(
295
+ "server",
296
+ "server",
297
+ );
298
+
299
+ const group = node1.node.createGroup();
300
+
301
+ group.addMember("everyone", "writeOnly");
302
+
303
+ const map = group.createMap();
304
+
305
+ map.set("fromAdmin", "Written from admin");
306
+
307
+ const groupOnNode2 = await loadCoValueOrFail(node2.node, group.id);
308
+
309
+ expect(groupOnNode2.myRole()).toEqual("writeOnly");
310
+
311
+ const mapOnNode2 = await loadCoValueOrFail(node2.node, map.id);
312
+
313
+ expect(mapOnNode2.get("test")).toEqual(undefined);
314
+
315
+ mapOnNode2.set("test", "Written from everyone");
316
+
317
+ await waitFor(async () => {
318
+ const mapOnNode1 = await loadCoValueOrFail(node1.node, map.id);
319
+ expect(mapOnNode1.get("test")).toEqual("Written from everyone");
320
+ });
321
+
322
+ group.addMember("everyone", "reader");
323
+
324
+ await group.core.waitForSync();
325
+
326
+ mapOnNode2.set("test", "Updated after the downgrade");
327
+
328
+ expect(mapOnNode2.get("test")).toEqual("Written from everyone");
329
+ expect(mapOnNode2.get("fromAdmin")).toEqual("Written from admin");
330
+ });
331
+
332
+ test("switching from everyone writeOnly to writer", async () => {
333
+ const { node1, node2 } = await createTwoConnectedNodes(
334
+ "server",
335
+ "server",
336
+ );
337
+
338
+ const group = node1.node.createGroup();
339
+
340
+ group.addMember("everyone", "writeOnly");
341
+
342
+ const map = group.createMap();
343
+
344
+ map.set("fromAdmin", "Written from admin");
345
+
346
+ const groupOnNode2 = await loadCoValueOrFail(node2.node, group.id);
347
+
348
+ expect(groupOnNode2.myRole()).toEqual("writeOnly");
349
+
350
+ const mapOnNode2 = await loadCoValueOrFail(node2.node, map.id);
351
+
352
+ expect(mapOnNode2.get("test")).toEqual(undefined);
353
+
354
+ mapOnNode2.set("test", "Written from everyone");
355
+
356
+ await waitFor(async () => {
357
+ const mapOnNode1 = await loadCoValueOrFail(node1.node, map.id);
358
+ expect(mapOnNode1.get("test")).toEqual("Written from everyone");
359
+ });
360
+
361
+ group.addMember("everyone", "writer");
362
+
363
+ await group.core.waitForSync();
364
+
365
+ mapOnNode2.set("test", "Updated after the upgrade");
366
+
367
+ expect(mapOnNode2.get("test")).toEqual("Updated after the upgrade");
368
+ expect(mapOnNode2.get("fromAdmin")).toEqual("Written from admin");
369
+ });
370
+
371
+ test("adding a reader member after writeOnly", async () => {
372
+ const { node1, node2, node3 } = await createThreeConnectedNodes(
373
+ "server",
374
+ "server",
375
+ "server",
376
+ );
377
+
378
+ const group = node1.node.createGroup();
379
+
380
+ group.addMember("everyone", "writeOnly");
381
+
382
+ const map = group.createMap();
383
+
384
+ map.set("fromAdmin", "Written from admin");
385
+
386
+ const groupOnNode2 = await loadCoValueOrFail(node2.node, group.id);
387
+
388
+ expect(groupOnNode2.myRole()).toEqual("writeOnly");
389
+
390
+ const mapOnNode2 = await loadCoValueOrFail(node2.node, map.id);
391
+
392
+ expect(mapOnNode2.get("test")).toEqual(undefined);
393
+
394
+ mapOnNode2.set("test", "Written from everyone");
395
+
396
+ await waitFor(async () => {
397
+ const mapOnNode1 = await loadCoValueOrFail(node1.node, map.id);
398
+ expect(mapOnNode1.get("test")).toEqual("Written from everyone");
399
+ });
400
+
401
+ const account3 = await loadCoValueOrFail(node1.node, node3.accountID);
402
+
403
+ group.addMember(account3, "reader");
404
+
405
+ await group.core.waitForSync();
406
+
407
+ const mapOnNode3 = await loadCoValueOrFail(node3.node, map.id);
408
+
409
+ expect(mapOnNode3.get("test")).toEqual("Written from everyone");
410
+ });
411
+
412
+ test.skip("adding a reader member while creating the writeOnly keys", async () => {
413
+ const { node1, node2, node3 } = await createThreeConnectedNodes(
414
+ "server",
415
+ "server",
416
+ "server",
417
+ );
418
+ const account3 = await loadCoValueOrFail(node1.node, node3.accountID);
419
+ const group = node1.node.createGroup();
420
+
421
+ group.addMember("everyone", "writeOnly");
422
+
423
+ const map = group.createMap();
424
+
425
+ map.set("fromAdmin", "Written from admin");
426
+
427
+ const groupOnNode2 = await loadCoValueOrFail(node2.node, group.id);
428
+
429
+ expect(groupOnNode2.myRole()).toEqual("writeOnly");
430
+
431
+ const mapOnNode2 = await loadCoValueOrFail(node2.node, map.id);
432
+ group.addMember(account3, "reader");
433
+
434
+ expect(mapOnNode2.get("test")).toEqual(undefined);
435
+
436
+ mapOnNode2.set("test", "Written from everyone");
437
+
438
+ await waitFor(async () => {
439
+ const mapOnNode1 = await loadCoValueOrFail(node1.node, map.id);
440
+ expect(mapOnNode1.get("test")).toEqual("Written from everyone");
441
+ });
442
+
443
+ await group.core.waitForSync();
444
+
445
+ const mapOnNode3 = await loadCoValueOrFail(node3.node, map.id);
446
+
447
+ expect(mapOnNode3.get("test")).toEqual("Written from everyone");
448
+ });
449
+ });
450
+ });