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