cojson 0.8.32 → 0.8.35

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/CHANGELOG.md +15 -0
  2. package/dist/native/coValueCore.js +73 -37
  3. package/dist/native/coValueCore.js.map +1 -1
  4. package/dist/native/coValues/coMap.js +2 -2
  5. package/dist/native/coValues/coMap.js.map +1 -1
  6. package/dist/native/coValues/group.js +132 -5
  7. package/dist/native/coValues/group.js.map +1 -1
  8. package/dist/native/exports.js +5 -2
  9. package/dist/native/exports.js.map +1 -1
  10. package/dist/native/ids.js +33 -0
  11. package/dist/native/ids.js.map +1 -1
  12. package/dist/native/permissions.js +206 -145
  13. package/dist/native/permissions.js.map +1 -1
  14. package/dist/native/storage/index.js +8 -4
  15. package/dist/native/storage/index.js.map +1 -1
  16. package/dist/native/sync.js +41 -31
  17. package/dist/native/sync.js.map +1 -1
  18. package/dist/web/coValueCore.js +73 -37
  19. package/dist/web/coValueCore.js.map +1 -1
  20. package/dist/web/coValues/coMap.js +2 -2
  21. package/dist/web/coValues/coMap.js.map +1 -1
  22. package/dist/web/coValues/group.js +132 -5
  23. package/dist/web/coValues/group.js.map +1 -1
  24. package/dist/web/exports.js +5 -2
  25. package/dist/web/exports.js.map +1 -1
  26. package/dist/web/ids.js +33 -0
  27. package/dist/web/ids.js.map +1 -1
  28. package/dist/web/permissions.js +206 -145
  29. package/dist/web/permissions.js.map +1 -1
  30. package/dist/web/storage/index.js +8 -4
  31. package/dist/web/storage/index.js.map +1 -1
  32. package/dist/web/sync.js +41 -31
  33. package/dist/web/sync.js.map +1 -1
  34. package/package.json +1 -1
  35. package/src/coValueCore.ts +119 -46
  36. package/src/coValues/coMap.ts +3 -6
  37. package/src/coValues/group.ts +219 -6
  38. package/src/exports.ts +18 -3
  39. package/src/ids.ts +48 -0
  40. package/src/permissions.ts +297 -204
  41. package/src/storage/index.ts +12 -4
  42. package/src/sync.ts +43 -34
  43. package/src/tests/group.test.ts +152 -1
  44. package/src/tests/permissions.test.ts +785 -2
  45. package/src/tests/sync.test.ts +29 -0
  46. package/src/tests/testUtils.ts +102 -1
@@ -5,7 +5,13 @@ import { RawCoStream } from "../coValues/coStream.js";
5
5
  import { RawBinaryCoStream } from "../coValues/coStream.js";
6
6
  import { WasmCrypto } from "../crypto/WasmCrypto.js";
7
7
  import { LocalNode } from "../localNode.js";
8
- import { randomAnonymousAccountAndSessionID } from "./testUtils.js";
8
+ import {
9
+ createThreeConnectedNodes,
10
+ createTwoConnectedNodes,
11
+ loadCoValueOrFail,
12
+ randomAnonymousAccountAndSessionID,
13
+ waitFor,
14
+ } from "./testUtils.js";
9
15
 
10
16
  const Crypto = await WasmCrypto.create();
11
17
 
@@ -53,3 +59,148 @@ test("Can create a FileStream in a group", () => {
53
59
  expect(stream.headerMeta.type).toEqual("binary");
54
60
  expect(stream instanceof RawBinaryCoStream).toEqual(true);
55
61
  });
62
+
63
+ test("Remove a member from a group where the admin role is inherited", async () => {
64
+ const { node1, node2, node3, node1ToNode2Peer, node2ToNode3Peer } =
65
+ createThreeConnectedNodes("server", "server", "server");
66
+
67
+ const group = node1.createGroup();
68
+
69
+ group.addMember(node2.account, "admin");
70
+ group.addMember(node3.account, "reader");
71
+
72
+ const groupOnNode2 = await loadCoValueOrFail(node2, group.id);
73
+
74
+ // The account of node2 create a child group and extend the initial group
75
+ // This way the node1 account should become "admin" of the child group
76
+ // by inheriting the admin role from the initial group
77
+ const childGroup = node2.createGroup();
78
+ childGroup.extend(groupOnNode2);
79
+
80
+ const map = childGroup.createMap();
81
+ map.set("test", "Available to everyone");
82
+
83
+ const mapOnNode3 = await loadCoValueOrFail(node3, map.id);
84
+
85
+ // Check that the sync between node2 and node3 worked
86
+ expect(mapOnNode3.get("test")).toEqual("Available to everyone");
87
+
88
+ // The node1 account removes the reader from the group
89
+ // The reader should be automatically kicked out of the child group
90
+ await group.removeMember(node3.account);
91
+
92
+ await node1.syncManager.waitForUploadIntoPeer(node1ToNode2Peer.id, group.id);
93
+
94
+ // Update the map to check that node3 can't read updates anymore
95
+ map.set("test", "Hidden to node3");
96
+
97
+ await node2.syncManager.waitForUploadIntoPeer(node2ToNode3Peer.id, map.id);
98
+
99
+ // Check that the value has not been updated on node3
100
+ expect(mapOnNode3.get("test")).toEqual("Available to everyone");
101
+
102
+ const mapOnNode1 = await loadCoValueOrFail(node1, map.id);
103
+
104
+ expect(mapOnNode1.get("test")).toEqual("Hidden to node3");
105
+ });
106
+
107
+ test("An admin should be able to rotate the readKey on child groups and keep access to new coValues", async () => {
108
+ const { node1, node2, node3, node1ToNode2Peer, node2ToNode1Peer } =
109
+ createThreeConnectedNodes("server", "server", "server");
110
+
111
+ const group = node1.createGroup();
112
+
113
+ group.addMember(node2.account, "admin");
114
+ group.addMember(node3.account, "reader");
115
+
116
+ const groupOnNode2 = await loadCoValueOrFail(node2, group.id);
117
+
118
+ // The account of node2 create a child group and extend the initial group
119
+ // This way the node1 account should become "admin" of the child group
120
+ // by inheriting the admin role from the initial group
121
+ const childGroup = node2.createGroup();
122
+ childGroup.extend(groupOnNode2);
123
+
124
+ await node2.syncManager.waitForUploadIntoPeer(
125
+ node2ToNode1Peer.id,
126
+ childGroup.id,
127
+ );
128
+
129
+ // The node1 account removes the reader from the group
130
+ // In this case we want to ensure that node1 is still able to read new coValues
131
+ // Even if some childs are not available when the readKey is rotated
132
+ await group.removeMember(node3.account);
133
+ await node1.syncManager.waitForUploadIntoPeer(node1ToNode2Peer.id, group.id);
134
+
135
+ const map = childGroup.createMap();
136
+ map.set("test", "Available to node1");
137
+
138
+ const mapOnNode1 = await loadCoValueOrFail(node1, map.id);
139
+ expect(mapOnNode1.get("test")).toEqual("Available to node1");
140
+ });
141
+
142
+ test("An admin should be able to rotate the readKey on child groups even if it was unavailable when kicking out a member from a parent group", async () => {
143
+ const { node1, node2, node3, node1ToNode2Peer, node2ToNode1Peer } =
144
+ createThreeConnectedNodes("server", "server", "server");
145
+
146
+ const group = node1.createGroup();
147
+
148
+ group.addMember(node2.account, "admin");
149
+ group.addMember(node3.account, "reader");
150
+
151
+ const groupOnNode2 = await loadCoValueOrFail(node2, group.id);
152
+
153
+ // The account of node2 create a child group and extend the initial group
154
+ // This way the node1 account should become "admin" of the child group
155
+ // by inheriting the admin role from the initial group
156
+ const childGroup = node2.createGroup();
157
+ childGroup.extend(groupOnNode2);
158
+
159
+ // The node1 account removes the reader from the group
160
+ // In this case we want to ensure that node1 is still able to read new coValues
161
+ // Even if some childs are not available when the readKey is rotated
162
+ await group.removeMember(node3.account);
163
+ await node1.syncManager.waitForUploadIntoPeer(node1ToNode2Peer.id, group.id);
164
+
165
+ const map = childGroup.createMap();
166
+ map.set("test", "Available to node1");
167
+
168
+ const mapOnNode1 = await loadCoValueOrFail(node1, map.id);
169
+ expect(mapOnNode1.get("test")).toEqual("Available to node1");
170
+ });
171
+
172
+ test("An admin should be able to rotate the readKey on child groups even if it was unavailable when kicking out a member from a parent group (grandChild)", async () => {
173
+ const { node1, node2, node3, node1ToNode2Peer } = createThreeConnectedNodes(
174
+ "server",
175
+ "server",
176
+ "server",
177
+ );
178
+
179
+ const group = node1.createGroup();
180
+
181
+ group.addMember(node2.account, "admin");
182
+ group.addMember(node3.account, "reader");
183
+
184
+ const groupOnNode2 = await loadCoValueOrFail(node2, group.id);
185
+
186
+ // The account of node2 create a child group and extend the initial group
187
+ // This way the node1 account should become "admin" of the child group
188
+ // by inheriting the admin role from the initial group
189
+ const childGroup = node2.createGroup();
190
+ childGroup.extend(groupOnNode2);
191
+ const grandChildGroup = node2.createGroup();
192
+ grandChildGroup.extend(childGroup);
193
+
194
+ // The node1 account removes the reader from the group
195
+ // In this case we want to ensure that node1 is still able to read new coValues
196
+ // Even if some childs are not available when the readKey is rotated
197
+ await group.removeMember(node3.account);
198
+ await node1.syncManager.waitForUploadIntoPeer(node1ToNode2Peer.id, group.id);
199
+
200
+ const map = childGroup.createMap();
201
+ map.set("test", "Available to node1");
202
+
203
+ const mapOnNode1 = await loadCoValueOrFail(node1, map.id);
204
+
205
+ expect(mapOnNode1.get("test")).toEqual("Available to node1");
206
+ });