mindoodb 0.0.53 → 0.0.55

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 (99) hide show
  1. package/README-server.md +125 -69
  2. package/dist/appendonlystores/network/ClientNetworkContentAddressedStore.d.ts +17 -0
  3. package/dist/appendonlystores/network/ClientNetworkContentAddressedStore.d.ts.map +1 -1
  4. package/dist/appendonlystores/network/ClientNetworkContentAddressedStore.js +22 -0
  5. package/dist/appendonlystores/network/ClientNetworkContentAddressedStore.js.map +1 -1
  6. package/dist/appendonlystores/network/ServerNetworkContentAddressedStore.d.ts +58 -0
  7. package/dist/appendonlystores/network/ServerNetworkContentAddressedStore.d.ts.map +1 -1
  8. package/dist/appendonlystores/network/ServerNetworkContentAddressedStore.js +156 -3
  9. package/dist/appendonlystores/network/ServerNetworkContentAddressedStore.js.map +1 -1
  10. package/dist/browser/index.mjs +2 -0
  11. package/dist/core/BaseMindooDB.d.ts +73 -74
  12. package/dist/core/BaseMindooDB.d.ts.map +1 -1
  13. package/dist/core/BaseMindooDB.js +263 -509
  14. package/dist/core/BaseMindooDB.js.map +1 -1
  15. package/dist/core/MindooDBServerAdmin.d.ts +44 -22
  16. package/dist/core/MindooDBServerAdmin.d.ts.map +1 -1
  17. package/dist/core/MindooDBServerAdmin.js +45 -21
  18. package/dist/core/MindooDBServerAdmin.js.map +1 -1
  19. package/dist/core/appendonlystores/syncStores.d.ts +147 -0
  20. package/dist/core/appendonlystores/syncStores.d.ts.map +1 -0
  21. package/dist/core/appendonlystores/syncStores.js +612 -0
  22. package/dist/core/appendonlystores/syncStores.js.map +1 -0
  23. package/dist/core/builtinDbInvariants.d.ts +30 -0
  24. package/dist/core/builtinDbInvariants.d.ts.map +1 -1
  25. package/dist/core/builtinDbInvariants.js +97 -0
  26. package/dist/core/builtinDbInvariants.js.map +1 -1
  27. package/dist/core/index.d.ts +1 -1
  28. package/dist/core/index.d.ts.map +1 -1
  29. package/dist/core/index.js +7 -4
  30. package/dist/core/index.js.map +1 -1
  31. package/dist/core/types.d.ts +42 -0
  32. package/dist/core/types.d.ts.map +1 -1
  33. package/dist/node/server/CapabilityMatcher.d.ts +2 -2
  34. package/dist/node/server/CapabilityMatcher.js +2 -2
  35. package/dist/node/server/MindooDBServer.d.ts +14 -1
  36. package/dist/node/server/MindooDBServer.d.ts.map +1 -1
  37. package/dist/node/server/MindooDBServer.js +166 -159
  38. package/dist/node/server/MindooDBServer.js.map +1 -1
  39. package/dist/node/server/SyncEventBus.d.ts +10 -0
  40. package/dist/node/server/SyncEventBus.d.ts.map +1 -1
  41. package/dist/node/server/SyncEventBus.js.map +1 -1
  42. package/dist/node/server/TenantManager.d.ts +58 -6
  43. package/dist/node/server/TenantManager.d.ts.map +1 -1
  44. package/dist/node/server/TenantManager.js +90 -65
  45. package/dist/node/server/TenantManager.js.map +1 -1
  46. package/dist/node/server/add-to-network.d.ts.map +1 -1
  47. package/dist/node/server/add-to-network.js +33 -15
  48. package/dist/node/server/add-to-network.js.map +1 -1
  49. package/dist/node/server/canonicalSetupName.d.ts +22 -0
  50. package/dist/node/server/canonicalSetupName.d.ts.map +1 -0
  51. package/dist/node/server/canonicalSetupName.js +38 -0
  52. package/dist/node/server/canonicalSetupName.js.map +1 -0
  53. package/dist/node/server/config.d.ts.map +1 -1
  54. package/dist/node/server/config.js +33 -1
  55. package/dist/node/server/config.js.map +1 -1
  56. package/dist/node/server/peer/ClusterAuditLog.d.ts +64 -0
  57. package/dist/node/server/peer/ClusterAuditLog.d.ts.map +1 -0
  58. package/dist/node/server/peer/ClusterAuditLog.js +99 -0
  59. package/dist/node/server/peer/ClusterAuditLog.js.map +1 -0
  60. package/dist/node/server/peer/ClusterJobRunner.d.ts +43 -0
  61. package/dist/node/server/peer/ClusterJobRunner.d.ts.map +1 -0
  62. package/dist/node/server/peer/ClusterJobRunner.js +119 -0
  63. package/dist/node/server/peer/ClusterJobRunner.js.map +1 -0
  64. package/dist/node/server/peer/ClusterManager.d.ts +116 -0
  65. package/dist/node/server/peer/ClusterManager.d.ts.map +1 -0
  66. package/dist/node/server/peer/ClusterManager.js +274 -0
  67. package/dist/node/server/peer/ClusterManager.js.map +1 -0
  68. package/dist/node/server/peer/PeerAuthService.d.ts +69 -0
  69. package/dist/node/server/peer/PeerAuthService.d.ts.map +1 -0
  70. package/dist/node/server/peer/PeerAuthService.js +208 -0
  71. package/dist/node/server/peer/PeerAuthService.js.map +1 -0
  72. package/dist/node/server/peer/PeerReplicator.d.ts +232 -0
  73. package/dist/node/server/peer/PeerReplicator.d.ts.map +1 -0
  74. package/dist/node/server/peer/PeerReplicator.js +879 -0
  75. package/dist/node/server/peer/PeerReplicator.js.map +1 -0
  76. package/dist/node/server/peer/routes.d.ts +66 -0
  77. package/dist/node/server/peer/routes.d.ts.map +1 -0
  78. package/dist/node/server/peer/routes.js +322 -0
  79. package/dist/node/server/peer/routes.js.map +1 -0
  80. package/dist/node/server/peer/types.d.ts +244 -0
  81. package/dist/node/server/peer/types.d.ts.map +1 -0
  82. package/dist/node/server/peer/types.js +189 -0
  83. package/dist/node/server/peer/types.js.map +1 -0
  84. package/dist/node/server/server.d.ts +1 -1
  85. package/dist/node/server/server.js +18 -37
  86. package/dist/node/server/server.js.map +1 -1
  87. package/dist/node/server/serverinit.d.ts +2 -1
  88. package/dist/node/server/serverinit.d.ts.map +1 -1
  89. package/dist/node/server/serverinit.js +34 -12
  90. package/dist/node/server/serverinit.js.map +1 -1
  91. package/dist/node/server/types.d.ts +42 -30
  92. package/dist/node/server/types.d.ts.map +1 -1
  93. package/dist/node/server/types.js +1 -7
  94. package/dist/node/server/types.js.map +1 -1
  95. package/dist/node/server/validation.d.ts +0 -6
  96. package/dist/node/server/validation.d.ts.map +1 -1
  97. package/dist/node/server/validation.js +1 -7
  98. package/dist/node/server/validation.js.map +1 -1
  99. package/package.json +1 -1
@@ -0,0 +1,612 @@
1
+ "use strict";
2
+ /**
3
+ * Store-to-store entry transfer (sync-v5).
4
+ *
5
+ * This is the reconciliation algorithm that moves {@link StoreEntry} blobs from
6
+ * one {@link ContentAddressedStore} to another: persisted scan cursors, bloom
7
+ * pre-screening, and parallel transfer batches. It works purely on encrypted
8
+ * entries and never opens an Automerge document, which is what lets both the
9
+ * client (`BaseMindooDB.pullChangesFrom` / `pushChangesTo`) and the server-side
10
+ * peer replicator share one implementation instead of maintaining a second,
11
+ * weaker server-to-server algorithm.
12
+ *
13
+ * ## Cursor invariant: strictly per (source, target) pair
14
+ *
15
+ * A cursor position is a `(receiptOrder, id)` pair, and `receiptOrder` is the
16
+ * *local insertion order* of the store that produced it — it is assigned when
17
+ * an entry lands in that store and is NOT part of the replicated entry data
18
+ * (see `StampedWitnessFields` in `core/crypto/WitnessReceipt.ts`, which carries
19
+ * only `receivedAt` / `receivedByPublicKey` / `receivedDateSignature`).
20
+ *
21
+ * Two servers holding the identical entry set therefore assign it different
22
+ * receipt orders. A cursor is only meaningful for the exact pair of stores it
23
+ * was recorded for, which is why {@link syncScanCursorKey} embeds both
24
+ * identities and why cursors must never be shared, reused across peers, or
25
+ * replicated. Getting this wrong silently skips entries.
26
+ */
27
+ Object.defineProperty(exports, "__esModule", { value: true });
28
+ exports.syncStoreIdentity = syncStoreIdentity;
29
+ exports.syncScanCursorKey = syncScanCursorKey;
30
+ exports.setSyncAbortSignalOnStore = setSyncAbortSignalOnStore;
31
+ exports.getStoreHeadSafe = getStoreHeadSafe;
32
+ exports.getStoreBloomSummary = getStoreBloomSummary;
33
+ exports.filterMissingIds = filterMissingIds;
34
+ exports.transferEntriesInBatches = transferEntriesInBatches;
35
+ exports.syncEntriesBetweenStores = syncEntriesBetweenStores;
36
+ const types_1 = require("./types");
37
+ const bloom_1 = require("./bloom");
38
+ /**
39
+ * Default window of transfer batches running in parallel (sync-v5, phase 4).
40
+ * Kept small: each in-flight batch holds one decrypted page of entries in
41
+ * memory, and HTTP/2 multiplexes the requests over a single connection anyway.
42
+ */
43
+ const DEFAULT_MAX_CONCURRENT_TRANSFER_BATCHES = 3;
44
+ /**
45
+ * Default `getEntries` batch size for document stores.
46
+ *
47
+ * Intentionally smaller than the metadata scan `pageSize` (1000): a full scan
48
+ * page transferred as one `putEntries` call serializes to a multi-megabyte JSON
49
+ * body whose upload cannot report progress, risks the HTTP timeout on slow
50
+ * uplinks (each retry restarts the whole body), and can exceed the remote JSON
51
+ * body limit. Smaller batches keep progress events frequent and make each POST
52
+ * cheap to retry.
53
+ */
54
+ const DEFAULT_DOCS_TRANSFER_BATCH_SIZE = 250;
55
+ /** Stable identity for a store in the persisted sync-cursor map. */
56
+ function syncStoreIdentity(store) {
57
+ return store.getCacheIdentity?.() ?? `${store.getId()}/${store.getStoreKind()}`;
58
+ }
59
+ /** Key for a scan cursor: one record per (source, target) pair. */
60
+ function syncScanCursorKey(sourceStore, targetStore) {
61
+ return `${syncStoreIdentity(sourceStore)}->${syncStoreIdentity(targetStore)}`;
62
+ }
63
+ function setSyncAbortSignalOnStore(store, signal) {
64
+ if ("setSyncAbortSignal" in store && typeof store.setSyncAbortSignal === "function") {
65
+ store.setSyncAbortSignal(signal);
66
+ }
67
+ }
68
+ /**
69
+ * Fetch a store's head descriptor (`{ epoch, maxReceiptOrder }`), returning null
70
+ * when the store (or the remote server behind it) does not support it or the
71
+ * request fails. A null head simply disables the persisted-cursor fast path.
72
+ */
73
+ async function getStoreHeadSafe(store, logger) {
74
+ if (typeof store.getStoreHead !== "function") {
75
+ return null;
76
+ }
77
+ try {
78
+ return await store.getStoreHead();
79
+ }
80
+ catch (error) {
81
+ logger.debug("Store head unavailable, falling back to full scan", error);
82
+ return null;
83
+ }
84
+ }
85
+ /**
86
+ * Fetch a store's bloom filter summary, returning null if unsupported or on
87
+ * error. Used on the target for missing-id pre-screening (callers fall back to
88
+ * exact checks) and on the source for the total-entry-count progress
89
+ * denominator.
90
+ */
91
+ async function getStoreBloomSummary(store, logger) {
92
+ if (typeof store.getIdBloomSummary !== "function") {
93
+ return null;
94
+ }
95
+ try {
96
+ return await store.getIdBloomSummary();
97
+ }
98
+ catch (error) {
99
+ logger.warn("Failed to get bloom summary from store, falling back to exact checks", error);
100
+ return null;
101
+ }
102
+ }
103
+ /**
104
+ * From a list of candidate IDs, return only those the target store is missing.
105
+ * Uses bloom-filter pre-screening when available, then falls back to exact
106
+ * `hasEntries` for the uncertain set.
107
+ */
108
+ async function filterMissingIds(targetStore, candidateIds, bloom) {
109
+ let definitelyMissing = [];
110
+ let maybeExisting = candidateIds;
111
+ if (bloom) {
112
+ definitelyMissing = [];
113
+ maybeExisting = [];
114
+ for (const id of candidateIds) {
115
+ if ((0, bloom_1.bloomMightContainId)(bloom, id)) {
116
+ maybeExisting.push(id);
117
+ }
118
+ else {
119
+ definitelyMissing.push(id);
120
+ }
121
+ }
122
+ }
123
+ let missingIds = definitelyMissing;
124
+ if (maybeExisting.length > 0) {
125
+ const existing = await targetStore.hasEntries(maybeExisting);
126
+ const existingSet = new Set(existing);
127
+ missingIds = missingIds.concat(maybeExisting.filter((id) => !existingSet.has(id)));
128
+ }
129
+ return missingIds;
130
+ }
131
+ /**
132
+ * Normalize the polymorphic putEntries result (`void`, receipts array, or
133
+ * structured {@link PutEntriesAck}) into receipts + per-entry rejections.
134
+ */
135
+ function normalizePutResult(putResult) {
136
+ if (Array.isArray(putResult)) {
137
+ return { receipts: putResult, batchRejected: [] };
138
+ }
139
+ if (putResult && typeof putResult === "object") {
140
+ return {
141
+ receipts: putResult.receipts ?? [],
142
+ batchRejected: putResult.rejected ?? [],
143
+ };
144
+ }
145
+ return { receipts: [], batchRejected: [] };
146
+ }
147
+ /**
148
+ * Determine how many entry IDs to fetch per `getEntries` call during sync.
149
+ *
150
+ * Intentionally separate from the metadata scan `pageSize` so scanning can page
151
+ * through large ID lists quickly while the heavier payload downloads use a
152
+ * smaller batch to keep progress responsive and cancellation timely.
153
+ *
154
+ * Priority: explicit option > attachment default (100) > docs default (250,
155
+ * capped by pageSize).
156
+ */
157
+ function resolveTransferBatchSize(options) {
158
+ if (options?.transferBatchSize && options.transferBatchSize > 0) {
159
+ return options.transferBatchSize;
160
+ }
161
+ if (options?.storeKind === types_1.StoreKind.attachments) {
162
+ return 100;
163
+ }
164
+ return Math.min(options?.pageSize ?? 1000, DEFAULT_DOCS_TRANSFER_BATCH_SIZE);
165
+ }
166
+ /**
167
+ * Transfer a set of entry IDs from source to target in fixed-size batches,
168
+ * emitting progress and checking for cancellation between each batch.
169
+ *
170
+ * Callers collect the IDs that need transferring, then delegate here instead of
171
+ * issuing one monolithic `getEntries`. This keeps progress updates frequent,
172
+ * lets cancellation interrupt between batches, and keeps each server-side
173
+ * `getEntries` + encryption unit small enough to avoid socket timeouts.
174
+ *
175
+ * Returns partial progress on cancellation so callers can report how much was
176
+ * actually transferred before the abort.
177
+ */
178
+ async function transferEntriesInBatches(sourceStore, targetStore, entryIds, options, state, logger) {
179
+ if (entryIds.length === 0) {
180
+ return {
181
+ transferred: state.transferred,
182
+ transferredBytes: state.transferredBytes,
183
+ cancelled: false,
184
+ rejected: [],
185
+ };
186
+ }
187
+ const onProgress = options?.onProgress;
188
+ const signal = options?.signal;
189
+ const transferBatchSize = resolveTransferBatchSize(options);
190
+ const totalTransferBatches = Math.max(1, Math.ceil(entryIds.length / transferBatchSize));
191
+ // Parallel transfer window (sync-v5, phase 4): each batch is one getEntries +
192
+ // putEntries round trip; a small window of concurrent batches overlaps
193
+ // network latency and server-side crypto. Witness receipts are applied per
194
+ // batch and are order-independent.
195
+ const maxConcurrent = Math.min(Math.max(1, Math.floor(options?.maxConcurrentBatches ?? DEFAULT_MAX_CONCURRENT_TRANSFER_BATCHES)), totalTransferBatches);
196
+ let transferred = state.transferred;
197
+ let transferredBytes = state.transferredBytes;
198
+ let cancelled = false;
199
+ let firstError = null;
200
+ let nextBatchIndex = 0;
201
+ // Per-entry rejections reported by a witnessing target (sync-v5): the push
202
+ // continues, the rejected entries are surfaced to the caller.
203
+ const rejected = [];
204
+ const runWorker = async () => {
205
+ while (true) {
206
+ if (firstError || cancelled || signal?.aborted) {
207
+ if (signal?.aborted)
208
+ cancelled = true;
209
+ return;
210
+ }
211
+ const batchIndex = nextBatchIndex++;
212
+ const offset = batchIndex * transferBatchSize;
213
+ if (offset >= entryIds.length) {
214
+ return;
215
+ }
216
+ const currentTransferBatch = batchIndex + 1;
217
+ const batchIds = entryIds.slice(offset, offset + transferBatchSize);
218
+ const pageSummary = state.currentPage ? `page ${state.currentPage}, ` : "";
219
+ onProgress?.({
220
+ phase: "transferring",
221
+ message: `Transferring batch ${currentTransferBatch}/${totalTransferBatches} (${batchIds.length} entries, ${pageSummary}scanned ${state.scanned})...`,
222
+ transferredEntries: transferred,
223
+ transferredBytes,
224
+ scannedEntries: state.scanned,
225
+ totalSourceEntries: state.totalSourceEntries,
226
+ currentPage: state.currentPage,
227
+ currentTransferBatch,
228
+ totalTransferBatches,
229
+ transferBatchSize,
230
+ });
231
+ try {
232
+ const batchEntries = await sourceStore.getEntries(batchIds);
233
+ if (signal?.aborted) {
234
+ cancelled = true;
235
+ return;
236
+ }
237
+ const putResult = await targetStore.putEntries(batchEntries);
238
+ // On push, the remote (witnessing) target returns receipts for accepted
239
+ // entries; persist them back onto the local source so the revision feed
240
+ // re-anchors them from the provisional head to their committed
241
+ // `receivedAt` (docs/accesscontrol.md §5.3). Pull targets return void.
242
+ // sync-v5 targets return a structured ack that additionally carries
243
+ // per-entry rejections (signature-class failures the remote skipped).
244
+ const { receipts, batchRejected } = normalizePutResult(putResult);
245
+ if (receipts.length > 0 && sourceStore.applyWitnessReceipts) {
246
+ await sourceStore.applyWitnessReceipts(receipts);
247
+ }
248
+ const rejectedIds = batchRejected.length > 0 ? new Set(batchRejected.map((entry) => entry.id)) : null;
249
+ if (rejectedIds) {
250
+ rejected.push(...batchRejected);
251
+ logger.warn(`Target rejected ${batchRejected.length} of ${batchEntries.length} entries in transfer batch ${currentTransferBatch}/${totalTransferBatches}`);
252
+ }
253
+ for (const entry of batchEntries) {
254
+ if (rejectedIds?.has(entry.id)) {
255
+ continue;
256
+ }
257
+ transferredBytes += entry.encryptedSize ?? entry.encryptedData.length;
258
+ }
259
+ transferred += batchEntries.length - batchRejected.length;
260
+ }
261
+ catch (error) {
262
+ if (signal?.aborted) {
263
+ cancelled = true;
264
+ return;
265
+ }
266
+ if (!firstError) {
267
+ firstError = error;
268
+ }
269
+ return;
270
+ }
271
+ onProgress?.({
272
+ phase: "transferring",
273
+ message: `Transferred ${transferred} entries after batch ${currentTransferBatch}/${totalTransferBatches}`,
274
+ transferredEntries: transferred,
275
+ transferredBytes,
276
+ scannedEntries: state.scanned,
277
+ totalSourceEntries: state.totalSourceEntries,
278
+ currentPage: state.currentPage,
279
+ currentTransferBatch,
280
+ totalTransferBatches,
281
+ transferBatchSize,
282
+ });
283
+ }
284
+ };
285
+ await Promise.all(Array.from({ length: maxConcurrent }, () => runWorker()));
286
+ if (signal?.aborted || cancelled) {
287
+ return { transferred, transferredBytes, cancelled: true, rejected };
288
+ }
289
+ if (firstError) {
290
+ throw firstError;
291
+ }
292
+ return { transferred, transferredBytes, cancelled: false, rejected };
293
+ }
294
+ function supportsCursorScan(store) {
295
+ return typeof store.scanEntriesSince === "function";
296
+ }
297
+ /**
298
+ * Reconcile `targetStore` with `sourceStore`: find the entries the target is
299
+ * missing and transfer them.
300
+ *
301
+ * Takes the persisted-cursor fast path when the source supports
302
+ * `scanEntriesSince`, otherwise falls back to the `getAllIds` + `findNewEntries`
303
+ * path for older stores.
304
+ */
305
+ async function syncEntriesBetweenStores(sourceStore, targetStore, options, ctx) {
306
+ const { logger, cursors } = ctx;
307
+ const holdCursorOnRejection = ctx.rejectionPolicy === "hold";
308
+ let transferred = 0;
309
+ let transferredBytes = 0;
310
+ let scanned = 0;
311
+ // Per-entry rejections reported by a witnessing target (sync-v5): the sync
312
+ // completes; rejected entries are surfaced to the caller as warnings.
313
+ const rejected = [];
314
+ const onProgress = options?.onProgress;
315
+ const pageSize = options?.pageSize ?? 1000;
316
+ const signal = options?.signal;
317
+ if (supportsCursorScan(sourceStore)) {
318
+ // Persisted-cursor fast path (sync-v5, phase 1): resume the metadata scan
319
+ // where the previous sync between this (source, target) pair left off — or
320
+ // skip the sync entirely when the source head shows nothing new. The heads
321
+ // are fetched up front (cheap; one request per side for network stores) and
322
+ // also anchor the epochs persisted with the cursor.
323
+ const cursorKey = syncScanCursorKey(sourceStore, targetStore);
324
+ const persisted = options?.forceFullScan ? null : cursors.get(cursorKey);
325
+ const [sourceHead, targetHead] = await Promise.all([
326
+ getStoreHeadSafe(sourceStore, logger),
327
+ getStoreHeadSafe(targetStore, logger),
328
+ ]);
329
+ let cursor = null;
330
+ if (persisted && sourceHead && targetHead) {
331
+ if (persisted.sourceEpoch === sourceHead.epoch &&
332
+ persisted.targetEpoch === targetHead.epoch) {
333
+ if (sourceHead.maxReceiptOrder <= persisted.cursor.receiptOrder) {
334
+ logger.debug(`Sync skip: source head ${sourceHead.maxReceiptOrder} already covered by persisted cursor (${cursorKey})`);
335
+ onProgress?.({
336
+ phase: "preparing",
337
+ message: "Source unchanged since last sync, nothing to scan",
338
+ transferredEntries: 0,
339
+ scannedEntries: 0,
340
+ });
341
+ return { transferred: 0, scanned: 0, cancelled: false };
342
+ }
343
+ cursor = persisted.cursor;
344
+ logger.debug(`Resuming sync scan from persisted cursor receiptOrder=${cursor.receiptOrder} (${cursorKey})`);
345
+ }
346
+ else {
347
+ // Epoch change on either side: the cursor lineage is broken (store
348
+ // reset / receipt-order migration) — full rescan.
349
+ logger.info(`Sync cursor epoch changed for ${cursorKey}, discarding persisted cursor and re-scanning`);
350
+ cursors.delete(cursorKey);
351
+ }
352
+ }
353
+ // Under the "hold" rejection policy this pins the cursor to the position
354
+ // immediately before the earliest rejected entry, so the next run re-offers
355
+ // it instead of skipping it forever. Null means "nothing rejected yet".
356
+ let heldCursor = null;
357
+ let cursorIsHeld = false;
358
+ const persistScanCursor = (finalCursor) => {
359
+ const effective = cursorIsHeld ? heldCursor : finalCursor;
360
+ if (effective && sourceHead && targetHead) {
361
+ cursors.save(cursorKey, {
362
+ sourceEpoch: sourceHead.epoch,
363
+ targetEpoch: targetHead.epoch,
364
+ cursor: effective,
365
+ });
366
+ }
367
+ };
368
+ const targetBloom = await getStoreBloomSummary(targetStore, logger);
369
+ // Fixed progress denominator: the SOURCE's total entry count. The cursor
370
+ // scan below examines every source entry, so scannedEntries/totalSourceEntries
371
+ // is a real completion ratio. (Local stores serve this from a cached bloom
372
+ // summary; network stores answer with one extra request.) The target bloom
373
+ // stays dedicated to missing-id pre-screening.
374
+ const sourceBloom = await getStoreBloomSummary(sourceStore, logger);
375
+ const totalSourceEstimate = sourceBloom?.totalIds;
376
+ onProgress?.({
377
+ phase: "preparing",
378
+ message: "Preparing to sync entries...",
379
+ transferredEntries: 0,
380
+ scannedEntries: 0,
381
+ totalSourceEntries: totalSourceEstimate,
382
+ });
383
+ // Upper scan bound: the source head captured BEFORE the scan started.
384
+ // Pushing to a witnessing target re-anchors the just-transferred entries to
385
+ // a fresh receiptOrder on the source (applyWitnessReceipts), i.e. past the
386
+ // running cursor — without this bound the scan would re-discover its own
387
+ // transfers and never terminate (first-sync loop). Entries beyond the bound
388
+ // (re-anchored or written concurrently) are picked up by the next sync.
389
+ const scanUpperBound = sourceHead?.maxReceiptOrder;
390
+ // IDs already transferred in this sync session. Guards against re-pushing
391
+ // entries the scan re-discovers when the target bloom snapshot is stale
392
+ // (fetched once up front; empty on a first sync, so it would classify every
393
+ // re-discovered id as "definitely missing" and skip the exact hasEntries
394
+ // check).
395
+ const transferredThisSync = new Set();
396
+ let currentPage = 0;
397
+ // Scan-page pipelining (sync-v5, phase 4): while page N is being filtered
398
+ // and transferred, page N+1 is already being fetched.
399
+ let nextPagePromise = null;
400
+ const discardPrefetch = () => {
401
+ // Swallow errors of an in-flight prefetch we will never consume
402
+ // (abort/cancel paths) to avoid unhandled rejections.
403
+ nextPagePromise?.catch(() => { });
404
+ nextPagePromise = null;
405
+ };
406
+ while (true) {
407
+ if (signal?.aborted) {
408
+ discardPrefetch();
409
+ persistScanCursor(cursor);
410
+ return {
411
+ transferred,
412
+ transferredBytes,
413
+ scanned,
414
+ cancelled: true,
415
+ rejected,
416
+ cursorHeldForRetry: cursorIsHeld,
417
+ };
418
+ }
419
+ const cursorAtPageStart = cursor;
420
+ const page = nextPagePromise
421
+ ? await nextPagePromise
422
+ : await sourceStore.scanEntriesSince(cursor, pageSize);
423
+ nextPagePromise = page.hasMore
424
+ ? sourceStore.scanEntriesSince(page.nextCursor, pageSize)
425
+ : null;
426
+ currentPage++;
427
+ // Clamp the page to the scan bound. Pages are ordered by
428
+ // (receiptOrder, id), so everything past the first out-of-bound entry is
429
+ // out of bound as well.
430
+ let pageEntries = page.entries;
431
+ let reachedScanBound = false;
432
+ if (scanUpperBound !== undefined && pageEntries.length > 0) {
433
+ const inBound = pageEntries.filter((m) => (m.receiptOrder ?? 0) <= scanUpperBound);
434
+ if (inBound.length < pageEntries.length) {
435
+ reachedScanBound = true;
436
+ pageEntries = inBound;
437
+ }
438
+ }
439
+ scanned += pageEntries.length;
440
+ if (signal?.aborted) {
441
+ discardPrefetch();
442
+ persistScanCursor(cursor);
443
+ return {
444
+ transferred,
445
+ transferredBytes,
446
+ scanned,
447
+ cancelled: true,
448
+ rejected,
449
+ cursorHeldForRetry: cursorIsHeld,
450
+ };
451
+ }
452
+ if (pageEntries.length > 0) {
453
+ onProgress?.({
454
+ phase: "transferring",
455
+ message: `Scanned ${scanned} entries, checking for changes (page ${currentPage})...`,
456
+ transferredEntries: transferred,
457
+ scannedEntries: scanned,
458
+ totalSourceEntries: totalSourceEstimate,
459
+ currentPage,
460
+ });
461
+ const ids = pageEntries.map((m) => m.id).filter((id) => !transferredThisSync.has(id));
462
+ const missingIds = ids.length > 0 ? await filterMissingIds(targetStore, ids, targetBloom) : [];
463
+ if (signal?.aborted) {
464
+ discardPrefetch();
465
+ persistScanCursor(cursor);
466
+ return {
467
+ transferred,
468
+ transferredBytes,
469
+ scanned,
470
+ cancelled: true,
471
+ rejected,
472
+ cursorHeldForRetry: cursorIsHeld,
473
+ };
474
+ }
475
+ if (missingIds.length > 0) {
476
+ const transferResult = await transferEntriesInBatches(sourceStore, targetStore, missingIds, options, {
477
+ transferred,
478
+ transferredBytes,
479
+ scanned,
480
+ totalSourceEntries: totalSourceEstimate,
481
+ currentPage,
482
+ }, logger);
483
+ transferred = transferResult.transferred;
484
+ transferredBytes = transferResult.transferredBytes;
485
+ rejected.push(...transferResult.rejected);
486
+ // Clamp the cursor at the first rejection so the retry actually
487
+ // re-offers the entry. Only the earliest one matters: everything
488
+ // after it is re-scanned anyway.
489
+ if (holdCursorOnRejection && transferResult.rejected.length > 0 && !cursorIsHeld) {
490
+ const rejectedIds = new Set(transferResult.rejected.map((entry) => entry.id));
491
+ const firstRejectedIndex = pageEntries.findIndex((m) => rejectedIds.has(m.id));
492
+ if (firstRejectedIndex >= 0) {
493
+ cursorIsHeld = true;
494
+ const previous = firstRejectedIndex > 0 ? pageEntries[firstRejectedIndex - 1] : null;
495
+ heldCursor = previous
496
+ ? { receiptOrder: previous.receiptOrder ?? 0, id: previous.id }
497
+ : cursorAtPageStart;
498
+ logger.warn(`Holding sync cursor at receiptOrder=${heldCursor?.receiptOrder ?? "start"} for ${cursorKey}: ` +
499
+ `${transferResult.rejected.length} entr${transferResult.rejected.length === 1 ? "y was" : "ies were"} rejected and must be retried`);
500
+ }
501
+ }
502
+ if (transferResult.cancelled) {
503
+ // The current page's transfer did not complete: persist the
504
+ // boundary of the last fully transferred page instead.
505
+ discardPrefetch();
506
+ persistScanCursor(cursor);
507
+ return {
508
+ transferred,
509
+ transferredBytes,
510
+ scanned,
511
+ cancelled: true,
512
+ rejected,
513
+ cursorHeldForRetry: cursorIsHeld,
514
+ };
515
+ }
516
+ for (const id of missingIds) {
517
+ transferredThisSync.add(id);
518
+ }
519
+ }
520
+ }
521
+ onProgress?.({
522
+ phase: "transferring",
523
+ message: `Transferred ${transferred} entries (page ${currentPage}, scanned ${scanned})`,
524
+ transferredEntries: transferred,
525
+ transferredBytes,
526
+ scannedEntries: scanned,
527
+ totalSourceEntries: totalSourceEstimate,
528
+ currentPage,
529
+ });
530
+ if (reachedScanBound) {
531
+ // Persist the last in-bound position (NOT page.nextCursor, which
532
+ // already points into the out-of-bound tail): a concurrent write that
533
+ // landed between the bound and the re-anchored tail must be scanned by
534
+ // the next sync.
535
+ const lastInBound = pageEntries.length > 0 ? pageEntries[pageEntries.length - 1] : null;
536
+ if (lastInBound) {
537
+ cursor = { receiptOrder: lastInBound.receiptOrder ?? 0, id: lastInBound.id };
538
+ }
539
+ discardPrefetch();
540
+ break;
541
+ }
542
+ cursor = page.nextCursor;
543
+ if (!page.hasMore) {
544
+ break;
545
+ }
546
+ }
547
+ persistScanCursor(cursor);
548
+ return {
549
+ transferred,
550
+ transferredBytes,
551
+ scanned,
552
+ cancelled: false,
553
+ rejected,
554
+ cursorHeldForRetry: cursorIsHeld,
555
+ };
556
+ }
557
+ onProgress?.({
558
+ phase: "preparing",
559
+ message: "Finding new entries...",
560
+ transferredEntries: 0,
561
+ scannedEntries: 0,
562
+ });
563
+ const targetIds = await targetStore.getAllIds();
564
+ const sourceNewMetadata = await sourceStore.findNewEntries(targetIds);
565
+ if (sourceNewMetadata.length === 0) {
566
+ return { transferred: 0, scanned: 0, cancelled: false };
567
+ }
568
+ if (options?.signal?.aborted) {
569
+ return { transferred: 0, scanned: 0, cancelled: true };
570
+ }
571
+ onProgress?.({
572
+ phase: "transferring",
573
+ message: `Transferring ${sourceNewMetadata.length} entries...`,
574
+ transferredEntries: transferred,
575
+ scannedEntries: sourceNewMetadata.length,
576
+ totalSourceEntries: sourceNewMetadata.length,
577
+ });
578
+ const transferResult = await transferEntriesInBatches(sourceStore, targetStore, sourceNewMetadata.map((m) => m.id), options, {
579
+ transferred,
580
+ transferredBytes,
581
+ scanned: sourceNewMetadata.length,
582
+ totalSourceEntries: sourceNewMetadata.length,
583
+ }, logger);
584
+ transferred = transferResult.transferred;
585
+ transferredBytes = transferResult.transferredBytes;
586
+ rejected.push(...transferResult.rejected);
587
+ if (transferResult.cancelled) {
588
+ return {
589
+ transferred,
590
+ transferredBytes,
591
+ scanned: sourceNewMetadata.length,
592
+ cancelled: true,
593
+ rejected,
594
+ };
595
+ }
596
+ onProgress?.({
597
+ phase: "transferring",
598
+ message: `Transferred ${transferred} entries`,
599
+ transferredEntries: transferred,
600
+ transferredBytes,
601
+ scannedEntries: sourceNewMetadata.length,
602
+ totalSourceEntries: sourceNewMetadata.length,
603
+ });
604
+ return {
605
+ transferred,
606
+ transferredBytes,
607
+ scanned: sourceNewMetadata.length,
608
+ cancelled: false,
609
+ rejected,
610
+ };
611
+ }
612
+ //# sourceMappingURL=syncStores.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"syncStores.js","sourceRoot":"","sources":["../../../src/core/appendonlystores/syncStores.ts"],"names":[],"mappings":"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"}