cojson 0.20.9 → 0.20.10

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 (169) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +20 -0
  3. package/dist/PeerState.d.ts +2 -2
  4. package/dist/PeerState.d.ts.map +1 -1
  5. package/dist/PeerState.js +3 -3
  6. package/dist/PeerState.js.map +1 -1
  7. package/dist/StorageReconciliationAckTracker.d.ts +14 -0
  8. package/dist/StorageReconciliationAckTracker.d.ts.map +1 -0
  9. package/dist/StorageReconciliationAckTracker.js +72 -0
  10. package/dist/StorageReconciliationAckTracker.js.map +1 -0
  11. package/dist/SyncStateManager.js +2 -2
  12. package/dist/SyncStateManager.js.map +1 -1
  13. package/dist/coValueCore/coValueCore.d.ts +2 -1
  14. package/dist/coValueCore/coValueCore.d.ts.map +1 -1
  15. package/dist/coValueCore/coValueCore.js +43 -10
  16. package/dist/coValueCore/coValueCore.js.map +1 -1
  17. package/dist/coValues/coList.d.ts +2 -0
  18. package/dist/coValues/coList.d.ts.map +1 -1
  19. package/dist/coValues/coList.js +28 -0
  20. package/dist/coValues/coList.js.map +1 -1
  21. package/dist/coValues/group.d.ts +4 -1
  22. package/dist/coValues/group.d.ts.map +1 -1
  23. package/dist/coValues/group.js +15 -1
  24. package/dist/coValues/group.js.map +1 -1
  25. package/dist/config.d.ts +8 -0
  26. package/dist/config.d.ts.map +1 -1
  27. package/dist/config.js +14 -0
  28. package/dist/config.js.map +1 -1
  29. package/dist/exports.d.ts +9 -1
  30. package/dist/exports.d.ts.map +1 -1
  31. package/dist/exports.js +5 -1
  32. package/dist/exports.js.map +1 -1
  33. package/dist/localNode.d.ts +7 -3
  34. package/dist/localNode.d.ts.map +1 -1
  35. package/dist/localNode.js +13 -5
  36. package/dist/localNode.js.map +1 -1
  37. package/dist/permissions.d.ts +1 -0
  38. package/dist/permissions.d.ts.map +1 -1
  39. package/dist/queue/LinkedList.d.ts +2 -0
  40. package/dist/queue/LinkedList.d.ts.map +1 -1
  41. package/dist/queue/LinkedList.js +7 -0
  42. package/dist/queue/LinkedList.js.map +1 -1
  43. package/dist/queue/OutgoingLoadQueue.d.ts +4 -1
  44. package/dist/queue/OutgoingLoadQueue.d.ts.map +1 -1
  45. package/dist/queue/OutgoingLoadQueue.js +41 -13
  46. package/dist/queue/OutgoingLoadQueue.js.map +1 -1
  47. package/dist/queue/PriorityBasedMessageQueue.d.ts +1 -0
  48. package/dist/queue/PriorityBasedMessageQueue.d.ts.map +1 -1
  49. package/dist/queue/PriorityBasedMessageQueue.js +11 -1
  50. package/dist/queue/PriorityBasedMessageQueue.js.map +1 -1
  51. package/dist/storage/knownState.d.ts +2 -0
  52. package/dist/storage/knownState.d.ts.map +1 -1
  53. package/dist/storage/knownState.js +11 -0
  54. package/dist/storage/knownState.js.map +1 -1
  55. package/dist/storage/sqlite/client.d.ts +10 -1
  56. package/dist/storage/sqlite/client.d.ts.map +1 -1
  57. package/dist/storage/sqlite/client.js +84 -0
  58. package/dist/storage/sqlite/client.js.map +1 -1
  59. package/dist/storage/sqlite/sqliteMigrations.d.ts.map +1 -1
  60. package/dist/storage/sqlite/sqliteMigrations.js +11 -0
  61. package/dist/storage/sqlite/sqliteMigrations.js.map +1 -1
  62. package/dist/storage/sqliteAsync/client.d.ts +10 -1
  63. package/dist/storage/sqliteAsync/client.d.ts.map +1 -1
  64. package/dist/storage/sqliteAsync/client.js +86 -0
  65. package/dist/storage/sqliteAsync/client.js.map +1 -1
  66. package/dist/storage/storageAsync.d.ts +9 -2
  67. package/dist/storage/storageAsync.d.ts.map +1 -1
  68. package/dist/storage/storageAsync.js +19 -0
  69. package/dist/storage/storageAsync.js.map +1 -1
  70. package/dist/storage/storageSync.d.ts +9 -2
  71. package/dist/storage/storageSync.d.ts.map +1 -1
  72. package/dist/storage/storageSync.js +20 -13
  73. package/dist/storage/storageSync.js.map +1 -1
  74. package/dist/storage/types.d.ts +64 -0
  75. package/dist/storage/types.d.ts.map +1 -1
  76. package/dist/storage/types.js.map +1 -1
  77. package/dist/sync.d.ts +44 -2
  78. package/dist/sync.d.ts.map +1 -1
  79. package/dist/sync.js +268 -44
  80. package/dist/sync.js.map +1 -1
  81. package/dist/tests/OutgoingLoadQueue.test.js +137 -39
  82. package/dist/tests/OutgoingLoadQueue.test.js.map +1 -1
  83. package/dist/tests/SQLiteClientAsync.test.js +1 -1
  84. package/dist/tests/SQLiteClientAsync.test.js.map +1 -1
  85. package/dist/tests/StorageApiAsync.test.js +138 -0
  86. package/dist/tests/StorageApiAsync.test.js.map +1 -1
  87. package/dist/tests/StorageApiSync.test.js +154 -0
  88. package/dist/tests/StorageApiSync.test.js.map +1 -1
  89. package/dist/tests/StorageReconciliationAckTracker.test.d.ts +2 -0
  90. package/dist/tests/StorageReconciliationAckTracker.test.d.ts.map +1 -0
  91. package/dist/tests/StorageReconciliationAckTracker.test.js +74 -0
  92. package/dist/tests/StorageReconciliationAckTracker.test.js.map +1 -0
  93. package/dist/tests/SyncStateManager.test.js +18 -0
  94. package/dist/tests/SyncStateManager.test.js.map +1 -1
  95. package/dist/tests/coList.test.js +112 -1
  96. package/dist/tests/coList.test.js.map +1 -1
  97. package/dist/tests/coValueCore.loadFromStorage.test.js +36 -0
  98. package/dist/tests/coValueCore.loadFromStorage.test.js.map +1 -1
  99. package/dist/tests/group.test.js +44 -0
  100. package/dist/tests/group.test.js.map +1 -1
  101. package/dist/tests/knownState.lazyLoading.test.js +6 -0
  102. package/dist/tests/knownState.lazyLoading.test.js.map +1 -1
  103. package/dist/tests/messagesTestUtils.d.ts.map +1 -1
  104. package/dist/tests/messagesTestUtils.js +4 -0
  105. package/dist/tests/messagesTestUtils.js.map +1 -1
  106. package/dist/tests/sync.concurrentLoad.test.js +333 -1
  107. package/dist/tests/sync.concurrentLoad.test.js.map +1 -1
  108. package/dist/tests/sync.garbageCollection.test.js +4 -0
  109. package/dist/tests/sync.garbageCollection.test.js.map +1 -1
  110. package/dist/tests/sync.load.test.js +19 -0
  111. package/dist/tests/sync.load.test.js.map +1 -1
  112. package/dist/tests/sync.mesh.test.js +1 -0
  113. package/dist/tests/sync.mesh.test.js.map +1 -1
  114. package/dist/tests/sync.multipleServers.test.js +41 -3
  115. package/dist/tests/sync.multipleServers.test.js.map +1 -1
  116. package/dist/tests/sync.storage.test.js +2 -0
  117. package/dist/tests/sync.storage.test.js.map +1 -1
  118. package/dist/tests/sync.storageAsync.test.js +1 -0
  119. package/dist/tests/sync.storageAsync.test.js.map +1 -1
  120. package/dist/tests/sync.storageReconciliation.test.d.ts +2 -0
  121. package/dist/tests/sync.storageReconciliation.test.d.ts.map +1 -0
  122. package/dist/tests/sync.storageReconciliation.test.js +501 -0
  123. package/dist/tests/sync.storageReconciliation.test.js.map +1 -0
  124. package/dist/tests/testUtils.d.ts +1 -0
  125. package/dist/tests/testUtils.d.ts.map +1 -1
  126. package/dist/tests/testUtils.js +3 -2
  127. package/dist/tests/testUtils.js.map +1 -1
  128. package/package.json +4 -4
  129. package/src/PeerState.ts +10 -3
  130. package/src/StorageReconciliationAckTracker.ts +83 -0
  131. package/src/SyncStateManager.ts +3 -3
  132. package/src/coValueCore/coValueCore.ts +47 -16
  133. package/src/coValues/coList.ts +23 -0
  134. package/src/coValues/group.ts +18 -0
  135. package/src/config.ts +18 -0
  136. package/src/exports.ts +8 -0
  137. package/src/localNode.ts +18 -0
  138. package/src/permissions.ts +1 -1
  139. package/src/queue/LinkedList.ts +10 -0
  140. package/src/queue/OutgoingLoadQueue.ts +57 -15
  141. package/src/queue/PriorityBasedMessageQueue.ts +15 -1
  142. package/src/storage/knownState.ts +14 -0
  143. package/src/storage/sqlite/client.ts +128 -0
  144. package/src/storage/sqlite/sqliteMigrations.ts +11 -0
  145. package/src/storage/sqliteAsync/client.ts +139 -0
  146. package/src/storage/storageAsync.ts +37 -0
  147. package/src/storage/storageSync.ts +41 -16
  148. package/src/storage/types.ts +110 -0
  149. package/src/sync.ts +311 -14
  150. package/src/tests/OutgoingLoadQueue.test.ts +226 -59
  151. package/src/tests/SQLiteClientAsync.test.ts +1 -1
  152. package/src/tests/StorageApiAsync.test.ts +161 -1
  153. package/src/tests/StorageApiSync.test.ts +176 -0
  154. package/src/tests/StorageReconciliationAckTracker.test.ts +99 -0
  155. package/src/tests/SyncStateManager.test.ts +25 -0
  156. package/src/tests/coList.test.ts +138 -0
  157. package/src/tests/coValueCore.loadFromStorage.test.ts +72 -1
  158. package/src/tests/group.test.ts +87 -0
  159. package/src/tests/knownState.lazyLoading.test.ts +36 -1
  160. package/src/tests/messagesTestUtils.ts +4 -0
  161. package/src/tests/sync.concurrentLoad.test.ts +491 -0
  162. package/src/tests/sync.garbageCollection.test.ts +4 -0
  163. package/src/tests/sync.load.test.ts +26 -0
  164. package/src/tests/sync.mesh.test.ts +1 -0
  165. package/src/tests/sync.multipleServers.test.ts +60 -2
  166. package/src/tests/sync.storage.test.ts +2 -0
  167. package/src/tests/sync.storageAsync.test.ts +1 -0
  168. package/src/tests/sync.storageReconciliation.test.ts +697 -0
  169. package/src/tests/testUtils.ts +10 -1
@@ -29,6 +29,7 @@ import type {
29
29
  SignatureAfterRow,
30
30
  StoredCoValueRow,
31
31
  StoredSessionRow,
32
+ StorageReconciliationAcquireResult,
32
33
  } from "./types.js";
33
34
  import { DeletedCoValuesEraserScheduler } from "./DeletedCoValuesEraserScheduler.js";
34
35
  import {
@@ -68,26 +69,48 @@ export class StorageApiSync implements StorageAPI {
68
69
  return this.knownStates.getKnownState(id);
69
70
  }
70
71
 
71
- loadKnownState(
72
- id: string,
73
- callback: (knownState: CoValueKnownState | undefined) => void,
72
+ getCoValueIDs(
73
+ limit: number,
74
+ offset: number,
75
+ callback: (batch: { id: RawCoID }[]) => void,
74
76
  ): void {
75
- // Check in-memory cache first
76
- const cached = this.knownStates.getCachedKnownState(id);
77
- if (cached) {
78
- callback(cached);
79
- return;
80
- }
77
+ const batch = this.dbClient.getCoValueIDs(limit, offset);
78
+ callback(batch);
79
+ }
81
80
 
82
- // Load from database
83
- const knownState = this.dbClient.getCoValueKnownState(id);
81
+ getCoValueCount(callback: (count: number) => void): void {
82
+ callback(this.dbClient.getCoValueCount());
83
+ }
84
84
 
85
- if (knownState) {
86
- // Cache for future use
87
- this.knownStates.setKnownState(id, knownState);
88
- }
85
+ tryAcquireStorageReconciliationLock(
86
+ sessionId: SessionID,
87
+ peerId: PeerID,
88
+ callback: (result: StorageReconciliationAcquireResult) => void,
89
+ ): void {
90
+ const result = this.dbClient.tryAcquireStorageReconciliationLock(
91
+ sessionId,
92
+ peerId,
93
+ );
94
+ callback(result);
95
+ }
96
+
97
+ renewStorageReconciliationLock(
98
+ sessionId: SessionID,
99
+ peerId: PeerID,
100
+ offset: number,
101
+ ): void {
102
+ this.dbClient.renewStorageReconciliationLock(sessionId, peerId, offset);
103
+ }
104
+
105
+ releaseStorageReconciliationLock(sessionId: SessionID, peerId: PeerID): void {
106
+ this.dbClient.releaseStorageReconciliationLock(sessionId, peerId);
107
+ }
89
108
 
90
- callback(knownState);
109
+ loadKnownState(
110
+ id: string,
111
+ callback: (knownState: CoValueKnownState | undefined) => void,
112
+ ): void {
113
+ callback(this.dbClient.getCoValueKnownState(id));
91
114
  }
92
115
 
93
116
  async load(
@@ -515,11 +538,13 @@ export class StorageApiSync implements StorageAPI {
515
538
 
516
539
  onCoValueUnmounted(id: RawCoID): void {
517
540
  this.inMemoryCoValues.delete(id);
541
+ this.knownStates.deleteKnownState(id);
518
542
  }
519
543
 
520
544
  close() {
521
545
  this.deletedCoValuesEraserScheduler?.dispose();
522
546
  this.inMemoryCoValues.clear();
547
+ this.knownStates.clear();
523
548
  return undefined;
524
549
  }
525
550
  }
@@ -13,6 +13,10 @@ export type CorrectionCallback = (
13
13
  correction: CoValueKnownState,
14
14
  ) => NewContentMessage[] | undefined;
15
15
 
16
+ export type StorageReconciliationAcquireResult =
17
+ | { acquired: true; lastProcessedOffset: number }
18
+ | { acquired: false; reason: "not_due" | "lock_held" };
19
+
16
20
  /**
17
21
  * Deletion work queue status for `deletedCoValues` (SQLite).
18
22
  *
@@ -86,6 +90,52 @@ export interface StorageAPI {
86
90
  */
87
91
  stopTrackingSyncState(id: RawCoID): void;
88
92
 
93
+ /**
94
+ * Get a batch of CoValue IDs from storage.
95
+ * Used for full storage reconciliation. Call repeatedly with increasing offset
96
+ * until the returned batch has length < limit (or 0) to enumerate all IDs.
97
+ * @param limit - Max number of IDs to return (e.g. 100).
98
+ * @param offset - Number of IDs to skip (0 for first batch).
99
+ * @param callback - Called with the batch. Ordering must be stable (e.g. by id).
100
+ */
101
+ getCoValueIDs(
102
+ limit: number,
103
+ offset: number,
104
+ callback: (batch: { id: RawCoID }[]) => void,
105
+ ): void;
106
+
107
+ /**
108
+ * Get the total number of CoValues in storage.
109
+ */
110
+ getCoValueCount(callback: (count: number) => void): void;
111
+
112
+ /**
113
+ * Try to acquire the storage reconciliation lock for a given peer.
114
+ * Atomically checks if reconciliation is due for this peer (lastRun older than 30 days or missing)
115
+ * and if no other process/tab holds the lock for this peer, then acquires it.
116
+ */
117
+ tryAcquireStorageReconciliationLock(
118
+ sessionId: SessionID,
119
+ peerId: PeerID,
120
+ callback: (result: StorageReconciliationAcquireResult) => void,
121
+ ): void;
122
+
123
+ /**
124
+ * Update the last processed offset for the storage reconciliation lock held for this peer.
125
+ * Only call after a batch has been acked; used to resume from this offset on interrupt.
126
+ */
127
+ renewStorageReconciliationLock(
128
+ sessionId: SessionID,
129
+ peerId: PeerID,
130
+ offset: number,
131
+ ): void;
132
+
133
+ /**
134
+ * Release the storage reconciliation lock for a peer and record completion. Only call on successful completion.
135
+ * On failure/interrupt, do not call; the lock expires after LOCK_TTL_MS and another process can retry for this peer.
136
+ */
137
+ releaseStorageReconciliationLock(sessionId: SessionID, peerId: PeerID): void;
138
+
89
139
  /**
90
140
  * Load only the knownState (header presence + session counters) for a CoValue.
91
141
  * This is more efficient than load() when we only need to check if a peer needs new content.
@@ -136,6 +186,15 @@ export type SignatureAfterRow = {
136
186
  signature: Signature;
137
187
  };
138
188
 
189
+ export type StorageReconciliationLockRow = {
190
+ key: string;
191
+ holderSessionId: SessionID;
192
+ acquiredAt: number;
193
+ releasedAt?: number;
194
+ /** Offset up to which all batches have been acked; used to resume after interrupt. */
195
+ lastProcessedOffset: number;
196
+ };
197
+
139
198
  export interface DBTransactionInterfaceAsync {
140
199
  getSingleCoValueSession(
141
200
  coValueRowId: number,
@@ -176,6 +235,14 @@ export interface DBTransactionInterfaceAsync {
176
235
  deleteCoValueContent(
177
236
  coValueRow: Pick<StoredCoValueRow, "rowID" | "id">,
178
237
  ): Promise<unknown>;
238
+
239
+ getStorageReconciliationLock(
240
+ key: string,
241
+ ): Promise<StorageReconciliationLockRow | undefined>;
242
+
243
+ putStorageReconciliationLock(
244
+ entry: StorageReconciliationLockRow,
245
+ ): Promise<void>;
179
246
  }
180
247
 
181
248
  export interface DBClientInterfaceAsync {
@@ -232,6 +299,26 @@ export interface DBClientInterfaceAsync {
232
299
  getCoValueKnownState(
233
300
  coValueId: string,
234
301
  ): Promise<CoValueKnownState | undefined>;
302
+
303
+ getCoValueIDs(limit: number, offset: number): Promise<{ id: RawCoID }[]>;
304
+
305
+ getCoValueCount(): Promise<number>;
306
+
307
+ tryAcquireStorageReconciliationLock(
308
+ sessionId: SessionID,
309
+ peerId: PeerID,
310
+ ): Promise<StorageReconciliationAcquireResult>;
311
+
312
+ renewStorageReconciliationLock(
313
+ sessionId: SessionID,
314
+ peerId: PeerID,
315
+ offset: number,
316
+ ): Promise<void>;
317
+
318
+ releaseStorageReconciliationLock(
319
+ sessionId: SessionID,
320
+ peerId: PeerID,
321
+ ): Promise<void>;
235
322
  }
236
323
 
237
324
  export interface DBTransactionInterfaceSync {
@@ -270,6 +357,12 @@ export interface DBTransactionInterfaceSync {
270
357
  idx: number;
271
358
  signature: Signature;
272
359
  }): number | undefined | unknown;
360
+
361
+ getStorageReconciliationLock(
362
+ key: string,
363
+ ): StorageReconciliationLockRow | undefined;
364
+
365
+ putStorageReconciliationLock(entry: StorageReconciliationLockRow): void;
273
366
  }
274
367
 
275
368
  export interface DBClientInterfaceSync {
@@ -317,4 +410,21 @@ export interface DBClientInterfaceSync {
317
410
  * Returns undefined if the CoValue doesn't exist.
318
411
  */
319
412
  getCoValueKnownState(coValueId: string): CoValueKnownState | undefined;
413
+
414
+ getCoValueIDs(limit: number, offset: number): { id: RawCoID }[];
415
+
416
+ getCoValueCount(): number;
417
+
418
+ tryAcquireStorageReconciliationLock(
419
+ sessionId: SessionID,
420
+ peerId: PeerID,
421
+ ): StorageReconciliationAcquireResult;
422
+
423
+ renewStorageReconciliationLock(
424
+ sessionId: SessionID,
425
+ peerId: PeerID,
426
+ offset: number,
427
+ ): void;
428
+
429
+ releaseStorageReconciliationLock(sessionId: SessionID, peerId: PeerID): void;
320
430
  }