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/src/sync.test.ts
CHANGED
|
@@ -1,115 +1,106 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
} from
|
|
7
|
-
import { LocalNode } from './node.js';
|
|
8
|
-
import { Peer, PeerID, SyncMessage } from './sync.js';
|
|
9
|
-
import { expectMap } from './contentType.js';
|
|
10
|
-
import { MapOpPayload } from './contentTypes/coMap.js';
|
|
11
|
-
import { Team } from './permissions.js';
|
|
1
|
+
import { newRandomSessionID } from "./coValue.js";
|
|
2
|
+
import { LocalNode } from "./node.js";
|
|
3
|
+
import { Peer, PeerID, SyncMessage } from "./sync.js";
|
|
4
|
+
import { expectMap } from "./contentType.js";
|
|
5
|
+
import { MapOpPayload } from "./contentTypes/coMap.js";
|
|
6
|
+
import { Team } from "./permissions.js";
|
|
12
7
|
import {
|
|
13
8
|
ReadableStream,
|
|
14
9
|
WritableStream,
|
|
15
10
|
TransformStream,
|
|
16
11
|
} from "isomorphic-streams";
|
|
17
|
-
import {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const node = new LocalNode(admin, newRandomSessionID(adminID));
|
|
12
|
+
import {
|
|
13
|
+
connectedPeers,
|
|
14
|
+
newStreamPair,
|
|
15
|
+
randomAnonymousAccountAndSessionID,
|
|
16
|
+
shouldNotResolve,
|
|
17
|
+
} from "./testUtils.js";
|
|
18
|
+
import { AccountID } from "./account.js";
|
|
26
19
|
|
|
27
|
-
|
|
20
|
+
test("Node replies with initial tx and header to empty subscribe", async () => {
|
|
21
|
+
const [admin, session] = randomAnonymousAccountAndSessionID();
|
|
22
|
+
const node = new LocalNode(admin, session);
|
|
28
23
|
|
|
29
|
-
|
|
24
|
+
const team = node.createTeam();
|
|
30
25
|
|
|
31
|
-
|
|
32
|
-
editable.set("hello", "world", "trusting");
|
|
33
|
-
});
|
|
26
|
+
const map = team.createMap();
|
|
34
27
|
|
|
35
|
-
|
|
36
|
-
|
|
28
|
+
map.edit((editable) => {
|
|
29
|
+
editable.set("hello", "world", "trusting");
|
|
30
|
+
});
|
|
37
31
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
incoming: inRx,
|
|
41
|
-
outgoing: outTx,
|
|
42
|
-
role: "peer",
|
|
43
|
-
});
|
|
32
|
+
const [inRx, inTx] = newStreamPair<SyncMessage>();
|
|
33
|
+
const [outRx, outTx] = newStreamPair<SyncMessage>();
|
|
44
34
|
|
|
45
|
-
|
|
35
|
+
node.sync.addPeer({
|
|
36
|
+
id: "test",
|
|
37
|
+
incoming: inRx,
|
|
38
|
+
outgoing: outTx,
|
|
39
|
+
role: "peer",
|
|
40
|
+
});
|
|
46
41
|
|
|
47
|
-
|
|
48
|
-
action: "subscribe",
|
|
49
|
-
coValueID: map.coValue.id,
|
|
50
|
-
header: false,
|
|
51
|
-
sessions: {},
|
|
52
|
-
});
|
|
42
|
+
const writer = inTx.getWriter();
|
|
53
43
|
|
|
54
|
-
|
|
44
|
+
await writer.write({
|
|
45
|
+
action: "load",
|
|
46
|
+
id: map.coValue.id,
|
|
47
|
+
header: false,
|
|
48
|
+
sessions: {},
|
|
49
|
+
});
|
|
55
50
|
|
|
56
|
-
|
|
57
|
-
expect((await reader.read()).value).toMatchObject(teamStateEx(team));
|
|
51
|
+
const reader = outRx.getReader();
|
|
58
52
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
action: "tellKnownState",
|
|
62
|
-
...map.coValue.knownState(),
|
|
63
|
-
} satisfies SyncMessage);
|
|
53
|
+
// expect((await reader.read()).value).toMatchObject(admStateEx(admin.id));
|
|
54
|
+
expect((await reader.read()).value).toMatchObject(teamStateEx(team));
|
|
64
55
|
|
|
65
|
-
|
|
66
|
-
|
|
56
|
+
const mapTellKnownStateMsg = await reader.read();
|
|
57
|
+
expect(mapTellKnownStateMsg.value).toEqual({
|
|
58
|
+
action: "known",
|
|
59
|
+
...map.coValue.knownState(),
|
|
60
|
+
} satisfies SyncMessage);
|
|
67
61
|
|
|
68
|
-
|
|
62
|
+
// expect((await reader.read()).value).toMatchObject(admContEx(admin.id));
|
|
63
|
+
expect((await reader.read()).value).toMatchObject(teamContentEx(team));
|
|
69
64
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
lastSignature
|
|
101
|
-
map.coValue.sessions[node.ownSessionID]!.lastSignature!,
|
|
102
|
-
},
|
|
65
|
+
const newContentMsg = await reader.read();
|
|
66
|
+
|
|
67
|
+
expect(newContentMsg.value).toEqual({
|
|
68
|
+
action: "content",
|
|
69
|
+
id: map.coValue.id,
|
|
70
|
+
header: {
|
|
71
|
+
type: "comap",
|
|
72
|
+
ruleset: { type: "ownedByTeam", team: team.id },
|
|
73
|
+
meta: null,
|
|
74
|
+
createdAt: map.coValue.header.createdAt,
|
|
75
|
+
uniqueness: map.coValue.header.uniqueness,
|
|
76
|
+
},
|
|
77
|
+
new: {
|
|
78
|
+
[node.ownSessionID]: {
|
|
79
|
+
after: 0,
|
|
80
|
+
newTransactions: [
|
|
81
|
+
{
|
|
82
|
+
privacy: "trusting" as const,
|
|
83
|
+
madeAt: map.coValue.sessions[node.ownSessionID]!
|
|
84
|
+
.transactions[0]!.madeAt,
|
|
85
|
+
changes: [
|
|
86
|
+
{
|
|
87
|
+
op: "insert",
|
|
88
|
+
key: "hello",
|
|
89
|
+
value: "world",
|
|
90
|
+
} satisfies MapOpPayload<string, string>,
|
|
91
|
+
],
|
|
92
|
+
},
|
|
93
|
+
],
|
|
94
|
+
lastSignature:
|
|
95
|
+
map.coValue.sessions[node.ownSessionID]!.lastSignature!,
|
|
103
96
|
},
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
);
|
|
97
|
+
},
|
|
98
|
+
} satisfies SyncMessage);
|
|
99
|
+
});
|
|
107
100
|
|
|
108
101
|
test("Node replies with only new tx to subscribe with some known state", async () => {
|
|
109
|
-
const admin =
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
const node = new LocalNode(admin, newRandomSessionID(adminID));
|
|
102
|
+
const [admin, session] = randomAnonymousAccountAndSessionID();
|
|
103
|
+
const node = new LocalNode(admin, session);
|
|
113
104
|
|
|
114
105
|
const team = node.createTeam();
|
|
115
106
|
|
|
@@ -133,8 +124,8 @@ test("Node replies with only new tx to subscribe with some known state", async (
|
|
|
133
124
|
const writer = inTx.getWriter();
|
|
134
125
|
|
|
135
126
|
await writer.write({
|
|
136
|
-
action: "
|
|
137
|
-
|
|
127
|
+
action: "load",
|
|
128
|
+
id: map.coValue.id,
|
|
138
129
|
header: true,
|
|
139
130
|
sessions: {
|
|
140
131
|
[node.ownSessionID]: 1,
|
|
@@ -143,30 +134,30 @@ test("Node replies with only new tx to subscribe with some known state", async (
|
|
|
143
134
|
|
|
144
135
|
const reader = outRx.getReader();
|
|
145
136
|
|
|
146
|
-
expect((await reader.read()).value).toMatchObject(admStateEx(
|
|
137
|
+
// expect((await reader.read()).value).toMatchObject(admStateEx(admin.id));
|
|
147
138
|
expect((await reader.read()).value).toMatchObject(teamStateEx(team));
|
|
148
139
|
|
|
149
140
|
const mapTellKnownStateMsg = await reader.read();
|
|
150
141
|
expect(mapTellKnownStateMsg.value).toEqual({
|
|
151
|
-
action: "
|
|
142
|
+
action: "known",
|
|
152
143
|
...map.coValue.knownState(),
|
|
153
144
|
} satisfies SyncMessage);
|
|
154
145
|
|
|
155
|
-
expect((await reader.read()).value).toMatchObject(admContEx(
|
|
146
|
+
// expect((await reader.read()).value).toMatchObject(admContEx(admin.id));
|
|
156
147
|
expect((await reader.read()).value).toMatchObject(teamContentEx(team));
|
|
157
148
|
|
|
158
149
|
const mapNewContentMsg = await reader.read();
|
|
159
150
|
|
|
160
151
|
expect(mapNewContentMsg.value).toEqual({
|
|
161
|
-
action: "
|
|
162
|
-
|
|
152
|
+
action: "content",
|
|
153
|
+
id: map.coValue.id,
|
|
163
154
|
header: undefined,
|
|
164
|
-
|
|
155
|
+
new: {
|
|
165
156
|
[node.ownSessionID]: {
|
|
166
157
|
after: 1,
|
|
167
158
|
newTransactions: [
|
|
168
159
|
{
|
|
169
|
-
privacy: "trusting",
|
|
160
|
+
privacy: "trusting" as const,
|
|
170
161
|
madeAt: map.coValue.sessions[node.ownSessionID]!
|
|
171
162
|
.transactions[1]!.madeAt,
|
|
172
163
|
changes: [
|
|
@@ -178,7 +169,6 @@ test("Node replies with only new tx to subscribe with some known state", async (
|
|
|
178
169
|
],
|
|
179
170
|
},
|
|
180
171
|
],
|
|
181
|
-
lastHash: map.coValue.sessions[node.ownSessionID]!.lastHash!,
|
|
182
172
|
lastSignature:
|
|
183
173
|
map.coValue.sessions[node.ownSessionID]!.lastSignature!,
|
|
184
174
|
},
|
|
@@ -187,14 +177,12 @@ test("Node replies with only new tx to subscribe with some known state", async (
|
|
|
187
177
|
});
|
|
188
178
|
|
|
189
179
|
test.todo(
|
|
190
|
-
"TODO: node only replies with new tx to subscribe with some known state, even in the depended on coValues"
|
|
180
|
+
"TODO: node only replies with new tx to subscribe with some known state, even in the depended on coValues"
|
|
191
181
|
);
|
|
192
182
|
|
|
193
183
|
test("After subscribing, node sends own known state and new txs to peer", async () => {
|
|
194
|
-
const admin =
|
|
195
|
-
const
|
|
196
|
-
|
|
197
|
-
const node = new LocalNode(admin, newRandomSessionID(adminID));
|
|
184
|
+
const [admin, session] = randomAnonymousAccountAndSessionID();
|
|
185
|
+
const node = new LocalNode(admin, session);
|
|
198
186
|
|
|
199
187
|
const team = node.createTeam();
|
|
200
188
|
|
|
@@ -213,8 +201,8 @@ test("After subscribing, node sends own known state and new txs to peer", async
|
|
|
213
201
|
const writer = inTx.getWriter();
|
|
214
202
|
|
|
215
203
|
await writer.write({
|
|
216
|
-
action: "
|
|
217
|
-
|
|
204
|
+
action: "load",
|
|
205
|
+
id: map.coValue.id,
|
|
218
206
|
header: false,
|
|
219
207
|
sessions: {
|
|
220
208
|
[node.ownSessionID]: 0,
|
|
@@ -223,25 +211,25 @@ test("After subscribing, node sends own known state and new txs to peer", async
|
|
|
223
211
|
|
|
224
212
|
const reader = outRx.getReader();
|
|
225
213
|
|
|
226
|
-
expect((await reader.read()).value).toMatchObject(admStateEx(
|
|
214
|
+
// expect((await reader.read()).value).toMatchObject(admStateEx(admin.id));
|
|
227
215
|
expect((await reader.read()).value).toMatchObject(teamStateEx(team));
|
|
228
216
|
|
|
229
217
|
const mapTellKnownStateMsg = await reader.read();
|
|
230
218
|
expect(mapTellKnownStateMsg.value).toEqual({
|
|
231
|
-
action: "
|
|
219
|
+
action: "known",
|
|
232
220
|
...map.coValue.knownState(),
|
|
233
221
|
} satisfies SyncMessage);
|
|
234
222
|
|
|
235
|
-
expect((await reader.read()).value).toMatchObject(admContEx(
|
|
223
|
+
// expect((await reader.read()).value).toMatchObject(admContEx(admin.id));
|
|
236
224
|
expect((await reader.read()).value).toMatchObject(teamContentEx(team));
|
|
237
225
|
|
|
238
226
|
const mapNewContentHeaderOnlyMsg = await reader.read();
|
|
239
227
|
|
|
240
228
|
expect(mapNewContentHeaderOnlyMsg.value).toEqual({
|
|
241
|
-
action: "
|
|
242
|
-
|
|
229
|
+
action: "content",
|
|
230
|
+
id: map.coValue.id,
|
|
243
231
|
header: map.coValue.header,
|
|
244
|
-
|
|
232
|
+
new: {},
|
|
245
233
|
} satisfies SyncMessage);
|
|
246
234
|
|
|
247
235
|
map.edit((editable) => {
|
|
@@ -251,14 +239,14 @@ test("After subscribing, node sends own known state and new txs to peer", async
|
|
|
251
239
|
const mapEditMsg1 = await reader.read();
|
|
252
240
|
|
|
253
241
|
expect(mapEditMsg1.value).toEqual({
|
|
254
|
-
action: "
|
|
255
|
-
|
|
256
|
-
|
|
242
|
+
action: "content",
|
|
243
|
+
id: map.coValue.id,
|
|
244
|
+
new: {
|
|
257
245
|
[node.ownSessionID]: {
|
|
258
246
|
after: 0,
|
|
259
247
|
newTransactions: [
|
|
260
248
|
{
|
|
261
|
-
privacy: "trusting",
|
|
249
|
+
privacy: "trusting" as const,
|
|
262
250
|
madeAt: map.coValue.sessions[node.ownSessionID]!
|
|
263
251
|
.transactions[0]!.madeAt,
|
|
264
252
|
changes: [
|
|
@@ -270,7 +258,6 @@ test("After subscribing, node sends own known state and new txs to peer", async
|
|
|
270
258
|
],
|
|
271
259
|
},
|
|
272
260
|
],
|
|
273
|
-
lastHash: map.coValue.sessions[node.ownSessionID]!.lastHash!,
|
|
274
261
|
lastSignature:
|
|
275
262
|
map.coValue.sessions[node.ownSessionID]!.lastSignature!,
|
|
276
263
|
},
|
|
@@ -284,14 +271,14 @@ test("After subscribing, node sends own known state and new txs to peer", async
|
|
|
284
271
|
const mapEditMsg2 = await reader.read();
|
|
285
272
|
|
|
286
273
|
expect(mapEditMsg2.value).toEqual({
|
|
287
|
-
action: "
|
|
288
|
-
|
|
289
|
-
|
|
274
|
+
action: "content",
|
|
275
|
+
id: map.coValue.id,
|
|
276
|
+
new: {
|
|
290
277
|
[node.ownSessionID]: {
|
|
291
278
|
after: 1,
|
|
292
279
|
newTransactions: [
|
|
293
280
|
{
|
|
294
|
-
privacy: "trusting",
|
|
281
|
+
privacy: "trusting" as const,
|
|
295
282
|
madeAt: map.coValue.sessions[node.ownSessionID]!
|
|
296
283
|
.transactions[1]!.madeAt,
|
|
297
284
|
changes: [
|
|
@@ -303,7 +290,6 @@ test("After subscribing, node sends own known state and new txs to peer", async
|
|
|
303
290
|
],
|
|
304
291
|
},
|
|
305
292
|
],
|
|
306
|
-
lastHash: map.coValue.sessions[node.ownSessionID]!.lastHash!,
|
|
307
293
|
lastSignature:
|
|
308
294
|
map.coValue.sessions[node.ownSessionID]!.lastSignature!,
|
|
309
295
|
},
|
|
@@ -312,10 +298,8 @@ test("After subscribing, node sends own known state and new txs to peer", async
|
|
|
312
298
|
});
|
|
313
299
|
|
|
314
300
|
test("Client replies with known new content to tellKnownState from server", async () => {
|
|
315
|
-
const admin =
|
|
316
|
-
const
|
|
317
|
-
|
|
318
|
-
const node = new LocalNode(admin, newRandomSessionID(adminID));
|
|
301
|
+
const [admin, session] = randomAnonymousAccountAndSessionID();
|
|
302
|
+
const node = new LocalNode(admin, session);
|
|
319
303
|
|
|
320
304
|
const team = node.createTeam();
|
|
321
305
|
|
|
@@ -342,38 +326,38 @@ test("Client replies with known new content to tellKnownState from server", asyn
|
|
|
342
326
|
const writer = inTx.getWriter();
|
|
343
327
|
|
|
344
328
|
await writer.write({
|
|
345
|
-
action: "
|
|
346
|
-
|
|
329
|
+
action: "known",
|
|
330
|
+
id: map.coValue.id,
|
|
347
331
|
header: false,
|
|
348
332
|
sessions: {
|
|
349
333
|
[node.ownSessionID]: 0,
|
|
350
334
|
},
|
|
351
335
|
});
|
|
352
336
|
|
|
353
|
-
expect((await reader.read()).value).toMatchObject(admStateEx(
|
|
337
|
+
// expect((await reader.read()).value).toMatchObject(admStateEx(admin.id));
|
|
354
338
|
expect((await reader.read()).value).toMatchObject(teamStateEx(team));
|
|
355
339
|
|
|
356
340
|
const mapTellKnownStateMsg = await reader.read();
|
|
357
341
|
expect(mapTellKnownStateMsg.value).toEqual({
|
|
358
|
-
action: "
|
|
342
|
+
action: "known",
|
|
359
343
|
...map.coValue.knownState(),
|
|
360
344
|
} satisfies SyncMessage);
|
|
361
345
|
|
|
362
|
-
expect((await reader.read()).value).toMatchObject(admContEx(
|
|
346
|
+
// expect((await reader.read()).value).toMatchObject(admContEx(admin.id));
|
|
363
347
|
expect((await reader.read()).value).toMatchObject(teamContentEx(team));
|
|
364
348
|
|
|
365
349
|
const mapNewContentMsg = await reader.read();
|
|
366
350
|
|
|
367
351
|
expect(mapNewContentMsg.value).toEqual({
|
|
368
|
-
action: "
|
|
369
|
-
|
|
352
|
+
action: "content",
|
|
353
|
+
id: map.coValue.id,
|
|
370
354
|
header: map.coValue.header,
|
|
371
|
-
|
|
355
|
+
new: {
|
|
372
356
|
[node.ownSessionID]: {
|
|
373
357
|
after: 0,
|
|
374
358
|
newTransactions: [
|
|
375
359
|
{
|
|
376
|
-
privacy: "trusting",
|
|
360
|
+
privacy: "trusting" as const,
|
|
377
361
|
madeAt: map.coValue.sessions[node.ownSessionID]!
|
|
378
362
|
.transactions[0]!.madeAt,
|
|
379
363
|
changes: [
|
|
@@ -385,7 +369,6 @@ test("Client replies with known new content to tellKnownState from server", asyn
|
|
|
385
369
|
],
|
|
386
370
|
},
|
|
387
371
|
],
|
|
388
|
-
lastHash: map.coValue.sessions[node.ownSessionID]!.lastHash!,
|
|
389
372
|
lastSignature:
|
|
390
373
|
map.coValue.sessions[node.ownSessionID]!.lastSignature!,
|
|
391
374
|
},
|
|
@@ -394,10 +377,8 @@ test("Client replies with known new content to tellKnownState from server", asyn
|
|
|
394
377
|
});
|
|
395
378
|
|
|
396
379
|
test("No matter the optimistic known state, node respects invalid known state messages and resyncs", async () => {
|
|
397
|
-
const admin =
|
|
398
|
-
const
|
|
399
|
-
|
|
400
|
-
const node = new LocalNode(admin, newRandomSessionID(adminID));
|
|
380
|
+
const [admin, session] = randomAnonymousAccountAndSessionID();
|
|
381
|
+
const node = new LocalNode(admin, session);
|
|
401
382
|
|
|
402
383
|
const team = node.createTeam();
|
|
403
384
|
|
|
@@ -416,8 +397,8 @@ test("No matter the optimistic known state, node respects invalid known state me
|
|
|
416
397
|
const writer = inTx.getWriter();
|
|
417
398
|
|
|
418
399
|
await writer.write({
|
|
419
|
-
action: "
|
|
420
|
-
|
|
400
|
+
action: "load",
|
|
401
|
+
id: map.coValue.id,
|
|
421
402
|
header: false,
|
|
422
403
|
sessions: {
|
|
423
404
|
[node.ownSessionID]: 0,
|
|
@@ -426,25 +407,25 @@ test("No matter the optimistic known state, node respects invalid known state me
|
|
|
426
407
|
|
|
427
408
|
const reader = outRx.getReader();
|
|
428
409
|
|
|
429
|
-
expect((await reader.read()).value).toMatchObject(admStateEx(
|
|
410
|
+
// expect((await reader.read()).value).toMatchObject(admStateEx(admin.id));
|
|
430
411
|
expect((await reader.read()).value).toMatchObject(teamStateEx(team));
|
|
431
412
|
|
|
432
413
|
const mapTellKnownStateMsg = await reader.read();
|
|
433
414
|
expect(mapTellKnownStateMsg.value).toEqual({
|
|
434
|
-
action: "
|
|
415
|
+
action: "known",
|
|
435
416
|
...map.coValue.knownState(),
|
|
436
417
|
} satisfies SyncMessage);
|
|
437
418
|
|
|
438
|
-
expect((await reader.read()).value).toMatchObject(admContEx(
|
|
419
|
+
// expect((await reader.read()).value).toMatchObject(admContEx(admin.id));
|
|
439
420
|
expect((await reader.read()).value).toMatchObject(teamContentEx(team));
|
|
440
421
|
|
|
441
422
|
const mapNewContentHeaderOnlyMsg = await reader.read();
|
|
442
423
|
|
|
443
424
|
expect(mapNewContentHeaderOnlyMsg.value).toEqual({
|
|
444
|
-
action: "
|
|
445
|
-
|
|
425
|
+
action: "content",
|
|
426
|
+
id: map.coValue.id,
|
|
446
427
|
header: map.coValue.header,
|
|
447
|
-
|
|
428
|
+
new: {},
|
|
448
429
|
} satisfies SyncMessage);
|
|
449
430
|
|
|
450
431
|
map.edit((editable) => {
|
|
@@ -459,8 +440,9 @@ test("No matter the optimistic known state, node respects invalid known state me
|
|
|
459
440
|
const _mapEditMsg2 = await reader.read();
|
|
460
441
|
|
|
461
442
|
await writer.write({
|
|
462
|
-
action: "
|
|
463
|
-
|
|
443
|
+
action: "known",
|
|
444
|
+
isCorrection: true,
|
|
445
|
+
id: map.coValue.id,
|
|
464
446
|
header: true,
|
|
465
447
|
sessions: {
|
|
466
448
|
[node.ownSessionID]: 1,
|
|
@@ -470,15 +452,15 @@ test("No matter the optimistic known state, node respects invalid known state me
|
|
|
470
452
|
const newContentAfterWrongAssumedState = await reader.read();
|
|
471
453
|
|
|
472
454
|
expect(newContentAfterWrongAssumedState.value).toEqual({
|
|
473
|
-
action: "
|
|
474
|
-
|
|
455
|
+
action: "content",
|
|
456
|
+
id: map.coValue.id,
|
|
475
457
|
header: undefined,
|
|
476
|
-
|
|
458
|
+
new: {
|
|
477
459
|
[node.ownSessionID]: {
|
|
478
460
|
after: 1,
|
|
479
461
|
newTransactions: [
|
|
480
462
|
{
|
|
481
|
-
privacy: "trusting",
|
|
463
|
+
privacy: "trusting" as const,
|
|
482
464
|
madeAt: map.coValue.sessions[node.ownSessionID]!
|
|
483
465
|
.transactions[1]!.madeAt,
|
|
484
466
|
changes: [
|
|
@@ -490,7 +472,6 @@ test("No matter the optimistic known state, node respects invalid known state me
|
|
|
490
472
|
],
|
|
491
473
|
},
|
|
492
474
|
],
|
|
493
|
-
lastHash: map.coValue.sessions[node.ownSessionID]!.lastHash!,
|
|
494
475
|
lastSignature:
|
|
495
476
|
map.coValue.sessions[node.ownSessionID]!.lastSignature!,
|
|
496
477
|
},
|
|
@@ -499,10 +480,8 @@ test("No matter the optimistic known state, node respects invalid known state me
|
|
|
499
480
|
});
|
|
500
481
|
|
|
501
482
|
test("If we add a peer, but it never subscribes to a coValue, it won't get any messages", async () => {
|
|
502
|
-
const admin =
|
|
503
|
-
const
|
|
504
|
-
|
|
505
|
-
const node = new LocalNode(admin, newRandomSessionID(adminID));
|
|
483
|
+
const [admin, session] = randomAnonymousAccountAndSessionID();
|
|
484
|
+
const node = new LocalNode(admin, session);
|
|
506
485
|
|
|
507
486
|
const team = node.createTeam();
|
|
508
487
|
|
|
@@ -524,14 +503,14 @@ test("If we add a peer, but it never subscribes to a coValue, it won't get any m
|
|
|
524
503
|
|
|
525
504
|
const reader = outRx.getReader();
|
|
526
505
|
|
|
527
|
-
await expect(
|
|
506
|
+
await expect(
|
|
507
|
+
shouldNotResolve(reader.read(), { timeout: 100 })
|
|
508
|
+
).resolves.toBeUndefined();
|
|
528
509
|
});
|
|
529
510
|
|
|
530
511
|
test("If we add a server peer, all updates to all coValues are sent to it, even if it doesn't subscribe", async () => {
|
|
531
|
-
const admin =
|
|
532
|
-
const
|
|
533
|
-
|
|
534
|
-
const node = new LocalNode(admin, newRandomSessionID(adminID));
|
|
512
|
+
const [admin, session] = randomAnonymousAccountAndSessionID();
|
|
513
|
+
const node = new LocalNode(admin, session);
|
|
535
514
|
|
|
536
515
|
const team = node.createTeam();
|
|
537
516
|
|
|
@@ -548,20 +527,20 @@ test("If we add a server peer, all updates to all coValues are sent to it, even
|
|
|
548
527
|
});
|
|
549
528
|
|
|
550
529
|
const reader = outRx.getReader();
|
|
530
|
+
// expect((await reader.read()).value).toMatchObject({
|
|
531
|
+
// action: "load",
|
|
532
|
+
// id: adminID,
|
|
533
|
+
// });
|
|
551
534
|
expect((await reader.read()).value).toMatchObject({
|
|
552
|
-
action: "
|
|
553
|
-
|
|
554
|
-
});
|
|
555
|
-
expect((await reader.read()).value).toMatchObject({
|
|
556
|
-
action: "subscribe",
|
|
557
|
-
coValueID: team.teamMap.coValue.id,
|
|
535
|
+
action: "load",
|
|
536
|
+
id: team.teamMap.coValue.id,
|
|
558
537
|
});
|
|
559
538
|
|
|
560
539
|
const mapSubscribeMsg = await reader.read();
|
|
561
540
|
|
|
562
541
|
expect(mapSubscribeMsg.value).toEqual({
|
|
563
|
-
action: "
|
|
564
|
-
|
|
542
|
+
action: "load",
|
|
543
|
+
id: map.coValue.id,
|
|
565
544
|
header: true,
|
|
566
545
|
sessions: {},
|
|
567
546
|
} satisfies SyncMessage);
|
|
@@ -570,21 +549,21 @@ test("If we add a server peer, all updates to all coValues are sent to it, even
|
|
|
570
549
|
editable.set("hello", "world", "trusting");
|
|
571
550
|
});
|
|
572
551
|
|
|
573
|
-
expect((await reader.read()).value).toMatchObject(admContEx(
|
|
552
|
+
// expect((await reader.read()).value).toMatchObject(admContEx(admin.id));
|
|
574
553
|
expect((await reader.read()).value).toMatchObject(teamContentEx(team));
|
|
575
554
|
|
|
576
555
|
const mapNewContentMsg = await reader.read();
|
|
577
556
|
|
|
578
557
|
expect(mapNewContentMsg.value).toEqual({
|
|
579
|
-
action: "
|
|
580
|
-
|
|
558
|
+
action: "content",
|
|
559
|
+
id: map.coValue.id,
|
|
581
560
|
header: map.coValue.header,
|
|
582
|
-
|
|
561
|
+
new: {
|
|
583
562
|
[node.ownSessionID]: {
|
|
584
563
|
after: 0,
|
|
585
564
|
newTransactions: [
|
|
586
565
|
{
|
|
587
|
-
privacy: "trusting",
|
|
566
|
+
privacy: "trusting" as const,
|
|
588
567
|
madeAt: map.coValue.sessions[node.ownSessionID]!
|
|
589
568
|
.transactions[0]!.madeAt,
|
|
590
569
|
changes: [
|
|
@@ -596,7 +575,6 @@ test("If we add a server peer, all updates to all coValues are sent to it, even
|
|
|
596
575
|
],
|
|
597
576
|
},
|
|
598
577
|
],
|
|
599
|
-
lastHash: map.coValue.sessions[node.ownSessionID]!.lastHash!,
|
|
600
578
|
lastSignature:
|
|
601
579
|
map.coValue.sessions[node.ownSessionID]!.lastSignature!,
|
|
602
580
|
},
|
|
@@ -605,10 +583,8 @@ test("If we add a server peer, all updates to all coValues are sent to it, even
|
|
|
605
583
|
});
|
|
606
584
|
|
|
607
585
|
test("If we add a server peer, newly created coValues are auto-subscribed to", async () => {
|
|
608
|
-
const admin =
|
|
609
|
-
const
|
|
610
|
-
|
|
611
|
-
const node = new LocalNode(admin, newRandomSessionID(adminID));
|
|
586
|
+
const [admin, session] = randomAnonymousAccountAndSessionID();
|
|
587
|
+
const node = new LocalNode(admin, session);
|
|
612
588
|
|
|
613
589
|
const team = node.createTeam();
|
|
614
590
|
|
|
@@ -623,13 +599,13 @@ test("If we add a server peer, newly created coValues are auto-subscribed to", a
|
|
|
623
599
|
});
|
|
624
600
|
|
|
625
601
|
const reader = outRx.getReader();
|
|
602
|
+
// expect((await reader.read()).value).toMatchObject({
|
|
603
|
+
// action: "load",
|
|
604
|
+
// id: admin.id,
|
|
605
|
+
// });
|
|
626
606
|
expect((await reader.read()).value).toMatchObject({
|
|
627
|
-
action: "
|
|
628
|
-
|
|
629
|
-
});
|
|
630
|
-
expect((await reader.read()).value).toMatchObject({
|
|
631
|
-
action: "subscribe",
|
|
632
|
-
coValueID: team.teamMap.coValue.id,
|
|
607
|
+
action: "load",
|
|
608
|
+
id: team.teamMap.coValue.id,
|
|
633
609
|
});
|
|
634
610
|
|
|
635
611
|
const map = team.createMap();
|
|
@@ -637,32 +613,30 @@ test("If we add a server peer, newly created coValues are auto-subscribed to", a
|
|
|
637
613
|
const mapSubscribeMsg = await reader.read();
|
|
638
614
|
|
|
639
615
|
expect(mapSubscribeMsg.value).toEqual({
|
|
640
|
-
action: "
|
|
616
|
+
action: "load",
|
|
641
617
|
...map.coValue.knownState(),
|
|
642
618
|
} satisfies SyncMessage);
|
|
643
619
|
|
|
644
|
-
expect((await reader.read()).value).toMatchObject(admContEx(adminID));
|
|
620
|
+
// expect((await reader.read()).value).toMatchObject(admContEx(adminID));
|
|
645
621
|
expect((await reader.read()).value).toMatchObject(teamContentEx(team));
|
|
646
622
|
|
|
647
623
|
const mapContentMsg = await reader.read();
|
|
648
624
|
|
|
649
625
|
expect(mapContentMsg.value).toEqual({
|
|
650
|
-
action: "
|
|
651
|
-
|
|
626
|
+
action: "content",
|
|
627
|
+
id: map.coValue.id,
|
|
652
628
|
header: map.coValue.header,
|
|
653
|
-
|
|
629
|
+
new: {},
|
|
654
630
|
} satisfies SyncMessage);
|
|
655
631
|
});
|
|
656
632
|
|
|
657
633
|
test.todo(
|
|
658
|
-
"TODO: when receiving a subscribe response that is behind our optimistic state (due to already sent content), we ignore it"
|
|
634
|
+
"TODO: when receiving a subscribe response that is behind our optimistic state (due to already sent content), we ignore it"
|
|
659
635
|
);
|
|
660
636
|
|
|
661
637
|
test("When we connect a new server peer, we try to sync all existing coValues to it", async () => {
|
|
662
|
-
const admin =
|
|
663
|
-
const
|
|
664
|
-
|
|
665
|
-
const node = new LocalNode(admin, newRandomSessionID(adminID));
|
|
638
|
+
const [admin, session] = randomAnonymousAccountAndSessionID();
|
|
639
|
+
const node = new LocalNode(admin, session);
|
|
666
640
|
|
|
667
641
|
const team = node.createTeam();
|
|
668
642
|
|
|
@@ -680,27 +654,25 @@ test("When we connect a new server peer, we try to sync all existing coValues to
|
|
|
680
654
|
|
|
681
655
|
const reader = outRx.getReader();
|
|
682
656
|
|
|
683
|
-
const _adminSubscribeMessage = await reader.read();
|
|
657
|
+
// const _adminSubscribeMessage = await reader.read();
|
|
684
658
|
const teamSubscribeMessage = await reader.read();
|
|
685
659
|
|
|
686
660
|
expect(teamSubscribeMessage.value).toEqual({
|
|
687
|
-
action: "
|
|
661
|
+
action: "load",
|
|
688
662
|
...team.teamMap.coValue.knownState(),
|
|
689
663
|
} satisfies SyncMessage);
|
|
690
664
|
|
|
691
665
|
const secondMessage = await reader.read();
|
|
692
666
|
|
|
693
667
|
expect(secondMessage.value).toEqual({
|
|
694
|
-
action: "
|
|
668
|
+
action: "load",
|
|
695
669
|
...map.coValue.knownState(),
|
|
696
670
|
} satisfies SyncMessage);
|
|
697
671
|
});
|
|
698
672
|
|
|
699
673
|
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 () => {
|
|
700
|
-
const admin =
|
|
701
|
-
const
|
|
702
|
-
|
|
703
|
-
const node = new LocalNode(admin, newRandomSessionID(adminID));
|
|
674
|
+
const [admin, session] = randomAnonymousAccountAndSessionID();
|
|
675
|
+
const node = new LocalNode(admin, session);
|
|
704
676
|
|
|
705
677
|
const team = node.createTeam();
|
|
706
678
|
|
|
@@ -719,8 +691,8 @@ test("When receiving a subscribe with a known state that is ahead of our own, pe
|
|
|
719
691
|
const writer = inTx.getWriter();
|
|
720
692
|
|
|
721
693
|
await writer.write({
|
|
722
|
-
action: "
|
|
723
|
-
|
|
694
|
+
action: "load",
|
|
695
|
+
id: map.coValue.id,
|
|
724
696
|
header: true,
|
|
725
697
|
sessions: {
|
|
726
698
|
[node.ownSessionID]: 1,
|
|
@@ -729,22 +701,21 @@ test("When receiving a subscribe with a known state that is ahead of our own, pe
|
|
|
729
701
|
|
|
730
702
|
const reader = outRx.getReader();
|
|
731
703
|
|
|
732
|
-
expect((await reader.read()).value).toMatchObject(admStateEx(
|
|
704
|
+
// expect((await reader.read()).value).toMatchObject(admStateEx(admin.id));
|
|
733
705
|
expect((await reader.read()).value).toMatchObject(teamStateEx(team));
|
|
734
706
|
const mapTellKnownState = await reader.read();
|
|
735
707
|
|
|
736
708
|
expect(mapTellKnownState.value).toEqual({
|
|
737
|
-
action: "
|
|
709
|
+
action: "known",
|
|
738
710
|
...map.coValue.knownState(),
|
|
739
711
|
} satisfies SyncMessage);
|
|
740
712
|
});
|
|
741
713
|
|
|
742
714
|
test.skip("When replaying creation and transactions of a coValue as new content, the receiving peer integrates this information", async () => {
|
|
743
715
|
// 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
|
|
744
|
-
const admin =
|
|
745
|
-
const adminID = getAgentID(getAgent(admin));
|
|
716
|
+
const [admin, session] = randomAnonymousAccountAndSessionID();
|
|
746
717
|
|
|
747
|
-
const node1 = new LocalNode(admin,
|
|
718
|
+
const node1 = new LocalNode(admin, session);
|
|
748
719
|
|
|
749
720
|
const team = node1.createTeam();
|
|
750
721
|
|
|
@@ -761,7 +732,7 @@ test.skip("When replaying creation and transactions of a coValue as new content,
|
|
|
761
732
|
const to1 = inTx1.getWriter();
|
|
762
733
|
const from1 = outRx1.getReader();
|
|
763
734
|
|
|
764
|
-
const node2 = new LocalNode(admin, newRandomSessionID(
|
|
735
|
+
const node2 = new LocalNode(admin, newRandomSessionID(admin.id));
|
|
765
736
|
|
|
766
737
|
const [inRx2, inTx2] = newStreamPair<SyncMessage>();
|
|
767
738
|
const [outRx2, outTx2] = newStreamPair<SyncMessage>();
|
|
@@ -778,20 +749,20 @@ test.skip("When replaying creation and transactions of a coValue as new content,
|
|
|
778
749
|
|
|
779
750
|
const adminSubscribeMessage = await from1.read();
|
|
780
751
|
expect(adminSubscribeMessage.value).toMatchObject({
|
|
781
|
-
action: "
|
|
782
|
-
|
|
752
|
+
action: "load",
|
|
753
|
+
id: admin.id,
|
|
783
754
|
});
|
|
784
755
|
const teamSubscribeMsg = await from1.read();
|
|
785
756
|
expect(teamSubscribeMsg.value).toMatchObject({
|
|
786
|
-
action: "
|
|
787
|
-
|
|
757
|
+
action: "load",
|
|
758
|
+
id: team.teamMap.coValue.id,
|
|
788
759
|
});
|
|
789
760
|
|
|
790
761
|
await to2.write(adminSubscribeMessage.value!);
|
|
791
762
|
await to2.write(teamSubscribeMsg.value!);
|
|
792
763
|
|
|
793
|
-
const adminTellKnownStateMsg = await from2.read();
|
|
794
|
-
expect(adminTellKnownStateMsg.value).toMatchObject(admStateEx(
|
|
764
|
+
// const adminTellKnownStateMsg = await from2.read();
|
|
765
|
+
// expect(adminTellKnownStateMsg.value).toMatchObject(admStateEx(admin.id));
|
|
795
766
|
|
|
796
767
|
const teamTellKnownStateMsg = await from2.read();
|
|
797
768
|
expect(teamTellKnownStateMsg.value).toMatchObject(teamStateEx(team));
|
|
@@ -802,40 +773,40 @@ test.skip("When replaying creation and transactions of a coValue as new content,
|
|
|
802
773
|
]
|
|
803
774
|
).toBeDefined();
|
|
804
775
|
|
|
805
|
-
await to1.write(adminTellKnownStateMsg.value!);
|
|
776
|
+
// await to1.write(adminTellKnownStateMsg.value!);
|
|
806
777
|
await to1.write(teamTellKnownStateMsg.value!);
|
|
807
778
|
|
|
808
|
-
const adminContentMsg = await from1.read();
|
|
809
|
-
expect(adminContentMsg.value).toMatchObject(admContEx(
|
|
779
|
+
// const adminContentMsg = await from1.read();
|
|
780
|
+
// expect(adminContentMsg.value).toMatchObject(admContEx(admin.id));
|
|
810
781
|
|
|
811
782
|
const teamContentMsg = await from1.read();
|
|
812
783
|
expect(teamContentMsg.value).toMatchObject(teamContentEx(team));
|
|
813
784
|
|
|
814
|
-
await to2.write(adminContentMsg.value!);
|
|
785
|
+
// await to2.write(adminContentMsg.value!);
|
|
815
786
|
await to2.write(teamContentMsg.value!);
|
|
816
787
|
|
|
817
788
|
const map = team.createMap();
|
|
818
789
|
|
|
819
790
|
const mapSubscriptionMsg = await from1.read();
|
|
820
791
|
expect(mapSubscriptionMsg.value).toMatchObject({
|
|
821
|
-
action: "
|
|
822
|
-
|
|
792
|
+
action: "load",
|
|
793
|
+
id: map.coValue.id,
|
|
823
794
|
});
|
|
824
795
|
|
|
825
796
|
const mapNewContentMsg = await from1.read();
|
|
826
797
|
expect(mapNewContentMsg.value).toEqual({
|
|
827
|
-
action: "
|
|
828
|
-
|
|
798
|
+
action: "content",
|
|
799
|
+
id: map.coValue.id,
|
|
829
800
|
header: map.coValue.header,
|
|
830
|
-
|
|
801
|
+
new: {},
|
|
831
802
|
} satisfies SyncMessage);
|
|
832
803
|
|
|
833
804
|
await to2.write(mapSubscriptionMsg.value!);
|
|
834
805
|
|
|
835
806
|
const mapTellKnownStateMsg = await from2.read();
|
|
836
807
|
expect(mapTellKnownStateMsg.value).toEqual({
|
|
837
|
-
action: "
|
|
838
|
-
|
|
808
|
+
action: "known",
|
|
809
|
+
id: map.coValue.id,
|
|
839
810
|
header: false,
|
|
840
811
|
sessions: {},
|
|
841
812
|
} satisfies SyncMessage);
|
|
@@ -863,10 +834,9 @@ test.skip("When replaying creation and transactions of a coValue as new content,
|
|
|
863
834
|
|
|
864
835
|
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 () => {
|
|
865
836
|
// 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
|
|
866
|
-
const admin =
|
|
867
|
-
const adminID = getAgentID(getAgent(admin));
|
|
837
|
+
const [admin, session] = randomAnonymousAccountAndSessionID();
|
|
868
838
|
|
|
869
|
-
const node1 = new LocalNode(admin,
|
|
839
|
+
const node1 = new LocalNode(admin, session);
|
|
870
840
|
|
|
871
841
|
const team = node1.createTeam();
|
|
872
842
|
|
|
@@ -875,7 +845,7 @@ test.skip("When loading a coValue on one node, the server node it is requested f
|
|
|
875
845
|
editable.set("hello", "world", "trusting");
|
|
876
846
|
});
|
|
877
847
|
|
|
878
|
-
const node2 = new LocalNode(admin, newRandomSessionID(
|
|
848
|
+
const node2 = new LocalNode(admin, newRandomSessionID(admin.id));
|
|
879
849
|
|
|
880
850
|
const [node1asPeer, node2asPeer] = connectedPeers("peer1", "peer2");
|
|
881
851
|
|
|
@@ -892,10 +862,9 @@ test.skip("When loading a coValue on one node, the server node it is requested f
|
|
|
892
862
|
});
|
|
893
863
|
|
|
894
864
|
test("Can sync a coValue through a server to another client", async () => {
|
|
895
|
-
const admin =
|
|
896
|
-
const adminID = getAgentID(getAgent(admin));
|
|
865
|
+
const [admin, session] = randomAnonymousAccountAndSessionID();
|
|
897
866
|
|
|
898
|
-
const client1 = new LocalNode(admin,
|
|
867
|
+
const client1 = new LocalNode(admin, session);
|
|
899
868
|
|
|
900
869
|
const team = client1.createTeam();
|
|
901
870
|
|
|
@@ -904,10 +873,9 @@ test("Can sync a coValue through a server to another client", async () => {
|
|
|
904
873
|
editable.set("hello", "world", "trusting");
|
|
905
874
|
});
|
|
906
875
|
|
|
907
|
-
const serverUser =
|
|
908
|
-
const serverUserID = getAgentID(getAgent(serverUser));
|
|
876
|
+
const [serverUser, serverSession] = randomAnonymousAccountAndSessionID();
|
|
909
877
|
|
|
910
|
-
const server = new LocalNode(serverUser,
|
|
878
|
+
const server = new LocalNode(serverUser, serverSession);
|
|
911
879
|
|
|
912
880
|
const [serverAsPeer, client1AsPeer] = connectedPeers("server", "client1", {
|
|
913
881
|
peer1role: "server",
|
|
@@ -917,7 +885,7 @@ test("Can sync a coValue through a server to another client", async () => {
|
|
|
917
885
|
client1.sync.addPeer(serverAsPeer);
|
|
918
886
|
server.sync.addPeer(client1AsPeer);
|
|
919
887
|
|
|
920
|
-
const client2 = new LocalNode(admin, newRandomSessionID(
|
|
888
|
+
const client2 = new LocalNode(admin, newRandomSessionID(admin.id));
|
|
921
889
|
|
|
922
890
|
const [serverAsOtherPeer, client2AsPeer] = connectedPeers(
|
|
923
891
|
"server",
|
|
@@ -936,10 +904,9 @@ test("Can sync a coValue through a server to another client", async () => {
|
|
|
936
904
|
});
|
|
937
905
|
|
|
938
906
|
test("Can sync a coValue with private transactions through a server to another client", async () => {
|
|
939
|
-
const admin =
|
|
940
|
-
const adminID = getAgentID(getAgent(admin));
|
|
907
|
+
const [admin, session] = randomAnonymousAccountAndSessionID();
|
|
941
908
|
|
|
942
|
-
const client1 = new LocalNode(admin,
|
|
909
|
+
const client1 = new LocalNode(admin, session);
|
|
943
910
|
|
|
944
911
|
const team = client1.createTeam();
|
|
945
912
|
|
|
@@ -948,10 +915,9 @@ test("Can sync a coValue with private transactions through a server to another c
|
|
|
948
915
|
editable.set("hello", "world", "private");
|
|
949
916
|
});
|
|
950
917
|
|
|
951
|
-
const serverUser =
|
|
952
|
-
const serverUserID = getAgentID(getAgent(serverUser));
|
|
918
|
+
const [serverUser, serverSession] = randomAnonymousAccountAndSessionID();
|
|
953
919
|
|
|
954
|
-
const server = new LocalNode(serverUser,
|
|
920
|
+
const server = new LocalNode(serverUser, serverSession);
|
|
955
921
|
|
|
956
922
|
const [serverAsPeer, client1AsPeer] = connectedPeers("server", "client1", {
|
|
957
923
|
trace: true,
|
|
@@ -962,7 +928,7 @@ test("Can sync a coValue with private transactions through a server to another c
|
|
|
962
928
|
client1.sync.addPeer(serverAsPeer);
|
|
963
929
|
server.sync.addPeer(client1AsPeer);
|
|
964
930
|
|
|
965
|
-
const client2 = new LocalNode(admin, newRandomSessionID(
|
|
931
|
+
const client2 = new LocalNode(admin, newRandomSessionID(admin.id));
|
|
966
932
|
|
|
967
933
|
const [serverAsOtherPeer, client2AsPeer] = connectedPeers(
|
|
968
934
|
"server",
|
|
@@ -981,10 +947,8 @@ test("Can sync a coValue with private transactions through a server to another c
|
|
|
981
947
|
});
|
|
982
948
|
|
|
983
949
|
test("When a peer's incoming/readable stream closes, we remove the peer", async () => {
|
|
984
|
-
const admin =
|
|
985
|
-
const
|
|
986
|
-
|
|
987
|
-
const node = new LocalNode(admin, newRandomSessionID(adminID));
|
|
950
|
+
const [admin, session] = randomAnonymousAccountAndSessionID();
|
|
951
|
+
const node = new LocalNode(admin, session);
|
|
988
952
|
|
|
989
953
|
const team = node.createTeam();
|
|
990
954
|
|
|
@@ -999,13 +963,13 @@ test("When a peer's incoming/readable stream closes, we remove the peer", async
|
|
|
999
963
|
});
|
|
1000
964
|
|
|
1001
965
|
const reader = outRx.getReader();
|
|
966
|
+
// expect((await reader.read()).value).toMatchObject({
|
|
967
|
+
// action: "load",
|
|
968
|
+
// id: admin.id,
|
|
969
|
+
// });
|
|
1002
970
|
expect((await reader.read()).value).toMatchObject({
|
|
1003
|
-
action: "
|
|
1004
|
-
|
|
1005
|
-
});
|
|
1006
|
-
expect((await reader.read()).value).toMatchObject({
|
|
1007
|
-
action: "subscribe",
|
|
1008
|
-
coValueID: team.teamMap.coValue.id,
|
|
971
|
+
action: "load",
|
|
972
|
+
id: team.teamMap.coValue.id,
|
|
1009
973
|
});
|
|
1010
974
|
|
|
1011
975
|
const map = team.createMap();
|
|
@@ -1013,20 +977,20 @@ test("When a peer's incoming/readable stream closes, we remove the peer", async
|
|
|
1013
977
|
const mapSubscribeMsg = await reader.read();
|
|
1014
978
|
|
|
1015
979
|
expect(mapSubscribeMsg.value).toEqual({
|
|
1016
|
-
action: "
|
|
980
|
+
action: "load",
|
|
1017
981
|
...map.coValue.knownState(),
|
|
1018
982
|
} satisfies SyncMessage);
|
|
1019
983
|
|
|
1020
|
-
expect((await reader.read()).value).toMatchObject(admContEx(
|
|
984
|
+
// expect((await reader.read()).value).toMatchObject(admContEx(admin.id));
|
|
1021
985
|
expect((await reader.read()).value).toMatchObject(teamContentEx(team));
|
|
1022
986
|
|
|
1023
987
|
const mapContentMsg = await reader.read();
|
|
1024
988
|
|
|
1025
989
|
expect(mapContentMsg.value).toEqual({
|
|
1026
|
-
action: "
|
|
1027
|
-
|
|
990
|
+
action: "content",
|
|
991
|
+
id: map.coValue.id,
|
|
1028
992
|
header: map.coValue.header,
|
|
1029
|
-
|
|
993
|
+
new: {},
|
|
1030
994
|
} satisfies SyncMessage);
|
|
1031
995
|
|
|
1032
996
|
await inTx.abort();
|
|
@@ -1037,10 +1001,8 @@ test("When a peer's incoming/readable stream closes, we remove the peer", async
|
|
|
1037
1001
|
});
|
|
1038
1002
|
|
|
1039
1003
|
test("When a peer's outgoing/writable stream closes, we remove the peer", async () => {
|
|
1040
|
-
const admin =
|
|
1041
|
-
const
|
|
1042
|
-
|
|
1043
|
-
const node = new LocalNode(admin, newRandomSessionID(adminID));
|
|
1004
|
+
const [admin, session] = randomAnonymousAccountAndSessionID();
|
|
1005
|
+
const node = new LocalNode(admin, session);
|
|
1044
1006
|
|
|
1045
1007
|
const team = node.createTeam();
|
|
1046
1008
|
|
|
@@ -1055,13 +1017,13 @@ test("When a peer's outgoing/writable stream closes, we remove the peer", async
|
|
|
1055
1017
|
});
|
|
1056
1018
|
|
|
1057
1019
|
const reader = outRx.getReader();
|
|
1020
|
+
// expect((await reader.read()).value).toMatchObject({
|
|
1021
|
+
// action: "load",
|
|
1022
|
+
// id: admin.id,
|
|
1023
|
+
// });
|
|
1058
1024
|
expect((await reader.read()).value).toMatchObject({
|
|
1059
|
-
action: "
|
|
1060
|
-
|
|
1061
|
-
});
|
|
1062
|
-
expect((await reader.read()).value).toMatchObject({
|
|
1063
|
-
action: "subscribe",
|
|
1064
|
-
coValueID: team.teamMap.coValue.id,
|
|
1025
|
+
action: "load",
|
|
1026
|
+
id: team.teamMap.coValue.id,
|
|
1065
1027
|
});
|
|
1066
1028
|
|
|
1067
1029
|
const map = team.createMap();
|
|
@@ -1069,20 +1031,20 @@ test("When a peer's outgoing/writable stream closes, we remove the peer", async
|
|
|
1069
1031
|
const mapSubscribeMsg = await reader.read();
|
|
1070
1032
|
|
|
1071
1033
|
expect(mapSubscribeMsg.value).toEqual({
|
|
1072
|
-
action: "
|
|
1034
|
+
action: "load",
|
|
1073
1035
|
...map.coValue.knownState(),
|
|
1074
1036
|
} satisfies SyncMessage);
|
|
1075
1037
|
|
|
1076
|
-
expect((await reader.read()).value).toMatchObject(admContEx(
|
|
1038
|
+
// expect((await reader.read()).value).toMatchObject(admContEx(admin.id));
|
|
1077
1039
|
expect((await reader.read()).value).toMatchObject(teamContentEx(team));
|
|
1078
1040
|
|
|
1079
1041
|
const mapContentMsg = await reader.read();
|
|
1080
1042
|
|
|
1081
1043
|
expect(mapContentMsg.value).toEqual({
|
|
1082
|
-
action: "
|
|
1083
|
-
|
|
1044
|
+
action: "content",
|
|
1045
|
+
id: map.coValue.id,
|
|
1084
1046
|
header: map.coValue.header,
|
|
1085
|
-
|
|
1047
|
+
new: {},
|
|
1086
1048
|
} satisfies SyncMessage);
|
|
1087
1049
|
|
|
1088
1050
|
reader.releaseLock();
|
|
@@ -1095,13 +1057,12 @@ test("When a peer's outgoing/writable stream closes, we remove the peer", async
|
|
|
1095
1057
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
1096
1058
|
|
|
1097
1059
|
expect(node.sync.peers["test"]).toBeUndefined();
|
|
1098
|
-
})
|
|
1060
|
+
});
|
|
1099
1061
|
|
|
1100
1062
|
test("If we start loading a coValue before connecting to a peer that has it, it will load it once we connect", async () => {
|
|
1101
|
-
const admin =
|
|
1102
|
-
const adminID = getAgentID(getAgent(admin));
|
|
1063
|
+
const [admin, session] = randomAnonymousAccountAndSessionID();
|
|
1103
1064
|
|
|
1104
|
-
const node1 = new LocalNode(admin,
|
|
1065
|
+
const node1 = new LocalNode(admin, session);
|
|
1105
1066
|
|
|
1106
1067
|
const team = node1.createTeam();
|
|
1107
1068
|
|
|
@@ -1110,9 +1071,13 @@ test("If we start loading a coValue before connecting to a peer that has it, it
|
|
|
1110
1071
|
editable.set("hello", "world", "trusting");
|
|
1111
1072
|
});
|
|
1112
1073
|
|
|
1113
|
-
const node2 = new LocalNode(admin, newRandomSessionID(
|
|
1074
|
+
const node2 = new LocalNode(admin, newRandomSessionID(admin.id));
|
|
1114
1075
|
|
|
1115
|
-
const [node1asPeer, node2asPeer] = connectedPeers("peer1", "peer2", {
|
|
1076
|
+
const [node1asPeer, node2asPeer] = connectedPeers("peer1", "peer2", {
|
|
1077
|
+
peer1role: "server",
|
|
1078
|
+
peer2role: "client",
|
|
1079
|
+
trace: true,
|
|
1080
|
+
});
|
|
1116
1081
|
|
|
1117
1082
|
node1.sync.addPeer(node2asPeer);
|
|
1118
1083
|
|
|
@@ -1127,175 +1092,32 @@ test("If we start loading a coValue before connecting to a peer that has it, it
|
|
|
1127
1092
|
expect(expectMap(mapOnNode2.getCurrentContent()).get("hello")).toEqual(
|
|
1128
1093
|
"world"
|
|
1129
1094
|
);
|
|
1130
|
-
})
|
|
1095
|
+
});
|
|
1131
1096
|
|
|
1132
1097
|
function teamContentEx(team: Team) {
|
|
1133
1098
|
return {
|
|
1134
|
-
action: "
|
|
1135
|
-
|
|
1099
|
+
action: "content",
|
|
1100
|
+
id: team.teamMap.coValue.id,
|
|
1136
1101
|
};
|
|
1137
1102
|
}
|
|
1138
1103
|
|
|
1139
|
-
function admContEx(adminID:
|
|
1104
|
+
function admContEx(adminID: AccountID) {
|
|
1140
1105
|
return {
|
|
1141
|
-
action: "
|
|
1142
|
-
|
|
1106
|
+
action: "content",
|
|
1107
|
+
id: adminID,
|
|
1143
1108
|
};
|
|
1144
1109
|
}
|
|
1145
1110
|
|
|
1146
1111
|
function teamStateEx(team: Team) {
|
|
1147
1112
|
return {
|
|
1148
|
-
action: "
|
|
1149
|
-
|
|
1113
|
+
action: "known",
|
|
1114
|
+
id: team.teamMap.coValue.id,
|
|
1150
1115
|
};
|
|
1151
1116
|
}
|
|
1152
1117
|
|
|
1153
|
-
function admStateEx(adminID:
|
|
1118
|
+
function admStateEx(adminID: AccountID) {
|
|
1154
1119
|
return {
|
|
1155
|
-
action: "
|
|
1156
|
-
|
|
1157
|
-
};
|
|
1158
|
-
}
|
|
1159
|
-
|
|
1160
|
-
function newStreamPair<T>(): [ReadableStream<T>, WritableStream<T>] {
|
|
1161
|
-
const queue: T[] = [];
|
|
1162
|
-
let resolveNextItemReady: () => void = () => {};
|
|
1163
|
-
let nextItemReady: Promise<void> = new Promise((resolve) => {
|
|
1164
|
-
resolveNextItemReady = resolve;
|
|
1165
|
-
});
|
|
1166
|
-
|
|
1167
|
-
let writerClosed = false;
|
|
1168
|
-
let readerClosed = false;
|
|
1169
|
-
|
|
1170
|
-
const readable = new ReadableStream<T>({
|
|
1171
|
-
async pull(controller) {
|
|
1172
|
-
let retriesLeft = 3;
|
|
1173
|
-
while (retriesLeft > 0) {
|
|
1174
|
-
if (writerClosed) {
|
|
1175
|
-
controller.close();
|
|
1176
|
-
return;
|
|
1177
|
-
}
|
|
1178
|
-
retriesLeft--;
|
|
1179
|
-
if (queue.length > 0) {
|
|
1180
|
-
controller.enqueue(queue.shift()!);
|
|
1181
|
-
if (queue.length === 0) {
|
|
1182
|
-
nextItemReady = new Promise((resolve) => {
|
|
1183
|
-
resolveNextItemReady = resolve;
|
|
1184
|
-
});
|
|
1185
|
-
}
|
|
1186
|
-
return;
|
|
1187
|
-
} else {
|
|
1188
|
-
await nextItemReady;
|
|
1189
|
-
}
|
|
1190
|
-
}
|
|
1191
|
-
throw new Error("Should only use one retry to get next item in queue.")
|
|
1192
|
-
},
|
|
1193
|
-
|
|
1194
|
-
cancel(reason) {
|
|
1195
|
-
console.log("Manually closing reader")
|
|
1196
|
-
readerClosed = true;
|
|
1197
|
-
},
|
|
1198
|
-
});
|
|
1199
|
-
|
|
1200
|
-
const writable = new WritableStream<T>({
|
|
1201
|
-
write(chunk, controller) {
|
|
1202
|
-
if (readerClosed) {
|
|
1203
|
-
console.log("Reader closed, not writing chunk", chunk);
|
|
1204
|
-
throw new Error("Reader closed, not writing chunk");
|
|
1205
|
-
}
|
|
1206
|
-
queue.push(chunk);
|
|
1207
|
-
if (queue.length === 1) {
|
|
1208
|
-
// make sure that await write resolves before corresponding read
|
|
1209
|
-
process.nextTick(() => resolveNextItemReady());
|
|
1210
|
-
}
|
|
1211
|
-
},
|
|
1212
|
-
abort(reason) {
|
|
1213
|
-
console.log("Manually closing writer")
|
|
1214
|
-
writerClosed = true;
|
|
1215
|
-
resolveNextItemReady();
|
|
1216
|
-
return Promise.resolve();
|
|
1217
|
-
},
|
|
1218
|
-
});
|
|
1219
|
-
|
|
1220
|
-
return [readable, writable];
|
|
1221
|
-
}
|
|
1222
|
-
|
|
1223
|
-
function shouldNotResolve<T>(promise: Promise<T>, ops: { timeout: number }): Promise<void> {
|
|
1224
|
-
return new Promise((resolve, reject) => {
|
|
1225
|
-
promise
|
|
1226
|
-
.then((v) =>
|
|
1227
|
-
reject(
|
|
1228
|
-
new Error(
|
|
1229
|
-
"Should not have resolved, but resolved to " +
|
|
1230
|
-
JSON.stringify(v)
|
|
1231
|
-
)
|
|
1232
|
-
)
|
|
1233
|
-
)
|
|
1234
|
-
.catch(reject);
|
|
1235
|
-
setTimeout(resolve, ops.timeout);
|
|
1236
|
-
});
|
|
1237
|
-
}
|
|
1238
|
-
|
|
1239
|
-
function connectedPeers(
|
|
1240
|
-
peer1id: PeerID,
|
|
1241
|
-
peer2id: PeerID,
|
|
1242
|
-
{
|
|
1243
|
-
trace = false,
|
|
1244
|
-
peer1role = "peer",
|
|
1245
|
-
peer2role = "peer",
|
|
1246
|
-
}: {
|
|
1247
|
-
trace?: boolean;
|
|
1248
|
-
peer1role?: Peer["role"];
|
|
1249
|
-
peer2role?: Peer["role"];
|
|
1250
|
-
} = {}
|
|
1251
|
-
): [Peer, Peer] {
|
|
1252
|
-
const [inRx1, inTx1] = newStreamPair<SyncMessage>();
|
|
1253
|
-
const [outRx1, outTx1] = newStreamPair<SyncMessage>();
|
|
1254
|
-
|
|
1255
|
-
const [inRx2, inTx2] = newStreamPair<SyncMessage>();
|
|
1256
|
-
const [outRx2, outTx2] = newStreamPair<SyncMessage>();
|
|
1257
|
-
|
|
1258
|
-
void outRx2
|
|
1259
|
-
.pipeThrough(
|
|
1260
|
-
new TransformStream({
|
|
1261
|
-
transform(
|
|
1262
|
-
chunk: SyncMessage,
|
|
1263
|
-
controller: { enqueue: (msg: SyncMessage) => void }
|
|
1264
|
-
) {
|
|
1265
|
-
trace && console.log(`${peer2id} -> ${peer1id}`, chunk);
|
|
1266
|
-
controller.enqueue(chunk);
|
|
1267
|
-
},
|
|
1268
|
-
})
|
|
1269
|
-
)
|
|
1270
|
-
.pipeTo(inTx1);
|
|
1271
|
-
|
|
1272
|
-
void outRx1
|
|
1273
|
-
.pipeThrough(
|
|
1274
|
-
new TransformStream({
|
|
1275
|
-
transform(
|
|
1276
|
-
chunk: SyncMessage,
|
|
1277
|
-
controller: { enqueue: (msg: SyncMessage) => void }
|
|
1278
|
-
) {
|
|
1279
|
-
trace && console.log(`${peer1id} -> ${peer2id}`, chunk);
|
|
1280
|
-
controller.enqueue(chunk);
|
|
1281
|
-
},
|
|
1282
|
-
})
|
|
1283
|
-
)
|
|
1284
|
-
.pipeTo(inTx2);
|
|
1285
|
-
|
|
1286
|
-
const peer2AsPeer: Peer = {
|
|
1287
|
-
id: peer2id,
|
|
1288
|
-
incoming: inRx1,
|
|
1289
|
-
outgoing: outTx1,
|
|
1290
|
-
role: peer2role,
|
|
1291
|
-
};
|
|
1292
|
-
|
|
1293
|
-
const peer1AsPeer: Peer = {
|
|
1294
|
-
id: peer1id,
|
|
1295
|
-
incoming: inRx2,
|
|
1296
|
-
outgoing: outTx2,
|
|
1297
|
-
role: peer1role,
|
|
1120
|
+
action: "known",
|
|
1121
|
+
id: adminID,
|
|
1298
1122
|
};
|
|
1299
|
-
|
|
1300
|
-
return [peer1AsPeer, peer2AsPeer];
|
|
1301
1123
|
}
|