cojson 0.19.14 → 0.19.16

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 (45) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +18 -0
  3. package/dist/PeerState.d.ts +1 -1
  4. package/dist/PeerState.d.ts.map +1 -1
  5. package/dist/PeerState.js.map +1 -1
  6. package/dist/coValueCore/coValueCore.d.ts +8 -1
  7. package/dist/coValueCore/coValueCore.d.ts.map +1 -1
  8. package/dist/coValueCore/coValueCore.js +13 -0
  9. package/dist/coValueCore/coValueCore.js.map +1 -1
  10. package/dist/coValues/group.d.ts.map +1 -1
  11. package/dist/coValues/group.js +16 -4
  12. package/dist/coValues/group.js.map +1 -1
  13. package/dist/localNode.d.ts +0 -1
  14. package/dist/localNode.d.ts.map +1 -1
  15. package/dist/localNode.js +4 -4
  16. package/dist/localNode.js.map +1 -1
  17. package/dist/queue/LocalTransactionsSyncQueue.d.ts +0 -1
  18. package/dist/queue/LocalTransactionsSyncQueue.d.ts.map +1 -1
  19. package/dist/queue/LocalTransactionsSyncQueue.js +0 -2
  20. package/dist/queue/LocalTransactionsSyncQueue.js.map +1 -1
  21. package/dist/storage/sqlite/client.d.ts.map +1 -1
  22. package/dist/storage/sqlite/client.js.map +1 -1
  23. package/dist/storage/sqliteAsync/client.d.ts.map +1 -1
  24. package/dist/storage/sqliteAsync/client.js.map +1 -1
  25. package/dist/storage/storageAsync.d.ts +1 -1
  26. package/dist/storage/storageAsync.js +8 -8
  27. package/dist/storage/storageSync.d.ts +1 -1
  28. package/dist/storage/storageSync.js +8 -8
  29. package/dist/sync.d.ts.map +1 -1
  30. package/dist/sync.js +13 -2
  31. package/dist/sync.js.map +1 -1
  32. package/dist/tests/SyncStateManager.test.js +24 -1
  33. package/dist/tests/SyncStateManager.test.js.map +1 -1
  34. package/package.json +4 -4
  35. package/src/PeerState.ts +1 -1
  36. package/src/coValueCore/coValueCore.ts +15 -1
  37. package/src/coValues/group.ts +16 -4
  38. package/src/localNode.ts +4 -5
  39. package/src/queue/LocalTransactionsSyncQueue.ts +0 -2
  40. package/src/storage/sqlite/client.ts +0 -1
  41. package/src/storage/sqliteAsync/client.ts +0 -1
  42. package/src/storage/storageAsync.ts +8 -8
  43. package/src/storage/storageSync.ts +8 -8
  44. package/src/sync.ts +15 -2
  45. package/src/tests/SyncStateManager.test.ts +41 -0
@@ -315,6 +315,14 @@ export class CoValueCore {
315
315
  return this.getLoadingStateForPeer(peerId) === "errored";
316
316
  }
317
317
 
318
+ getErroredInPeerError(peerId: PeerID) {
319
+ const loadingState = this.loadingStatuses.get(peerId);
320
+ if (loadingState?.type === "errored") {
321
+ return loadingState.error;
322
+ }
323
+ return undefined;
324
+ }
325
+
318
326
  waitFor(opts: {
319
327
  predicate: (value: CoValueCore) => boolean;
320
328
  onSuccess: (value: CoValueCore) => void;
@@ -575,6 +583,9 @@ export class CoValueCore {
575
583
  }
576
584
  }
577
585
 
586
+ /**
587
+ * Apply new transactions that were not generated by the current node to the CoValue
588
+ */
578
589
  tryAddTransactions(
579
590
  sessionID: SessionID,
580
591
  newTransactions: Transaction[],
@@ -722,6 +733,9 @@ export class CoValueCore {
722
733
  };
723
734
  }
724
735
 
736
+ /**
737
+ * Creates a new transaction with local changes and syncs it to all peers
738
+ */
725
739
  makeTransaction(
726
740
  changes: JsonValue[],
727
741
  privacy: "private" | "trusting",
@@ -1507,7 +1521,7 @@ export class CoValueCore {
1507
1521
  }
1508
1522
  }
1509
1523
 
1510
- internalLoadFromPeer(peer: PeerState) {
1524
+ private internalLoadFromPeer(peer: PeerState) {
1511
1525
  if (peer.closed && !peer.persistent) {
1512
1526
  this.markNotFoundInPeer(peer.id);
1513
1527
  return;
@@ -1249,7 +1249,10 @@ export class RawGroup<
1249
1249
  group: this.id,
1250
1250
  },
1251
1251
  meta: meta || null,
1252
- ...uniqueness,
1252
+ ...(uniqueness.createdAt !== undefined
1253
+ ? { createdAt: uniqueness.createdAt }
1254
+ : {}),
1255
+ uniqueness: uniqueness.uniqueness,
1253
1256
  })
1254
1257
  .getCurrentContent() as M;
1255
1258
 
@@ -1283,7 +1286,10 @@ export class RawGroup<
1283
1286
  group: this.id,
1284
1287
  },
1285
1288
  meta: meta || null,
1286
- ...uniqueness,
1289
+ ...(uniqueness.createdAt !== undefined
1290
+ ? { createdAt: uniqueness.createdAt }
1291
+ : {}),
1292
+ uniqueness: uniqueness.uniqueness,
1287
1293
  })
1288
1294
  .getCurrentContent() as L;
1289
1295
 
@@ -1340,7 +1346,10 @@ export class RawGroup<
1340
1346
  group: this.id,
1341
1347
  },
1342
1348
  meta: meta || null,
1343
- ...uniqueness,
1349
+ ...(uniqueness.createdAt !== undefined
1350
+ ? { createdAt: uniqueness.createdAt }
1351
+ : {}),
1352
+ uniqueness: uniqueness.uniqueness,
1344
1353
  })
1345
1354
  .getCurrentContent() as C;
1346
1355
 
@@ -1365,7 +1374,10 @@ export class RawGroup<
1365
1374
  group: this.id,
1366
1375
  },
1367
1376
  meta: meta,
1368
- ...uniqueness,
1377
+ ...(uniqueness.createdAt !== undefined
1378
+ ? { createdAt: uniqueness.createdAt }
1379
+ : {}),
1380
+ uniqueness: uniqueness.uniqueness,
1369
1381
  })
1370
1382
  .getCurrentContent() as C;
1371
1383
  }
package/src/localNode.ts CHANGED
@@ -395,10 +395,6 @@ export class LocalNode {
395
395
  return coValue;
396
396
  }
397
397
 
398
- hasLoadingSources(id: RawCoID) {
399
- return this.storage || this.syncManager.getServerPeers(id).length > 0;
400
- }
401
-
402
398
  /** @internal */
403
399
  async loadCoValueCore(
404
400
  id: RawCoID,
@@ -742,7 +738,10 @@ export class LocalNode {
742
738
  type: "comap",
743
739
  ruleset: { type: "group", initialAdmin: account.id },
744
740
  meta: null,
745
- ...uniqueness,
741
+ ...(uniqueness.createdAt !== undefined
742
+ ? { createdAt: uniqueness.createdAt }
743
+ : {}),
744
+ uniqueness: uniqueness.uniqueness,
746
745
  });
747
746
 
748
747
  const group = expectGroup(groupCoValue.getCurrentContent());
@@ -15,7 +15,6 @@ import { NewContentMessage } from "../sync.js";
15
15
  */
16
16
  export class LocalTransactionsSyncQueue {
17
17
  private batch: NewContentMessage[] = [];
18
- private firstChunks = new Map<RawCoID, NewContentMessage>();
19
18
  private lastUpdatedValue: VerifiedState | undefined;
20
19
  private lastUpdatedValueKnownState: CoValueKnownState | undefined;
21
20
 
@@ -78,7 +77,6 @@ export class LocalTransactionsSyncQueue {
78
77
 
79
78
  this.lastUpdatedValue = undefined;
80
79
  this.lastUpdatedValueKnownState = undefined;
81
- this.firstChunks = new Map();
82
80
  this.batch = [];
83
81
  this.nextBatchScheduled = false;
84
82
 
@@ -5,7 +5,6 @@ import type {
5
5
  import type { Signature } from "../../crypto/crypto.js";
6
6
  import type { RawCoID, SessionID } from "../../exports.js";
7
7
  import { logger } from "../../logger.js";
8
- import type { NewContentMessage } from "../../sync.js";
9
8
  import type {
10
9
  DBClientInterfaceSync,
11
10
  DBTransactionInterfaceSync,
@@ -5,7 +5,6 @@ import type {
5
5
  import type { Signature } from "../../crypto/crypto.js";
6
6
  import type { RawCoID, SessionID } from "../../exports.js";
7
7
  import { logger } from "../../logger.js";
8
- import type { NewContentMessage } from "../../sync.js";
9
8
  import type {
10
9
  DBClientInterfaceAsync,
11
10
  DBTransactionInterfaceAsync,
@@ -40,10 +40,10 @@ export class StorageApiAsync implements StorageAPI {
40
40
  this.dbClient = dbClient;
41
41
  }
42
42
 
43
- knwonStates = new StorageKnownState();
43
+ knownStates = new StorageKnownState();
44
44
 
45
45
  getKnownState(id: string): CoValueKnownState {
46
- return this.knwonStates.getKnownState(id);
46
+ return this.knownStates.getKnownState(id);
47
47
  }
48
48
 
49
49
  async load(
@@ -91,7 +91,7 @@ export class StorageApiAsync implements StorageAPI {
91
91
  }),
92
92
  );
93
93
 
94
- const knownState = this.knwonStates.getKnownState(coValueRow.id);
94
+ const knownState = this.knownStates.getKnownState(coValueRow.id);
95
95
  knownState.header = true;
96
96
 
97
97
  for (const sessionRow of allCoValueSessions) {
@@ -169,7 +169,7 @@ export class StorageApiAsync implements StorageAPI {
169
169
  );
170
170
  }
171
171
 
172
- this.knwonStates.handleUpdate(coValueRow.id, knownState);
172
+ this.knownStates.handleUpdate(coValueRow.id, knownState);
173
173
  done?.(true);
174
174
  }
175
175
 
@@ -270,12 +270,12 @@ export class StorageApiAsync implements StorageAPI {
270
270
 
271
271
  if (!storedCoValueRowID) {
272
272
  const knownState = emptyKnownState(id as RawCoID);
273
- this.knwonStates.setKnownState(id, knownState);
273
+ this.knownStates.setKnownState(id, knownState);
274
274
 
275
275
  return this.handleCorrection(knownState, correctionCallback);
276
276
  }
277
277
 
278
- const knownState = this.knwonStates.getKnownState(id);
278
+ const knownState = this.knownStates.getKnownState(id);
279
279
  knownState.header = true;
280
280
 
281
281
  let invalidAssumptions = false;
@@ -313,7 +313,7 @@ export class StorageApiAsync implements StorageAPI {
313
313
  });
314
314
  }
315
315
 
316
- this.knwonStates.handleUpdate(id, knownState);
316
+ this.knownStates.handleUpdate(id, knownState);
317
317
 
318
318
  if (invalidAssumptions) {
319
319
  return this.handleCorrection(knownState, correctionCallback);
@@ -389,7 +389,7 @@ export class StorageApiAsync implements StorageAPI {
389
389
  }
390
390
 
391
391
  waitForSync(id: string, coValue: CoValueCore) {
392
- return this.knwonStates.waitForSync(id, coValue);
392
+ return this.knownStates.waitForSync(id, coValue);
393
393
  }
394
394
 
395
395
  close() {
@@ -48,10 +48,10 @@ export class StorageApiSync implements StorageAPI {
48
48
  this.streamingCounter.add(0);
49
49
  }
50
50
 
51
- knwonStates = new StorageKnownState();
51
+ knownStates = new StorageKnownState();
52
52
 
53
53
  getKnownState(id: string): CoValueKnownState {
54
- return this.knwonStates.getKnownState(id);
54
+ return this.knownStates.getKnownState(id);
55
55
  }
56
56
 
57
57
  async load(
@@ -93,7 +93,7 @@ export class StorageApiSync implements StorageAPI {
93
93
  }
94
94
  }
95
95
 
96
- const knownState = this.knwonStates.getKnownState(coValueRow.id);
96
+ const knownState = this.knownStates.getKnownState(coValueRow.id);
97
97
  knownState.header = true;
98
98
 
99
99
  for (const sessionRow of allCoValueSessions) {
@@ -174,7 +174,7 @@ export class StorageApiSync implements StorageAPI {
174
174
  this.streamingCounter.add(-1);
175
175
  }
176
176
 
177
- this.knwonStates.handleUpdate(coValueRow.id, knownState);
177
+ this.knownStates.handleUpdate(coValueRow.id, knownState);
178
178
  done?.(true);
179
179
  }
180
180
 
@@ -247,12 +247,12 @@ export class StorageApiSync implements StorageAPI {
247
247
 
248
248
  if (!storedCoValueRowID) {
249
249
  const knownState = emptyKnownState(id as RawCoID);
250
- this.knwonStates.setKnownState(id, knownState);
250
+ this.knownStates.setKnownState(id, knownState);
251
251
 
252
252
  return this.handleCorrection(knownState, correctionCallback);
253
253
  }
254
254
 
255
- const knownState = this.knwonStates.getKnownState(id);
255
+ const knownState = this.knownStates.getKnownState(id);
256
256
  knownState.header = true;
257
257
 
258
258
  let invalidAssumptions = false;
@@ -287,7 +287,7 @@ export class StorageApiSync implements StorageAPI {
287
287
  });
288
288
  }
289
289
 
290
- this.knwonStates.handleUpdate(id, knownState);
290
+ this.knownStates.handleUpdate(id, knownState);
291
291
 
292
292
  if (invalidAssumptions) {
293
293
  return this.handleCorrection(knownState, correctionCallback);
@@ -362,7 +362,7 @@ export class StorageApiSync implements StorageAPI {
362
362
  }
363
363
 
364
364
  waitForSync(id: string, coValue: CoValueCore) {
365
- return this.knwonStates.waitForSync(id, coValue);
365
+ return this.knownStates.waitForSync(id, coValue);
366
366
  }
367
367
 
368
368
  close() {
package/src/sync.ts CHANGED
@@ -358,7 +358,7 @@ export class SyncManager {
358
358
  });
359
359
 
360
360
  if (!skipReconciliation && peerState.role === "server") {
361
- void this.startPeerReconciliation(peerState);
361
+ this.startPeerReconciliation(peerState);
362
362
  }
363
363
 
364
364
  peerState.incoming.onMessage((msg) => {
@@ -870,7 +870,20 @@ export class SyncManager {
870
870
  );
871
871
 
872
872
  const timeoutId = setTimeout(() => {
873
- reject(new Error(`Timeout waiting for sync on ${peerId}/${id}`));
873
+ const coValue = this.local.getCoValue(id);
874
+ const erroredInPeer = coValue.getErroredInPeerError(peerId);
875
+ const knownState = coValue.knownState().sessions;
876
+ const peerKnownState = peerState.getKnownState(id)?.sessions ?? {};
877
+ let errorMessage = `Timeout on waiting for sync with peer ${peerId} for coValue ${id}:
878
+ Known state: ${JSON.stringify(knownState)}
879
+ Peer state: ${JSON.stringify(peerKnownState)}
880
+ `;
881
+
882
+ if (erroredInPeer) {
883
+ errorMessage += `\nMarked as errored: "${erroredInPeer}"`;
884
+ }
885
+
886
+ reject(new Error(errorMessage));
874
887
  unsubscribe?.();
875
888
  }, timeout);
876
889
  });
@@ -7,6 +7,7 @@ import { connectedPeers } from "../streamUtils.js";
7
7
  import { emptyKnownState } from "../exports.js";
8
8
  import {
9
9
  SyncMessagesLog,
10
+ blockMessageTypeOnOutgoingPeer,
10
11
  loadCoValueOrFail,
11
12
  setupTestNode,
12
13
  waitFor,
@@ -309,4 +310,44 @@ describe("SyncStateManager", () => {
309
310
  ]
310
311
  `);
311
312
  });
313
+
314
+ test("should throw if the timeout is reached", async () => {
315
+ const client = setupTestNode();
316
+
317
+ const { peer } = client.connectToSyncServer();
318
+
319
+ const group = client.node.createGroup();
320
+ const map = group.createMap();
321
+ map.set("key1", "value1", "trusting");
322
+
323
+ blockMessageTypeOnOutgoingPeer(peer, "content", {
324
+ id: map.core.id,
325
+ });
326
+
327
+ await expect(map.core.waitForSync({ timeout: 1 })).rejects.toThrow(
328
+ new RegExp(
329
+ `Timeout on waiting for sync with peer ${peer.id} for coValue ${map.core.id}:`,
330
+ ),
331
+ );
332
+ });
333
+
334
+ test("should throw if the timeout is reached, reporting the errorInPeer if any", async () => {
335
+ const client = setupTestNode();
336
+
337
+ const { peer } = client.connectToSyncServer();
338
+
339
+ const group = client.node.createGroup();
340
+ const map = group.createMap();
341
+ map.set("key1", "value1", "trusting");
342
+
343
+ map.core.markErrored(peer.id, new Error("test error"));
344
+
345
+ blockMessageTypeOnOutgoingPeer(peer, "content", {
346
+ id: map.core.id,
347
+ });
348
+
349
+ await expect(map.core.waitForSync({ timeout: 1 })).rejects.toThrow(
350
+ new RegExp(`Marked as errored: "Error: test error"`),
351
+ );
352
+ });
312
353
  });