cojson 0.7.11 → 0.7.14

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.
@@ -1,45 +1,46 @@
1
1
  import { expect, test } from "vitest";
2
- import { newRandomSessionID } from "../coValueCore.js";
3
2
  import { LocalNode } from "../localNode.js";
4
- import { expectMap } from "../coValue.js";
5
- import { randomAnonymousAccountAndSessionID, shouldNotResolve, } from "./testUtils.js";
6
- import { connectedPeers, newStreamPair } from "../streamUtils.js";
3
+ import { randomAnonymousAccountAndSessionID } from "./testUtils.js";
4
+ import { connectedPeers, newQueuePair } from "../streamUtils.js";
7
5
  import { stableStringify } from "../jsonStringify.js";
8
6
  import { WasmCrypto } from "../crypto/WasmCrypto.js";
7
+ import { Effect, Queue, Sink, Stream } from "effect";
8
+ import { newRandomSessionID } from "../coValueCore.js";
9
+ import { expectMap } from "../coValue.js";
9
10
  const Crypto = await WasmCrypto.create();
10
- test("Node replies with initial tx and header to empty subscribe", async () => {
11
+ test("Node replies with initial tx and header to empty subscribe", () => Effect.gen(function* () {
11
12
  const [admin, session] = randomAnonymousAccountAndSessionID();
12
13
  const node = new LocalNode(admin, session, Crypto);
13
14
  const group = node.createGroup();
14
15
  const map = group.createMap();
15
16
  map.set("hello", "world", "trusting");
16
- const [inRx, inTx] = newStreamPair();
17
- const [outRx, outTx] = newStreamPair();
17
+ const [inRx, inTx] = yield* newQueuePair();
18
+ const [outRx, outTx] = yield* newQueuePair();
19
+ const outRxQ = yield* Queue.unbounded();
20
+ yield* Effect.fork(Stream.run(outRx, Sink.fromQueue(outRxQ)));
18
21
  node.syncManager.addPeer({
19
22
  id: "test",
20
23
  incoming: inRx,
21
24
  outgoing: outTx,
22
25
  role: "peer",
23
26
  });
24
- const writer = inTx.getWriter();
25
- await writer.write({
27
+ yield* Queue.offer(inTx, {
26
28
  action: "load",
27
29
  id: map.core.id,
28
30
  header: false,
29
31
  sessions: {},
30
32
  });
31
- const reader = outRx.getReader();
32
- // expect((await reader.read()).value).toMatchObject(admStateEx(admin.id));
33
- expect((await reader.read()).value).toMatchObject(groupStateEx(group));
34
- const mapTellKnownStateMsg = await reader.read();
35
- expect(mapTellKnownStateMsg.value).toEqual({
33
+ // expect((yield* Queue.take(outRxQ))).toMatchObject(admStateEx(admin.id));
34
+ expect(yield* Queue.take(outRxQ)).toMatchObject(groupStateEx(group));
35
+ const mapTellKnownStateMsg = yield* Queue.take(outRxQ);
36
+ expect(mapTellKnownStateMsg).toEqual({
36
37
  action: "known",
37
38
  ...map.core.knownState(),
38
39
  });
39
- // expect((await reader.read()).value).toMatchObject(admContEx(admin.id));
40
- expect((await reader.read()).value).toMatchObject(groupContentEx(group));
41
- const newContentMsg = await reader.read();
42
- expect(newContentMsg.value).toEqual({
40
+ // expect((yield * Queue.take(outRxQ))).toMatchObject(admContEx(admin.id));
41
+ expect(yield* Queue.take(outRxQ)).toMatchObject(groupContentEx(group));
42
+ const newContentMsg = yield* Queue.take(outRxQ);
43
+ expect(newContentMsg).toEqual({
43
44
  action: "content",
44
45
  id: map.core.id,
45
46
  header: {
@@ -55,8 +56,7 @@ test("Node replies with initial tx and header to empty subscribe", async () => {
55
56
  newTransactions: [
56
57
  {
57
58
  privacy: "trusting",
58
- madeAt: map.core.sessionLogs.get(node.currentSessionID)
59
- .transactions[0].madeAt,
59
+ madeAt: map.core.sessionLogs.get(node.currentSessionID).transactions[0].madeAt,
60
60
  changes: stableStringify([
61
61
  {
62
62
  op: "set",
@@ -66,29 +66,29 @@ test("Node replies with initial tx and header to empty subscribe", async () => {
66
66
  ]),
67
67
  },
68
68
  ],
69
- lastSignature: map.core.sessionLogs.get(node.currentSessionID)
70
- .lastSignature,
69
+ lastSignature: map.core.sessionLogs.get(node.currentSessionID).lastSignature,
71
70
  },
72
71
  },
73
72
  });
74
- });
75
- test("Node replies with only new tx to subscribe with some known state", async () => {
73
+ }).pipe(Effect.scoped, Effect.runPromise));
74
+ test("Node replies with only new tx to subscribe with some known state", () => Effect.gen(function* () {
76
75
  const [admin, session] = randomAnonymousAccountAndSessionID();
77
76
  const node = new LocalNode(admin, session, Crypto);
78
77
  const group = node.createGroup();
79
78
  const map = group.createMap();
80
79
  map.set("hello", "world", "trusting");
81
80
  map.set("goodbye", "world", "trusting");
82
- const [inRx, inTx] = newStreamPair();
83
- const [outRx, outTx] = newStreamPair();
81
+ const [inRx, inTx] = yield* newQueuePair();
82
+ const [outRx, outTx] = yield* newQueuePair();
83
+ const outRxQ = yield* Queue.unbounded();
84
+ yield* Effect.fork(Stream.run(outRx, Sink.fromQueue(outRxQ)));
84
85
  node.syncManager.addPeer({
85
86
  id: "test",
86
87
  incoming: inRx,
87
88
  outgoing: outTx,
88
89
  role: "peer",
89
90
  });
90
- const writer = inTx.getWriter();
91
- await writer.write({
91
+ yield* Queue.offer(inTx, {
92
92
  action: "load",
93
93
  id: map.core.id,
94
94
  header: true,
@@ -96,18 +96,17 @@ test("Node replies with only new tx to subscribe with some known state", async (
96
96
  [node.currentSessionID]: 1,
97
97
  },
98
98
  });
99
- const reader = outRx.getReader();
100
- // expect((await reader.read()).value).toMatchObject(admStateEx(admin.id));
101
- expect((await reader.read()).value).toMatchObject(groupStateEx(group));
102
- const mapTellKnownStateMsg = await reader.read();
103
- expect(mapTellKnownStateMsg.value).toEqual({
99
+ // expect(yield* Queue.take(outRxQ)).toMatchObject(admStateEx(admin.id));
100
+ expect(yield* Queue.take(outRxQ)).toMatchObject(groupStateEx(group));
101
+ const mapTellKnownStateMsg = yield* Queue.take(outRxQ);
102
+ expect(mapTellKnownStateMsg).toEqual({
104
103
  action: "known",
105
104
  ...map.core.knownState(),
106
105
  });
107
- // expect((await reader.read()).value).toMatchObject(admContEx(admin.id));
108
- expect((await reader.read()).value).toMatchObject(groupContentEx(group));
109
- const mapNewContentMsg = await reader.read();
110
- expect(mapNewContentMsg.value).toEqual({
106
+ // expect(yield* Queue.take(outRxQ))).toMatchObject(admContEx(admin.id));
107
+ expect(yield* Queue.take(outRxQ)).toMatchObject(groupContentEx(group));
108
+ const mapNewContentMsg = yield* Queue.take(outRxQ);
109
+ expect(mapNewContentMsg).toEqual({
111
110
  action: "content",
112
111
  id: map.core.id,
113
112
  header: undefined,
@@ -117,8 +116,7 @@ test("Node replies with only new tx to subscribe with some known state", async (
117
116
  newTransactions: [
118
117
  {
119
118
  privacy: "trusting",
120
- madeAt: map.core.sessionLogs.get(node.currentSessionID)
121
- .transactions[1].madeAt,
119
+ madeAt: map.core.sessionLogs.get(node.currentSessionID).transactions[1].madeAt,
122
120
  changes: stableStringify([
123
121
  {
124
122
  op: "set",
@@ -128,28 +126,28 @@ test("Node replies with only new tx to subscribe with some known state", async (
128
126
  ]),
129
127
  },
130
128
  ],
131
- lastSignature: map.core.sessionLogs.get(node.currentSessionID)
132
- .lastSignature,
129
+ lastSignature: map.core.sessionLogs.get(node.currentSessionID).lastSignature,
133
130
  },
134
131
  },
135
132
  });
136
- });
133
+ }).pipe(Effect.scoped, Effect.runPromise));
137
134
  test.todo("TODO: node only replies with new tx to subscribe with some known state, even in the depended on coValues");
138
- test("After subscribing, node sends own known state and new txs to peer", async () => {
135
+ test("After subscribing, node sends own known state and new txs to peer", () => Effect.gen(function* () {
139
136
  const [admin, session] = randomAnonymousAccountAndSessionID();
140
137
  const node = new LocalNode(admin, session, Crypto);
141
138
  const group = node.createGroup();
142
139
  const map = group.createMap();
143
- const [inRx, inTx] = newStreamPair();
144
- const [outRx, outTx] = newStreamPair();
140
+ const [inRx, inTx] = yield* newQueuePair();
141
+ const [outRx, outTx] = yield* newQueuePair();
142
+ const outRxQ = yield* Queue.unbounded();
143
+ yield* Effect.fork(Stream.run(outRx, Sink.fromQueue(outRxQ)));
145
144
  node.syncManager.addPeer({
146
145
  id: "test",
147
146
  incoming: inRx,
148
147
  outgoing: outTx,
149
148
  role: "peer",
150
149
  });
151
- const writer = inTx.getWriter();
152
- await writer.write({
150
+ yield* Queue.offer(inTx, {
153
151
  action: "load",
154
152
  id: map.core.id,
155
153
  header: false,
@@ -157,26 +155,25 @@ test("After subscribing, node sends own known state and new txs to peer", async
157
155
  [node.currentSessionID]: 0,
158
156
  },
159
157
  });
160
- const reader = outRx.getReader();
161
- // expect((await reader.read()).value).toMatchObject(admStateEx(admin.id));
162
- expect((await reader.read()).value).toMatchObject(groupStateEx(group));
163
- const mapTellKnownStateMsg = await reader.read();
164
- expect(mapTellKnownStateMsg.value).toEqual({
158
+ // expect(yield* Queue.take(outRxQ)).toMatchObject(admStateEx(admin.id));
159
+ expect(yield* Queue.take(outRxQ)).toMatchObject(groupStateEx(group));
160
+ const mapTellKnownStateMsg = yield* Queue.take(outRxQ);
161
+ expect(mapTellKnownStateMsg).toEqual({
165
162
  action: "known",
166
163
  ...map.core.knownState(),
167
164
  });
168
- // expect((await reader.read()).value).toMatchObject(admContEx(admin.id));
169
- expect((await reader.read()).value).toMatchObject(groupContentEx(group));
170
- const mapNewContentHeaderOnlyMsg = await reader.read();
171
- expect(mapNewContentHeaderOnlyMsg.value).toEqual({
165
+ // expect(yield* Queue.take(outRxQ)).toMatchObject(admContEx(admin.id));
166
+ expect(yield* Queue.take(outRxQ)).toMatchObject(groupContentEx(group));
167
+ const mapNewContentHeaderOnlyMsg = yield* Queue.take(outRxQ);
168
+ expect(mapNewContentHeaderOnlyMsg).toEqual({
172
169
  action: "content",
173
170
  id: map.core.id,
174
171
  header: map.core.header,
175
172
  new: {},
176
173
  });
177
174
  map.set("hello", "world", "trusting");
178
- const mapEditMsg1 = await reader.read();
179
- expect(mapEditMsg1.value).toEqual({
175
+ const mapEditMsg1 = yield* Queue.take(outRxQ);
176
+ expect(mapEditMsg1).toEqual({
180
177
  action: "content",
181
178
  id: map.core.id,
182
179
  new: {
@@ -185,8 +182,7 @@ test("After subscribing, node sends own known state and new txs to peer", async
185
182
  newTransactions: [
186
183
  {
187
184
  privacy: "trusting",
188
- madeAt: map.core.sessionLogs.get(node.currentSessionID)
189
- .transactions[0].madeAt,
185
+ madeAt: map.core.sessionLogs.get(node.currentSessionID).transactions[0].madeAt,
190
186
  changes: stableStringify([
191
187
  {
192
188
  op: "set",
@@ -196,14 +192,13 @@ test("After subscribing, node sends own known state and new txs to peer", async
196
192
  ]),
197
193
  },
198
194
  ],
199
- lastSignature: map.core.sessionLogs.get(node.currentSessionID)
200
- .lastSignature,
195
+ lastSignature: map.core.sessionLogs.get(node.currentSessionID).lastSignature,
201
196
  },
202
197
  },
203
198
  });
204
199
  map.set("goodbye", "world", "trusting");
205
- const mapEditMsg2 = await reader.read();
206
- expect(mapEditMsg2.value).toEqual({
200
+ const mapEditMsg2 = yield* Queue.take(outRxQ);
201
+ expect(mapEditMsg2).toEqual({
207
202
  action: "content",
208
203
  id: map.core.id,
209
204
  new: {
@@ -212,8 +207,7 @@ test("After subscribing, node sends own known state and new txs to peer", async
212
207
  newTransactions: [
213
208
  {
214
209
  privacy: "trusting",
215
- madeAt: map.core.sessionLogs.get(node.currentSessionID)
216
- .transactions[1].madeAt,
210
+ madeAt: map.core.sessionLogs.get(node.currentSessionID).transactions[1].madeAt,
217
211
  changes: stableStringify([
218
212
  {
219
213
  op: "set",
@@ -223,30 +217,29 @@ test("After subscribing, node sends own known state and new txs to peer", async
223
217
  ]),
224
218
  },
225
219
  ],
226
- lastSignature: map.core.sessionLogs.get(node.currentSessionID)
227
- .lastSignature,
220
+ lastSignature: map.core.sessionLogs.get(node.currentSessionID).lastSignature,
228
221
  },
229
222
  },
230
223
  });
231
- });
232
- test("Client replies with known new content to tellKnownState from server", async () => {
224
+ }).pipe(Effect.scoped, Effect.runPromise));
225
+ test("Client replies with known new content to tellKnownState from server", () => Effect.gen(function* () {
233
226
  const [admin, session] = randomAnonymousAccountAndSessionID();
234
227
  const node = new LocalNode(admin, session, Crypto);
235
228
  const group = node.createGroup();
236
229
  const map = group.createMap();
237
230
  map.set("hello", "world", "trusting");
238
- const [inRx, inTx] = newStreamPair();
239
- const [outRx, outTx] = newStreamPair();
231
+ const [inRx, inTx] = yield* newQueuePair();
232
+ const [outRx, outTx] = yield* newQueuePair();
233
+ const outRxQ = yield* Queue.unbounded();
234
+ yield* Effect.fork(Stream.run(outRx, Sink.fromQueue(outRxQ)));
240
235
  node.syncManager.addPeer({
241
236
  id: "test",
242
237
  incoming: inRx,
243
238
  outgoing: outTx,
244
239
  role: "peer",
245
240
  });
246
- const reader = outRx.getReader();
247
- // expect((await reader.read()).value).toMatchObject(groupStateEx(group));
248
- const writer = inTx.getWriter();
249
- await writer.write({
241
+ // expect(yield* Queue.take(outRxQ)).toMatchObject(groupStateEx(group));
242
+ yield* Queue.offer(inTx, {
250
243
  action: "known",
251
244
  id: map.core.id,
252
245
  header: false,
@@ -254,17 +247,17 @@ test("Client replies with known new content to tellKnownState from server", asyn
254
247
  [node.currentSessionID]: 0,
255
248
  },
256
249
  });
257
- // expect((await reader.read()).value).toMatchObject(admStateEx(admin.id));
258
- expect((await reader.read()).value).toMatchObject(groupStateEx(group));
259
- const mapTellKnownStateMsg = await reader.read();
260
- expect(mapTellKnownStateMsg.value).toEqual({
250
+ // expect(yield* Queue.take(outRxQ)).toMatchObject(admStateEx(admin.id));
251
+ expect(yield* Queue.take(outRxQ)).toMatchObject(groupStateEx(group));
252
+ const mapTellKnownStateMsg = yield* Queue.take(outRxQ);
253
+ expect(mapTellKnownStateMsg).toEqual({
261
254
  action: "known",
262
255
  ...map.core.knownState(),
263
256
  });
264
- // expect((await reader.read()).value).toMatchObject(admContEx(admin.id));
265
- expect((await reader.read()).value).toMatchObject(groupContentEx(group));
266
- const mapNewContentMsg = await reader.read();
267
- expect(mapNewContentMsg.value).toEqual({
257
+ // expect(yield* Queue.take(outRxQ)).toMatchObject(admContEx(admin.id));
258
+ expect(yield* Queue.take(outRxQ)).toMatchObject(groupContentEx(group));
259
+ const mapNewContentMsg = yield* Queue.take(outRxQ);
260
+ expect(mapNewContentMsg).toEqual({
268
261
  action: "content",
269
262
  id: map.core.id,
270
263
  header: map.core.header,
@@ -274,8 +267,7 @@ test("Client replies with known new content to tellKnownState from server", asyn
274
267
  newTransactions: [
275
268
  {
276
269
  privacy: "trusting",
277
- madeAt: map.core.sessionLogs.get(node.currentSessionID)
278
- .transactions[0].madeAt,
270
+ madeAt: map.core.sessionLogs.get(node.currentSessionID).transactions[0].madeAt,
279
271
  changes: stableStringify([
280
272
  {
281
273
  op: "set",
@@ -285,27 +277,27 @@ test("Client replies with known new content to tellKnownState from server", asyn
285
277
  ]),
286
278
  },
287
279
  ],
288
- lastSignature: map.core.sessionLogs.get(node.currentSessionID)
289
- .lastSignature,
280
+ lastSignature: map.core.sessionLogs.get(node.currentSessionID).lastSignature,
290
281
  },
291
282
  },
292
283
  });
293
- });
294
- test("No matter the optimistic known state, node respects invalid known state messages and resyncs", async () => {
284
+ }).pipe(Effect.scoped, Effect.runPromise));
285
+ test("No matter the optimistic known state, node respects invalid known state messages and resyncs", () => Effect.gen(function* () {
295
286
  const [admin, session] = randomAnonymousAccountAndSessionID();
296
287
  const node = new LocalNode(admin, session, Crypto);
297
288
  const group = node.createGroup();
298
289
  const map = group.createMap();
299
- const [inRx, inTx] = newStreamPair();
300
- const [outRx, outTx] = newStreamPair();
290
+ const [inRx, inTx] = yield* newQueuePair();
291
+ const [outRx, outTx] = yield* newQueuePair();
292
+ const outRxQ = yield* Queue.unbounded();
293
+ yield* Effect.fork(Stream.run(outRx, Sink.fromQueue(outRxQ)));
301
294
  node.syncManager.addPeer({
302
295
  id: "test",
303
296
  incoming: inRx,
304
297
  outgoing: outTx,
305
298
  role: "peer",
306
299
  });
307
- const writer = inTx.getWriter();
308
- await writer.write({
300
+ yield* Queue.offer(inTx, {
309
301
  action: "load",
310
302
  id: map.core.id,
311
303
  header: false,
@@ -313,18 +305,17 @@ test("No matter the optimistic known state, node respects invalid known state me
313
305
  [node.currentSessionID]: 0,
314
306
  },
315
307
  });
316
- const reader = outRx.getReader();
317
- // expect((await reader.read()).value).toMatchObject(admStateEx(admin.id));
318
- expect((await reader.read()).value).toMatchObject(groupStateEx(group));
319
- const mapTellKnownStateMsg = await reader.read();
320
- expect(mapTellKnownStateMsg.value).toEqual({
308
+ // expect(yield* Queue.take(outRxQ)).toMatchObject(admStateEx(admin.id));
309
+ expect(yield* Queue.take(outRxQ)).toMatchObject(groupStateEx(group));
310
+ const mapTellKnownStateMsg = yield* Queue.take(outRxQ);
311
+ expect(mapTellKnownStateMsg).toEqual({
321
312
  action: "known",
322
313
  ...map.core.knownState(),
323
314
  });
324
- // expect((await reader.read()).value).toMatchObject(admContEx(admin.id));
325
- expect((await reader.read()).value).toMatchObject(groupContentEx(group));
326
- const mapNewContentHeaderOnlyMsg = await reader.read();
327
- expect(mapNewContentHeaderOnlyMsg.value).toEqual({
315
+ // expect(yield* Queue.take(outRxQ)).toMatchObject(admContEx(admin.id));
316
+ expect(yield* Queue.take(outRxQ)).toMatchObject(groupContentEx(group));
317
+ const mapNewContentHeaderOnlyMsg = yield* Queue.take(outRxQ);
318
+ expect(mapNewContentHeaderOnlyMsg).toEqual({
328
319
  action: "content",
329
320
  id: map.core.id,
330
321
  header: map.core.header,
@@ -332,9 +323,9 @@ test("No matter the optimistic known state, node respects invalid known state me
332
323
  });
333
324
  map.set("hello", "world", "trusting");
334
325
  map.set("goodbye", "world", "trusting");
335
- const _mapEditMsgs = await reader.read();
326
+ const _mapEditMsgs = yield* Queue.take(outRxQ);
336
327
  console.log("Sending correction");
337
- await writer.write({
328
+ yield* Queue.offer(inTx, {
338
329
  action: "known",
339
330
  isCorrection: true,
340
331
  id: map.core.id,
@@ -343,8 +334,8 @@ test("No matter the optimistic known state, node respects invalid known state me
343
334
  [node.currentSessionID]: 1,
344
335
  },
345
336
  });
346
- const newContentAfterWrongAssumedState = await reader.read();
347
- expect(newContentAfterWrongAssumedState.value).toEqual({
337
+ const newContentAfterWrongAssumedState = yield* Queue.take(outRxQ);
338
+ expect(newContentAfterWrongAssumedState).toEqual({
348
339
  action: "content",
349
340
  id: map.core.id,
350
341
  header: undefined,
@@ -354,8 +345,7 @@ test("No matter the optimistic known state, node respects invalid known state me
354
345
  newTransactions: [
355
346
  {
356
347
  privacy: "trusting",
357
- madeAt: map.core.sessionLogs.get(node.currentSessionID)
358
- .transactions[1].madeAt,
348
+ madeAt: map.core.sessionLogs.get(node.currentSessionID).transactions[1].madeAt,
359
349
  changes: stableStringify([
360
350
  {
361
351
  op: "set",
@@ -365,19 +355,20 @@ test("No matter the optimistic known state, node respects invalid known state me
365
355
  ]),
366
356
  },
367
357
  ],
368
- lastSignature: map.core.sessionLogs.get(node.currentSessionID)
369
- .lastSignature,
358
+ lastSignature: map.core.sessionLogs.get(node.currentSessionID).lastSignature,
370
359
  },
371
360
  },
372
361
  });
373
- });
374
- test("If we add a peer, but it never subscribes to a coValue, it won't get any messages", async () => {
362
+ }).pipe(Effect.scoped, Effect.runPromise));
363
+ test("If we add a peer, but it never subscribes to a coValue, it won't get any messages", () => Effect.gen(function* () {
375
364
  const [admin, session] = randomAnonymousAccountAndSessionID();
376
365
  const node = new LocalNode(admin, session, Crypto);
377
366
  const group = node.createGroup();
378
367
  const map = group.createMap();
379
- const [inRx, _inTx] = newStreamPair();
380
- const [outRx, outTx] = newStreamPair();
368
+ const [inRx, _inTx] = yield* newQueuePair();
369
+ const [outRx, outTx] = yield* newQueuePair();
370
+ const outRxQ = yield* Queue.unbounded();
371
+ yield* Effect.fork(Stream.run(outRx, Sink.fromQueue(outRxQ)));
381
372
  node.syncManager.addPeer({
382
373
  id: "test",
383
374
  incoming: inRx,
@@ -385,43 +376,46 @@ test("If we add a peer, but it never subscribes to a coValue, it won't get any m
385
376
  role: "peer",
386
377
  });
387
378
  map.set("hello", "world", "trusting");
388
- const reader = outRx.getReader();
389
- await expect(shouldNotResolve(reader.read(), { timeout: 100 })).resolves.toBeUndefined();
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 () => {
379
+ expect(yield* Queue.take(outRxQ).pipe(Effect.timeout(100), Effect.catch("_tag", {
380
+ failure: "TimeoutException",
381
+ onFailure: () => Effect.succeed("neverHappened"),
382
+ }))).toEqual("neverHappened");
383
+ }).pipe(Effect.scoped, Effect.runPromise));
384
+ test.todo("If we add a server peer, all updates to all coValues are sent to it, even if it doesn't subscribe", () => Effect.gen(function* () {
392
385
  const [admin, session] = randomAnonymousAccountAndSessionID();
393
386
  const node = new LocalNode(admin, session, Crypto);
394
387
  const group = node.createGroup();
395
388
  const map = group.createMap();
396
- const [inRx, _inTx] = newStreamPair();
397
- const [outRx, outTx] = newStreamPair();
389
+ const [inRx, _inTx] = yield* newQueuePair();
390
+ const [outRx, outTx] = yield* newQueuePair();
391
+ const outRxQ = yield* Queue.unbounded();
392
+ yield* Effect.fork(Stream.run(outRx, Sink.fromQueue(outRxQ)));
398
393
  node.syncManager.addPeer({
399
394
  id: "test",
400
395
  incoming: inRx,
401
396
  outgoing: outTx,
402
397
  role: "server",
403
398
  });
404
- const reader = outRx.getReader();
405
- // expect((await reader.read()).value).toMatchObject({
399
+ // expect(yield* Queue.take(outRxQ)).toMatchObject({
406
400
  // action: "load",
407
401
  // id: adminID,
408
402
  // });
409
- expect((await reader.read()).value).toMatchObject({
403
+ expect(yield* Queue.take(outRxQ)).toMatchObject({
410
404
  action: "load",
411
405
  id: group.core.id,
412
406
  });
413
- const mapSubscribeMsg = await reader.read();
414
- expect(mapSubscribeMsg.value).toEqual({
407
+ const mapSubscribeMsg = Queue.take(outRxQ);
408
+ expect(mapSubscribeMsg).toEqual({
415
409
  action: "load",
416
410
  id: map.core.id,
417
411
  header: true,
418
412
  sessions: {},
419
413
  });
420
414
  map.set("hello", "world", "trusting");
421
- // expect((await reader.read()).value).toMatchObject(admContEx(admin.id));
422
- expect((await reader.read()).value).toMatchObject(groupContentEx(group));
423
- const mapNewContentMsg = await reader.read();
424
- expect(mapNewContentMsg.value).toEqual({
415
+ // expect(yield* Queue.take(outRxQ)).toMatchObject(admContEx(admin.id));
416
+ expect(yield* Queue.take(outRxQ)).toMatchObject(groupContentEx(group));
417
+ const mapNewContentMsg = Queue.take(outRxQ);
418
+ expect(mapNewContentMsg).toEqual({
425
419
  action: "content",
426
420
  id: map.core.id,
427
421
  header: map.core.header,
@@ -445,86 +439,89 @@ test.todo("If we add a server peer, all updates to all coValues are sent to it,
445
439
  },
446
440
  },
447
441
  });
448
- });
449
- test.skip("If we add a server peer, newly created coValues are auto-subscribed to", async () => {
442
+ }).pipe(Effect.scoped, Effect.runPromise));
443
+ test.skip("If we add a server peer, newly created coValues are auto-subscribed to", () => Effect.gen(function* () {
450
444
  const [admin, session] = randomAnonymousAccountAndSessionID();
451
445
  const node = new LocalNode(admin, session, Crypto);
452
446
  const group = node.createGroup();
453
- const [inRx, _inTx] = newStreamPair();
454
- const [outRx, outTx] = newStreamPair();
447
+ const [inRx, _inTx] = yield* newQueuePair();
448
+ const [outRx, outTx] = yield* newQueuePair();
449
+ const outRxQ = yield* Queue.unbounded();
450
+ yield* Effect.fork(Stream.run(outRx, Sink.fromQueue(outRxQ)));
455
451
  node.syncManager.addPeer({
456
452
  id: "test",
457
453
  incoming: inRx,
458
454
  outgoing: outTx,
459
455
  role: "server",
460
456
  });
461
- const reader = outRx.getReader();
462
- // expect((await reader.read()).value).toMatchObject({
457
+ // expect(yield* Queue.take(outRxQ)).toMatchObject({
463
458
  // action: "load",
464
459
  // id: admin.id,
465
460
  // });
466
- expect((await reader.read()).value).toMatchObject({
461
+ expect(yield* Queue.take(outRxQ)).toMatchObject({
467
462
  action: "load",
468
463
  id: group.core.id,
469
464
  });
470
465
  const map = group.createMap();
471
- const mapSubscribeMsg = await reader.read();
472
- expect(mapSubscribeMsg.value).toEqual({
466
+ const mapSubscribeMsg = Queue.take(outRxQ);
467
+ expect(mapSubscribeMsg).toEqual({
473
468
  action: "load",
474
469
  ...map.core.knownState(),
475
470
  });
476
- // expect((await reader.read()).value).toMatchObject(admContEx(adminID));
477
- expect((await reader.read()).value).toMatchObject(groupContentEx(group));
478
- const mapContentMsg = await reader.read();
479
- expect(mapContentMsg.value).toEqual({
471
+ // expect(yield* Queue.take(outRxQ)).toMatchObject(admContEx(adminID));
472
+ expect(yield* Queue.take(outRxQ)).toMatchObject(groupContentEx(group));
473
+ const mapContentMsg = Queue.take(outRxQ);
474
+ expect(mapContentMsg).toEqual({
480
475
  action: "content",
481
476
  id: map.core.id,
482
477
  header: map.core.header,
483
478
  new: {},
484
479
  });
485
- });
480
+ }).pipe(Effect.scoped, Effect.runPromise));
486
481
  test.todo("TODO: when receiving a subscribe response that is behind our optimistic state (due to already sent content), we ignore it");
487
- test("When we connect a new server peer, we try to sync all existing coValues to it", async () => {
482
+ test("When we connect a new server peer, we try to sync all existing coValues to it", () => Effect.gen(function* () {
488
483
  const [admin, session] = randomAnonymousAccountAndSessionID();
489
484
  const node = new LocalNode(admin, session, Crypto);
490
485
  const group = node.createGroup();
491
486
  const map = group.createMap();
492
- const [inRx, _inTx] = newStreamPair();
493
- const [outRx, outTx] = newStreamPair();
487
+ const [inRx, _inTx] = yield* newQueuePair();
488
+ const [outRx, outTx] = yield* newQueuePair();
489
+ const outRxQ = yield* Queue.unbounded();
490
+ yield* Effect.fork(Stream.run(outRx, Sink.fromQueue(outRxQ)));
494
491
  node.syncManager.addPeer({
495
492
  id: "test",
496
493
  incoming: inRx,
497
494
  outgoing: outTx,
498
495
  role: "server",
499
496
  });
500
- const reader = outRx.getReader();
501
- // const _adminSubscribeMessage = await reader.read();
502
- const groupSubscribeMessage = await reader.read();
503
- expect(groupSubscribeMessage.value).toEqual({
497
+ // const _adminSubscribeMessage = yield* Queue.take(outRxQ);
498
+ const groupSubscribeMessage = yield* Queue.take(outRxQ);
499
+ expect(groupSubscribeMessage).toEqual({
504
500
  action: "load",
505
501
  ...group.core.knownState(),
506
502
  });
507
- const secondMessage = await reader.read();
508
- expect(secondMessage.value).toEqual({
503
+ const secondMessage = yield* Queue.take(outRxQ);
504
+ expect(secondMessage).toEqual({
509
505
  action: "load",
510
506
  ...map.core.knownState(),
511
507
  });
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 () => {
508
+ }).pipe(Effect.scoped, Effect.runPromise));
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", () => Effect.gen(function* () {
514
510
  const [admin, session] = randomAnonymousAccountAndSessionID();
515
511
  const node = new LocalNode(admin, session, Crypto);
516
512
  const group = node.createGroup();
517
513
  const map = group.createMap();
518
- const [inRx, inTx] = newStreamPair();
519
- const [outRx, outTx] = newStreamPair();
514
+ const [inRx, inTx] = yield* newQueuePair();
515
+ const [outRx, outTx] = yield* newQueuePair();
516
+ const outRxQ = yield* Queue.unbounded();
517
+ yield* Effect.fork(Stream.run(outRx, Sink.fromQueue(outRxQ)));
520
518
  node.syncManager.addPeer({
521
519
  id: "test",
522
520
  incoming: inRx,
523
521
  outgoing: outTx,
524
522
  role: "peer",
525
523
  });
526
- const writer = inTx.getWriter();
527
- await writer.write({
524
+ yield* Queue.offer(inTx, {
528
525
  action: "load",
529
526
  id: map.core.id,
530
527
  header: true,
@@ -532,110 +529,123 @@ test("When receiving a subscribe with a known state that is ahead of our own, pe
532
529
  [node.currentSessionID]: 1,
533
530
  },
534
531
  });
535
- const reader = outRx.getReader();
536
- // expect((await reader.read()).value).toMatchObject(admStateEx(admin.id));
537
- expect((await reader.read()).value).toMatchObject(groupStateEx(group));
538
- const mapTellKnownState = await reader.read();
539
- expect(mapTellKnownState.value).toEqual({
532
+ // expect(yield* Queue.take(outRxQ)).toMatchObject(admStateEx(admin.id));
533
+ expect(yield* Queue.take(outRxQ)).toMatchObject(groupStateEx(group));
534
+ const mapTellKnownState = yield* Queue.take(outRxQ);
535
+ expect(mapTellKnownState).toEqual({
540
536
  action: "known",
541
537
  ...map.core.knownState(),
542
538
  });
543
- });
544
- test.skip("When replaying creation and transactions of a coValue as new content, the receiving peer integrates this information", async () => {
539
+ }).pipe(Effect.scoped, Effect.runPromise));
540
+ test.skip("When replaying creation and transactions of a coValue as new content, the receiving peer integrates this information", () => Effect.gen(function* () {
545
541
  // 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
546
542
  const [admin, session] = randomAnonymousAccountAndSessionID();
547
543
  const node1 = new LocalNode(admin, session, Crypto);
548
544
  const group = node1.createGroup();
549
- const [inRx1, inTx1] = newStreamPair();
550
- const [outRx1, outTx1] = newStreamPair();
545
+ const [inRx1, inTx1] = yield* newQueuePair();
546
+ const [outRx1, outTx1] = yield* newQueuePair();
547
+ const outRxQ1 = yield* Queue.unbounded();
548
+ yield* Effect.fork(Stream.run(outRx1, Sink.fromQueue(outRxQ1)));
551
549
  node1.syncManager.addPeer({
552
550
  id: "test2",
553
551
  incoming: inRx1,
554
552
  outgoing: outTx1,
555
553
  role: "server",
556
554
  });
557
- const to1 = inTx1.getWriter();
558
- const from1 = outRx1.getReader();
559
555
  const node2 = new LocalNode(admin, newRandomSessionID(admin.id), Crypto);
560
- const [inRx2, inTx2] = newStreamPair();
561
- const [outRx2, outTx2] = newStreamPair();
556
+ const [inRx2, inTx2] = yield* newQueuePair();
557
+ const [outRx2, outTx2] = yield* newQueuePair();
558
+ const outRxQ2 = yield* Queue.unbounded();
559
+ yield* Effect.fork(Stream.run(outRx2, Sink.fromQueue(outRxQ1)));
562
560
  node2.syncManager.addPeer({
563
561
  id: "test1",
564
562
  incoming: inRx2,
565
563
  outgoing: outTx2,
566
564
  role: "client",
567
565
  });
568
- const to2 = inTx2.getWriter();
569
- const from2 = outRx2.getReader();
570
- const adminSubscribeMessage = await from1.read();
571
- expect(adminSubscribeMessage.value).toMatchObject({
566
+ const adminSubscribeMessage = yield* Queue.take(outRxQ1);
567
+ expect(adminSubscribeMessage).toMatchObject({
572
568
  action: "load",
573
569
  id: admin.id,
574
570
  });
575
- const groupSubscribeMsg = await from1.read();
576
- expect(groupSubscribeMsg.value).toMatchObject({
571
+ const groupSubscribeMsg = yield* Queue.take(outRxQ1);
572
+ expect(groupSubscribeMsg).toMatchObject({
577
573
  action: "load",
578
574
  id: group.core.id,
579
575
  });
580
- await to2.write(adminSubscribeMessage.value);
581
- await to2.write(groupSubscribeMsg.value);
582
- // const adminTellKnownStateMsg = await from2.read();
583
- // expect(adminTellKnownStateMsg.value).toMatchObject(admStateEx(admin.id));
584
- const groupTellKnownStateMsg = await from2.read();
585
- expect(groupTellKnownStateMsg.value).toMatchObject(groupStateEx(group));
576
+ yield* Queue.offer(inTx2, adminSubscribeMessage);
577
+ yield* Queue.offer(inTx2, groupSubscribeMsg);
578
+ // const adminTellKnownStateMsg = yield* Queue.take(outRxQ2);
579
+ // expect(adminTellKnownStateMsg).toMatchObject(admStateEx(admin.id));
580
+ const groupTellKnownStateMsg = yield* Queue.take(outRxQ2);
581
+ expect(groupTellKnownStateMsg).toMatchObject(groupStateEx(group));
586
582
  expect(node2.syncManager.peers["test1"].optimisticKnownStates[group.core.id]).toBeDefined();
587
- // await to1.write(adminTellKnownStateMsg.value!);
588
- await to1.write(groupTellKnownStateMsg.value);
589
- // const adminContentMsg = await from1.read();
590
- // expect(adminContentMsg.value).toMatchObject(admContEx(admin.id));
591
- const groupContentMsg = await from1.read();
592
- expect(groupContentMsg.value).toMatchObject(groupContentEx(group));
593
- // await to2.write(adminContentMsg.value!);
594
- await to2.write(groupContentMsg.value);
583
+ // yield* Queue.offer(inTx1, adminTellKnownStateMsg);
584
+ yield* Queue.offer(inTx1, groupTellKnownStateMsg);
585
+ // const adminContentMsg = yield* Queue.take(outRxQ1);
586
+ // expect(adminContentMsg).toMatchObject(admContEx(admin.id));
587
+ const groupContentMsg = yield* Queue.take(outRxQ1);
588
+ expect(groupContentMsg).toMatchObject(groupContentEx(group));
589
+ // yield* Queue.offer(inTx2, adminContentMsg);
590
+ yield* Queue.offer(inTx2, groupContentMsg);
595
591
  const map = group.createMap();
596
- const mapSubscriptionMsg = await from1.read();
597
- expect(mapSubscriptionMsg.value).toMatchObject({
592
+ const mapSubscriptionMsg = yield* Queue.take(outRxQ1);
593
+ expect(mapSubscriptionMsg).toMatchObject({
598
594
  action: "load",
599
595
  id: map.core.id,
600
596
  });
601
- const mapNewContentMsg = await from1.read();
602
- expect(mapNewContentMsg.value).toEqual({
597
+ const mapNewContentMsg = yield* Queue.take(outRxQ1);
598
+ expect(mapNewContentMsg).toEqual({
603
599
  action: "content",
604
600
  id: map.core.id,
605
601
  header: map.core.header,
606
602
  new: {},
607
603
  });
608
- await to2.write(mapSubscriptionMsg.value);
609
- const mapTellKnownStateMsg = await from2.read();
610
- expect(mapTellKnownStateMsg.value).toEqual({
604
+ yield* Queue.offer(inTx2, mapSubscriptionMsg);
605
+ const mapTellKnownStateMsg = yield* Queue.take(outRxQ2);
606
+ expect(mapTellKnownStateMsg).toEqual({
611
607
  action: "known",
612
608
  id: map.core.id,
613
609
  header: false,
614
610
  sessions: {},
615
611
  });
616
612
  expect(node2.coValues[map.core.id]?.state).toEqual("loading");
617
- await to2.write(mapNewContentMsg.value);
613
+ yield* Queue.offer(inTx2, mapNewContentMsg);
618
614
  map.set("hello", "world", "trusting");
619
- const mapEditMsg = await from1.read();
620
- await to2.write(mapEditMsg.value);
621
- await new Promise((resolve) => setTimeout(resolve, 100));
615
+ const mapEditMsg = yield* Queue.take(outRxQ1);
616
+ yield* Queue.offer(inTx2, mapEditMsg);
617
+ yield* Effect.sleep(100);
622
618
  expect(expectMap(node2.expectCoValueLoaded(map.core.id).getCurrentContent()).get("hello")).toEqual("world");
623
- });
619
+ }).pipe(Effect.scoped, Effect.runPromise));
624
620
  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
+ /*
625
622
  // 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
626
623
  const [admin, session] = randomAnonymousAccountAndSessionID();
624
+
627
625
  const node1 = new LocalNode(admin, session, Crypto);
626
+
628
627
  const group = node1.createGroup();
628
+
629
629
  const map = group.createMap();
630
630
  map.set("hello", "world", "trusting");
631
+
631
632
  const node2 = new LocalNode(admin, newRandomSessionID(admin.id), Crypto);
633
+
632
634
  const [node1asPeer, node2asPeer] = connectedPeers("peer1", "peer2");
635
+
633
636
  node1.syncManager.addPeer(node2asPeer);
634
637
  node2.syncManager.addPeer(node1asPeer);
638
+
635
639
  await node2.loadCoValueCore(map.core.id);
636
- expect(expectMap(node2.expectCoValueLoaded(map.core.id).getCurrentContent()).get("hello")).toEqual("world");
640
+
641
+ expect(
642
+ expectMap(
643
+ node2.expectCoValueLoaded(map.core.id).getCurrentContent(),
644
+ ).get("hello"),
645
+ ).toEqual("world");
646
+ */
637
647
  });
638
- test("Can sync a coValue through a server to another client", async () => {
648
+ test("Can sync a coValue through a server to another client", () => Effect.gen(function* () {
639
649
  const [admin, session] = randomAnonymousAccountAndSessionID();
640
650
  const client1 = new LocalNode(admin, session, Crypto);
641
651
  const group = client1.createGroup();
@@ -643,24 +653,28 @@ test("Can sync a coValue through a server to another client", async () => {
643
653
  map.set("hello", "world", "trusting");
644
654
  const [serverUser, serverSession] = randomAnonymousAccountAndSessionID();
645
655
  const server = new LocalNode(serverUser, serverSession, Crypto);
646
- const [serverAsPeer, client1AsPeer] = connectedPeers("server", "client1", {
656
+ const [serverAsPeerForClient1, client1AsPeer] = yield* connectedPeers("serverFor1", "client1", {
647
657
  peer1role: "server",
648
658
  peer2role: "client",
649
659
  trace: true,
650
660
  });
651
- client1.syncManager.addPeer(serverAsPeer);
661
+ client1.syncManager.addPeer(serverAsPeerForClient1);
652
662
  server.syncManager.addPeer(client1AsPeer);
653
663
  const client2 = new LocalNode(admin, newRandomSessionID(admin.id), Crypto);
654
- const [serverAsOtherPeer, client2AsPeer] = connectedPeers("server", "client2", { peer1role: "server", peer2role: "client", trace: true });
655
- client2.syncManager.addPeer(serverAsOtherPeer);
664
+ const [serverAsPeerForClient2, client2AsPeer] = yield* connectedPeers("serverFor2", "client2", {
665
+ peer1role: "server",
666
+ peer2role: "client",
667
+ trace: true,
668
+ });
669
+ client2.syncManager.addPeer(serverAsPeerForClient2);
656
670
  server.syncManager.addPeer(client2AsPeer);
657
- const mapOnClient2 = await client2.loadCoValueCore(map.core.id);
671
+ const mapOnClient2 = yield* Effect.promise(() => client2.loadCoValueCore(map.core.id));
658
672
  if (mapOnClient2 === "unavailable") {
659
673
  throw new Error("Map is unavailable");
660
674
  }
661
675
  expect(expectMap(mapOnClient2.getCurrentContent()).get("hello")).toEqual("world");
662
- });
663
- test("Can sync a coValue with private transactions through a server to another client", async () => {
676
+ }).pipe(Effect.scoped, Effect.runPromise));
677
+ test("Can sync a coValue with private transactions through a server to another client", () => Effect.gen(function* () {
664
678
  const [admin, session] = randomAnonymousAccountAndSessionID();
665
679
  const client1 = new LocalNode(admin, session, Crypto);
666
680
  const group = client1.createGroup();
@@ -668,7 +682,7 @@ test("Can sync a coValue with private transactions through a server to another c
668
682
  map.set("hello", "world", "private");
669
683
  const [serverUser, serverSession] = randomAnonymousAccountAndSessionID();
670
684
  const server = new LocalNode(serverUser, serverSession, Crypto);
671
- const [serverAsPeer, client1AsPeer] = connectedPeers("server", "client1", {
685
+ const [serverAsPeer, client1AsPeer] = yield* connectedPeers("server", "client1", {
672
686
  trace: true,
673
687
  peer1role: "server",
674
688
  peer2role: "client",
@@ -676,105 +690,138 @@ test("Can sync a coValue with private transactions through a server to another c
676
690
  client1.syncManager.addPeer(serverAsPeer);
677
691
  server.syncManager.addPeer(client1AsPeer);
678
692
  const client2 = new LocalNode(admin, newRandomSessionID(admin.id), Crypto);
679
- const [serverAsOtherPeer, client2AsPeer] = connectedPeers("server", "client2", { trace: true, peer1role: "server", peer2role: "client" });
693
+ const [serverAsOtherPeer, client2AsPeer] = yield* connectedPeers("server", "client2", {
694
+ trace: true,
695
+ peer1role: "server",
696
+ peer2role: "client",
697
+ });
680
698
  client2.syncManager.addPeer(serverAsOtherPeer);
681
699
  server.syncManager.addPeer(client2AsPeer);
682
- const mapOnClient2 = await client2.loadCoValueCore(map.core.id);
700
+ const mapOnClient2 = yield* Effect.promise(() => client2.loadCoValueCore(map.core.id));
683
701
  if (mapOnClient2 === "unavailable") {
684
702
  throw new Error("Map is unavailable");
685
703
  }
686
704
  expect(expectMap(mapOnClient2.getCurrentContent()).get("hello")).toEqual("world");
687
- });
705
+ }).pipe(Effect.scoped, Effect.runPromise));
688
706
  test.skip("When a peer's incoming/readable stream closes, we remove the peer", async () => {
707
+ /*
689
708
  const [admin, session] = randomAnonymousAccountAndSessionID();
690
709
  const node = new LocalNode(admin, session, Crypto);
710
+
691
711
  const group = node.createGroup();
692
- const [inRx, inTx] = newStreamPair();
693
- const [outRx, outTx] = newStreamPair();
712
+
713
+ const [inRx, inTx] = await Effect.runPromise(newStreamPair());
714
+ const [outRx, outTx] = await Effect.runPromise(newStreamPair());
715
+
694
716
  node.syncManager.addPeer({
695
717
  id: "test",
696
718
  incoming: inRx,
697
719
  outgoing: outTx,
698
720
  role: "server",
699
721
  });
700
- const reader = outRx.getReader();
701
- // expect((await reader.read()).value).toMatchObject({
722
+
723
+ // expect(yield* Queue.take(outRxQ)).toMatchObject({
702
724
  // action: "load",
703
725
  // id: admin.id,
704
726
  // });
705
- expect((await reader.read()).value).toMatchObject({
727
+ expect(yield * Queue.take(outRxQ)).toMatchObject({
706
728
  action: "load",
707
729
  id: group.core.id,
708
730
  });
731
+
709
732
  const map = group.createMap();
733
+
710
734
  const mapSubscribeMsg = await reader.read();
735
+
711
736
  expect(mapSubscribeMsg.value).toEqual({
712
737
  action: "load",
713
738
  ...map.core.knownState(),
714
- });
715
- // expect((await reader.read()).value).toMatchObject(admContEx(admin.id));
716
- expect((await reader.read()).value).toMatchObject(groupContentEx(group));
739
+ } satisfies SyncMessage);
740
+
741
+ // expect(yield* Queue.take(outRxQ)).toMatchObject(admContEx(admin.id));
742
+ expect(yield * Queue.take(outRxQ)).toMatchObject(groupContentEx(group));
743
+
717
744
  const mapContentMsg = await reader.read();
745
+
718
746
  expect(mapContentMsg.value).toEqual({
719
747
  action: "content",
720
748
  id: map.core.id,
721
749
  header: map.core.header,
722
750
  new: {},
723
- });
751
+ } satisfies SyncMessage);
752
+
724
753
  await inTx.abort();
754
+
725
755
  await new Promise((resolve) => setTimeout(resolve, 100));
756
+
726
757
  expect(node.syncManager.peers["test"]).toBeUndefined();
758
+ */
727
759
  });
728
760
  test.skip("When a peer's outgoing/writable stream closes, we remove the peer", async () => {
761
+ /*
729
762
  const [admin, session] = randomAnonymousAccountAndSessionID();
730
763
  const node = new LocalNode(admin, session, Crypto);
764
+
731
765
  const group = node.createGroup();
732
- const [inRx] = newStreamPair();
733
- const [outRx, outTx] = newStreamPair();
766
+
767
+ const [inRx] = await Effect.runPromise(newStreamPair());
768
+ const [outRx, outTx] = await Effect.runPromise(newStreamPair());
769
+
734
770
  node.syncManager.addPeer({
735
771
  id: "test",
736
772
  incoming: inRx,
737
773
  outgoing: outTx,
738
774
  role: "server",
739
775
  });
740
- const reader = outRx.getReader();
741
- // expect((await reader.read()).value).toMatchObject({
776
+
777
+ // expect(yield* Queue.take(outRxQ)).toMatchObject({
742
778
  // action: "load",
743
779
  // id: admin.id,
744
780
  // });
745
- expect((await reader.read()).value).toMatchObject({
781
+ expect(yield * Queue.take(outRxQ)).toMatchObject({
746
782
  action: "load",
747
783
  id: group.core.id,
748
784
  });
785
+
749
786
  const map = group.createMap();
787
+
750
788
  const mapSubscribeMsg = await reader.read();
789
+
751
790
  expect(mapSubscribeMsg.value).toEqual({
752
791
  action: "load",
753
792
  ...map.core.knownState(),
754
- });
755
- // expect((await reader.read()).value).toMatchObject(admContEx(admin.id));
756
- expect((await reader.read()).value).toMatchObject(groupContentEx(group));
793
+ } satisfies SyncMessage);
794
+
795
+ // expect(yield* Queue.take(outRxQ)).toMatchObject(admContEx(admin.id));
796
+ expect(yield * Queue.take(outRxQ)).toMatchObject(groupContentEx(group));
797
+
757
798
  const mapContentMsg = await reader.read();
799
+
758
800
  expect(mapContentMsg.value).toEqual({
759
801
  action: "content",
760
802
  id: map.core.id,
761
803
  header: map.core.header,
762
804
  new: {},
763
- });
805
+ } satisfies SyncMessage);
806
+
764
807
  reader.releaseLock();
765
808
  await outRx.cancel();
809
+
766
810
  map.set("hello", "world", "trusting");
811
+
767
812
  await new Promise((resolve) => setTimeout(resolve, 100));
813
+
768
814
  expect(node.syncManager.peers["test"]).toBeUndefined();
815
+ */
769
816
  });
770
- test("If we start loading a coValue before connecting to a peer that has it, it will load it once we connect", async () => {
817
+ test("If we start loading a coValue before connecting to a peer that has it, it will load it once we connect", () => Effect.gen(function* () {
771
818
  const [admin, session] = randomAnonymousAccountAndSessionID();
772
819
  const node1 = new LocalNode(admin, session, Crypto);
773
820
  const group = node1.createGroup();
774
821
  const map = group.createMap();
775
822
  map.set("hello", "world", "trusting");
776
823
  const node2 = new LocalNode(admin, newRandomSessionID(admin.id), Crypto);
777
- const [node1asPeer, node2asPeer] = connectedPeers("peer1", "peer2", {
824
+ const [node1asPeer, node2asPeer] = yield* connectedPeers("peer1", "peer2", {
778
825
  peer1role: "server",
779
826
  peer2role: "client",
780
827
  trace: true,
@@ -783,12 +830,12 @@ test("If we start loading a coValue before connecting to a peer that has it, it
783
830
  const mapOnNode2Promise = node2.loadCoValueCore(map.core.id);
784
831
  expect(node2.coValues[map.core.id]?.state).toEqual("loading");
785
832
  node2.syncManager.addPeer(node1asPeer);
786
- const mapOnNode2 = await mapOnNode2Promise;
833
+ const mapOnNode2 = yield* Effect.promise(() => mapOnNode2Promise);
787
834
  if (mapOnNode2 === "unavailable") {
788
835
  throw new Error("Map is unavailable");
789
836
  }
790
837
  expect(expectMap(mapOnNode2.getCurrentContent()).get("hello")).toEqual("world");
791
- });
838
+ }).pipe(Effect.scoped, Effect.runPromise));
792
839
  function groupContentEx(group) {
793
840
  return {
794
841
  action: "content",