cojson 0.13.16 → 0.13.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +7 -0
  3. package/dist/coValue.d.ts +2 -0
  4. package/dist/coValue.d.ts.map +1 -1
  5. package/dist/coValue.js +1 -0
  6. package/dist/coValue.js.map +1 -1
  7. package/dist/coValueCore.d.ts +1 -0
  8. package/dist/coValueCore.d.ts.map +1 -1
  9. package/dist/coValueCore.js.map +1 -1
  10. package/dist/coValueState.d.ts.map +1 -1
  11. package/dist/coValueState.js +58 -96
  12. package/dist/coValueState.js.map +1 -1
  13. package/dist/coValues/coList.d.ts +7 -3
  14. package/dist/coValues/coList.d.ts.map +1 -1
  15. package/dist/coValues/coList.js +35 -12
  16. package/dist/coValues/coList.js.map +1 -1
  17. package/dist/coValues/coMap.d.ts +1 -0
  18. package/dist/coValues/coMap.d.ts.map +1 -1
  19. package/dist/coValues/coMap.js +2 -0
  20. package/dist/coValues/coMap.js.map +1 -1
  21. package/dist/coValues/coPlainText.d.ts.map +1 -1
  22. package/dist/coValues/coPlainText.js +1 -1
  23. package/dist/coValues/coPlainText.js.map +1 -1
  24. package/dist/coValues/coStream.d.ts +2 -1
  25. package/dist/coValues/coStream.d.ts.map +1 -1
  26. package/dist/coValues/coStream.js +2 -0
  27. package/dist/coValues/coStream.js.map +1 -1
  28. package/dist/coreToCoValue.d.ts +2 -1
  29. package/dist/coreToCoValue.d.ts.map +1 -1
  30. package/dist/localNode.d.ts.map +1 -1
  31. package/dist/localNode.js +21 -14
  32. package/dist/localNode.js.map +1 -1
  33. package/dist/tests/coList.test.js +119 -2
  34. package/dist/tests/coList.test.js.map +1 -1
  35. package/dist/tests/coMap.test.js +32 -2
  36. package/dist/tests/coMap.test.js.map +1 -1
  37. package/dist/tests/coStream.test.js +28 -2
  38. package/dist/tests/coStream.test.js.map +1 -1
  39. package/dist/tests/coValueState.test.js +10 -143
  40. package/dist/tests/coValueState.test.js.map +1 -1
  41. package/dist/tests/sync.load.test.js +59 -1
  42. package/dist/tests/sync.load.test.js.map +1 -1
  43. package/dist/tests/sync.mesh.test.js +48 -1
  44. package/dist/tests/sync.mesh.test.js.map +1 -1
  45. package/package.json +1 -1
  46. package/src/coValue.ts +3 -0
  47. package/src/coValueCore.ts +1 -0
  48. package/src/coValueState.ts +67 -122
  49. package/src/coValues/coList.ts +51 -23
  50. package/src/coValues/coMap.ts +4 -0
  51. package/src/coValues/coPlainText.ts +1 -2
  52. package/src/coValues/coStream.ts +3 -1
  53. package/src/localNode.ts +29 -18
  54. package/src/tests/coList.test.ts +184 -2
  55. package/src/tests/coMap.test.ts +54 -2
  56. package/src/tests/coStream.test.ts +56 -2
  57. package/src/tests/coValueState.test.ts +9 -207
  58. package/src/tests/sync.load.test.ts +78 -1
  59. package/src/tests/sync.mesh.test.ts +67 -0
@@ -1,11 +1,20 @@
1
- import { expect, test } from "vitest";
1
+ import { beforeEach, expect, test } from "vitest";
2
2
  import { expectList } from "../coValue.js";
3
3
  import { WasmCrypto } from "../crypto/WasmCrypto.js";
4
4
  import { LocalNode } from "../localNode.js";
5
- import { randomAnonymousAccountAndSessionID } from "./testUtils.js";
5
+ import {
6
+ loadCoValueOrFail,
7
+ randomAnonymousAccountAndSessionID,
8
+ setupTestNode,
9
+ waitFor,
10
+ } from "./testUtils.js";
6
11
 
7
12
  const Crypto = await WasmCrypto.create();
8
13
 
14
+ beforeEach(async () => {
15
+ setupTestNode({ isSyncServer: true });
16
+ });
17
+
9
18
  test("Empty CoList works", () => {
10
19
  const node = new LocalNode(...randomAnonymousAccountAndSessionID(), Crypto);
11
20
 
@@ -221,3 +230,176 @@ test("Items prepended to start appear with latest first", () => {
221
230
 
222
231
  expect(content.toJSON()).toEqual(["third", "second", "first"]);
223
232
  });
233
+
234
+ test("mixing prepend and append", () => {
235
+ const node = new LocalNode(...randomAnonymousAccountAndSessionID(), Crypto);
236
+
237
+ const coValue = node.createCoValue({
238
+ type: "colist",
239
+ ruleset: { type: "unsafeAllowAll" },
240
+ meta: null,
241
+ ...Crypto.createdNowUnique(),
242
+ });
243
+
244
+ const list = expectList(coValue.getCurrentContent());
245
+
246
+ list.append(2, undefined, "trusting");
247
+ list.prepend(1, undefined, "trusting");
248
+ list.append(3, undefined, "trusting");
249
+
250
+ expect(list.toJSON()).toEqual([1, 2, 3]);
251
+ });
252
+
253
+ test("Items appended to start", () => {
254
+ const node = new LocalNode(...randomAnonymousAccountAndSessionID(), Crypto);
255
+
256
+ const coValue = node.createCoValue({
257
+ type: "colist",
258
+ ruleset: { type: "unsafeAllowAll" },
259
+ meta: null,
260
+ ...Crypto.createdNowUnique(),
261
+ });
262
+
263
+ const content = expectList(coValue.getCurrentContent());
264
+
265
+ content.append("first", 0, "trusting");
266
+ content.append("second", 0, "trusting");
267
+ content.append("third", 0, "trusting");
268
+
269
+ // This result is correct because "third" is appended after "first"
270
+ // Using the Array methods this would be the same as doing content.splice(1, 0, "third")
271
+ expect(content.toJSON()).toEqual(["first", "third", "second"]);
272
+ });
273
+
274
+ test("syncing appends with an older timestamp", async () => {
275
+ const client = setupTestNode({
276
+ connected: true,
277
+ });
278
+ const otherClient = setupTestNode({});
279
+
280
+ const otherClientConnection = otherClient.connectToSyncServer();
281
+
282
+ const coValue = client.node.createCoValue({
283
+ type: "colist",
284
+ ruleset: { type: "unsafeAllowAll" },
285
+ meta: null,
286
+ ...Crypto.createdNowUnique(),
287
+ });
288
+
289
+ const list = expectList(coValue.getCurrentContent());
290
+
291
+ list.append(1, undefined, "trusting");
292
+ list.append(2, undefined, "trusting");
293
+
294
+ const listOnOtherClient = await loadCoValueOrFail(otherClient.node, list.id);
295
+
296
+ otherClientConnection.peerState.gracefulShutdown();
297
+
298
+ listOnOtherClient.append(3, undefined, "trusting");
299
+
300
+ await new Promise((resolve) => setTimeout(resolve, 50));
301
+
302
+ list.append(4, undefined, "trusting");
303
+
304
+ await new Promise((resolve) => setTimeout(resolve, 50));
305
+
306
+ listOnOtherClient.append(5, undefined, "trusting");
307
+
308
+ await new Promise((resolve) => setTimeout(resolve, 50));
309
+
310
+ list.append(6, undefined, "trusting");
311
+
312
+ otherClient.connectToSyncServer();
313
+
314
+ await waitFor(() => {
315
+ expect(list.toJSON()).toEqual([1, 2, 4, 6, 3, 5]);
316
+ });
317
+
318
+ expect(listOnOtherClient.toJSON()).toEqual(list.toJSON());
319
+ });
320
+
321
+ test("syncing prepends with an older timestamp", async () => {
322
+ const client = setupTestNode({
323
+ connected: true,
324
+ });
325
+ const otherClient = setupTestNode({});
326
+
327
+ const otherClientConnection = otherClient.connectToSyncServer();
328
+
329
+ const coValue = client.node.createCoValue({
330
+ type: "colist",
331
+ ruleset: { type: "unsafeAllowAll" },
332
+ meta: null,
333
+ ...Crypto.createdNowUnique(),
334
+ });
335
+
336
+ const list = expectList(coValue.getCurrentContent());
337
+
338
+ list.prepend(1, undefined, "trusting");
339
+ list.prepend(2, undefined, "trusting");
340
+
341
+ const listOnOtherClient = await loadCoValueOrFail(otherClient.node, list.id);
342
+
343
+ otherClientConnection.peerState.gracefulShutdown();
344
+
345
+ listOnOtherClient.prepend(3, undefined, "trusting");
346
+
347
+ await new Promise((resolve) => setTimeout(resolve, 50));
348
+
349
+ list.prepend(4, undefined, "trusting");
350
+
351
+ await new Promise((resolve) => setTimeout(resolve, 50));
352
+
353
+ listOnOtherClient.prepend(5, undefined, "trusting");
354
+
355
+ await new Promise((resolve) => setTimeout(resolve, 50));
356
+
357
+ list.prepend(6, undefined, "trusting");
358
+
359
+ otherClient.connectToSyncServer();
360
+
361
+ await waitFor(() => {
362
+ expect(list.toJSON()).toEqual([6, 4, 5, 3, 2, 1]);
363
+ });
364
+
365
+ expect(listOnOtherClient.toJSON()).toEqual(list.toJSON());
366
+ });
367
+
368
+ test("totalValidTransactions should return the number of valid transactions processed", async () => {
369
+ const client = setupTestNode({
370
+ connected: true,
371
+ });
372
+ const otherClient = setupTestNode({});
373
+
374
+ const otherClientConnection = otherClient.connectToSyncServer();
375
+
376
+ const group = client.node.createGroup();
377
+ group.addMember("everyone", "reader");
378
+
379
+ const list = group.createList([1, 2]);
380
+
381
+ const listOnOtherClient = await loadCoValueOrFail(otherClient.node, list.id);
382
+
383
+ otherClientConnection.peerState.gracefulShutdown();
384
+
385
+ group.addMember("everyone", "writer");
386
+
387
+ await new Promise((resolve) => setTimeout(resolve, 50));
388
+
389
+ listOnOtherClient.append(3, undefined, "trusting");
390
+
391
+ expect(listOnOtherClient.toJSON()).toEqual([1, 2]);
392
+ expect(listOnOtherClient.totalValidTransactions).toEqual(1);
393
+
394
+ otherClient.connectToSyncServer();
395
+
396
+ await waitFor(() => {
397
+ expect(listOnOtherClient.core.getCurrentContent().toJSON()).toEqual([
398
+ 1, 2, 3,
399
+ ]);
400
+ });
401
+
402
+ expect(
403
+ listOnOtherClient.core.getCurrentContent().totalValidTransactions,
404
+ ).toEqual(2);
405
+ });
@@ -1,13 +1,23 @@
1
- import { expect, test } from "vitest";
1
+ import { beforeEach, expect, test } from "vitest";
2
2
  import { expectMap } from "../coValue.js";
3
3
  import { operationToEditEntry } from "../coValues/coMap.js";
4
4
  import { WasmCrypto } from "../crypto/WasmCrypto.js";
5
5
  import { LocalNode } from "../localNode.js";
6
6
  import { accountOrAgentIDfromSessionID } from "../typeUtils/accountOrAgentIDfromSessionID.js";
7
- import { hotSleep, randomAnonymousAccountAndSessionID } from "./testUtils.js";
7
+ import {
8
+ hotSleep,
9
+ loadCoValueOrFail,
10
+ randomAnonymousAccountAndSessionID,
11
+ setupTestNode,
12
+ waitFor,
13
+ } from "./testUtils.js";
8
14
 
9
15
  const Crypto = await WasmCrypto.create();
10
16
 
17
+ beforeEach(async () => {
18
+ setupTestNode({ isSyncServer: true });
19
+ });
20
+
11
21
  test("Empty CoMap works", () => {
12
22
  const node = new LocalNode(...randomAnonymousAccountAndSessionID(), Crypto);
13
23
 
@@ -207,3 +217,45 @@ test("Can set items in bulk with assign", () => {
207
217
  key3: "assign3",
208
218
  });
209
219
  });
220
+
221
+ test("totalValidTransactions should return the number of valid transactions processed", async () => {
222
+ const client = setupTestNode({
223
+ connected: true,
224
+ });
225
+ const otherClient = setupTestNode({});
226
+
227
+ const otherClientConnection = otherClient.connectToSyncServer();
228
+
229
+ const group = client.node.createGroup();
230
+ group.addMember("everyone", "reader");
231
+
232
+ const map = group.createMap({ fromClient: true });
233
+
234
+ const mapOnOtherClient = await loadCoValueOrFail(otherClient.node, map.id);
235
+
236
+ otherClientConnection.peerState.gracefulShutdown();
237
+
238
+ group.addMember("everyone", "writer");
239
+
240
+ await new Promise((resolve) => setTimeout(resolve, 50));
241
+
242
+ mapOnOtherClient.set("fromOtherClient", true, "trusting");
243
+
244
+ expect(mapOnOtherClient.totalValidTransactions).toEqual(1);
245
+ expect(mapOnOtherClient.toJSON()).toEqual({
246
+ fromClient: true,
247
+ });
248
+
249
+ otherClient.connectToSyncServer();
250
+
251
+ await waitFor(() => {
252
+ expect(mapOnOtherClient.core.getCurrentContent().toJSON()).toEqual({
253
+ fromClient: true,
254
+ fromOtherClient: true,
255
+ });
256
+ });
257
+
258
+ expect(
259
+ mapOnOtherClient.core.getCurrentContent().totalValidTransactions,
260
+ ).toEqual(2);
261
+ });
@@ -1,4 +1,4 @@
1
- import { describe, expect, test } from "vitest";
1
+ import { beforeEach, describe, expect, test } from "vitest";
2
2
  import { expectStream } from "../coValue.js";
3
3
  import { MAX_RECOMMENDED_TX_SIZE } from "../coValueCore.js";
4
4
  import {
@@ -10,10 +10,19 @@ import {
10
10
  import { WasmCrypto } from "../crypto/WasmCrypto.js";
11
11
  import { SessionID } from "../ids.js";
12
12
  import { LocalNode } from "../localNode.js";
13
- import { randomAnonymousAccountAndSessionID } from "./testUtils.js";
13
+ import {
14
+ loadCoValueOrFail,
15
+ randomAnonymousAccountAndSessionID,
16
+ setupTestNode,
17
+ waitFor,
18
+ } from "./testUtils.js";
14
19
 
15
20
  const Crypto = await WasmCrypto.create();
16
21
 
22
+ beforeEach(async () => {
23
+ setupTestNode({ isSyncServer: true });
24
+ });
25
+
17
26
  test("Empty CoStream works", () => {
18
27
  const node = new LocalNode(...randomAnonymousAccountAndSessionID(), Crypto);
19
28
 
@@ -252,6 +261,51 @@ test("When adding large transactions (bigger than MAX_RECOMMENDED_TX_SIZE), we s
252
261
  );
253
262
  });
254
263
 
264
+ test("totalValidTransactions should return the number of valid transactions processed", async () => {
265
+ const client = setupTestNode({
266
+ connected: true,
267
+ });
268
+ const otherClient = setupTestNode({});
269
+
270
+ const otherClientConnection = otherClient.connectToSyncServer();
271
+
272
+ const group = client.node.createGroup();
273
+ group.addMember("everyone", "reader");
274
+
275
+ const stream = group.createStream();
276
+ stream.push(1, "trusting");
277
+
278
+ const streamOnOtherClient = await loadCoValueOrFail(
279
+ otherClient.node,
280
+ stream.id,
281
+ );
282
+
283
+ otherClientConnection.peerState.gracefulShutdown();
284
+
285
+ group.addMember("everyone", "writer");
286
+
287
+ await new Promise((resolve) => setTimeout(resolve, 50));
288
+
289
+ streamOnOtherClient.push(2, "trusting");
290
+
291
+ expect(streamOnOtherClient.totalValidTransactions).toEqual(1);
292
+ expect(Object.keys(streamOnOtherClient.toJSON()).length).toEqual(1);
293
+
294
+ otherClient.connectToSyncServer();
295
+
296
+ await waitFor(() => {
297
+ expect(
298
+ Object.keys(
299
+ streamOnOtherClient.core.getCurrentContent().toJSON() as object,
300
+ ).length,
301
+ ).toEqual(2);
302
+ });
303
+
304
+ expect(
305
+ streamOnOtherClient.core.getCurrentContent().totalValidTransactions,
306
+ ).toEqual(2);
307
+ });
308
+
255
309
  describe("isBinaryStreamEnded", () => {
256
310
  function setup() {
257
311
  const node = new LocalNode(...randomAnonymousAccountAndSessionID(), Crypto);
@@ -10,26 +10,15 @@ import {
10
10
  } from "vitest";
11
11
  import { PeerState } from "../PeerState";
12
12
  import { CoValueCore } from "../coValueCore";
13
- import { CO_VALUE_LOADING_CONFIG, CoValueState } from "../coValueState";
13
+ import { CoValueState } from "../coValueState";
14
14
  import { RawCoID } from "../ids";
15
15
  import { Peer } from "../sync";
16
16
  import { createTestMetricReader, tearDownTestMetricReader } from "./testUtils";
17
17
 
18
- const initialMaxRetries = CO_VALUE_LOADING_CONFIG.MAX_RETRIES;
19
-
20
- function mockMaxRetries(maxRetries: number) {
21
- CO_VALUE_LOADING_CONFIG.MAX_RETRIES = maxRetries;
22
-
23
- onTestFinished(() => {
24
- CO_VALUE_LOADING_CONFIG.MAX_RETRIES = initialMaxRetries;
25
- });
26
- }
27
-
28
18
  let metricReader: ReturnType<typeof createTestMetricReader>;
29
19
 
30
20
  beforeEach(() => {
31
21
  metricReader = createTestMetricReader();
32
- mockMaxRetries(5);
33
22
  });
34
23
 
35
24
  afterEach(() => {
@@ -122,51 +111,6 @@ describe("CoValueState", () => {
122
111
  ).toBe(0);
123
112
  });
124
113
 
125
- test("should retry loading from peers when unsuccessful", async () => {
126
- vi.useFakeTimers();
127
-
128
- const peer1 = createMockPeerState(
129
- {
130
- id: "peer1",
131
- role: "server",
132
- },
133
- async () => {
134
- state.markNotFoundInPeer("peer1");
135
- },
136
- );
137
- const peer2 = createMockPeerState(
138
- {
139
- id: "peer2",
140
- role: "server",
141
- },
142
- async () => {
143
- state.markNotFoundInPeer("peer2");
144
- },
145
- );
146
- const mockPeers = [peer1, peer2] as unknown as PeerState[];
147
-
148
- const state = new CoValueState(mockCoValueId);
149
- const loadPromise = state.loadFromPeers(mockPeers);
150
-
151
- // Should attempt CO_VALUE_LOADING_CONFIG.MAX_RETRIES retries
152
- for (let i = 0; i < CO_VALUE_LOADING_CONFIG.MAX_RETRIES; i++) {
153
- await vi.runAllTimersAsync();
154
- }
155
-
156
- await loadPromise;
157
-
158
- expect(peer1.pushOutgoingMessage).toHaveBeenCalledTimes(
159
- CO_VALUE_LOADING_CONFIG.MAX_RETRIES,
160
- );
161
- expect(peer2.pushOutgoingMessage).toHaveBeenCalledTimes(
162
- CO_VALUE_LOADING_CONFIG.MAX_RETRIES,
163
- );
164
- expect(state.highLevelState).toBe("unavailable");
165
- await expect(state.getCoValue()).resolves.toBe("unavailable");
166
-
167
- vi.useRealTimers();
168
- });
169
-
170
114
  test("should skip errored coValues when loading from peers", async () => {
171
115
  vi.useFakeTimers();
172
116
 
@@ -194,108 +138,18 @@ describe("CoValueState", () => {
194
138
  const state = new CoValueState(mockCoValueId);
195
139
  const loadPromise = state.loadFromPeers(mockPeers);
196
140
 
197
- // Should attempt CO_VALUE_LOADING_CONFIG.MAX_RETRIES retries
198
- for (let i = 0; i < CO_VALUE_LOADING_CONFIG.MAX_RETRIES; i++) {
199
- await vi.runAllTimersAsync();
200
- }
141
+ await vi.runAllTimersAsync();
201
142
 
202
143
  await loadPromise;
203
144
 
204
145
  expect(peer1.pushOutgoingMessage).toHaveBeenCalledTimes(1);
205
- expect(peer2.pushOutgoingMessage).toHaveBeenCalledTimes(
206
- CO_VALUE_LOADING_CONFIG.MAX_RETRIES,
207
- );
146
+ expect(peer2.pushOutgoingMessage).toHaveBeenCalledTimes(1);
208
147
  expect(state.highLevelState).toBe("unavailable");
209
148
  await expect(state.getCoValue()).resolves.toBe("unavailable");
210
149
 
211
150
  vi.useRealTimers();
212
151
  });
213
152
 
214
- test("should retry only on server peers", async () => {
215
- vi.useFakeTimers();
216
-
217
- const peer1 = createMockPeerState(
218
- {
219
- id: "peer1",
220
- role: "storage",
221
- },
222
- async () => {
223
- state.markNotFoundInPeer("peer1");
224
- },
225
- );
226
- const peer2 = createMockPeerState(
227
- {
228
- id: "peer2",
229
- role: "server",
230
- },
231
- async () => {
232
- state.markNotFoundInPeer("peer2");
233
- },
234
- );
235
- const mockPeers = [peer1, peer2] as unknown as PeerState[];
236
-
237
- const state = new CoValueState(mockCoValueId);
238
- const loadPromise = state.loadFromPeers(mockPeers);
239
-
240
- // Should attempt CO_VALUE_LOADING_CONFIG.MAX_RETRIES retries
241
- for (let i = 0; i < CO_VALUE_LOADING_CONFIG.MAX_RETRIES; i++) {
242
- await vi.runAllTimersAsync();
243
- }
244
-
245
- await loadPromise;
246
-
247
- expect(peer1.pushOutgoingMessage).toHaveBeenCalledTimes(1);
248
- expect(peer2.pushOutgoingMessage).toHaveBeenCalledTimes(
249
- CO_VALUE_LOADING_CONFIG.MAX_RETRIES,
250
- );
251
- expect(state.highLevelState).toBe("unavailable");
252
- await expect(state.getCoValue()).resolves.toEqual("unavailable");
253
-
254
- vi.useRealTimers();
255
- });
256
-
257
- test("should handle the coValues that become available in between of the retries", async () => {
258
- vi.useFakeTimers();
259
-
260
- mockMaxRetries(5);
261
-
262
- let retries = 0;
263
-
264
- const peer1 = createMockPeerState(
265
- {
266
- id: "peer1",
267
- role: "server",
268
- },
269
- async () => {
270
- retries++;
271
- state.markNotFoundInPeer("peer1");
272
-
273
- if (retries === 2) {
274
- setTimeout(() => {
275
- state.markAvailable(createMockCoValueCore(mockCoValueId), "peer1");
276
- }, 100);
277
- }
278
- },
279
- );
280
-
281
- const mockPeers = [peer1] as unknown as PeerState[];
282
-
283
- const state = new CoValueState(mockCoValueId);
284
- const loadPromise = state.loadFromPeers(mockPeers);
285
-
286
- // Should attempt CO_VALUE_LOADING_CONFIG.MAX_RETRIES retries
287
- for (let i = 0; i < CO_VALUE_LOADING_CONFIG.MAX_RETRIES + 1; i++) {
288
- await vi.runAllTimersAsync();
289
- }
290
-
291
- await loadPromise;
292
-
293
- expect(peer1.pushOutgoingMessage).toHaveBeenCalledTimes(2);
294
- expect(state.highLevelState).toBe("available");
295
- await expect(state.getCoValue()).resolves.toEqual({ id: mockCoValueId });
296
- vi.useRealTimers();
297
- });
298
-
299
153
  test("should have a coValue as value property when becomes available after that have been marked as unavailable", async () => {
300
154
  vi.useFakeTimers();
301
155
 
@@ -314,57 +168,13 @@ describe("CoValueState", () => {
314
168
  const state = new CoValueState(mockCoValueId);
315
169
  const loadPromise = state.loadFromPeers(mockPeers);
316
170
 
317
- // Should attempt CO_VALUE_LOADING_CONFIG.MAX_RETRIES retries
318
- for (let i = 0; i < CO_VALUE_LOADING_CONFIG.MAX_RETRIES; i++) {
319
- await vi.runAllTimersAsync();
320
- }
171
+ await vi.runAllTimersAsync();
321
172
 
322
173
  state.internalMarkMagicallyAvailable(createMockCoValueCore(mockCoValueId));
323
174
 
324
175
  await loadPromise;
325
176
 
326
- expect(peer1.pushOutgoingMessage).toHaveBeenCalledTimes(
327
- CO_VALUE_LOADING_CONFIG.MAX_RETRIES,
328
- );
329
- expect(state.highLevelState).toBe("available");
330
- await expect(state.getCoValue()).resolves.toEqual({ id: mockCoValueId });
331
-
332
- vi.useRealTimers();
333
- });
334
-
335
- test("should stop retrying when value becomes available", async () => {
336
- vi.useFakeTimers();
337
-
338
- mockMaxRetries(5);
339
-
340
- let run = 1;
341
-
342
- const peer1 = createMockPeerState(
343
- {
344
- id: "peer1",
345
- role: "server",
346
- },
347
- async () => {
348
- if (run > 2) {
349
- state.markAvailable(createMockCoValueCore(mockCoValueId), "peer1");
350
- } else {
351
- state.markNotFoundInPeer("peer1");
352
- run++;
353
- }
354
- },
355
- );
356
-
357
- const mockPeers = [peer1] as unknown as PeerState[];
358
-
359
- const state = new CoValueState(mockCoValueId);
360
- const loadPromise = state.loadFromPeers(mockPeers);
361
-
362
- for (let i = 0; i < CO_VALUE_LOADING_CONFIG.MAX_RETRIES; i++) {
363
- await vi.runAllTimersAsync();
364
- }
365
- await loadPromise;
366
-
367
- expect(peer1.pushOutgoingMessage).toHaveBeenCalledTimes(3);
177
+ expect(peer1.pushOutgoingMessage).toHaveBeenCalledTimes(1);
368
178
  expect(state.highLevelState).toBe("available");
369
179
  await expect(state.getCoValue()).resolves.toEqual({ id: mockCoValueId });
370
180
 
@@ -398,9 +208,7 @@ describe("CoValueState", () => {
398
208
  const state = new CoValueState(mockCoValueId);
399
209
  const loadPromise = state.loadFromPeers([peer1, peer2]);
400
210
 
401
- for (let i = 0; i < CO_VALUE_LOADING_CONFIG.MAX_RETRIES; i++) {
402
- await vi.runAllTimersAsync();
403
- }
211
+ await vi.runAllTimersAsync();
404
212
  await loadPromise;
405
213
 
406
214
  expect(peer1.pushOutgoingMessage).toHaveBeenCalledTimes(1);
@@ -444,9 +252,7 @@ describe("CoValueState", () => {
444
252
  const state = new CoValueState(mockCoValueId);
445
253
  const loadPromise = state.loadFromPeers([peer1, peer2]);
446
254
 
447
- for (let i = 0; i < CO_VALUE_LOADING_CONFIG.MAX_RETRIES; i++) {
448
- await vi.runAllTimersAsync();
449
- }
255
+ await vi.runAllTimersAsync();
450
256
  await loadPromise;
451
257
 
452
258
  expect(peer1.pushOutgoingMessage).toHaveBeenCalledTimes(0);
@@ -472,14 +278,10 @@ describe("CoValueState", () => {
472
278
  const state = new CoValueState(mockCoValueId);
473
279
  const loadPromise = state.loadFromPeers([peer1]);
474
280
 
475
- for (let i = 0; i < CO_VALUE_LOADING_CONFIG.MAX_RETRIES * 2; i++) {
476
- await vi.runAllTimersAsync();
477
- }
281
+ await vi.runAllTimersAsync();
478
282
  await loadPromise;
479
283
 
480
- expect(peer1.pushOutgoingMessage).toHaveBeenCalledTimes(
481
- CO_VALUE_LOADING_CONFIG.MAX_RETRIES,
482
- );
284
+ expect(peer1.pushOutgoingMessage).toHaveBeenCalledTimes(1);
483
285
 
484
286
  expect(state.highLevelState).toBe("unavailable");
485
287
  await expect(state.getCoValue()).resolves.toEqual("unavailable");