cojson 0.7.18 → 0.7.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +2 -2
- package/.turbo/turbo-lint.log +0 -4
- package/.turbo/turbo-test.log +262 -336
- package/CHANGELOG.md +12 -0
- package/dist/coValueCore.js +8 -1
- package/dist/coValueCore.js.map +1 -1
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/localNode.js +3 -0
- package/dist/localNode.js.map +1 -1
- package/dist/storage/FileSystem.js +48 -57
- package/dist/storage/FileSystem.js.map +1 -1
- package/dist/storage/chunksAndKnownStates.js +2 -3
- package/dist/storage/chunksAndKnownStates.js.map +1 -1
- package/dist/storage/index.js +295 -215
- package/dist/storage/index.js.map +1 -1
- package/dist/streamUtils.js +34 -30
- package/dist/streamUtils.js.map +1 -1
- package/dist/sync.js +48 -40
- package/dist/sync.js.map +1 -1
- package/dist/tests/account.test.js +2 -3
- package/dist/tests/account.test.js.map +1 -1
- package/dist/tests/sync.test.js +183 -182
- package/dist/tests/sync.test.js.map +1 -1
- package/package.json +4 -4
- package/src/coValueCore.ts +8 -1
- package/src/index.ts +5 -10
- package/src/localNode.ts +4 -0
- package/src/storage/FileSystem.ts +85 -105
- package/src/storage/chunksAndKnownStates.ts +3 -4
- package/src/storage/index.ts +413 -310
- package/src/streamUtils.ts +47 -43
- package/src/sync.ts +68 -76
- package/src/tests/account.test.ts +3 -4
- package/src/tests/sync.test.ts +731 -798
package/dist/tests/sync.test.js
CHANGED
|
@@ -4,42 +4,40 @@ import { randomAnonymousAccountAndSessionID } from "./testUtils.js";
|
|
|
4
4
|
import { connectedPeers, newQueuePair } from "../streamUtils.js";
|
|
5
5
|
import { stableStringify } from "../jsonStringify.js";
|
|
6
6
|
import { WasmCrypto } from "../crypto/WasmCrypto.js";
|
|
7
|
-
import { Effect, Queue, Sink, Stream } from "effect";
|
|
8
|
-
import { newRandomSessionID } from "../coValueCore.js";
|
|
9
7
|
import { expectMap } from "../coValue.js";
|
|
8
|
+
import { newRandomSessionID } from "../coValueCore.js";
|
|
10
9
|
const Crypto = await WasmCrypto.create();
|
|
11
|
-
test("Node replies with initial tx and header to empty subscribe", () =>
|
|
10
|
+
test("Node replies with initial tx and header to empty subscribe", async () => {
|
|
12
11
|
const [admin, session] = randomAnonymousAccountAndSessionID();
|
|
13
12
|
const node = new LocalNode(admin, session, Crypto);
|
|
14
13
|
const group = node.createGroup();
|
|
15
14
|
const map = group.createMap();
|
|
16
15
|
map.set("hello", "world", "trusting");
|
|
17
|
-
const [inRx, inTx] =
|
|
18
|
-
const [outRx, outTx] =
|
|
19
|
-
const outRxQ =
|
|
20
|
-
yield* Effect.fork(Stream.run(outRx, Sink.fromQueue(outRxQ)));
|
|
16
|
+
const [inRx, inTx] = newQueuePair();
|
|
17
|
+
const [outRx, outTx] = newQueuePair();
|
|
18
|
+
const outRxQ = outRx[Symbol.asyncIterator]();
|
|
21
19
|
node.syncManager.addPeer({
|
|
22
20
|
id: "test",
|
|
23
21
|
incoming: inRx,
|
|
24
22
|
outgoing: outTx,
|
|
25
23
|
role: "peer",
|
|
26
24
|
});
|
|
27
|
-
|
|
25
|
+
await inTx.push({
|
|
28
26
|
action: "load",
|
|
29
27
|
id: map.core.id,
|
|
30
28
|
header: false,
|
|
31
29
|
sessions: {},
|
|
32
30
|
});
|
|
33
|
-
// expect((
|
|
34
|
-
expect(
|
|
35
|
-
const mapTellKnownStateMsg =
|
|
31
|
+
// expect((await outRxQ.next()).value).toMatchObject(admStateEx(admin.id));
|
|
32
|
+
expect((await outRxQ.next()).value).toMatchObject(groupStateEx(group));
|
|
33
|
+
const mapTellKnownStateMsg = (await outRxQ.next()).value;
|
|
36
34
|
expect(mapTellKnownStateMsg).toEqual({
|
|
37
35
|
action: "known",
|
|
38
36
|
...map.core.knownState(),
|
|
39
37
|
});
|
|
40
|
-
// expect((
|
|
41
|
-
expect(
|
|
42
|
-
const newContentMsg =
|
|
38
|
+
// expect((await outRxQ.next()).value).toMatchObject(admContEx(admin.id));
|
|
39
|
+
expect((await outRxQ.next()).value).toMatchObject(groupContentEx(group));
|
|
40
|
+
const newContentMsg = (await outRxQ.next()).value;
|
|
43
41
|
expect(newContentMsg).toEqual({
|
|
44
42
|
action: "content",
|
|
45
43
|
id: map.core.id,
|
|
@@ -56,7 +54,8 @@ test("Node replies with initial tx and header to empty subscribe", () => Effect.
|
|
|
56
54
|
newTransactions: [
|
|
57
55
|
{
|
|
58
56
|
privacy: "trusting",
|
|
59
|
-
madeAt: map.core.sessionLogs.get(node.currentSessionID)
|
|
57
|
+
madeAt: map.core.sessionLogs.get(node.currentSessionID)
|
|
58
|
+
.transactions[0].madeAt,
|
|
60
59
|
changes: stableStringify([
|
|
61
60
|
{
|
|
62
61
|
op: "set",
|
|
@@ -66,29 +65,29 @@ test("Node replies with initial tx and header to empty subscribe", () => Effect.
|
|
|
66
65
|
]),
|
|
67
66
|
},
|
|
68
67
|
],
|
|
69
|
-
lastSignature: map.core.sessionLogs.get(node.currentSessionID)
|
|
68
|
+
lastSignature: map.core.sessionLogs.get(node.currentSessionID)
|
|
69
|
+
.lastSignature,
|
|
70
70
|
},
|
|
71
71
|
},
|
|
72
72
|
});
|
|
73
|
-
})
|
|
74
|
-
test("Node replies with only new tx to subscribe with some known state", () =>
|
|
73
|
+
});
|
|
74
|
+
test("Node replies with only new tx to subscribe with some known state", async () => {
|
|
75
75
|
const [admin, session] = randomAnonymousAccountAndSessionID();
|
|
76
76
|
const node = new LocalNode(admin, session, Crypto);
|
|
77
77
|
const group = node.createGroup();
|
|
78
78
|
const map = group.createMap();
|
|
79
79
|
map.set("hello", "world", "trusting");
|
|
80
80
|
map.set("goodbye", "world", "trusting");
|
|
81
|
-
const [inRx, inTx] =
|
|
82
|
-
const [outRx, outTx] =
|
|
83
|
-
const outRxQ =
|
|
84
|
-
yield* Effect.fork(Stream.run(outRx, Sink.fromQueue(outRxQ)));
|
|
81
|
+
const [inRx, inTx] = newQueuePair();
|
|
82
|
+
const [outRx, outTx] = newQueuePair();
|
|
83
|
+
const outRxQ = outRx[Symbol.asyncIterator]();
|
|
85
84
|
node.syncManager.addPeer({
|
|
86
85
|
id: "test",
|
|
87
86
|
incoming: inRx,
|
|
88
87
|
outgoing: outTx,
|
|
89
88
|
role: "peer",
|
|
90
89
|
});
|
|
91
|
-
|
|
90
|
+
await inTx.push({
|
|
92
91
|
action: "load",
|
|
93
92
|
id: map.core.id,
|
|
94
93
|
header: true,
|
|
@@ -96,16 +95,16 @@ test("Node replies with only new tx to subscribe with some known state", () => E
|
|
|
96
95
|
[node.currentSessionID]: 1,
|
|
97
96
|
},
|
|
98
97
|
});
|
|
99
|
-
// expect(
|
|
100
|
-
expect(
|
|
101
|
-
const mapTellKnownStateMsg =
|
|
98
|
+
// expect((await outRxQ.next()).value).toMatchObject(admStateEx(admin.id));
|
|
99
|
+
expect((await outRxQ.next()).value).toMatchObject(groupStateEx(group));
|
|
100
|
+
const mapTellKnownStateMsg = (await outRxQ.next()).value;
|
|
102
101
|
expect(mapTellKnownStateMsg).toEqual({
|
|
103
102
|
action: "known",
|
|
104
103
|
...map.core.knownState(),
|
|
105
104
|
});
|
|
106
|
-
// expect(
|
|
107
|
-
expect(
|
|
108
|
-
const mapNewContentMsg =
|
|
105
|
+
// expect((await outRxQ.next()).value).toMatchObject(admContEx(admin.id));
|
|
106
|
+
expect((await outRxQ.next()).value).toMatchObject(groupContentEx(group));
|
|
107
|
+
const mapNewContentMsg = (await outRxQ.next()).value;
|
|
109
108
|
expect(mapNewContentMsg).toEqual({
|
|
110
109
|
action: "content",
|
|
111
110
|
id: map.core.id,
|
|
@@ -116,7 +115,8 @@ test("Node replies with only new tx to subscribe with some known state", () => E
|
|
|
116
115
|
newTransactions: [
|
|
117
116
|
{
|
|
118
117
|
privacy: "trusting",
|
|
119
|
-
madeAt: map.core.sessionLogs.get(node.currentSessionID)
|
|
118
|
+
madeAt: map.core.sessionLogs.get(node.currentSessionID)
|
|
119
|
+
.transactions[1].madeAt,
|
|
120
120
|
changes: stableStringify([
|
|
121
121
|
{
|
|
122
122
|
op: "set",
|
|
@@ -126,28 +126,28 @@ test("Node replies with only new tx to subscribe with some known state", () => E
|
|
|
126
126
|
]),
|
|
127
127
|
},
|
|
128
128
|
],
|
|
129
|
-
lastSignature: map.core.sessionLogs.get(node.currentSessionID)
|
|
129
|
+
lastSignature: map.core.sessionLogs.get(node.currentSessionID)
|
|
130
|
+
.lastSignature,
|
|
130
131
|
},
|
|
131
132
|
},
|
|
132
133
|
});
|
|
133
|
-
})
|
|
134
|
+
});
|
|
134
135
|
test.todo("TODO: node only replies with new tx to subscribe with some known state, even in the depended on coValues");
|
|
135
|
-
test("After subscribing, node sends own known state and new txs to peer", () =>
|
|
136
|
+
test("After subscribing, node sends own known state and new txs to peer", async () => {
|
|
136
137
|
const [admin, session] = randomAnonymousAccountAndSessionID();
|
|
137
138
|
const node = new LocalNode(admin, session, Crypto);
|
|
138
139
|
const group = node.createGroup();
|
|
139
140
|
const map = group.createMap();
|
|
140
|
-
const [inRx, inTx] =
|
|
141
|
-
const [outRx, outTx] =
|
|
142
|
-
const outRxQ =
|
|
143
|
-
yield* Effect.fork(Stream.run(outRx, Sink.fromQueue(outRxQ)));
|
|
141
|
+
const [inRx, inTx] = newQueuePair();
|
|
142
|
+
const [outRx, outTx] = newQueuePair();
|
|
143
|
+
const outRxQ = outRx[Symbol.asyncIterator]();
|
|
144
144
|
node.syncManager.addPeer({
|
|
145
145
|
id: "test",
|
|
146
146
|
incoming: inRx,
|
|
147
147
|
outgoing: outTx,
|
|
148
148
|
role: "peer",
|
|
149
149
|
});
|
|
150
|
-
|
|
150
|
+
await inTx.push({
|
|
151
151
|
action: "load",
|
|
152
152
|
id: map.core.id,
|
|
153
153
|
header: false,
|
|
@@ -155,16 +155,16 @@ test("After subscribing, node sends own known state and new txs to peer", () =>
|
|
|
155
155
|
[node.currentSessionID]: 0,
|
|
156
156
|
},
|
|
157
157
|
});
|
|
158
|
-
// expect(
|
|
159
|
-
expect(
|
|
160
|
-
const mapTellKnownStateMsg =
|
|
158
|
+
// expect((await outRxQ.next()).value).toMatchObject(admStateEx(admin.id));
|
|
159
|
+
expect((await outRxQ.next()).value).toMatchObject(groupStateEx(group));
|
|
160
|
+
const mapTellKnownStateMsg = (await outRxQ.next()).value;
|
|
161
161
|
expect(mapTellKnownStateMsg).toEqual({
|
|
162
162
|
action: "known",
|
|
163
163
|
...map.core.knownState(),
|
|
164
164
|
});
|
|
165
|
-
// expect(
|
|
166
|
-
expect(
|
|
167
|
-
const mapNewContentHeaderOnlyMsg =
|
|
165
|
+
// expect((await outRxQ.next()).value).toMatchObject(admContEx(admin.id));
|
|
166
|
+
expect((await outRxQ.next()).value).toMatchObject(groupContentEx(group));
|
|
167
|
+
const mapNewContentHeaderOnlyMsg = (await outRxQ.next()).value;
|
|
168
168
|
expect(mapNewContentHeaderOnlyMsg).toEqual({
|
|
169
169
|
action: "content",
|
|
170
170
|
id: map.core.id,
|
|
@@ -172,7 +172,7 @@ test("After subscribing, node sends own known state and new txs to peer", () =>
|
|
|
172
172
|
new: {},
|
|
173
173
|
});
|
|
174
174
|
map.set("hello", "world", "trusting");
|
|
175
|
-
const mapEditMsg1 =
|
|
175
|
+
const mapEditMsg1 = (await outRxQ.next()).value;
|
|
176
176
|
expect(mapEditMsg1).toEqual({
|
|
177
177
|
action: "content",
|
|
178
178
|
id: map.core.id,
|
|
@@ -182,7 +182,8 @@ test("After subscribing, node sends own known state and new txs to peer", () =>
|
|
|
182
182
|
newTransactions: [
|
|
183
183
|
{
|
|
184
184
|
privacy: "trusting",
|
|
185
|
-
madeAt: map.core.sessionLogs.get(node.currentSessionID)
|
|
185
|
+
madeAt: map.core.sessionLogs.get(node.currentSessionID)
|
|
186
|
+
.transactions[0].madeAt,
|
|
186
187
|
changes: stableStringify([
|
|
187
188
|
{
|
|
188
189
|
op: "set",
|
|
@@ -192,12 +193,13 @@ test("After subscribing, node sends own known state and new txs to peer", () =>
|
|
|
192
193
|
]),
|
|
193
194
|
},
|
|
194
195
|
],
|
|
195
|
-
lastSignature: map.core.sessionLogs.get(node.currentSessionID)
|
|
196
|
+
lastSignature: map.core.sessionLogs.get(node.currentSessionID)
|
|
197
|
+
.lastSignature,
|
|
196
198
|
},
|
|
197
199
|
},
|
|
198
200
|
});
|
|
199
201
|
map.set("goodbye", "world", "trusting");
|
|
200
|
-
const mapEditMsg2 =
|
|
202
|
+
const mapEditMsg2 = (await outRxQ.next()).value;
|
|
201
203
|
expect(mapEditMsg2).toEqual({
|
|
202
204
|
action: "content",
|
|
203
205
|
id: map.core.id,
|
|
@@ -207,7 +209,8 @@ test("After subscribing, node sends own known state and new txs to peer", () =>
|
|
|
207
209
|
newTransactions: [
|
|
208
210
|
{
|
|
209
211
|
privacy: "trusting",
|
|
210
|
-
madeAt: map.core.sessionLogs.get(node.currentSessionID)
|
|
212
|
+
madeAt: map.core.sessionLogs.get(node.currentSessionID)
|
|
213
|
+
.transactions[1].madeAt,
|
|
211
214
|
changes: stableStringify([
|
|
212
215
|
{
|
|
213
216
|
op: "set",
|
|
@@ -217,29 +220,29 @@ test("After subscribing, node sends own known state and new txs to peer", () =>
|
|
|
217
220
|
]),
|
|
218
221
|
},
|
|
219
222
|
],
|
|
220
|
-
lastSignature: map.core.sessionLogs.get(node.currentSessionID)
|
|
223
|
+
lastSignature: map.core.sessionLogs.get(node.currentSessionID)
|
|
224
|
+
.lastSignature,
|
|
221
225
|
},
|
|
222
226
|
},
|
|
223
227
|
});
|
|
224
|
-
})
|
|
225
|
-
test("Client replies with known new content to tellKnownState from server", () =>
|
|
228
|
+
});
|
|
229
|
+
test("Client replies with known new content to tellKnownState from server", async () => {
|
|
226
230
|
const [admin, session] = randomAnonymousAccountAndSessionID();
|
|
227
231
|
const node = new LocalNode(admin, session, Crypto);
|
|
228
232
|
const group = node.createGroup();
|
|
229
233
|
const map = group.createMap();
|
|
230
234
|
map.set("hello", "world", "trusting");
|
|
231
|
-
const [inRx, inTx] =
|
|
232
|
-
const [outRx, outTx] =
|
|
233
|
-
const outRxQ =
|
|
234
|
-
yield* Effect.fork(Stream.run(outRx, Sink.fromQueue(outRxQ)));
|
|
235
|
+
const [inRx, inTx] = newQueuePair();
|
|
236
|
+
const [outRx, outTx] = newQueuePair();
|
|
237
|
+
const outRxQ = outRx[Symbol.asyncIterator]();
|
|
235
238
|
node.syncManager.addPeer({
|
|
236
239
|
id: "test",
|
|
237
240
|
incoming: inRx,
|
|
238
241
|
outgoing: outTx,
|
|
239
242
|
role: "peer",
|
|
240
243
|
});
|
|
241
|
-
// expect(
|
|
242
|
-
|
|
244
|
+
// expect((await outRxQ.next()).value).toMatchObject(groupStateEx(group));
|
|
245
|
+
await inTx.push({
|
|
243
246
|
action: "known",
|
|
244
247
|
id: map.core.id,
|
|
245
248
|
header: false,
|
|
@@ -247,16 +250,16 @@ test("Client replies with known new content to tellKnownState from server", () =
|
|
|
247
250
|
[node.currentSessionID]: 0,
|
|
248
251
|
},
|
|
249
252
|
});
|
|
250
|
-
// expect(
|
|
251
|
-
expect(
|
|
252
|
-
const mapTellKnownStateMsg =
|
|
253
|
+
// expect((await outRxQ.next()).value).toMatchObject(admStateEx(admin.id));
|
|
254
|
+
expect((await outRxQ.next()).value).toMatchObject(groupStateEx(group));
|
|
255
|
+
const mapTellKnownStateMsg = (await outRxQ.next()).value;
|
|
253
256
|
expect(mapTellKnownStateMsg).toEqual({
|
|
254
257
|
action: "known",
|
|
255
258
|
...map.core.knownState(),
|
|
256
259
|
});
|
|
257
|
-
// expect(
|
|
258
|
-
expect(
|
|
259
|
-
const mapNewContentMsg =
|
|
260
|
+
// expect((await outRxQ.next()).value).toMatchObject(admContEx(admin.id));
|
|
261
|
+
expect((await outRxQ.next()).value).toMatchObject(groupContentEx(group));
|
|
262
|
+
const mapNewContentMsg = (await outRxQ.next()).value;
|
|
260
263
|
expect(mapNewContentMsg).toEqual({
|
|
261
264
|
action: "content",
|
|
262
265
|
id: map.core.id,
|
|
@@ -267,7 +270,8 @@ test("Client replies with known new content to tellKnownState from server", () =
|
|
|
267
270
|
newTransactions: [
|
|
268
271
|
{
|
|
269
272
|
privacy: "trusting",
|
|
270
|
-
madeAt: map.core.sessionLogs.get(node.currentSessionID)
|
|
273
|
+
madeAt: map.core.sessionLogs.get(node.currentSessionID)
|
|
274
|
+
.transactions[0].madeAt,
|
|
271
275
|
changes: stableStringify([
|
|
272
276
|
{
|
|
273
277
|
op: "set",
|
|
@@ -277,27 +281,27 @@ test("Client replies with known new content to tellKnownState from server", () =
|
|
|
277
281
|
]),
|
|
278
282
|
},
|
|
279
283
|
],
|
|
280
|
-
lastSignature: map.core.sessionLogs.get(node.currentSessionID)
|
|
284
|
+
lastSignature: map.core.sessionLogs.get(node.currentSessionID)
|
|
285
|
+
.lastSignature,
|
|
281
286
|
},
|
|
282
287
|
},
|
|
283
288
|
});
|
|
284
|
-
})
|
|
285
|
-
test("No matter the optimistic known state, node respects invalid known state messages and resyncs", () =>
|
|
289
|
+
});
|
|
290
|
+
test("No matter the optimistic known state, node respects invalid known state messages and resyncs", async () => {
|
|
286
291
|
const [admin, session] = randomAnonymousAccountAndSessionID();
|
|
287
292
|
const node = new LocalNode(admin, session, Crypto);
|
|
288
293
|
const group = node.createGroup();
|
|
289
294
|
const map = group.createMap();
|
|
290
|
-
const [inRx, inTx] =
|
|
291
|
-
const [outRx, outTx] =
|
|
292
|
-
const outRxQ =
|
|
293
|
-
yield* Effect.fork(Stream.run(outRx, Sink.fromQueue(outRxQ)));
|
|
295
|
+
const [inRx, inTx] = newQueuePair();
|
|
296
|
+
const [outRx, outTx] = newQueuePair();
|
|
297
|
+
const outRxQ = outRx[Symbol.asyncIterator]();
|
|
294
298
|
node.syncManager.addPeer({
|
|
295
299
|
id: "test",
|
|
296
300
|
incoming: inRx,
|
|
297
301
|
outgoing: outTx,
|
|
298
302
|
role: "peer",
|
|
299
303
|
});
|
|
300
|
-
|
|
304
|
+
await inTx.push({
|
|
301
305
|
action: "load",
|
|
302
306
|
id: map.core.id,
|
|
303
307
|
header: false,
|
|
@@ -305,16 +309,16 @@ test("No matter the optimistic known state, node respects invalid known state me
|
|
|
305
309
|
[node.currentSessionID]: 0,
|
|
306
310
|
},
|
|
307
311
|
});
|
|
308
|
-
// expect(
|
|
309
|
-
expect(
|
|
310
|
-
const mapTellKnownStateMsg =
|
|
312
|
+
// expect((await outRxQ.next()).value).toMatchObject(admStateEx(admin.id));
|
|
313
|
+
expect((await outRxQ.next()).value).toMatchObject(groupStateEx(group));
|
|
314
|
+
const mapTellKnownStateMsg = (await outRxQ.next()).value;
|
|
311
315
|
expect(mapTellKnownStateMsg).toEqual({
|
|
312
316
|
action: "known",
|
|
313
317
|
...map.core.knownState(),
|
|
314
318
|
});
|
|
315
|
-
// expect(
|
|
316
|
-
expect(
|
|
317
|
-
const mapNewContentHeaderOnlyMsg =
|
|
319
|
+
// expect((await outRxQ.next()).value).toMatchObject(admContEx(admin.id));
|
|
320
|
+
expect((await outRxQ.next()).value).toMatchObject(groupContentEx(group));
|
|
321
|
+
const mapNewContentHeaderOnlyMsg = (await outRxQ.next()).value;
|
|
318
322
|
expect(mapNewContentHeaderOnlyMsg).toEqual({
|
|
319
323
|
action: "content",
|
|
320
324
|
id: map.core.id,
|
|
@@ -323,9 +327,9 @@ test("No matter the optimistic known state, node respects invalid known state me
|
|
|
323
327
|
});
|
|
324
328
|
map.set("hello", "world", "trusting");
|
|
325
329
|
map.set("goodbye", "world", "trusting");
|
|
326
|
-
const _mapEditMsgs =
|
|
330
|
+
const _mapEditMsgs = (await outRxQ.next()).value;
|
|
327
331
|
console.log("Sending correction");
|
|
328
|
-
|
|
332
|
+
await inTx.push({
|
|
329
333
|
action: "known",
|
|
330
334
|
isCorrection: true,
|
|
331
335
|
id: map.core.id,
|
|
@@ -334,7 +338,7 @@ test("No matter the optimistic known state, node respects invalid known state me
|
|
|
334
338
|
[node.currentSessionID]: 1,
|
|
335
339
|
},
|
|
336
340
|
});
|
|
337
|
-
const newContentAfterWrongAssumedState =
|
|
341
|
+
const newContentAfterWrongAssumedState = (await outRxQ.next()).value;
|
|
338
342
|
expect(newContentAfterWrongAssumedState).toEqual({
|
|
339
343
|
action: "content",
|
|
340
344
|
id: map.core.id,
|
|
@@ -345,7 +349,8 @@ test("No matter the optimistic known state, node respects invalid known state me
|
|
|
345
349
|
newTransactions: [
|
|
346
350
|
{
|
|
347
351
|
privacy: "trusting",
|
|
348
|
-
madeAt: map.core.sessionLogs.get(node.currentSessionID)
|
|
352
|
+
madeAt: map.core.sessionLogs.get(node.currentSessionID)
|
|
353
|
+
.transactions[1].madeAt,
|
|
349
354
|
changes: stableStringify([
|
|
350
355
|
{
|
|
351
356
|
op: "set",
|
|
@@ -355,20 +360,20 @@ test("No matter the optimistic known state, node respects invalid known state me
|
|
|
355
360
|
]),
|
|
356
361
|
},
|
|
357
362
|
],
|
|
358
|
-
lastSignature: map.core.sessionLogs.get(node.currentSessionID)
|
|
363
|
+
lastSignature: map.core.sessionLogs.get(node.currentSessionID)
|
|
364
|
+
.lastSignature,
|
|
359
365
|
},
|
|
360
366
|
},
|
|
361
367
|
});
|
|
362
|
-
})
|
|
363
|
-
test("If we add a peer, but it never subscribes to a coValue, it won't get any messages", () =>
|
|
368
|
+
});
|
|
369
|
+
test("If we add a peer, but it never subscribes to a coValue, it won't get any messages", async () => {
|
|
364
370
|
const [admin, session] = randomAnonymousAccountAndSessionID();
|
|
365
371
|
const node = new LocalNode(admin, session, Crypto);
|
|
366
372
|
const group = node.createGroup();
|
|
367
373
|
const map = group.createMap();
|
|
368
|
-
const [inRx, _inTx] =
|
|
369
|
-
const [outRx, outTx] =
|
|
370
|
-
const outRxQ =
|
|
371
|
-
yield* Effect.fork(Stream.run(outRx, Sink.fromQueue(outRxQ)));
|
|
374
|
+
const [inRx, _inTx] = newQueuePair();
|
|
375
|
+
const [outRx, outTx] = newQueuePair();
|
|
376
|
+
const outRxQ = outRx[Symbol.asyncIterator]();
|
|
372
377
|
node.syncManager.addPeer({
|
|
373
378
|
id: "test",
|
|
374
379
|
incoming: inRx,
|
|
@@ -376,35 +381,36 @@ test("If we add a peer, but it never subscribes to a coValue, it won't get any m
|
|
|
376
381
|
role: "peer",
|
|
377
382
|
});
|
|
378
383
|
map.set("hello", "world", "trusting");
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
384
|
+
const timeoutPromise = new Promise((resolve) => setTimeout(() => resolve("neverHappened"), 100));
|
|
385
|
+
const result = await Promise.race([
|
|
386
|
+
outRxQ.next().then((value) => value.value),
|
|
387
|
+
timeoutPromise,
|
|
388
|
+
]);
|
|
389
|
+
expect(result).toEqual("neverHappened");
|
|
390
|
+
});
|
|
391
|
+
test.todo("If we add a server peer, all updates to all coValues are sent to it, even if it doesn't subscribe", async () => {
|
|
385
392
|
const [admin, session] = randomAnonymousAccountAndSessionID();
|
|
386
393
|
const node = new LocalNode(admin, session, Crypto);
|
|
387
394
|
const group = node.createGroup();
|
|
388
395
|
const map = group.createMap();
|
|
389
|
-
const [inRx, _inTx] =
|
|
390
|
-
const [outRx, outTx] =
|
|
391
|
-
const outRxQ =
|
|
392
|
-
yield* Effect.fork(Stream.run(outRx, Sink.fromQueue(outRxQ)));
|
|
396
|
+
const [inRx, _inTx] = newQueuePair();
|
|
397
|
+
const [outRx, outTx] = newQueuePair();
|
|
398
|
+
const outRxQ = outRx[Symbol.asyncIterator]();
|
|
393
399
|
node.syncManager.addPeer({
|
|
394
400
|
id: "test",
|
|
395
401
|
incoming: inRx,
|
|
396
402
|
outgoing: outTx,
|
|
397
403
|
role: "server",
|
|
398
404
|
});
|
|
399
|
-
// expect(
|
|
405
|
+
// expect((await outRxQ.next()).value).toMatchObject({
|
|
400
406
|
// action: "load",
|
|
401
407
|
// id: adminID,
|
|
402
408
|
// });
|
|
403
|
-
expect(
|
|
409
|
+
expect((await outRxQ.next()).value).toMatchObject({
|
|
404
410
|
action: "load",
|
|
405
411
|
id: group.core.id,
|
|
406
412
|
});
|
|
407
|
-
const mapSubscribeMsg =
|
|
413
|
+
const mapSubscribeMsg = (await outRxQ.next()).value;
|
|
408
414
|
expect(mapSubscribeMsg).toEqual({
|
|
409
415
|
action: "load",
|
|
410
416
|
id: map.core.id,
|
|
@@ -412,9 +418,9 @@ test.todo("If we add a server peer, all updates to all coValues are sent to it,
|
|
|
412
418
|
sessions: {},
|
|
413
419
|
});
|
|
414
420
|
map.set("hello", "world", "trusting");
|
|
415
|
-
// expect(
|
|
416
|
-
expect(
|
|
417
|
-
const mapNewContentMsg =
|
|
421
|
+
// expect((await outRxQ.next()).value).toMatchObject(admContEx(admin.id));
|
|
422
|
+
expect((await outRxQ.next()).value).toMatchObject(groupContentEx(group));
|
|
423
|
+
const mapNewContentMsg = (await outRxQ.next()).value;
|
|
418
424
|
expect(mapNewContentMsg).toEqual({
|
|
419
425
|
action: "content",
|
|
420
426
|
id: map.core.id,
|
|
@@ -439,89 +445,86 @@ test.todo("If we add a server peer, all updates to all coValues are sent to it,
|
|
|
439
445
|
},
|
|
440
446
|
},
|
|
441
447
|
});
|
|
442
|
-
})
|
|
443
|
-
test.skip("If we add a server peer, newly created coValues are auto-subscribed to", () =>
|
|
448
|
+
});
|
|
449
|
+
test.skip("If we add a server peer, newly created coValues are auto-subscribed to", async () => {
|
|
444
450
|
const [admin, session] = randomAnonymousAccountAndSessionID();
|
|
445
451
|
const node = new LocalNode(admin, session, Crypto);
|
|
446
452
|
const group = node.createGroup();
|
|
447
|
-
const [inRx, _inTx] =
|
|
448
|
-
const [outRx, outTx] =
|
|
449
|
-
const outRxQ =
|
|
450
|
-
yield* Effect.fork(Stream.run(outRx, Sink.fromQueue(outRxQ)));
|
|
453
|
+
const [inRx, _inTx] = newQueuePair();
|
|
454
|
+
const [outRx, outTx] = newQueuePair();
|
|
455
|
+
const outRxQ = outRx[Symbol.asyncIterator]();
|
|
451
456
|
node.syncManager.addPeer({
|
|
452
457
|
id: "test",
|
|
453
458
|
incoming: inRx,
|
|
454
459
|
outgoing: outTx,
|
|
455
460
|
role: "server",
|
|
456
461
|
});
|
|
457
|
-
// expect(
|
|
462
|
+
// expect((await outRxQ.next()).value).toMatchObject({
|
|
458
463
|
// action: "load",
|
|
459
464
|
// id: admin.id,
|
|
460
465
|
// });
|
|
461
|
-
expect(
|
|
466
|
+
expect((await outRxQ.next()).value).toMatchObject({
|
|
462
467
|
action: "load",
|
|
463
468
|
id: group.core.id,
|
|
464
469
|
});
|
|
465
470
|
const map = group.createMap();
|
|
466
|
-
const mapSubscribeMsg =
|
|
471
|
+
const mapSubscribeMsg = (await outRxQ.next()).value;
|
|
467
472
|
expect(mapSubscribeMsg).toEqual({
|
|
468
473
|
action: "load",
|
|
469
474
|
...map.core.knownState(),
|
|
470
475
|
});
|
|
471
|
-
// expect(
|
|
472
|
-
expect(
|
|
473
|
-
const mapContentMsg =
|
|
476
|
+
// expect((await outRxQ.next()).value).toMatchObject(admContEx(adminID));
|
|
477
|
+
expect((await outRxQ.next()).value).toMatchObject(groupContentEx(group));
|
|
478
|
+
const mapContentMsg = (await outRxQ.next()).value;
|
|
474
479
|
expect(mapContentMsg).toEqual({
|
|
475
480
|
action: "content",
|
|
476
481
|
id: map.core.id,
|
|
477
482
|
header: map.core.header,
|
|
478
483
|
new: {},
|
|
479
484
|
});
|
|
480
|
-
})
|
|
485
|
+
});
|
|
481
486
|
test.todo("TODO: when receiving a subscribe response that is behind our optimistic state (due to already sent content), we ignore it");
|
|
482
|
-
test("When we connect a new server peer, we try to sync all existing coValues to it", () =>
|
|
487
|
+
test("When we connect a new server peer, we try to sync all existing coValues to it", async () => {
|
|
483
488
|
const [admin, session] = randomAnonymousAccountAndSessionID();
|
|
484
489
|
const node = new LocalNode(admin, session, Crypto);
|
|
485
490
|
const group = node.createGroup();
|
|
486
491
|
const map = group.createMap();
|
|
487
|
-
const [inRx, _inTx] =
|
|
488
|
-
const [outRx, outTx] =
|
|
489
|
-
const outRxQ =
|
|
490
|
-
yield* Effect.fork(Stream.run(outRx, Sink.fromQueue(outRxQ)));
|
|
492
|
+
const [inRx, _inTx] = newQueuePair();
|
|
493
|
+
const [outRx, outTx] = newQueuePair();
|
|
494
|
+
const outRxQ = outRx[Symbol.asyncIterator]();
|
|
491
495
|
node.syncManager.addPeer({
|
|
492
496
|
id: "test",
|
|
493
497
|
incoming: inRx,
|
|
494
498
|
outgoing: outTx,
|
|
495
499
|
role: "server",
|
|
496
500
|
});
|
|
497
|
-
// const _adminSubscribeMessage =
|
|
498
|
-
const groupSubscribeMessage =
|
|
501
|
+
// const _adminSubscribeMessage = await outRxQ.next();
|
|
502
|
+
const groupSubscribeMessage = (await outRxQ.next()).value;
|
|
499
503
|
expect(groupSubscribeMessage).toEqual({
|
|
500
504
|
action: "load",
|
|
501
505
|
...group.core.knownState(),
|
|
502
506
|
});
|
|
503
|
-
const secondMessage =
|
|
507
|
+
const secondMessage = (await outRxQ.next()).value;
|
|
504
508
|
expect(secondMessage).toEqual({
|
|
505
509
|
action: "load",
|
|
506
510
|
...map.core.knownState(),
|
|
507
511
|
});
|
|
508
|
-
})
|
|
509
|
-
test("When receiving a subscribe with a known state that is ahead of our own, peers should respond with a corresponding subscribe response message", () =>
|
|
512
|
+
});
|
|
513
|
+
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 () => {
|
|
510
514
|
const [admin, session] = randomAnonymousAccountAndSessionID();
|
|
511
515
|
const node = new LocalNode(admin, session, Crypto);
|
|
512
516
|
const group = node.createGroup();
|
|
513
517
|
const map = group.createMap();
|
|
514
|
-
const [inRx, inTx] =
|
|
515
|
-
const [outRx, outTx] =
|
|
516
|
-
const outRxQ =
|
|
517
|
-
yield* Effect.fork(Stream.run(outRx, Sink.fromQueue(outRxQ)));
|
|
518
|
+
const [inRx, inTx] = newQueuePair();
|
|
519
|
+
const [outRx, outTx] = newQueuePair();
|
|
520
|
+
const outRxQ = outRx[Symbol.asyncIterator]();
|
|
518
521
|
node.syncManager.addPeer({
|
|
519
522
|
id: "test",
|
|
520
523
|
incoming: inRx,
|
|
521
524
|
outgoing: outTx,
|
|
522
525
|
role: "peer",
|
|
523
526
|
});
|
|
524
|
-
|
|
527
|
+
await inTx.push({
|
|
525
528
|
action: "load",
|
|
526
529
|
id: map.core.id,
|
|
527
530
|
header: true,
|
|
@@ -529,23 +532,22 @@ test("When receiving a subscribe with a known state that is ahead of our own, pe
|
|
|
529
532
|
[node.currentSessionID]: 1,
|
|
530
533
|
},
|
|
531
534
|
});
|
|
532
|
-
// expect(
|
|
533
|
-
expect(
|
|
534
|
-
const mapTellKnownState =
|
|
535
|
+
// expect((await outRxQ.next()).value).toMatchObject(admStateEx(admin.id));
|
|
536
|
+
expect((await outRxQ.next()).value).toMatchObject(groupStateEx(group));
|
|
537
|
+
const mapTellKnownState = (await outRxQ.next()).value;
|
|
535
538
|
expect(mapTellKnownState).toEqual({
|
|
536
539
|
action: "known",
|
|
537
540
|
...map.core.knownState(),
|
|
538
541
|
});
|
|
539
|
-
})
|
|
540
|
-
test.skip("When replaying creation and transactions of a coValue as new content, the receiving peer integrates this information", () =>
|
|
542
|
+
});
|
|
543
|
+
test.skip("When replaying creation and transactions of a coValue as new content, the receiving peer integrates this information", async () => {
|
|
541
544
|
// 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
|
|
542
545
|
const [admin, session] = randomAnonymousAccountAndSessionID();
|
|
543
546
|
const node1 = new LocalNode(admin, session, Crypto);
|
|
544
547
|
const group = node1.createGroup();
|
|
545
|
-
const [inRx1, inTx1] =
|
|
546
|
-
const [outRx1, outTx1] =
|
|
547
|
-
const outRxQ1 =
|
|
548
|
-
yield* Effect.fork(Stream.run(outRx1, Sink.fromQueue(outRxQ1)));
|
|
548
|
+
const [inRx1, inTx1] = newQueuePair();
|
|
549
|
+
const [outRx1, outTx1] = newQueuePair();
|
|
550
|
+
const outRxQ1 = outRx1[Symbol.asyncIterator]();
|
|
549
551
|
node1.syncManager.addPeer({
|
|
550
552
|
id: "test2",
|
|
551
553
|
incoming: inRx1,
|
|
@@ -553,56 +555,55 @@ test.skip("When replaying creation and transactions of a coValue as new content,
|
|
|
553
555
|
role: "server",
|
|
554
556
|
});
|
|
555
557
|
const node2 = new LocalNode(admin, newRandomSessionID(admin.id), Crypto);
|
|
556
|
-
const [inRx2, inTx2] =
|
|
557
|
-
const [outRx2, outTx2] =
|
|
558
|
-
const outRxQ2 =
|
|
559
|
-
yield* Effect.fork(Stream.run(outRx2, Sink.fromQueue(outRxQ1)));
|
|
558
|
+
const [inRx2, inTx2] = newQueuePair();
|
|
559
|
+
const [outRx2, outTx2] = newQueuePair();
|
|
560
|
+
const outRxQ2 = outRx2[Symbol.asyncIterator]();
|
|
560
561
|
node2.syncManager.addPeer({
|
|
561
562
|
id: "test1",
|
|
562
563
|
incoming: inRx2,
|
|
563
564
|
outgoing: outTx2,
|
|
564
565
|
role: "client",
|
|
565
566
|
});
|
|
566
|
-
const adminSubscribeMessage =
|
|
567
|
+
const adminSubscribeMessage = (await outRxQ1.next()).value;
|
|
567
568
|
expect(adminSubscribeMessage).toMatchObject({
|
|
568
569
|
action: "load",
|
|
569
570
|
id: admin.id,
|
|
570
571
|
});
|
|
571
|
-
const groupSubscribeMsg =
|
|
572
|
+
const groupSubscribeMsg = (await outRxQ1.next()).value;
|
|
572
573
|
expect(groupSubscribeMsg).toMatchObject({
|
|
573
574
|
action: "load",
|
|
574
575
|
id: group.core.id,
|
|
575
576
|
});
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
// const adminTellKnownStateMsg =
|
|
577
|
+
await inTx2.push(adminSubscribeMessage);
|
|
578
|
+
await inTx2.push(groupSubscribeMsg);
|
|
579
|
+
// const adminTellKnownStateMsg = (await outRxQ2.next()).value;
|
|
579
580
|
// expect(adminTellKnownStateMsg).toMatchObject(admStateEx(admin.id));
|
|
580
|
-
const groupTellKnownStateMsg =
|
|
581
|
+
const groupTellKnownStateMsg = (await outRxQ2.next()).value;
|
|
581
582
|
expect(groupTellKnownStateMsg).toMatchObject(groupStateEx(group));
|
|
582
583
|
expect(node2.syncManager.peers["test1"].optimisticKnownStates[group.core.id]).toBeDefined();
|
|
583
|
-
//
|
|
584
|
-
|
|
585
|
-
// const adminContentMsg =
|
|
584
|
+
// await inTx1.push(adminTellKnownStateMsg);
|
|
585
|
+
await inTx1.push(groupTellKnownStateMsg);
|
|
586
|
+
// const adminContentMsg = (await outRxQ1.next()).value;
|
|
586
587
|
// expect(adminContentMsg).toMatchObject(admContEx(admin.id));
|
|
587
|
-
const groupContentMsg =
|
|
588
|
+
const groupContentMsg = (await outRxQ1.next()).value;
|
|
588
589
|
expect(groupContentMsg).toMatchObject(groupContentEx(group));
|
|
589
|
-
//
|
|
590
|
-
|
|
590
|
+
// await inTx2.push(adminContentMsg);
|
|
591
|
+
await inTx2.push(groupContentMsg);
|
|
591
592
|
const map = group.createMap();
|
|
592
|
-
const mapSubscriptionMsg =
|
|
593
|
+
const mapSubscriptionMsg = (await outRxQ1.next()).value;
|
|
593
594
|
expect(mapSubscriptionMsg).toMatchObject({
|
|
594
595
|
action: "load",
|
|
595
596
|
id: map.core.id,
|
|
596
597
|
});
|
|
597
|
-
const mapNewContentMsg =
|
|
598
|
+
const mapNewContentMsg = (await outRxQ1.next()).value;
|
|
598
599
|
expect(mapNewContentMsg).toEqual({
|
|
599
600
|
action: "content",
|
|
600
601
|
id: map.core.id,
|
|
601
602
|
header: map.core.header,
|
|
602
603
|
new: {},
|
|
603
604
|
});
|
|
604
|
-
|
|
605
|
-
const mapTellKnownStateMsg =
|
|
605
|
+
await inTx2.push(mapSubscriptionMsg);
|
|
606
|
+
const mapTellKnownStateMsg = (await outRxQ2.next()).value;
|
|
606
607
|
expect(mapTellKnownStateMsg).toEqual({
|
|
607
608
|
action: "known",
|
|
608
609
|
id: map.core.id,
|
|
@@ -610,13 +611,13 @@ test.skip("When replaying creation and transactions of a coValue as new content,
|
|
|
610
611
|
sessions: {},
|
|
611
612
|
});
|
|
612
613
|
expect(node2.coValues[map.core.id]?.state).toEqual("loading");
|
|
613
|
-
|
|
614
|
+
await inTx2.push(mapNewContentMsg);
|
|
614
615
|
map.set("hello", "world", "trusting");
|
|
615
|
-
const mapEditMsg =
|
|
616
|
-
|
|
617
|
-
|
|
616
|
+
const mapEditMsg = (await outRxQ1.next()).value;
|
|
617
|
+
await inTx2.push(mapEditMsg);
|
|
618
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
618
619
|
expect(expectMap(node2.expectCoValueLoaded(map.core.id).getCurrentContent()).get("hello")).toEqual("world");
|
|
619
|
-
})
|
|
620
|
+
});
|
|
620
621
|
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 () => {
|
|
621
622
|
/*
|
|
622
623
|
// 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
|
|
@@ -645,7 +646,7 @@ test.skip("When loading a coValue on one node, the server node it is requested f
|
|
|
645
646
|
).toEqual("world");
|
|
646
647
|
*/
|
|
647
648
|
});
|
|
648
|
-
test("Can sync a coValue through a server to another client", () =>
|
|
649
|
+
test("Can sync a coValue through a server to another client", async () => {
|
|
649
650
|
const [admin, session] = randomAnonymousAccountAndSessionID();
|
|
650
651
|
const client1 = new LocalNode(admin, session, Crypto);
|
|
651
652
|
const group = client1.createGroup();
|
|
@@ -653,7 +654,7 @@ test("Can sync a coValue through a server to another client", () => Effect.gen(f
|
|
|
653
654
|
map.set("hello", "world", "trusting");
|
|
654
655
|
const [serverUser, serverSession] = randomAnonymousAccountAndSessionID();
|
|
655
656
|
const server = new LocalNode(serverUser, serverSession, Crypto);
|
|
656
|
-
const [serverAsPeerForClient1, client1AsPeer] =
|
|
657
|
+
const [serverAsPeerForClient1, client1AsPeer] = await connectedPeers("serverFor1", "client1", {
|
|
657
658
|
peer1role: "server",
|
|
658
659
|
peer2role: "client",
|
|
659
660
|
trace: true,
|
|
@@ -661,20 +662,20 @@ test("Can sync a coValue through a server to another client", () => Effect.gen(f
|
|
|
661
662
|
client1.syncManager.addPeer(serverAsPeerForClient1);
|
|
662
663
|
server.syncManager.addPeer(client1AsPeer);
|
|
663
664
|
const client2 = new LocalNode(admin, newRandomSessionID(admin.id), Crypto);
|
|
664
|
-
const [serverAsPeerForClient2, client2AsPeer] =
|
|
665
|
+
const [serverAsPeerForClient2, client2AsPeer] = connectedPeers("serverFor2", "client2", {
|
|
665
666
|
peer1role: "server",
|
|
666
667
|
peer2role: "client",
|
|
667
668
|
trace: true,
|
|
668
669
|
});
|
|
669
670
|
client2.syncManager.addPeer(serverAsPeerForClient2);
|
|
670
671
|
server.syncManager.addPeer(client2AsPeer);
|
|
671
|
-
const mapOnClient2 =
|
|
672
|
+
const mapOnClient2 = await client2.loadCoValueCore(map.core.id);
|
|
672
673
|
if (mapOnClient2 === "unavailable") {
|
|
673
674
|
throw new Error("Map is unavailable");
|
|
674
675
|
}
|
|
675
676
|
expect(expectMap(mapOnClient2.getCurrentContent()).get("hello")).toEqual("world");
|
|
676
|
-
})
|
|
677
|
-
test("Can sync a coValue with private transactions through a server to another client", () =>
|
|
677
|
+
});
|
|
678
|
+
test("Can sync a coValue with private transactions through a server to another client", async () => {
|
|
678
679
|
const [admin, session] = randomAnonymousAccountAndSessionID();
|
|
679
680
|
const client1 = new LocalNode(admin, session, Crypto);
|
|
680
681
|
const group = client1.createGroup();
|
|
@@ -682,7 +683,7 @@ test("Can sync a coValue with private transactions through a server to another c
|
|
|
682
683
|
map.set("hello", "world", "private");
|
|
683
684
|
const [serverUser, serverSession] = randomAnonymousAccountAndSessionID();
|
|
684
685
|
const server = new LocalNode(serverUser, serverSession, Crypto);
|
|
685
|
-
const [serverAsPeer, client1AsPeer] =
|
|
686
|
+
const [serverAsPeer, client1AsPeer] = await connectedPeers("server", "client1", {
|
|
686
687
|
trace: true,
|
|
687
688
|
peer1role: "server",
|
|
688
689
|
peer2role: "client",
|
|
@@ -690,19 +691,19 @@ test("Can sync a coValue with private transactions through a server to another c
|
|
|
690
691
|
client1.syncManager.addPeer(serverAsPeer);
|
|
691
692
|
server.syncManager.addPeer(client1AsPeer);
|
|
692
693
|
const client2 = new LocalNode(admin, newRandomSessionID(admin.id), Crypto);
|
|
693
|
-
const [serverAsOtherPeer, client2AsPeer] =
|
|
694
|
+
const [serverAsOtherPeer, client2AsPeer] = await connectedPeers("server", "client2", {
|
|
694
695
|
trace: true,
|
|
695
696
|
peer1role: "server",
|
|
696
697
|
peer2role: "client",
|
|
697
698
|
});
|
|
698
699
|
client2.syncManager.addPeer(serverAsOtherPeer);
|
|
699
700
|
server.syncManager.addPeer(client2AsPeer);
|
|
700
|
-
const mapOnClient2 =
|
|
701
|
+
const mapOnClient2 = await client2.loadCoValueCore(map.core.id);
|
|
701
702
|
if (mapOnClient2 === "unavailable") {
|
|
702
703
|
throw new Error("Map is unavailable");
|
|
703
704
|
}
|
|
704
705
|
expect(expectMap(mapOnClient2.getCurrentContent()).get("hello")).toEqual("world");
|
|
705
|
-
})
|
|
706
|
+
});
|
|
706
707
|
test.skip("When a peer's incoming/readable stream closes, we remove the peer", async () => {
|
|
707
708
|
/*
|
|
708
709
|
const [admin, session] = randomAnonymousAccountAndSessionID();
|
|
@@ -814,14 +815,14 @@ test.skip("When a peer's outgoing/writable stream closes, we remove the peer", a
|
|
|
814
815
|
expect(node.syncManager.peers["test"]).toBeUndefined();
|
|
815
816
|
*/
|
|
816
817
|
});
|
|
817
|
-
test("If we start loading a coValue before connecting to a peer that has it, it will load it once we connect", () =>
|
|
818
|
+
test("If we start loading a coValue before connecting to a peer that has it, it will load it once we connect", async () => {
|
|
818
819
|
const [admin, session] = randomAnonymousAccountAndSessionID();
|
|
819
820
|
const node1 = new LocalNode(admin, session, Crypto);
|
|
820
821
|
const group = node1.createGroup();
|
|
821
822
|
const map = group.createMap();
|
|
822
823
|
map.set("hello", "world", "trusting");
|
|
823
824
|
const node2 = new LocalNode(admin, newRandomSessionID(admin.id), Crypto);
|
|
824
|
-
const [node1asPeer, node2asPeer] =
|
|
825
|
+
const [node1asPeer, node2asPeer] = await connectedPeers("peer1", "peer2", {
|
|
825
826
|
peer1role: "server",
|
|
826
827
|
peer2role: "client",
|
|
827
828
|
trace: true,
|
|
@@ -830,12 +831,12 @@ test("If we start loading a coValue before connecting to a peer that has it, it
|
|
|
830
831
|
const mapOnNode2Promise = node2.loadCoValueCore(map.core.id);
|
|
831
832
|
expect(node2.coValues[map.core.id]?.state).toEqual("loading");
|
|
832
833
|
node2.syncManager.addPeer(node1asPeer);
|
|
833
|
-
const mapOnNode2 =
|
|
834
|
+
const mapOnNode2 = await mapOnNode2Promise;
|
|
834
835
|
if (mapOnNode2 === "unavailable") {
|
|
835
836
|
throw new Error("Map is unavailable");
|
|
836
837
|
}
|
|
837
838
|
expect(expectMap(mapOnNode2.getCurrentContent()).get("hello")).toEqual("world");
|
|
838
|
-
})
|
|
839
|
+
});
|
|
839
840
|
function groupContentEx(group) {
|
|
840
841
|
return {
|
|
841
842
|
action: "content",
|