cojson 0.0.6 → 0.0.8

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 (74) hide show
  1. package/.eslintrc.cjs +11 -8
  2. package/dist/coValue.d.ts +97 -0
  3. package/dist/coValue.js +341 -401
  4. package/dist/coValue.js.map +1 -0
  5. package/dist/coValue.test.d.ts +1 -0
  6. package/dist/coValue.test.js +69 -113
  7. package/dist/coValue.test.js.map +1 -0
  8. package/dist/contentType.d.ts +15 -0
  9. package/dist/contentType.js +5 -5
  10. package/dist/contentType.js.map +1 -0
  11. package/dist/contentType.test.d.ts +1 -0
  12. package/dist/contentType.test.js +138 -168
  13. package/dist/contentType.test.js.map +1 -0
  14. package/dist/contentTypes/coList.d.ts +11 -0
  15. package/dist/contentTypes/coList.js +14 -16
  16. package/dist/contentTypes/coList.js.map +1 -0
  17. package/dist/contentTypes/coMap.d.ts +56 -0
  18. package/dist/contentTypes/coMap.js +112 -112
  19. package/dist/contentTypes/coMap.js.map +1 -0
  20. package/dist/contentTypes/coStream.d.ts +11 -0
  21. package/dist/contentTypes/coStream.js +14 -16
  22. package/dist/contentTypes/coStream.js.map +1 -0
  23. package/dist/contentTypes/static.d.ts +11 -0
  24. package/dist/contentTypes/static.js +12 -14
  25. package/dist/contentTypes/static.js.map +1 -0
  26. package/dist/crypto.d.ts +97 -0
  27. package/dist/crypto.js +100 -151
  28. package/dist/crypto.js.map +1 -0
  29. package/dist/crypto.test.d.ts +1 -0
  30. package/dist/crypto.test.js +94 -134
  31. package/dist/crypto.test.js.map +1 -0
  32. package/dist/ids.d.ts +7 -0
  33. package/dist/ids.js +2 -1
  34. package/dist/ids.js.map +1 -0
  35. package/dist/index.d.ts +19 -0
  36. package/dist/index.js +10 -18
  37. package/dist/index.js.map +1 -0
  38. package/dist/jsonValue.d.ts +7 -0
  39. package/dist/jsonValue.js +2 -1
  40. package/dist/jsonValue.js.map +1 -0
  41. package/dist/node.d.ts +33 -0
  42. package/dist/node.js +102 -133
  43. package/dist/node.js.map +1 -0
  44. package/dist/permissions.d.ts +54 -0
  45. package/dist/permissions.js +202 -228
  46. package/dist/permissions.js.map +1 -0
  47. package/dist/permissions.test.d.ts +1 -0
  48. package/dist/permissions.test.js +724 -915
  49. package/dist/permissions.test.js.map +1 -0
  50. package/dist/sync.d.ts +80 -0
  51. package/dist/sync.js +247 -294
  52. package/dist/sync.js.map +1 -0
  53. package/dist/sync.test.d.ts +1 -0
  54. package/dist/sync.test.js +763 -798
  55. package/dist/sync.test.js.map +1 -0
  56. package/package.json +7 -4
  57. package/src/coValue.test.ts +3 -4
  58. package/src/coValue.ts +11 -17
  59. package/src/contentType.test.ts +3 -3
  60. package/src/contentType.ts +6 -6
  61. package/src/contentTypes/coList.ts +4 -4
  62. package/src/contentTypes/coMap.ts +6 -6
  63. package/src/contentTypes/coStream.ts +4 -4
  64. package/src/contentTypes/static.ts +5 -5
  65. package/src/crypto.test.ts +1 -1
  66. package/src/crypto.ts +2 -2
  67. package/src/index.ts +9 -7
  68. package/src/jsonValue.ts +1 -1
  69. package/src/node.ts +6 -7
  70. package/src/permissions.test.ts +5 -5
  71. package/src/permissions.ts +7 -7
  72. package/src/sync.test.ts +7 -7
  73. package/src/sync.ts +6 -6
  74. package/tsconfig.json +1 -7
package/dist/sync.test.js CHANGED
@@ -1,861 +1,826 @@
1
- "use strict";
2
- import {
3
- getAgent,
4
- getAgentID,
5
- newRandomAgentCredential,
6
- newRandomSessionID
7
- } from "./coValue";
8
- import { LocalNode } from "./node";
9
- import { expectMap } from "./contentType";
10
- import {
11
- ReadableStream,
12
- WritableStream,
13
- TransformStream
14
- } from "isomorphic-streams";
15
- test(
16
- "Node replies with initial tx and header to empty subscribe",
17
- async () => {
1
+ import { getAgent, getAgentID, newRandomAgentCredential, newRandomSessionID, } from './coValue.js';
2
+ import { LocalNode } from './node.js';
3
+ import { expectMap } from './contentType.js';
4
+ import { ReadableStream, WritableStream, TransformStream, } from "isomorphic-streams";
5
+ test("Node replies with initial tx and header to empty subscribe", async () => {
18
6
  const admin = newRandomAgentCredential("admin");
19
7
  const adminID = getAgentID(getAgent(admin));
20
8
  const node = new LocalNode(admin, newRandomSessionID(adminID));
21
9
  const team = node.createTeam();
22
10
  const map = team.createMap();
23
11
  map.edit((editable) => {
24
- editable.set("hello", "world", "trusting");
12
+ editable.set("hello", "world", "trusting");
25
13
  });
26
14
  const [inRx, inTx] = newStreamPair();
27
15
  const [outRx, outTx] = newStreamPair();
28
16
  node.sync.addPeer({
29
- id: "test",
30
- incoming: inRx,
31
- outgoing: outTx,
32
- role: "peer"
17
+ id: "test",
18
+ incoming: inRx,
19
+ outgoing: outTx,
20
+ role: "peer",
33
21
  });
34
22
  const writer = inTx.getWriter();
35
23
  await writer.write({
36
- action: "subscribe",
37
- coValueID: map.coValue.id,
38
- header: false,
39
- sessions: {}
24
+ action: "subscribe",
25
+ coValueID: map.coValue.id,
26
+ header: false,
27
+ sessions: {},
40
28
  });
41
29
  const reader = outRx.getReader();
42
30
  expect((await reader.read()).value).toMatchObject(admStateEx(adminID));
43
31
  expect((await reader.read()).value).toMatchObject(teamStateEx(team));
44
32
  const mapTellKnownStateMsg = await reader.read();
45
33
  expect(mapTellKnownStateMsg.value).toEqual({
46
- action: "tellKnownState",
47
- ...map.coValue.knownState()
34
+ action: "tellKnownState",
35
+ ...map.coValue.knownState(),
48
36
  });
49
37
  expect((await reader.read()).value).toMatchObject(admContEx(adminID));
50
38
  expect((await reader.read()).value).toMatchObject(teamContentEx(team));
51
39
  const newContentMsg = await reader.read();
52
40
  expect(newContentMsg.value).toEqual({
53
- action: "newContent",
54
- coValueID: map.coValue.id,
55
- header: {
56
- type: "comap",
57
- ruleset: { type: "ownedByTeam", team: team.id },
58
- meta: null,
59
- createdAt: map.coValue.header.createdAt,
60
- uniqueness: map.coValue.header.uniqueness,
61
- publicNickname: "map"
62
- },
63
- newContent: {
64
- [node.ownSessionID]: {
65
- after: 0,
66
- newTransactions: [
67
- {
68
- privacy: "trusting",
69
- madeAt: map.coValue.sessions[node.ownSessionID].transactions[0].madeAt,
70
- changes: [
71
- {
72
- op: "insert",
73
- key: "hello",
74
- value: "world"
75
- }
76
- ]
77
- }
78
- ],
79
- lastHash: map.coValue.sessions[node.ownSessionID].lastHash,
80
- lastSignature: map.coValue.sessions[node.ownSessionID].lastSignature
81
- }
82
- }
83
- });
84
- }
85
- );
41
+ action: "newContent",
42
+ coValueID: map.coValue.id,
43
+ header: {
44
+ type: "comap",
45
+ ruleset: { type: "ownedByTeam", team: team.id },
46
+ meta: null,
47
+ createdAt: map.coValue.header.createdAt,
48
+ uniqueness: map.coValue.header.uniqueness,
49
+ publicNickname: "map",
50
+ },
51
+ newContent: {
52
+ [node.ownSessionID]: {
53
+ after: 0,
54
+ newTransactions: [
55
+ {
56
+ privacy: "trusting",
57
+ madeAt: map.coValue.sessions[node.ownSessionID]
58
+ .transactions[0].madeAt,
59
+ changes: [
60
+ {
61
+ op: "insert",
62
+ key: "hello",
63
+ value: "world",
64
+ },
65
+ ],
66
+ },
67
+ ],
68
+ lastHash: map.coValue.sessions[node.ownSessionID].lastHash,
69
+ lastSignature: map.coValue.sessions[node.ownSessionID].lastSignature,
70
+ },
71
+ },
72
+ });
73
+ });
86
74
  test("Node replies with only new tx to subscribe with some known state", async () => {
87
- const admin = newRandomAgentCredential("admin");
88
- const adminID = getAgentID(getAgent(admin));
89
- const node = new LocalNode(admin, newRandomSessionID(adminID));
90
- const team = node.createTeam();
91
- const map = team.createMap();
92
- map.edit((editable) => {
93
- editable.set("hello", "world", "trusting");
94
- editable.set("goodbye", "world", "trusting");
95
- });
96
- const [inRx, inTx] = newStreamPair();
97
- const [outRx, outTx] = newStreamPair();
98
- node.sync.addPeer({
99
- id: "test",
100
- incoming: inRx,
101
- outgoing: outTx,
102
- role: "peer"
103
- });
104
- const writer = inTx.getWriter();
105
- await writer.write({
106
- action: "subscribe",
107
- coValueID: map.coValue.id,
108
- header: true,
109
- sessions: {
110
- [node.ownSessionID]: 1
111
- }
112
- });
113
- const reader = outRx.getReader();
114
- expect((await reader.read()).value).toMatchObject(admStateEx(adminID));
115
- expect((await reader.read()).value).toMatchObject(teamStateEx(team));
116
- const mapTellKnownStateMsg = await reader.read();
117
- expect(mapTellKnownStateMsg.value).toEqual({
118
- action: "tellKnownState",
119
- ...map.coValue.knownState()
120
- });
121
- expect((await reader.read()).value).toMatchObject(admContEx(adminID));
122
- expect((await reader.read()).value).toMatchObject(teamContentEx(team));
123
- const mapNewContentMsg = await reader.read();
124
- expect(mapNewContentMsg.value).toEqual({
125
- action: "newContent",
126
- coValueID: map.coValue.id,
127
- header: void 0,
128
- newContent: {
129
- [node.ownSessionID]: {
130
- after: 1,
131
- newTransactions: [
132
- {
133
- privacy: "trusting",
134
- madeAt: map.coValue.sessions[node.ownSessionID].transactions[1].madeAt,
135
- changes: [
136
- {
137
- op: "insert",
138
- key: "goodbye",
139
- value: "world"
140
- }
141
- ]
142
- }
143
- ],
144
- lastHash: map.coValue.sessions[node.ownSessionID].lastHash,
145
- lastSignature: map.coValue.sessions[node.ownSessionID].lastSignature
146
- }
147
- }
148
- });
75
+ const admin = newRandomAgentCredential("admin");
76
+ const adminID = getAgentID(getAgent(admin));
77
+ const node = new LocalNode(admin, newRandomSessionID(adminID));
78
+ const team = node.createTeam();
79
+ const map = team.createMap();
80
+ map.edit((editable) => {
81
+ editable.set("hello", "world", "trusting");
82
+ editable.set("goodbye", "world", "trusting");
83
+ });
84
+ const [inRx, inTx] = newStreamPair();
85
+ const [outRx, outTx] = newStreamPair();
86
+ node.sync.addPeer({
87
+ id: "test",
88
+ incoming: inRx,
89
+ outgoing: outTx,
90
+ role: "peer",
91
+ });
92
+ const writer = inTx.getWriter();
93
+ await writer.write({
94
+ action: "subscribe",
95
+ coValueID: map.coValue.id,
96
+ header: true,
97
+ sessions: {
98
+ [node.ownSessionID]: 1,
99
+ },
100
+ });
101
+ const reader = outRx.getReader();
102
+ expect((await reader.read()).value).toMatchObject(admStateEx(adminID));
103
+ expect((await reader.read()).value).toMatchObject(teamStateEx(team));
104
+ const mapTellKnownStateMsg = await reader.read();
105
+ expect(mapTellKnownStateMsg.value).toEqual({
106
+ action: "tellKnownState",
107
+ ...map.coValue.knownState(),
108
+ });
109
+ expect((await reader.read()).value).toMatchObject(admContEx(adminID));
110
+ expect((await reader.read()).value).toMatchObject(teamContentEx(team));
111
+ const mapNewContentMsg = await reader.read();
112
+ expect(mapNewContentMsg.value).toEqual({
113
+ action: "newContent",
114
+ coValueID: map.coValue.id,
115
+ header: undefined,
116
+ newContent: {
117
+ [node.ownSessionID]: {
118
+ after: 1,
119
+ newTransactions: [
120
+ {
121
+ privacy: "trusting",
122
+ madeAt: map.coValue.sessions[node.ownSessionID]
123
+ .transactions[1].madeAt,
124
+ changes: [
125
+ {
126
+ op: "insert",
127
+ key: "goodbye",
128
+ value: "world",
129
+ },
130
+ ],
131
+ },
132
+ ],
133
+ lastHash: map.coValue.sessions[node.ownSessionID].lastHash,
134
+ lastSignature: map.coValue.sessions[node.ownSessionID].lastSignature,
135
+ },
136
+ },
137
+ });
149
138
  });
150
- test.todo(
151
- "TODO: node only replies with new tx to subscribe with some known state, even in the depended on coValues"
152
- );
139
+ test.todo("TODO: node only replies with new tx to subscribe with some known state, even in the depended on coValues");
153
140
  test("After subscribing, node sends own known state and new txs to peer", async () => {
154
- const admin = newRandomAgentCredential("admin");
155
- const adminID = getAgentID(getAgent(admin));
156
- const node = new LocalNode(admin, newRandomSessionID(adminID));
157
- const team = node.createTeam();
158
- const map = team.createMap();
159
- const [inRx, inTx] = newStreamPair();
160
- const [outRx, outTx] = newStreamPair();
161
- node.sync.addPeer({
162
- id: "test",
163
- incoming: inRx,
164
- outgoing: outTx,
165
- role: "peer"
166
- });
167
- const writer = inTx.getWriter();
168
- await writer.write({
169
- action: "subscribe",
170
- coValueID: map.coValue.id,
171
- header: false,
172
- sessions: {
173
- [node.ownSessionID]: 0
174
- }
175
- });
176
- const reader = outRx.getReader();
177
- expect((await reader.read()).value).toMatchObject(admStateEx(adminID));
178
- expect((await reader.read()).value).toMatchObject(teamStateEx(team));
179
- const mapTellKnownStateMsg = await reader.read();
180
- expect(mapTellKnownStateMsg.value).toEqual({
181
- action: "tellKnownState",
182
- ...map.coValue.knownState()
183
- });
184
- expect((await reader.read()).value).toMatchObject(admContEx(adminID));
185
- expect((await reader.read()).value).toMatchObject(teamContentEx(team));
186
- const mapNewContentHeaderOnlyMsg = await reader.read();
187
- expect(mapNewContentHeaderOnlyMsg.value).toEqual({
188
- action: "newContent",
189
- coValueID: map.coValue.id,
190
- header: map.coValue.header,
191
- newContent: {}
192
- });
193
- map.edit((editable) => {
194
- editable.set("hello", "world", "trusting");
195
- });
196
- const mapEditMsg1 = await reader.read();
197
- expect(mapEditMsg1.value).toEqual({
198
- action: "newContent",
199
- coValueID: map.coValue.id,
200
- newContent: {
201
- [node.ownSessionID]: {
202
- after: 0,
203
- newTransactions: [
204
- {
205
- privacy: "trusting",
206
- madeAt: map.coValue.sessions[node.ownSessionID].transactions[0].madeAt,
207
- changes: [
208
- {
209
- op: "insert",
210
- key: "hello",
211
- value: "world"
212
- }
213
- ]
214
- }
215
- ],
216
- lastHash: map.coValue.sessions[node.ownSessionID].lastHash,
217
- lastSignature: map.coValue.sessions[node.ownSessionID].lastSignature
218
- }
219
- }
220
- });
221
- map.edit((editable) => {
222
- editable.set("goodbye", "world", "trusting");
223
- });
224
- const mapEditMsg2 = await reader.read();
225
- expect(mapEditMsg2.value).toEqual({
226
- action: "newContent",
227
- coValueID: map.coValue.id,
228
- newContent: {
229
- [node.ownSessionID]: {
230
- after: 1,
231
- newTransactions: [
232
- {
233
- privacy: "trusting",
234
- madeAt: map.coValue.sessions[node.ownSessionID].transactions[1].madeAt,
235
- changes: [
236
- {
237
- op: "insert",
238
- key: "goodbye",
239
- value: "world"
240
- }
241
- ]
242
- }
243
- ],
244
- lastHash: map.coValue.sessions[node.ownSessionID].lastHash,
245
- lastSignature: map.coValue.sessions[node.ownSessionID].lastSignature
246
- }
247
- }
248
- });
141
+ const admin = newRandomAgentCredential("admin");
142
+ const adminID = getAgentID(getAgent(admin));
143
+ const node = new LocalNode(admin, newRandomSessionID(adminID));
144
+ const team = node.createTeam();
145
+ const map = team.createMap();
146
+ const [inRx, inTx] = newStreamPair();
147
+ const [outRx, outTx] = newStreamPair();
148
+ node.sync.addPeer({
149
+ id: "test",
150
+ incoming: inRx,
151
+ outgoing: outTx,
152
+ role: "peer",
153
+ });
154
+ const writer = inTx.getWriter();
155
+ await writer.write({
156
+ action: "subscribe",
157
+ coValueID: map.coValue.id,
158
+ header: false,
159
+ sessions: {
160
+ [node.ownSessionID]: 0,
161
+ },
162
+ });
163
+ const reader = outRx.getReader();
164
+ expect((await reader.read()).value).toMatchObject(admStateEx(adminID));
165
+ expect((await reader.read()).value).toMatchObject(teamStateEx(team));
166
+ const mapTellKnownStateMsg = await reader.read();
167
+ expect(mapTellKnownStateMsg.value).toEqual({
168
+ action: "tellKnownState",
169
+ ...map.coValue.knownState(),
170
+ });
171
+ expect((await reader.read()).value).toMatchObject(admContEx(adminID));
172
+ expect((await reader.read()).value).toMatchObject(teamContentEx(team));
173
+ const mapNewContentHeaderOnlyMsg = await reader.read();
174
+ expect(mapNewContentHeaderOnlyMsg.value).toEqual({
175
+ action: "newContent",
176
+ coValueID: map.coValue.id,
177
+ header: map.coValue.header,
178
+ newContent: {},
179
+ });
180
+ map.edit((editable) => {
181
+ editable.set("hello", "world", "trusting");
182
+ });
183
+ const mapEditMsg1 = await reader.read();
184
+ expect(mapEditMsg1.value).toEqual({
185
+ action: "newContent",
186
+ coValueID: map.coValue.id,
187
+ newContent: {
188
+ [node.ownSessionID]: {
189
+ after: 0,
190
+ newTransactions: [
191
+ {
192
+ privacy: "trusting",
193
+ madeAt: map.coValue.sessions[node.ownSessionID]
194
+ .transactions[0].madeAt,
195
+ changes: [
196
+ {
197
+ op: "insert",
198
+ key: "hello",
199
+ value: "world",
200
+ },
201
+ ],
202
+ },
203
+ ],
204
+ lastHash: map.coValue.sessions[node.ownSessionID].lastHash,
205
+ lastSignature: map.coValue.sessions[node.ownSessionID].lastSignature,
206
+ },
207
+ },
208
+ });
209
+ map.edit((editable) => {
210
+ editable.set("goodbye", "world", "trusting");
211
+ });
212
+ const mapEditMsg2 = await reader.read();
213
+ expect(mapEditMsg2.value).toEqual({
214
+ action: "newContent",
215
+ coValueID: map.coValue.id,
216
+ newContent: {
217
+ [node.ownSessionID]: {
218
+ after: 1,
219
+ newTransactions: [
220
+ {
221
+ privacy: "trusting",
222
+ madeAt: map.coValue.sessions[node.ownSessionID]
223
+ .transactions[1].madeAt,
224
+ changes: [
225
+ {
226
+ op: "insert",
227
+ key: "goodbye",
228
+ value: "world",
229
+ },
230
+ ],
231
+ },
232
+ ],
233
+ lastHash: map.coValue.sessions[node.ownSessionID].lastHash,
234
+ lastSignature: map.coValue.sessions[node.ownSessionID].lastSignature,
235
+ },
236
+ },
237
+ });
249
238
  });
250
239
  test("Client replies with known new content to tellKnownState from server", async () => {
251
- const admin = newRandomAgentCredential("admin");
252
- const adminID = getAgentID(getAgent(admin));
253
- const node = new LocalNode(admin, newRandomSessionID(adminID));
254
- const team = node.createTeam();
255
- const map = team.createMap();
256
- map.edit((editable) => {
257
- editable.set("hello", "world", "trusting");
258
- });
259
- const [inRx, inTx] = newStreamPair();
260
- const [outRx, outTx] = newStreamPair();
261
- node.sync.addPeer({
262
- id: "test",
263
- incoming: inRx,
264
- outgoing: outTx,
265
- role: "peer"
266
- });
267
- const reader = outRx.getReader();
268
- const writer = inTx.getWriter();
269
- await writer.write({
270
- action: "tellKnownState",
271
- coValueID: map.coValue.id,
272
- header: false,
273
- sessions: {
274
- [node.ownSessionID]: 0
275
- }
276
- });
277
- expect((await reader.read()).value).toMatchObject(admStateEx(adminID));
278
- expect((await reader.read()).value).toMatchObject(teamStateEx(team));
279
- const mapTellKnownStateMsg = await reader.read();
280
- expect(mapTellKnownStateMsg.value).toEqual({
281
- action: "tellKnownState",
282
- ...map.coValue.knownState()
283
- });
284
- expect((await reader.read()).value).toMatchObject(admContEx(adminID));
285
- expect((await reader.read()).value).toMatchObject(teamContentEx(team));
286
- const mapNewContentMsg = await reader.read();
287
- expect(mapNewContentMsg.value).toEqual({
288
- action: "newContent",
289
- coValueID: map.coValue.id,
290
- header: map.coValue.header,
291
- newContent: {
292
- [node.ownSessionID]: {
293
- after: 0,
294
- newTransactions: [
295
- {
296
- privacy: "trusting",
297
- madeAt: map.coValue.sessions[node.ownSessionID].transactions[0].madeAt,
298
- changes: [
299
- {
300
- op: "insert",
301
- key: "hello",
302
- value: "world"
303
- }
304
- ]
305
- }
306
- ],
307
- lastHash: map.coValue.sessions[node.ownSessionID].lastHash,
308
- lastSignature: map.coValue.sessions[node.ownSessionID].lastSignature
309
- }
310
- }
311
- });
240
+ const admin = newRandomAgentCredential("admin");
241
+ const adminID = getAgentID(getAgent(admin));
242
+ const node = new LocalNode(admin, newRandomSessionID(adminID));
243
+ const team = node.createTeam();
244
+ const map = team.createMap();
245
+ map.edit((editable) => {
246
+ editable.set("hello", "world", "trusting");
247
+ });
248
+ const [inRx, inTx] = newStreamPair();
249
+ const [outRx, outTx] = newStreamPair();
250
+ node.sync.addPeer({
251
+ id: "test",
252
+ incoming: inRx,
253
+ outgoing: outTx,
254
+ role: "peer",
255
+ });
256
+ const reader = outRx.getReader();
257
+ // expect((await reader.read()).value).toMatchObject(teamStateEx(team));
258
+ const writer = inTx.getWriter();
259
+ await writer.write({
260
+ action: "tellKnownState",
261
+ coValueID: map.coValue.id,
262
+ header: false,
263
+ sessions: {
264
+ [node.ownSessionID]: 0,
265
+ },
266
+ });
267
+ expect((await reader.read()).value).toMatchObject(admStateEx(adminID));
268
+ expect((await reader.read()).value).toMatchObject(teamStateEx(team));
269
+ const mapTellKnownStateMsg = await reader.read();
270
+ expect(mapTellKnownStateMsg.value).toEqual({
271
+ action: "tellKnownState",
272
+ ...map.coValue.knownState(),
273
+ });
274
+ expect((await reader.read()).value).toMatchObject(admContEx(adminID));
275
+ expect((await reader.read()).value).toMatchObject(teamContentEx(team));
276
+ const mapNewContentMsg = await reader.read();
277
+ expect(mapNewContentMsg.value).toEqual({
278
+ action: "newContent",
279
+ coValueID: map.coValue.id,
280
+ header: map.coValue.header,
281
+ newContent: {
282
+ [node.ownSessionID]: {
283
+ after: 0,
284
+ newTransactions: [
285
+ {
286
+ privacy: "trusting",
287
+ madeAt: map.coValue.sessions[node.ownSessionID]
288
+ .transactions[0].madeAt,
289
+ changes: [
290
+ {
291
+ op: "insert",
292
+ key: "hello",
293
+ value: "world",
294
+ },
295
+ ],
296
+ },
297
+ ],
298
+ lastHash: map.coValue.sessions[node.ownSessionID].lastHash,
299
+ lastSignature: map.coValue.sessions[node.ownSessionID].lastSignature,
300
+ },
301
+ },
302
+ });
312
303
  });
313
304
  test("No matter the optimistic known state, node respects invalid known state messages and resyncs", async () => {
314
- const admin = newRandomAgentCredential("admin");
315
- const adminID = getAgentID(getAgent(admin));
316
- const node = new LocalNode(admin, newRandomSessionID(adminID));
317
- const team = node.createTeam();
318
- const map = team.createMap();
319
- const [inRx, inTx] = newStreamPair();
320
- const [outRx, outTx] = newStreamPair();
321
- node.sync.addPeer({
322
- id: "test",
323
- incoming: inRx,
324
- outgoing: outTx,
325
- role: "peer"
326
- });
327
- const writer = inTx.getWriter();
328
- await writer.write({
329
- action: "subscribe",
330
- coValueID: map.coValue.id,
331
- header: false,
332
- sessions: {
333
- [node.ownSessionID]: 0
334
- }
335
- });
336
- const reader = outRx.getReader();
337
- expect((await reader.read()).value).toMatchObject(admStateEx(adminID));
338
- expect((await reader.read()).value).toMatchObject(teamStateEx(team));
339
- const mapTellKnownStateMsg = await reader.read();
340
- expect(mapTellKnownStateMsg.value).toEqual({
341
- action: "tellKnownState",
342
- ...map.coValue.knownState()
343
- });
344
- expect((await reader.read()).value).toMatchObject(admContEx(adminID));
345
- expect((await reader.read()).value).toMatchObject(teamContentEx(team));
346
- const mapNewContentHeaderOnlyMsg = await reader.read();
347
- expect(mapNewContentHeaderOnlyMsg.value).toEqual({
348
- action: "newContent",
349
- coValueID: map.coValue.id,
350
- header: map.coValue.header,
351
- newContent: {}
352
- });
353
- map.edit((editable) => {
354
- editable.set("hello", "world", "trusting");
355
- });
356
- map.edit((editable) => {
357
- editable.set("goodbye", "world", "trusting");
358
- });
359
- const _mapEditMsg1 = await reader.read();
360
- const _mapEditMsg2 = await reader.read();
361
- await writer.write({
362
- action: "wrongAssumedKnownState",
363
- coValueID: map.coValue.id,
364
- header: true,
365
- sessions: {
366
- [node.ownSessionID]: 1
367
- }
368
- });
369
- const newContentAfterWrongAssumedState = await reader.read();
370
- expect(newContentAfterWrongAssumedState.value).toEqual({
371
- action: "newContent",
372
- coValueID: map.coValue.id,
373
- header: void 0,
374
- newContent: {
375
- [node.ownSessionID]: {
376
- after: 1,
377
- newTransactions: [
378
- {
379
- privacy: "trusting",
380
- madeAt: map.coValue.sessions[node.ownSessionID].transactions[1].madeAt,
381
- changes: [
382
- {
383
- op: "insert",
384
- key: "goodbye",
385
- value: "world"
386
- }
387
- ]
388
- }
389
- ],
390
- lastHash: map.coValue.sessions[node.ownSessionID].lastHash,
391
- lastSignature: map.coValue.sessions[node.ownSessionID].lastSignature
392
- }
393
- }
394
- });
305
+ const admin = newRandomAgentCredential("admin");
306
+ const adminID = getAgentID(getAgent(admin));
307
+ const node = new LocalNode(admin, newRandomSessionID(adminID));
308
+ const team = node.createTeam();
309
+ const map = team.createMap();
310
+ const [inRx, inTx] = newStreamPair();
311
+ const [outRx, outTx] = newStreamPair();
312
+ node.sync.addPeer({
313
+ id: "test",
314
+ incoming: inRx,
315
+ outgoing: outTx,
316
+ role: "peer",
317
+ });
318
+ const writer = inTx.getWriter();
319
+ await writer.write({
320
+ action: "subscribe",
321
+ coValueID: map.coValue.id,
322
+ header: false,
323
+ sessions: {
324
+ [node.ownSessionID]: 0,
325
+ },
326
+ });
327
+ const reader = outRx.getReader();
328
+ expect((await reader.read()).value).toMatchObject(admStateEx(adminID));
329
+ expect((await reader.read()).value).toMatchObject(teamStateEx(team));
330
+ const mapTellKnownStateMsg = await reader.read();
331
+ expect(mapTellKnownStateMsg.value).toEqual({
332
+ action: "tellKnownState",
333
+ ...map.coValue.knownState(),
334
+ });
335
+ expect((await reader.read()).value).toMatchObject(admContEx(adminID));
336
+ expect((await reader.read()).value).toMatchObject(teamContentEx(team));
337
+ const mapNewContentHeaderOnlyMsg = await reader.read();
338
+ expect(mapNewContentHeaderOnlyMsg.value).toEqual({
339
+ action: "newContent",
340
+ coValueID: map.coValue.id,
341
+ header: map.coValue.header,
342
+ newContent: {},
343
+ });
344
+ map.edit((editable) => {
345
+ editable.set("hello", "world", "trusting");
346
+ });
347
+ map.edit((editable) => {
348
+ editable.set("goodbye", "world", "trusting");
349
+ });
350
+ const _mapEditMsg1 = await reader.read();
351
+ const _mapEditMsg2 = await reader.read();
352
+ await writer.write({
353
+ action: "wrongAssumedKnownState",
354
+ coValueID: map.coValue.id,
355
+ header: true,
356
+ sessions: {
357
+ [node.ownSessionID]: 1,
358
+ },
359
+ });
360
+ const newContentAfterWrongAssumedState = await reader.read();
361
+ expect(newContentAfterWrongAssumedState.value).toEqual({
362
+ action: "newContent",
363
+ coValueID: map.coValue.id,
364
+ header: undefined,
365
+ newContent: {
366
+ [node.ownSessionID]: {
367
+ after: 1,
368
+ newTransactions: [
369
+ {
370
+ privacy: "trusting",
371
+ madeAt: map.coValue.sessions[node.ownSessionID]
372
+ .transactions[1].madeAt,
373
+ changes: [
374
+ {
375
+ op: "insert",
376
+ key: "goodbye",
377
+ value: "world",
378
+ },
379
+ ],
380
+ },
381
+ ],
382
+ lastHash: map.coValue.sessions[node.ownSessionID].lastHash,
383
+ lastSignature: map.coValue.sessions[node.ownSessionID].lastSignature,
384
+ },
385
+ },
386
+ });
395
387
  });
396
388
  test("If we add a peer, but it never subscribes to a coValue, it won't get any messages", async () => {
397
- const admin = newRandomAgentCredential("admin");
398
- const adminID = getAgentID(getAgent(admin));
399
- const node = new LocalNode(admin, newRandomSessionID(adminID));
400
- const team = node.createTeam();
401
- const map = team.createMap();
402
- const [inRx, _inTx] = newStreamPair();
403
- const [outRx, outTx] = newStreamPair();
404
- node.sync.addPeer({
405
- id: "test",
406
- incoming: inRx,
407
- outgoing: outTx,
408
- role: "peer"
409
- });
410
- map.edit((editable) => {
411
- editable.set("hello", "world", "trusting");
412
- });
413
- const reader = outRx.getReader();
414
- await expect(shouldNotResolve(reader.read(), { timeout: 100 })).resolves.toBeUndefined();
389
+ const admin = newRandomAgentCredential("admin");
390
+ const adminID = getAgentID(getAgent(admin));
391
+ const node = new LocalNode(admin, newRandomSessionID(adminID));
392
+ const team = node.createTeam();
393
+ const map = team.createMap();
394
+ const [inRx, _inTx] = newStreamPair();
395
+ const [outRx, outTx] = newStreamPair();
396
+ node.sync.addPeer({
397
+ id: "test",
398
+ incoming: inRx,
399
+ outgoing: outTx,
400
+ role: "peer",
401
+ });
402
+ map.edit((editable) => {
403
+ editable.set("hello", "world", "trusting");
404
+ });
405
+ const reader = outRx.getReader();
406
+ await expect(shouldNotResolve(reader.read(), { timeout: 100 })).resolves.toBeUndefined();
415
407
  });
416
408
  test("If we add a server peer, all updates to all coValues are sent to it, even if it doesn't subscribe", async () => {
417
- const admin = newRandomAgentCredential("admin");
418
- const adminID = getAgentID(getAgent(admin));
419
- const node = new LocalNode(admin, newRandomSessionID(adminID));
420
- const team = node.createTeam();
421
- const map = team.createMap();
422
- const [inRx, _inTx] = newStreamPair();
423
- const [outRx, outTx] = newStreamPair();
424
- node.sync.addPeer({
425
- id: "test",
426
- incoming: inRx,
427
- outgoing: outTx,
428
- role: "server"
429
- });
430
- const reader = outRx.getReader();
431
- expect((await reader.read()).value).toMatchObject({
432
- action: "subscribe",
433
- coValueID: adminID
434
- });
435
- expect((await reader.read()).value).toMatchObject({
436
- action: "subscribe",
437
- coValueID: team.teamMap.coValue.id
438
- });
439
- const mapSubscribeMsg = await reader.read();
440
- expect(mapSubscribeMsg.value).toEqual({
441
- action: "subscribe",
442
- coValueID: map.coValue.id,
443
- header: true,
444
- sessions: {}
445
- });
446
- map.edit((editable) => {
447
- editable.set("hello", "world", "trusting");
448
- });
449
- expect((await reader.read()).value).toMatchObject(admContEx(adminID));
450
- expect((await reader.read()).value).toMatchObject(teamContentEx(team));
451
- const mapNewContentMsg = await reader.read();
452
- expect(mapNewContentMsg.value).toEqual({
453
- action: "newContent",
454
- coValueID: map.coValue.id,
455
- header: map.coValue.header,
456
- newContent: {
457
- [node.ownSessionID]: {
458
- after: 0,
459
- newTransactions: [
460
- {
461
- privacy: "trusting",
462
- madeAt: map.coValue.sessions[node.ownSessionID].transactions[0].madeAt,
463
- changes: [
464
- {
465
- op: "insert",
466
- key: "hello",
467
- value: "world"
468
- }
469
- ]
470
- }
471
- ],
472
- lastHash: map.coValue.sessions[node.ownSessionID].lastHash,
473
- lastSignature: map.coValue.sessions[node.ownSessionID].lastSignature
474
- }
475
- }
476
- });
409
+ const admin = newRandomAgentCredential("admin");
410
+ const adminID = getAgentID(getAgent(admin));
411
+ const node = new LocalNode(admin, newRandomSessionID(adminID));
412
+ const team = node.createTeam();
413
+ const map = team.createMap();
414
+ const [inRx, _inTx] = newStreamPair();
415
+ const [outRx, outTx] = newStreamPair();
416
+ node.sync.addPeer({
417
+ id: "test",
418
+ incoming: inRx,
419
+ outgoing: outTx,
420
+ role: "server",
421
+ });
422
+ const reader = outRx.getReader();
423
+ expect((await reader.read()).value).toMatchObject({
424
+ action: "subscribe",
425
+ coValueID: adminID,
426
+ });
427
+ expect((await reader.read()).value).toMatchObject({
428
+ action: "subscribe",
429
+ coValueID: team.teamMap.coValue.id,
430
+ });
431
+ const mapSubscribeMsg = await reader.read();
432
+ expect(mapSubscribeMsg.value).toEqual({
433
+ action: "subscribe",
434
+ coValueID: map.coValue.id,
435
+ header: true,
436
+ sessions: {},
437
+ });
438
+ map.edit((editable) => {
439
+ editable.set("hello", "world", "trusting");
440
+ });
441
+ expect((await reader.read()).value).toMatchObject(admContEx(adminID));
442
+ expect((await reader.read()).value).toMatchObject(teamContentEx(team));
443
+ const mapNewContentMsg = await reader.read();
444
+ expect(mapNewContentMsg.value).toEqual({
445
+ action: "newContent",
446
+ coValueID: map.coValue.id,
447
+ header: map.coValue.header,
448
+ newContent: {
449
+ [node.ownSessionID]: {
450
+ after: 0,
451
+ newTransactions: [
452
+ {
453
+ privacy: "trusting",
454
+ madeAt: map.coValue.sessions[node.ownSessionID]
455
+ .transactions[0].madeAt,
456
+ changes: [
457
+ {
458
+ op: "insert",
459
+ key: "hello",
460
+ value: "world",
461
+ },
462
+ ],
463
+ },
464
+ ],
465
+ lastHash: map.coValue.sessions[node.ownSessionID].lastHash,
466
+ lastSignature: map.coValue.sessions[node.ownSessionID].lastSignature,
467
+ },
468
+ },
469
+ });
477
470
  });
478
471
  test("If we add a server peer, newly created coValues are auto-subscribed to", async () => {
479
- const admin = newRandomAgentCredential("admin");
480
- const adminID = getAgentID(getAgent(admin));
481
- const node = new LocalNode(admin, newRandomSessionID(adminID));
482
- const team = node.createTeam();
483
- const [inRx, _inTx] = newStreamPair();
484
- const [outRx, outTx] = newStreamPair();
485
- node.sync.addPeer({
486
- id: "test",
487
- incoming: inRx,
488
- outgoing: outTx,
489
- role: "server"
490
- });
491
- const reader = outRx.getReader();
492
- expect((await reader.read()).value).toMatchObject({
493
- action: "subscribe",
494
- coValueID: adminID
495
- });
496
- expect((await reader.read()).value).toMatchObject({
497
- action: "subscribe",
498
- coValueID: team.teamMap.coValue.id
499
- });
500
- const map = team.createMap();
501
- const mapSubscribeMsg = await reader.read();
502
- expect(mapSubscribeMsg.value).toEqual({
503
- action: "subscribe",
504
- ...map.coValue.knownState()
505
- });
506
- expect((await reader.read()).value).toMatchObject(admContEx(adminID));
507
- expect((await reader.read()).value).toMatchObject(teamContentEx(team));
508
- const mapContentMsg = await reader.read();
509
- expect(mapContentMsg.value).toEqual({
510
- action: "newContent",
511
- coValueID: map.coValue.id,
512
- header: map.coValue.header,
513
- newContent: {}
514
- });
472
+ const admin = newRandomAgentCredential("admin");
473
+ const adminID = getAgentID(getAgent(admin));
474
+ const node = new LocalNode(admin, newRandomSessionID(adminID));
475
+ const team = node.createTeam();
476
+ const [inRx, _inTx] = newStreamPair();
477
+ const [outRx, outTx] = newStreamPair();
478
+ node.sync.addPeer({
479
+ id: "test",
480
+ incoming: inRx,
481
+ outgoing: outTx,
482
+ role: "server",
483
+ });
484
+ const reader = outRx.getReader();
485
+ expect((await reader.read()).value).toMatchObject({
486
+ action: "subscribe",
487
+ coValueID: adminID,
488
+ });
489
+ expect((await reader.read()).value).toMatchObject({
490
+ action: "subscribe",
491
+ coValueID: team.teamMap.coValue.id,
492
+ });
493
+ const map = team.createMap();
494
+ const mapSubscribeMsg = await reader.read();
495
+ expect(mapSubscribeMsg.value).toEqual({
496
+ action: "subscribe",
497
+ ...map.coValue.knownState(),
498
+ });
499
+ expect((await reader.read()).value).toMatchObject(admContEx(adminID));
500
+ expect((await reader.read()).value).toMatchObject(teamContentEx(team));
501
+ const mapContentMsg = await reader.read();
502
+ expect(mapContentMsg.value).toEqual({
503
+ action: "newContent",
504
+ coValueID: map.coValue.id,
505
+ header: map.coValue.header,
506
+ newContent: {},
507
+ });
515
508
  });
516
- test.todo(
517
- "TODO: when receiving a subscribe response that is behind our optimistic state (due to already sent content), we ignore it"
518
- );
509
+ test.todo("TODO: when receiving a subscribe response that is behind our optimistic state (due to already sent content), we ignore it");
519
510
  test("When we connect a new server peer, we try to sync all existing coValues to it", async () => {
520
- const admin = newRandomAgentCredential("admin");
521
- const adminID = getAgentID(getAgent(admin));
522
- const node = new LocalNode(admin, newRandomSessionID(adminID));
523
- const team = node.createTeam();
524
- const map = team.createMap();
525
- const [inRx, _inTx] = newStreamPair();
526
- const [outRx, outTx] = newStreamPair();
527
- node.sync.addPeer({
528
- id: "test",
529
- incoming: inRx,
530
- outgoing: outTx,
531
- role: "server"
532
- });
533
- const reader = outRx.getReader();
534
- const _adminSubscribeMessage = await reader.read();
535
- const teamSubscribeMessage = await reader.read();
536
- expect(teamSubscribeMessage.value).toEqual({
537
- action: "subscribe",
538
- ...team.teamMap.coValue.knownState()
539
- });
540
- const secondMessage = await reader.read();
541
- expect(secondMessage.value).toEqual({
542
- action: "subscribe",
543
- ...map.coValue.knownState()
544
- });
511
+ const admin = newRandomAgentCredential("admin");
512
+ const adminID = getAgentID(getAgent(admin));
513
+ const node = new LocalNode(admin, newRandomSessionID(adminID));
514
+ const team = node.createTeam();
515
+ const map = team.createMap();
516
+ const [inRx, _inTx] = newStreamPair();
517
+ const [outRx, outTx] = newStreamPair();
518
+ node.sync.addPeer({
519
+ id: "test",
520
+ incoming: inRx,
521
+ outgoing: outTx,
522
+ role: "server",
523
+ });
524
+ const reader = outRx.getReader();
525
+ const _adminSubscribeMessage = await reader.read();
526
+ const teamSubscribeMessage = await reader.read();
527
+ expect(teamSubscribeMessage.value).toEqual({
528
+ action: "subscribe",
529
+ ...team.teamMap.coValue.knownState(),
530
+ });
531
+ const secondMessage = await reader.read();
532
+ expect(secondMessage.value).toEqual({
533
+ action: "subscribe",
534
+ ...map.coValue.knownState(),
535
+ });
545
536
  });
546
537
  test("When receiving a subscribe with a known state that is ahead of our own, peers should respond with a corresponding subscribe response message", async () => {
547
- const admin = newRandomAgentCredential("admin");
548
- const adminID = getAgentID(getAgent(admin));
549
- const node = new LocalNode(admin, newRandomSessionID(adminID));
550
- const team = node.createTeam();
551
- const map = team.createMap();
552
- const [inRx, inTx] = newStreamPair();
553
- const [outRx, outTx] = newStreamPair();
554
- node.sync.addPeer({
555
- id: "test",
556
- incoming: inRx,
557
- outgoing: outTx,
558
- role: "peer"
559
- });
560
- const writer = inTx.getWriter();
561
- await writer.write({
562
- action: "subscribe",
563
- coValueID: map.coValue.id,
564
- header: true,
565
- sessions: {
566
- [node.ownSessionID]: 1
567
- }
568
- });
569
- const reader = outRx.getReader();
570
- expect((await reader.read()).value).toMatchObject(admStateEx(adminID));
571
- expect((await reader.read()).value).toMatchObject(teamStateEx(team));
572
- const mapTellKnownState = await reader.read();
573
- expect(mapTellKnownState.value).toEqual({
574
- action: "tellKnownState",
575
- ...map.coValue.knownState()
576
- });
538
+ const admin = newRandomAgentCredential("admin");
539
+ const adminID = getAgentID(getAgent(admin));
540
+ const node = new LocalNode(admin, newRandomSessionID(adminID));
541
+ const team = node.createTeam();
542
+ const map = team.createMap();
543
+ const [inRx, inTx] = newStreamPair();
544
+ const [outRx, outTx] = newStreamPair();
545
+ node.sync.addPeer({
546
+ id: "test",
547
+ incoming: inRx,
548
+ outgoing: outTx,
549
+ role: "peer",
550
+ });
551
+ const writer = inTx.getWriter();
552
+ await writer.write({
553
+ action: "subscribe",
554
+ coValueID: map.coValue.id,
555
+ header: true,
556
+ sessions: {
557
+ [node.ownSessionID]: 1,
558
+ },
559
+ });
560
+ const reader = outRx.getReader();
561
+ expect((await reader.read()).value).toMatchObject(admStateEx(adminID));
562
+ expect((await reader.read()).value).toMatchObject(teamStateEx(team));
563
+ const mapTellKnownState = await reader.read();
564
+ expect(mapTellKnownState.value).toEqual({
565
+ action: "tellKnownState",
566
+ ...map.coValue.knownState(),
567
+ });
577
568
  });
578
569
  test.skip("When replaying creation and transactions of a coValue as new content, the receiving peer integrates this information", async () => {
579
- var _a;
580
- const admin = newRandomAgentCredential("admin");
581
- const adminID = getAgentID(getAgent(admin));
582
- const node1 = new LocalNode(admin, newRandomSessionID(adminID));
583
- const team = node1.createTeam();
584
- const [inRx1, inTx1] = newStreamPair();
585
- const [outRx1, outTx1] = newStreamPair();
586
- node1.sync.addPeer({
587
- id: "test2",
588
- incoming: inRx1,
589
- outgoing: outTx1,
590
- role: "server"
591
- });
592
- const to1 = inTx1.getWriter();
593
- const from1 = outRx1.getReader();
594
- const node2 = new LocalNode(admin, newRandomSessionID(adminID));
595
- const [inRx2, inTx2] = newStreamPair();
596
- const [outRx2, outTx2] = newStreamPair();
597
- node2.sync.addPeer({
598
- id: "test1",
599
- incoming: inRx2,
600
- outgoing: outTx2,
601
- role: "client"
602
- });
603
- const to2 = inTx2.getWriter();
604
- const from2 = outRx2.getReader();
605
- const adminSubscribeMessage = await from1.read();
606
- expect(adminSubscribeMessage.value).toMatchObject({
607
- action: "subscribe",
608
- coValueID: adminID
609
- });
610
- const teamSubscribeMsg = await from1.read();
611
- expect(teamSubscribeMsg.value).toMatchObject({
612
- action: "subscribe",
613
- coValueID: team.teamMap.coValue.id
614
- });
615
- await to2.write(adminSubscribeMessage.value);
616
- await to2.write(teamSubscribeMsg.value);
617
- const adminTellKnownStateMsg = await from2.read();
618
- expect(adminTellKnownStateMsg.value).toMatchObject(admStateEx(adminID));
619
- const teamTellKnownStateMsg = await from2.read();
620
- expect(teamTellKnownStateMsg.value).toMatchObject(teamStateEx(team));
621
- expect(
622
- node2.sync.peers["test1"].optimisticKnownStates[team.teamMap.coValue.id]
623
- ).toBeDefined();
624
- await to1.write(adminTellKnownStateMsg.value);
625
- await to1.write(teamTellKnownStateMsg.value);
626
- const adminContentMsg = await from1.read();
627
- expect(adminContentMsg.value).toMatchObject(admContEx(adminID));
628
- const teamContentMsg = await from1.read();
629
- expect(teamContentMsg.value).toMatchObject(teamContentEx(team));
630
- await to2.write(adminContentMsg.value);
631
- await to2.write(teamContentMsg.value);
632
- const map = team.createMap();
633
- const mapSubscriptionMsg = await from1.read();
634
- expect(mapSubscriptionMsg.value).toMatchObject({
635
- action: "subscribe",
636
- coValueID: map.coValue.id
637
- });
638
- const mapNewContentMsg = await from1.read();
639
- expect(mapNewContentMsg.value).toEqual({
640
- action: "newContent",
641
- coValueID: map.coValue.id,
642
- header: map.coValue.header,
643
- newContent: {}
644
- });
645
- await to2.write(mapSubscriptionMsg.value);
646
- const mapTellKnownStateMsg = await from2.read();
647
- expect(mapTellKnownStateMsg.value).toEqual({
648
- action: "tellKnownState",
649
- coValueID: map.coValue.id,
650
- header: false,
651
- sessions: {}
652
- });
653
- expect((_a = node2.coValues[map.coValue.id]) == null ? void 0 : _a.state).toEqual("loading");
654
- await to2.write(mapNewContentMsg.value);
655
- map.edit((editable) => {
656
- editable.set("hello", "world", "trusting");
657
- });
658
- const mapEditMsg = await from1.read();
659
- await to2.write(mapEditMsg.value);
660
- await new Promise((resolve) => setTimeout(resolve, 100));
661
- expect(
662
- expectMap(
663
- node2.expectCoValueLoaded(map.coValue.id).getCurrentContent()
664
- ).get("hello")
665
- ).toEqual("world");
570
+ // TODO: this test is mostly correct but also slightly unrealistic, make sure we pass all messages back and forth as expected and then it should work
571
+ const admin = newRandomAgentCredential("admin");
572
+ const adminID = getAgentID(getAgent(admin));
573
+ const node1 = new LocalNode(admin, newRandomSessionID(adminID));
574
+ const team = node1.createTeam();
575
+ const [inRx1, inTx1] = newStreamPair();
576
+ const [outRx1, outTx1] = newStreamPair();
577
+ node1.sync.addPeer({
578
+ id: "test2",
579
+ incoming: inRx1,
580
+ outgoing: outTx1,
581
+ role: "server",
582
+ });
583
+ const to1 = inTx1.getWriter();
584
+ const from1 = outRx1.getReader();
585
+ const node2 = new LocalNode(admin, newRandomSessionID(adminID));
586
+ const [inRx2, inTx2] = newStreamPair();
587
+ const [outRx2, outTx2] = newStreamPair();
588
+ node2.sync.addPeer({
589
+ id: "test1",
590
+ incoming: inRx2,
591
+ outgoing: outTx2,
592
+ role: "client",
593
+ });
594
+ const to2 = inTx2.getWriter();
595
+ const from2 = outRx2.getReader();
596
+ const adminSubscribeMessage = await from1.read();
597
+ expect(adminSubscribeMessage.value).toMatchObject({
598
+ action: "subscribe",
599
+ coValueID: adminID,
600
+ });
601
+ const teamSubscribeMsg = await from1.read();
602
+ expect(teamSubscribeMsg.value).toMatchObject({
603
+ action: "subscribe",
604
+ coValueID: team.teamMap.coValue.id,
605
+ });
606
+ await to2.write(adminSubscribeMessage.value);
607
+ await to2.write(teamSubscribeMsg.value);
608
+ const adminTellKnownStateMsg = await from2.read();
609
+ expect(adminTellKnownStateMsg.value).toMatchObject(admStateEx(adminID));
610
+ const teamTellKnownStateMsg = await from2.read();
611
+ expect(teamTellKnownStateMsg.value).toMatchObject(teamStateEx(team));
612
+ expect(node2.sync.peers["test1"].optimisticKnownStates[team.teamMap.coValue.id]).toBeDefined();
613
+ await to1.write(adminTellKnownStateMsg.value);
614
+ await to1.write(teamTellKnownStateMsg.value);
615
+ const adminContentMsg = await from1.read();
616
+ expect(adminContentMsg.value).toMatchObject(admContEx(adminID));
617
+ const teamContentMsg = await from1.read();
618
+ expect(teamContentMsg.value).toMatchObject(teamContentEx(team));
619
+ await to2.write(adminContentMsg.value);
620
+ await to2.write(teamContentMsg.value);
621
+ const map = team.createMap();
622
+ const mapSubscriptionMsg = await from1.read();
623
+ expect(mapSubscriptionMsg.value).toMatchObject({
624
+ action: "subscribe",
625
+ coValueID: map.coValue.id,
626
+ });
627
+ const mapNewContentMsg = await from1.read();
628
+ expect(mapNewContentMsg.value).toEqual({
629
+ action: "newContent",
630
+ coValueID: map.coValue.id,
631
+ header: map.coValue.header,
632
+ newContent: {},
633
+ });
634
+ await to2.write(mapSubscriptionMsg.value);
635
+ const mapTellKnownStateMsg = await from2.read();
636
+ expect(mapTellKnownStateMsg.value).toEqual({
637
+ action: "tellKnownState",
638
+ coValueID: map.coValue.id,
639
+ header: false,
640
+ sessions: {},
641
+ });
642
+ expect(node2.coValues[map.coValue.id]?.state).toEqual("loading");
643
+ await to2.write(mapNewContentMsg.value);
644
+ map.edit((editable) => {
645
+ editable.set("hello", "world", "trusting");
646
+ });
647
+ const mapEditMsg = await from1.read();
648
+ await to2.write(mapEditMsg.value);
649
+ await new Promise((resolve) => setTimeout(resolve, 100));
650
+ expect(expectMap(node2.expectCoValueLoaded(map.coValue.id).getCurrentContent()).get("hello")).toEqual("world");
666
651
  });
667
652
  test.skip("When loading a coValue on one node, the server node it is requested from replies with all the necessary depended on coValues to make it work", async () => {
668
- const admin = newRandomAgentCredential("admin");
669
- const adminID = getAgentID(getAgent(admin));
670
- const node1 = new LocalNode(admin, newRandomSessionID(adminID));
671
- const team = node1.createTeam();
672
- const map = team.createMap();
673
- map.edit((editable) => {
674
- editable.set("hello", "world", "trusting");
675
- });
676
- const node2 = new LocalNode(admin, newRandomSessionID(adminID));
677
- const [node1asPeer, node2asPeer] = connectedPeers("peer1", "peer2");
678
- node1.sync.addPeer(node2asPeer);
679
- node2.sync.addPeer(node1asPeer);
680
- await node2.loadCoValue(map.coValue.id);
681
- expect(
682
- expectMap(
683
- node2.expectCoValueLoaded(map.coValue.id).getCurrentContent()
684
- ).get("hello")
685
- ).toEqual("world");
653
+ // TODO: this test is mostly correct but also slightly unrealistic, make sure we pass all messages back and forth as expected and then it should work
654
+ const admin = newRandomAgentCredential("admin");
655
+ const adminID = getAgentID(getAgent(admin));
656
+ const node1 = new LocalNode(admin, newRandomSessionID(adminID));
657
+ const team = node1.createTeam();
658
+ const map = team.createMap();
659
+ map.edit((editable) => {
660
+ editable.set("hello", "world", "trusting");
661
+ });
662
+ const node2 = new LocalNode(admin, newRandomSessionID(adminID));
663
+ const [node1asPeer, node2asPeer] = connectedPeers("peer1", "peer2");
664
+ node1.sync.addPeer(node2asPeer);
665
+ node2.sync.addPeer(node1asPeer);
666
+ await node2.loadCoValue(map.coValue.id);
667
+ expect(expectMap(node2.expectCoValueLoaded(map.coValue.id).getCurrentContent()).get("hello")).toEqual("world");
686
668
  });
687
669
  test("Can sync a coValue through a server to another client", async () => {
688
- const admin = newRandomAgentCredential("admin");
689
- const adminID = getAgentID(getAgent(admin));
690
- const client1 = new LocalNode(admin, newRandomSessionID(adminID));
691
- const team = client1.createTeam();
692
- const map = team.createMap();
693
- map.edit((editable) => {
694
- editable.set("hello", "world", "trusting");
695
- });
696
- const serverUser = newRandomAgentCredential("serverUser");
697
- const serverUserID = getAgentID(getAgent(serverUser));
698
- const server = new LocalNode(serverUser, newRandomSessionID(serverUserID));
699
- const [serverAsPeer, client1AsPeer] = connectedPeers("server", "client1", {
700
- peer1role: "server",
701
- peer2role: "client"
702
- });
703
- client1.sync.addPeer(serverAsPeer);
704
- server.sync.addPeer(client1AsPeer);
705
- const client2 = new LocalNode(admin, newRandomSessionID(adminID));
706
- const [serverAsOtherPeer, client2AsPeer] = connectedPeers(
707
- "server",
708
- "client2",
709
- { peer1role: "server", peer2role: "client" }
710
- );
711
- client2.sync.addPeer(serverAsOtherPeer);
712
- server.sync.addPeer(client2AsPeer);
713
- const mapOnClient2 = await client2.loadCoValue(map.coValue.id);
714
- expect(expectMap(mapOnClient2.getCurrentContent()).get("hello")).toEqual(
715
- "world"
716
- );
670
+ const admin = newRandomAgentCredential("admin");
671
+ const adminID = getAgentID(getAgent(admin));
672
+ const client1 = new LocalNode(admin, newRandomSessionID(adminID));
673
+ const team = client1.createTeam();
674
+ const map = team.createMap();
675
+ map.edit((editable) => {
676
+ editable.set("hello", "world", "trusting");
677
+ });
678
+ const serverUser = newRandomAgentCredential("serverUser");
679
+ const serverUserID = getAgentID(getAgent(serverUser));
680
+ const server = new LocalNode(serverUser, newRandomSessionID(serverUserID));
681
+ const [serverAsPeer, client1AsPeer] = connectedPeers("server", "client1", {
682
+ peer1role: "server",
683
+ peer2role: "client",
684
+ });
685
+ client1.sync.addPeer(serverAsPeer);
686
+ server.sync.addPeer(client1AsPeer);
687
+ const client2 = new LocalNode(admin, newRandomSessionID(adminID));
688
+ const [serverAsOtherPeer, client2AsPeer] = connectedPeers("server", "client2", { peer1role: "server", peer2role: "client" });
689
+ client2.sync.addPeer(serverAsOtherPeer);
690
+ server.sync.addPeer(client2AsPeer);
691
+ const mapOnClient2 = await client2.loadCoValue(map.coValue.id);
692
+ expect(expectMap(mapOnClient2.getCurrentContent()).get("hello")).toEqual("world");
717
693
  });
718
694
  test("Can sync a coValue with private transactions through a server to another client", async () => {
719
- const admin = newRandomAgentCredential("admin");
720
- const adminID = getAgentID(getAgent(admin));
721
- const client1 = new LocalNode(admin, newRandomSessionID(adminID));
722
- const team = client1.createTeam();
723
- const map = team.createMap();
724
- map.edit((editable) => {
725
- editable.set("hello", "world", "private");
726
- });
727
- const serverUser = newRandomAgentCredential("serverUser");
728
- const serverUserID = getAgentID(getAgent(serverUser));
729
- const server = new LocalNode(serverUser, newRandomSessionID(serverUserID));
730
- const [serverAsPeer, client1AsPeer] = connectedPeers("server", "client1", {
731
- trace: true,
732
- peer1role: "server",
733
- peer2role: "client"
734
- });
735
- client1.sync.addPeer(serverAsPeer);
736
- server.sync.addPeer(client1AsPeer);
737
- const client2 = new LocalNode(admin, newRandomSessionID(adminID));
738
- const [serverAsOtherPeer, client2AsPeer] = connectedPeers(
739
- "server",
740
- "client2",
741
- { trace: true, peer1role: "server", peer2role: "client" }
742
- );
743
- client2.sync.addPeer(serverAsOtherPeer);
744
- server.sync.addPeer(client2AsPeer);
745
- const mapOnClient2 = await client2.loadCoValue(map.coValue.id);
746
- expect(expectMap(mapOnClient2.getCurrentContent()).get("hello")).toEqual(
747
- "world"
748
- );
695
+ const admin = newRandomAgentCredential("admin");
696
+ const adminID = getAgentID(getAgent(admin));
697
+ const client1 = new LocalNode(admin, newRandomSessionID(adminID));
698
+ const team = client1.createTeam();
699
+ const map = team.createMap();
700
+ map.edit((editable) => {
701
+ editable.set("hello", "world", "private");
702
+ });
703
+ const serverUser = newRandomAgentCredential("serverUser");
704
+ const serverUserID = getAgentID(getAgent(serverUser));
705
+ const server = new LocalNode(serverUser, newRandomSessionID(serverUserID));
706
+ const [serverAsPeer, client1AsPeer] = connectedPeers("server", "client1", {
707
+ trace: true,
708
+ peer1role: "server",
709
+ peer2role: "client",
710
+ });
711
+ client1.sync.addPeer(serverAsPeer);
712
+ server.sync.addPeer(client1AsPeer);
713
+ const client2 = new LocalNode(admin, newRandomSessionID(adminID));
714
+ const [serverAsOtherPeer, client2AsPeer] = connectedPeers("server", "client2", { trace: true, peer1role: "server", peer2role: "client" });
715
+ client2.sync.addPeer(serverAsOtherPeer);
716
+ server.sync.addPeer(client2AsPeer);
717
+ const mapOnClient2 = await client2.loadCoValue(map.coValue.id);
718
+ expect(expectMap(mapOnClient2.getCurrentContent()).get("hello")).toEqual("world");
749
719
  });
750
720
  function teamContentEx(team) {
751
- return {
752
- action: "newContent",
753
- coValueID: team.teamMap.coValue.id
754
- };
721
+ return {
722
+ action: "newContent",
723
+ coValueID: team.teamMap.coValue.id,
724
+ };
755
725
  }
756
726
  function admContEx(adminID) {
757
- return {
758
- action: "newContent",
759
- coValueID: adminID
760
- };
727
+ return {
728
+ action: "newContent",
729
+ coValueID: adminID,
730
+ };
761
731
  }
762
732
  function teamStateEx(team) {
763
- return {
764
- action: "tellKnownState",
765
- coValueID: team.teamMap.coValue.id
766
- };
733
+ return {
734
+ action: "tellKnownState",
735
+ coValueID: team.teamMap.coValue.id,
736
+ };
767
737
  }
768
738
  function admStateEx(adminID) {
769
- return {
770
- action: "tellKnownState",
771
- coValueID: adminID
772
- };
739
+ return {
740
+ action: "tellKnownState",
741
+ coValueID: adminID,
742
+ };
773
743
  }
774
744
  function newStreamPair() {
775
- const queue = [];
776
- let resolveNextItemReady = () => {
777
- };
778
- let nextItemReady = new Promise((resolve) => {
779
- resolveNextItemReady = resolve;
780
- });
781
- const readable = new ReadableStream({
782
- async pull(controller) {
783
- let retriesLeft = 3;
784
- while (retriesLeft > 0) {
785
- retriesLeft--;
786
- if (queue.length > 0) {
787
- controller.enqueue(queue.shift());
788
- if (queue.length === 0) {
789
- nextItemReady = new Promise((resolve) => {
790
- resolveNextItemReady = resolve;
791
- });
792
- }
793
- return;
794
- } else {
795
- await nextItemReady;
796
- }
797
- }
798
- throw new Error("Should only use one retry to get next item in queue.");
799
- }
800
- });
801
- const writable = new WritableStream({
802
- write(chunk) {
803
- queue.push(chunk);
804
- if (queue.length === 1) {
805
- process.nextTick(() => resolveNextItemReady());
806
- }
807
- }
808
- });
809
- return [readable, writable];
745
+ const queue = [];
746
+ let resolveNextItemReady = () => { };
747
+ let nextItemReady = new Promise((resolve) => {
748
+ resolveNextItemReady = resolve;
749
+ });
750
+ const readable = new ReadableStream({
751
+ async pull(controller) {
752
+ let retriesLeft = 3;
753
+ while (retriesLeft > 0) {
754
+ retriesLeft--;
755
+ if (queue.length > 0) {
756
+ controller.enqueue(queue.shift());
757
+ if (queue.length === 0) {
758
+ nextItemReady = new Promise((resolve) => {
759
+ resolveNextItemReady = resolve;
760
+ });
761
+ }
762
+ return;
763
+ }
764
+ else {
765
+ await nextItemReady;
766
+ }
767
+ }
768
+ throw new Error("Should only use one retry to get next item in queue.");
769
+ },
770
+ });
771
+ const writable = new WritableStream({
772
+ write(chunk) {
773
+ queue.push(chunk);
774
+ if (queue.length === 1) {
775
+ // make sure that await write resolves before corresponding read
776
+ process.nextTick(() => resolveNextItemReady());
777
+ }
778
+ },
779
+ });
780
+ return [readable, writable];
810
781
  }
811
782
  function shouldNotResolve(promise, ops) {
812
- return new Promise((resolve, reject) => {
813
- promise.then(
814
- (v) => reject(
815
- new Error(
816
- "Should not have resolved, but resolved to " + JSON.stringify(v)
817
- )
818
- )
819
- ).catch(reject);
820
- setTimeout(resolve, ops.timeout);
821
- });
783
+ return new Promise((resolve, reject) => {
784
+ promise
785
+ .then((v) => reject(new Error("Should not have resolved, but resolved to " +
786
+ JSON.stringify(v))))
787
+ .catch(reject);
788
+ setTimeout(resolve, ops.timeout);
789
+ });
822
790
  }
823
- function connectedPeers(peer1id, peer2id, {
824
- trace = false,
825
- peer1role = "peer",
826
- peer2role = "peer"
827
- } = {}) {
828
- const [inRx1, inTx1] = newStreamPair();
829
- const [outRx1, outTx1] = newStreamPair();
830
- const [inRx2, inTx2] = newStreamPair();
831
- const [outRx2, outTx2] = newStreamPair();
832
- void outRx2.pipeThrough(
833
- new TransformStream({
834
- transform(chunk, controller) {
835
- trace && console.log(`${peer2id} -> ${peer1id}`, chunk);
836
- controller.enqueue(chunk);
837
- }
838
- })
839
- ).pipeTo(inTx1);
840
- void outRx1.pipeThrough(
841
- new TransformStream({
842
- transform(chunk, controller) {
843
- trace && console.log(`${peer1id} -> ${peer2id}`, chunk);
844
- controller.enqueue(chunk);
845
- }
846
- })
847
- ).pipeTo(inTx2);
848
- const peer2AsPeer = {
849
- id: peer2id,
850
- incoming: inRx1,
851
- outgoing: outTx1,
852
- role: peer2role
853
- };
854
- const peer1AsPeer = {
855
- id: peer1id,
856
- incoming: inRx2,
857
- outgoing: outTx2,
858
- role: peer1role
859
- };
860
- return [peer1AsPeer, peer2AsPeer];
791
+ function connectedPeers(peer1id, peer2id, { trace = false, peer1role = "peer", peer2role = "peer", } = {}) {
792
+ const [inRx1, inTx1] = newStreamPair();
793
+ const [outRx1, outTx1] = newStreamPair();
794
+ const [inRx2, inTx2] = newStreamPair();
795
+ const [outRx2, outTx2] = newStreamPair();
796
+ void outRx2
797
+ .pipeThrough(new TransformStream({
798
+ transform(chunk, controller) {
799
+ trace && console.log(`${peer2id} -> ${peer1id}`, chunk);
800
+ controller.enqueue(chunk);
801
+ },
802
+ }))
803
+ .pipeTo(inTx1);
804
+ void outRx1
805
+ .pipeThrough(new TransformStream({
806
+ transform(chunk, controller) {
807
+ trace && console.log(`${peer1id} -> ${peer2id}`, chunk);
808
+ controller.enqueue(chunk);
809
+ },
810
+ }))
811
+ .pipeTo(inTx2);
812
+ const peer2AsPeer = {
813
+ id: peer2id,
814
+ incoming: inRx1,
815
+ outgoing: outTx1,
816
+ role: peer2role,
817
+ };
818
+ const peer1AsPeer = {
819
+ id: peer1id,
820
+ incoming: inRx2,
821
+ outgoing: outTx2,
822
+ role: peer1role,
823
+ };
824
+ return [peer1AsPeer, peer2AsPeer];
861
825
  }
826
+ //# sourceMappingURL=sync.test.js.map