@tanstack/db-sqlite-persistence-core 0.2.20 → 0.2.23
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.
- package/dist/cjs/persisted.cjs +131 -81
- package/dist/cjs/persisted.cjs.map +1 -1
- package/dist/cjs/persisted.d.cts +1 -0
- package/dist/esm/persisted.d.ts +1 -0
- package/dist/esm/persisted.js +131 -81
- package/dist/esm/persisted.js.map +1 -1
- package/package.json +2 -2
- package/src/persisted.ts +171 -88
package/dist/cjs/persisted.cjs
CHANGED
|
@@ -165,15 +165,6 @@ function toStableSerializable(value) {
|
|
|
165
165
|
function stableSerialize(value) {
|
|
166
166
|
return JSON.stringify(toStableSerializable(value) ?? null);
|
|
167
167
|
}
|
|
168
|
-
function normalizeSubsetOptionsForKey(options) {
|
|
169
|
-
return {
|
|
170
|
-
where: toStableSerializable(options.where),
|
|
171
|
-
orderBy: toStableSerializable(options.orderBy),
|
|
172
|
-
limit: options.limit,
|
|
173
|
-
cursor: toStableSerializable(options.cursor),
|
|
174
|
-
offset: options.offset
|
|
175
|
-
};
|
|
176
|
-
}
|
|
177
168
|
function normalizeSyncFnResult(result) {
|
|
178
169
|
if (typeof result === `function`) {
|
|
179
170
|
return { cleanup: result };
|
|
@@ -220,7 +211,7 @@ class PersistedCollectionRuntime {
|
|
|
220
211
|
this.pendingRemoteSubsetEnsures = /* @__PURE__ */ new Map();
|
|
221
212
|
this.queuedHydrationTransactions = [];
|
|
222
213
|
this.queuedTxCommitted = [];
|
|
223
|
-
this.
|
|
214
|
+
this.requestIds = /* @__PURE__ */ new WeakMap();
|
|
224
215
|
this.collection = null;
|
|
225
216
|
this.syncControls = {
|
|
226
217
|
begin: null,
|
|
@@ -232,15 +223,17 @@ class PersistedCollectionRuntime {
|
|
|
232
223
|
this.started = false;
|
|
233
224
|
this.startupMetadataPromise = null;
|
|
234
225
|
this.startPromise = null;
|
|
226
|
+
this.resumeBaselinePromise = null;
|
|
227
|
+
this.lifecycleGeneration = 0;
|
|
235
228
|
this.internalApplyDepth = 0;
|
|
236
229
|
this.appliedReceiptSequence = 0;
|
|
237
230
|
this.pendingAppliedReceipts = /* @__PURE__ */ new Map();
|
|
238
|
-
this.
|
|
231
|
+
this.hydratingGeneration = null;
|
|
239
232
|
this.coordinatorUnsubscribe = null;
|
|
240
233
|
this.indexAddedUnsubscribe = null;
|
|
241
234
|
this.indexRemovedUnsubscribe = null;
|
|
242
235
|
this.remoteEnsureRetryTimer = null;
|
|
243
|
-
this.
|
|
236
|
+
this.nextRequestId = 0;
|
|
244
237
|
this.latestTerm = 0;
|
|
245
238
|
this.latestSeq = 0;
|
|
246
239
|
this.latestRowVersion = 0;
|
|
@@ -249,6 +242,7 @@ class PersistedCollectionRuntime {
|
|
|
249
242
|
this.localRowVersion = 0;
|
|
250
243
|
}
|
|
251
244
|
setSyncControls(syncControls) {
|
|
245
|
+
this.advanceLifecycle();
|
|
252
246
|
const commit = syncControls.commit;
|
|
253
247
|
this.syncControls = {
|
|
254
248
|
...syncControls,
|
|
@@ -283,7 +277,7 @@ class PersistedCollectionRuntime {
|
|
|
283
277
|
};
|
|
284
278
|
}
|
|
285
279
|
isHydratingNow() {
|
|
286
|
-
return this.
|
|
280
|
+
return this.hydratingGeneration === this.lifecycleGeneration;
|
|
287
281
|
}
|
|
288
282
|
isApplyingInternally() {
|
|
289
283
|
return this.internalApplyDepth > 0;
|
|
@@ -305,49 +299,75 @@ class PersistedCollectionRuntime {
|
|
|
305
299
|
if (this.startPromise) {
|
|
306
300
|
return this.startPromise;
|
|
307
301
|
}
|
|
308
|
-
|
|
302
|
+
const lifecycleGeneration = this.lifecycleGeneration;
|
|
303
|
+
this.startPromise = this.startInternal(lifecycleGeneration);
|
|
309
304
|
return this.startPromise;
|
|
310
305
|
}
|
|
306
|
+
ensureResumeBaselineHydrated() {
|
|
307
|
+
if (this.resumeBaselinePromise) {
|
|
308
|
+
return this.resumeBaselinePromise;
|
|
309
|
+
}
|
|
310
|
+
const lifecycleGeneration = this.lifecycleGeneration;
|
|
311
|
+
this.resumeBaselinePromise = (async () => {
|
|
312
|
+
await this.ensureStarted();
|
|
313
|
+
if (lifecycleGeneration !== this.lifecycleGeneration) return;
|
|
314
|
+
if (this.syncMode !== `on-demand`) return;
|
|
315
|
+
await this.hydrateBaseline(lifecycleGeneration);
|
|
316
|
+
})();
|
|
317
|
+
return this.resumeBaselinePromise;
|
|
318
|
+
}
|
|
319
|
+
async hydrateBaseline(lifecycleGeneration) {
|
|
320
|
+
if (lifecycleGeneration !== this.lifecycleGeneration) return;
|
|
321
|
+
const baseline = {};
|
|
322
|
+
this.activeSubsets.set(this.getSubsetKey(baseline), baseline);
|
|
323
|
+
const appliedCursor = this.appliedReceiptSequence;
|
|
324
|
+
await this.applyMutex.run(async () => {
|
|
325
|
+
if (lifecycleGeneration !== this.lifecycleGeneration) return;
|
|
326
|
+
await this.hydrateSubsetUnsafe(baseline, {
|
|
327
|
+
requestRemoteEnsure: false,
|
|
328
|
+
lifecycleGeneration
|
|
329
|
+
});
|
|
330
|
+
});
|
|
331
|
+
if (lifecycleGeneration !== this.lifecycleGeneration) return;
|
|
332
|
+
await this.waitForAppliedReceiptsAfter(appliedCursor);
|
|
333
|
+
}
|
|
311
334
|
async ensureStartupMetadataLoaded() {
|
|
312
335
|
if (this.startupMetadataPromise) {
|
|
313
336
|
return this.startupMetadataPromise;
|
|
314
337
|
}
|
|
315
|
-
|
|
338
|
+
const lifecycleGeneration = this.lifecycleGeneration;
|
|
339
|
+
this.startupMetadataPromise = this.loadStartupMetadataInternal(lifecycleGeneration);
|
|
316
340
|
return this.startupMetadataPromise;
|
|
317
341
|
}
|
|
318
|
-
async startInternal() {
|
|
342
|
+
async startInternal(lifecycleGeneration) {
|
|
319
343
|
if (this.started) {
|
|
320
344
|
return;
|
|
321
345
|
}
|
|
322
346
|
this.started = true;
|
|
323
347
|
await this.ensureStartupMetadataLoaded();
|
|
348
|
+
if (lifecycleGeneration !== this.lifecycleGeneration) return;
|
|
324
349
|
const indexBootstrapSnapshot = this.collection?.getIndexMetadata() ?? [];
|
|
325
350
|
this.attachIndexLifecycleListeners();
|
|
326
351
|
await this.bootstrapPersistedIndexes(indexBootstrapSnapshot);
|
|
352
|
+
if (lifecycleGeneration !== this.lifecycleGeneration) return;
|
|
327
353
|
if (this.syncMode !== `on-demand`) {
|
|
328
|
-
this.
|
|
329
|
-
const appliedCursor = this.appliedReceiptSequence;
|
|
330
|
-
await this.applyMutex.run(
|
|
331
|
-
() => this.hydrateSubsetUnsafe({}, { requestRemoteEnsure: false })
|
|
332
|
-
);
|
|
333
|
-
await this.waitForAppliedReceiptsAfter(appliedCursor);
|
|
354
|
+
await this.hydrateBaseline(lifecycleGeneration);
|
|
334
355
|
}
|
|
335
356
|
}
|
|
336
|
-
async loadStartupMetadataInternal() {
|
|
357
|
+
async loadStartupMetadataInternal(lifecycleGeneration) {
|
|
337
358
|
if (this.persistence.adapter.getStreamPosition) {
|
|
338
359
|
const position = await this.persistence.adapter.getStreamPosition(
|
|
339
360
|
this.collectionId
|
|
340
361
|
);
|
|
362
|
+
if (lifecycleGeneration !== this.lifecycleGeneration) return;
|
|
341
363
|
this.observeStreamPosition(
|
|
342
364
|
position.latestTerm,
|
|
343
365
|
position.latestSeq,
|
|
344
366
|
position.latestRowVersion
|
|
345
367
|
);
|
|
346
368
|
}
|
|
347
|
-
await this.loadCollectionMetadataIntoCollection();
|
|
348
|
-
}
|
|
349
|
-
async loadCollectionMetadataIntoCollection() {
|
|
350
369
|
const collectionMetadata = await this.loadCollectionMetadataSnapshot();
|
|
370
|
+
if (lifecycleGeneration !== this.lifecycleGeneration) return;
|
|
351
371
|
this.replaceCollectionMetadataSnapshot(collectionMetadata);
|
|
352
372
|
}
|
|
353
373
|
async loadCollectionMetadataSnapshot() {
|
|
@@ -378,40 +398,43 @@ class PersistedCollectionRuntime {
|
|
|
378
398
|
});
|
|
379
399
|
}
|
|
380
400
|
async loadSubset(options, upstreamLoadSubset) {
|
|
401
|
+
const lifecycleGeneration = this.lifecycleGeneration;
|
|
381
402
|
this.activeSubsets.set(this.getSubsetKey(options), options);
|
|
382
403
|
const appliedCursor = this.appliedReceiptSequence;
|
|
383
404
|
await this.applyMutex.run(
|
|
384
405
|
() => this.hydrateSubsetUnsafe(options, {
|
|
385
|
-
requestRemoteEnsure: this.mode === `sync-present
|
|
406
|
+
requestRemoteEnsure: this.mode === `sync-present`,
|
|
407
|
+
lifecycleGeneration
|
|
386
408
|
})
|
|
387
409
|
);
|
|
410
|
+
if (lifecycleGeneration !== this.lifecycleGeneration) return;
|
|
388
411
|
await this.waitForAppliedReceiptsAfter(appliedCursor);
|
|
389
412
|
if (upstreamLoadSubset) {
|
|
390
413
|
try {
|
|
391
|
-
|
|
392
|
-
if (maybePromise instanceof Promise) {
|
|
393
|
-
await maybePromise.catch((error) => {
|
|
394
|
-
console.warn(
|
|
395
|
-
`Failed to load remote subset in persisted wrapper:`,
|
|
396
|
-
error
|
|
397
|
-
);
|
|
398
|
-
this.queueRemoteSubsetEnsure(options);
|
|
399
|
-
});
|
|
400
|
-
}
|
|
414
|
+
await upstreamLoadSubset(options);
|
|
401
415
|
} catch (error) {
|
|
416
|
+
if (options.signal?.aborted || typeof error === `object` && error !== null && `name` in error && error.name === `AbortError`) {
|
|
417
|
+
this.pendingRemoteSubsetEnsures.delete(this.getSubsetKey(options));
|
|
418
|
+
throw error;
|
|
419
|
+
}
|
|
402
420
|
console.warn(`Failed to trigger remote subset load:`, error);
|
|
403
421
|
this.queueRemoteSubsetEnsure(options);
|
|
422
|
+
throw error;
|
|
404
423
|
}
|
|
405
424
|
}
|
|
406
425
|
}
|
|
407
426
|
unloadSubset(options, upstreamUnloadSubset) {
|
|
408
427
|
this.activeSubsets.delete(this.getSubsetKey(options));
|
|
428
|
+
this.pendingRemoteSubsetEnsures.delete(this.getSubsetKey(options));
|
|
409
429
|
upstreamUnloadSubset?.(options);
|
|
410
430
|
}
|
|
411
431
|
async forceReloadSubset(options) {
|
|
412
|
-
this.
|
|
432
|
+
const lifecycleGeneration = this.lifecycleGeneration;
|
|
413
433
|
await this.applyMutex.run(
|
|
414
|
-
() => this.hydrateSubsetUnsafe(options, {
|
|
434
|
+
() => this.hydrateSubsetUnsafe(options, {
|
|
435
|
+
requestRemoteEnsure: false,
|
|
436
|
+
lifecycleGeneration
|
|
437
|
+
})
|
|
415
438
|
);
|
|
416
439
|
}
|
|
417
440
|
queueHydrationBufferedTransaction(transaction) {
|
|
@@ -501,6 +524,7 @@ class PersistedCollectionRuntime {
|
|
|
501
524
|
await this.persistAndConfirmCollectionMutations(collectionMutations);
|
|
502
525
|
}
|
|
503
526
|
cleanup() {
|
|
527
|
+
this.advanceLifecycle();
|
|
504
528
|
this.coordinatorUnsubscribe?.();
|
|
505
529
|
this.coordinatorUnsubscribe = null;
|
|
506
530
|
this.indexAddedUnsubscribe?.();
|
|
@@ -519,6 +543,14 @@ class PersistedCollectionRuntime {
|
|
|
519
543
|
this.queuedHydrationTransactions.length = 0;
|
|
520
544
|
this.queuedTxCommitted.length = 0;
|
|
521
545
|
this.clearSyncControls();
|
|
546
|
+
this.collection = null;
|
|
547
|
+
}
|
|
548
|
+
advanceLifecycle() {
|
|
549
|
+
this.lifecycleGeneration++;
|
|
550
|
+
this.started = false;
|
|
551
|
+
this.startupMetadataPromise = null;
|
|
552
|
+
this.startPromise = null;
|
|
553
|
+
this.resumeBaselinePromise = null;
|
|
522
554
|
}
|
|
523
555
|
withInternalApply(task) {
|
|
524
556
|
this.internalApplyDepth++;
|
|
@@ -552,12 +584,15 @@ class PersistedCollectionRuntime {
|
|
|
552
584
|
return this.applyMutex.run(() => this.scanPersistedRowsUnsafe(options));
|
|
553
585
|
}
|
|
554
586
|
async hydrateSubsetUnsafe(options, config) {
|
|
555
|
-
this.
|
|
587
|
+
this.hydratingGeneration = config.lifecycleGeneration;
|
|
556
588
|
try {
|
|
557
589
|
const rows = await this.loadSubsetRowsUnsafe(options);
|
|
590
|
+
if (config.lifecycleGeneration !== this.lifecycleGeneration) return;
|
|
558
591
|
this.applyRowsToCollection(rows);
|
|
559
592
|
} finally {
|
|
560
|
-
this.
|
|
593
|
+
if (this.hydratingGeneration === config.lifecycleGeneration) {
|
|
594
|
+
this.hydratingGeneration = null;
|
|
595
|
+
}
|
|
561
596
|
}
|
|
562
597
|
await this.flushQueuedHydrationTransactionsUnsafe();
|
|
563
598
|
await this.flushQueuedTxCommittedUnsafe();
|
|
@@ -951,21 +986,15 @@ class PersistedCollectionRuntime {
|
|
|
951
986
|
};
|
|
952
987
|
}
|
|
953
988
|
getSubsetKey(options) {
|
|
954
|
-
|
|
955
|
-
if (
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
return existingId;
|
|
959
|
-
}
|
|
960
|
-
this.nextSubscriptionId++;
|
|
961
|
-
const id = `sub:${this.nextSubscriptionId}`;
|
|
962
|
-
this.subscriptionIds.set(subscription, id);
|
|
963
|
-
return id;
|
|
989
|
+
let id = this.requestIds.get(options);
|
|
990
|
+
if (id === void 0) {
|
|
991
|
+
id = `request:${++this.nextRequestId}`;
|
|
992
|
+
this.requestIds.set(options, id);
|
|
964
993
|
}
|
|
965
|
-
return
|
|
994
|
+
return id;
|
|
966
995
|
}
|
|
967
996
|
queueRemoteSubsetEnsure(options) {
|
|
968
|
-
if (this.mode !== `sync-present` || !this.persistence.coordinator.requestEnsureRemoteSubset) {
|
|
997
|
+
if (this.mode !== `sync-present` || !this.persistence.coordinator.requestEnsureRemoteSubset || this.activeSubsets.get(this.getSubsetKey(options)) !== options) {
|
|
969
998
|
return;
|
|
970
999
|
}
|
|
971
1000
|
this.pendingRemoteSubsetEnsures.set(this.getSubsetKey(options), options);
|
|
@@ -1022,7 +1051,7 @@ class PersistedCollectionRuntime {
|
|
|
1022
1051
|
const { payload } = message;
|
|
1023
1052
|
const isSelf = message.senderId === this.persistence.coordinator.getNodeId();
|
|
1024
1053
|
if (isTxCommittedPayload(payload)) {
|
|
1025
|
-
if (this.
|
|
1054
|
+
if (this.isHydratingNow()) {
|
|
1026
1055
|
this.queuedTxCommitted.push(payload);
|
|
1027
1056
|
return;
|
|
1028
1057
|
}
|
|
@@ -1192,13 +1221,16 @@ class PersistedCollectionRuntime {
|
|
|
1192
1221
|
});
|
|
1193
1222
|
}
|
|
1194
1223
|
async reloadActiveSubsetsUnsafe() {
|
|
1224
|
+
const lifecycleGeneration = this.lifecycleGeneration;
|
|
1195
1225
|
const activeSubsetOptions = this.activeSubsets.size > 0 ? Array.from(this.activeSubsets.values()) : [{}];
|
|
1196
|
-
this.
|
|
1226
|
+
this.hydratingGeneration = lifecycleGeneration;
|
|
1197
1227
|
try {
|
|
1198
1228
|
const mergedRows = /* @__PURE__ */ new Map();
|
|
1199
1229
|
const collectionMetadata = await this.loadCollectionMetadataSnapshot();
|
|
1230
|
+
if (lifecycleGeneration !== this.lifecycleGeneration) return;
|
|
1200
1231
|
for (const options of activeSubsetOptions) {
|
|
1201
1232
|
const subsetRows = await this.loadSubsetRowsUnsafe(options);
|
|
1233
|
+
if (lifecycleGeneration !== this.lifecycleGeneration) return;
|
|
1202
1234
|
for (const row of subsetRows) {
|
|
1203
1235
|
mergedRows.set(row.key, {
|
|
1204
1236
|
value: row.value,
|
|
@@ -1215,7 +1247,9 @@ class PersistedCollectionRuntime {
|
|
|
1215
1247
|
collectionMetadata
|
|
1216
1248
|
);
|
|
1217
1249
|
} finally {
|
|
1218
|
-
this.
|
|
1250
|
+
if (this.hydratingGeneration === lifecycleGeneration) {
|
|
1251
|
+
this.hydratingGeneration = null;
|
|
1252
|
+
}
|
|
1219
1253
|
}
|
|
1220
1254
|
await this.flushQueuedHydrationTransactionsUnsafe();
|
|
1221
1255
|
await this.flushQueuedTxCommittedUnsafe();
|
|
@@ -1299,23 +1333,8 @@ function createWrappedSyncConfig(sourceSyncConfig, runtime) {
|
|
|
1299
1333
|
const transactionStack = [];
|
|
1300
1334
|
const getOpenTransaction = () => transactionStack[transactionStack.length - 1];
|
|
1301
1335
|
let fullStartPromise = null;
|
|
1302
|
-
const
|
|
1303
|
-
const
|
|
1304
|
-
let nextLoadSubscriptionId = 0;
|
|
1305
|
-
const getLoadKey = (options) => {
|
|
1306
|
-
const subscription = options.subscription;
|
|
1307
|
-
if (subscription && typeof subscription === `object`) {
|
|
1308
|
-
const existingId = loadSubscriptionIds.get(subscription);
|
|
1309
|
-
if (existingId) {
|
|
1310
|
-
return `sub:${existingId}`;
|
|
1311
|
-
}
|
|
1312
|
-
nextLoadSubscriptionId++;
|
|
1313
|
-
const nextId = String(nextLoadSubscriptionId);
|
|
1314
|
-
loadSubscriptionIds.set(subscription, nextId);
|
|
1315
|
-
return `sub:${nextId}`;
|
|
1316
|
-
}
|
|
1317
|
-
return `opts:${stableSerialize(normalizeSubsetOptionsForKey(options))}`;
|
|
1318
|
-
};
|
|
1336
|
+
const startupState = { cleanedUp: false };
|
|
1337
|
+
const acquisitions = /* @__PURE__ */ new Map();
|
|
1319
1338
|
runtime.setSyncControls({
|
|
1320
1339
|
begin: params.begin,
|
|
1321
1340
|
write: params.write,
|
|
@@ -1329,9 +1348,12 @@ function createWrappedSyncConfig(sourceSyncConfig, runtime) {
|
|
|
1329
1348
|
const wrappedParams = {
|
|
1330
1349
|
...params,
|
|
1331
1350
|
markReady: () => {
|
|
1351
|
+
if (startupState.cleanedUp) return;
|
|
1332
1352
|
void (fullStartPromise ?? runtime.ensureStarted()).then(() => {
|
|
1353
|
+
if (startupState.cleanedUp) return;
|
|
1333
1354
|
params.markReady();
|
|
1334
1355
|
}).catch((error) => {
|
|
1356
|
+
if (startupState.cleanedUp) return;
|
|
1335
1357
|
console.warn(
|
|
1336
1358
|
`Failed persisted sync startup before markReady:`,
|
|
1337
1359
|
error
|
|
@@ -1340,6 +1362,7 @@ function createWrappedSyncConfig(sourceSyncConfig, runtime) {
|
|
|
1340
1362
|
});
|
|
1341
1363
|
},
|
|
1342
1364
|
begin: (options) => {
|
|
1365
|
+
if (startupState.cleanedUp) return;
|
|
1343
1366
|
const transaction = {
|
|
1344
1367
|
operations: [],
|
|
1345
1368
|
rowMetadataWrites: /* @__PURE__ */ new Map(),
|
|
@@ -1354,6 +1377,7 @@ function createWrappedSyncConfig(sourceSyncConfig, runtime) {
|
|
|
1354
1377
|
}
|
|
1355
1378
|
},
|
|
1356
1379
|
write: (message) => {
|
|
1380
|
+
if (startupState.cleanedUp) return;
|
|
1357
1381
|
const normalization = runtime.normalizeSyncWriteMessage(message);
|
|
1358
1382
|
const openTransaction = getOpenTransaction();
|
|
1359
1383
|
if (!openTransaction) {
|
|
@@ -1388,7 +1412,9 @@ function createWrappedSyncConfig(sourceSyncConfig, runtime) {
|
|
|
1388
1412
|
},
|
|
1389
1413
|
metadata: params.metadata ? {
|
|
1390
1414
|
row: {
|
|
1415
|
+
whenHydrated: () => startupState.cleanedUp ? Promise.resolve() : runtime.ensureResumeBaselineHydrated(),
|
|
1391
1416
|
get: (key) => {
|
|
1417
|
+
if (startupState.cleanedUp) return void 0;
|
|
1392
1418
|
const openTransaction = getOpenTransaction();
|
|
1393
1419
|
const pendingWrite = openTransaction?.rowMetadataWrites.get(key);
|
|
1394
1420
|
if (pendingWrite) {
|
|
@@ -1399,8 +1425,9 @@ function createWrappedSyncConfig(sourceSyncConfig, runtime) {
|
|
|
1399
1425
|
}
|
|
1400
1426
|
return params.metadata.row.get(key);
|
|
1401
1427
|
},
|
|
1402
|
-
scanPersisted: (options) => runtime.scanPersistedRows(options),
|
|
1428
|
+
scanPersisted: (options) => startupState.cleanedUp ? Promise.resolve([]) : runtime.scanPersistedRows(options),
|
|
1403
1429
|
set: (key, value) => {
|
|
1430
|
+
if (startupState.cleanedUp) return;
|
|
1404
1431
|
const openTransaction = getOpenTransaction();
|
|
1405
1432
|
if (!openTransaction) {
|
|
1406
1433
|
throw new errors.InvalidPersistedCollectionConfigError(
|
|
@@ -1416,6 +1443,7 @@ function createWrappedSyncConfig(sourceSyncConfig, runtime) {
|
|
|
1416
1443
|
}
|
|
1417
1444
|
},
|
|
1418
1445
|
delete: (key) => {
|
|
1446
|
+
if (startupState.cleanedUp) return;
|
|
1419
1447
|
const openTransaction = getOpenTransaction();
|
|
1420
1448
|
if (!openTransaction) {
|
|
1421
1449
|
throw new errors.InvalidPersistedCollectionConfigError(
|
|
@@ -1432,6 +1460,7 @@ function createWrappedSyncConfig(sourceSyncConfig, runtime) {
|
|
|
1432
1460
|
},
|
|
1433
1461
|
collection: {
|
|
1434
1462
|
get: (key) => {
|
|
1463
|
+
if (startupState.cleanedUp) return void 0;
|
|
1435
1464
|
const openTransaction = getOpenTransaction();
|
|
1436
1465
|
const pendingWrite = openTransaction?.collectionMetadataWrites.get(key);
|
|
1437
1466
|
if (pendingWrite) {
|
|
@@ -1440,6 +1469,7 @@ function createWrappedSyncConfig(sourceSyncConfig, runtime) {
|
|
|
1440
1469
|
return params.metadata.collection.get(key);
|
|
1441
1470
|
},
|
|
1442
1471
|
set: (key, value) => {
|
|
1472
|
+
if (startupState.cleanedUp) return;
|
|
1443
1473
|
const openTransaction = getOpenTransaction();
|
|
1444
1474
|
if (!openTransaction) {
|
|
1445
1475
|
throw new errors.InvalidPersistedCollectionConfigError(
|
|
@@ -1455,6 +1485,7 @@ function createWrappedSyncConfig(sourceSyncConfig, runtime) {
|
|
|
1455
1485
|
}
|
|
1456
1486
|
},
|
|
1457
1487
|
delete: (key) => {
|
|
1488
|
+
if (startupState.cleanedUp) return;
|
|
1458
1489
|
const openTransaction = getOpenTransaction();
|
|
1459
1490
|
if (!openTransaction) {
|
|
1460
1491
|
throw new errors.InvalidPersistedCollectionConfigError(
|
|
@@ -1469,6 +1500,7 @@ function createWrappedSyncConfig(sourceSyncConfig, runtime) {
|
|
|
1469
1500
|
}
|
|
1470
1501
|
},
|
|
1471
1502
|
list: (prefix) => {
|
|
1503
|
+
if (startupState.cleanedUp) return [];
|
|
1472
1504
|
const merged = new Map(
|
|
1473
1505
|
params.metadata.collection.list().map(({ key, value }) => [key, value])
|
|
1474
1506
|
);
|
|
@@ -1493,6 +1525,7 @@ function createWrappedSyncConfig(sourceSyncConfig, runtime) {
|
|
|
1493
1525
|
}
|
|
1494
1526
|
} : void 0,
|
|
1495
1527
|
truncate: () => {
|
|
1528
|
+
if (startupState.cleanedUp) return;
|
|
1496
1529
|
const openTransaction = getOpenTransaction();
|
|
1497
1530
|
if (!openTransaction) {
|
|
1498
1531
|
params.truncate();
|
|
@@ -1506,6 +1539,7 @@ function createWrappedSyncConfig(sourceSyncConfig, runtime) {
|
|
|
1506
1539
|
}
|
|
1507
1540
|
},
|
|
1508
1541
|
commit: (signal) => {
|
|
1542
|
+
if (startupState.cleanedUp) return true;
|
|
1509
1543
|
const openTransaction = transactionStack.pop();
|
|
1510
1544
|
if (!openTransaction) {
|
|
1511
1545
|
return params.commit(signal);
|
|
@@ -1555,7 +1589,6 @@ function createWrappedSyncConfig(sourceSyncConfig, runtime) {
|
|
|
1555
1589
|
}
|
|
1556
1590
|
};
|
|
1557
1591
|
let sourceResult = {};
|
|
1558
|
-
const startupState = { cleanedUp: false };
|
|
1559
1592
|
fullStartPromise = runtime.ensureStarted();
|
|
1560
1593
|
const sourceResultPromise = (async () => {
|
|
1561
1594
|
await runtime.ensureStartupMetadataLoaded();
|
|
@@ -1570,23 +1603,40 @@ function createWrappedSyncConfig(sourceSyncConfig, runtime) {
|
|
|
1570
1603
|
return {
|
|
1571
1604
|
cleanup: () => {
|
|
1572
1605
|
startupState.cleanedUp = true;
|
|
1606
|
+
acquisitions.clear();
|
|
1573
1607
|
sourceResult.cleanup?.();
|
|
1574
1608
|
runtime.cleanup();
|
|
1575
1609
|
runtime.clearSyncControls();
|
|
1576
1610
|
},
|
|
1577
1611
|
loadSubset: async (options) => {
|
|
1578
|
-
const
|
|
1579
|
-
|
|
1612
|
+
const acquisition = { forwarded: false };
|
|
1613
|
+
acquisitions.set(options, acquisition);
|
|
1580
1614
|
await fullStartPromise;
|
|
1581
1615
|
const resolvedSourceResult = await sourceResultPromise;
|
|
1582
|
-
if (startupState.cleanedUp ||
|
|
1616
|
+
if (startupState.cleanedUp || acquisitions.get(options) !== acquisition) {
|
|
1583
1617
|
return;
|
|
1584
1618
|
}
|
|
1585
|
-
|
|
1619
|
+
return runtime.loadSubset(options, (loadOptions) => {
|
|
1620
|
+
if (startupState.cleanedUp || acquisitions.get(options) !== acquisition) {
|
|
1621
|
+
return true;
|
|
1622
|
+
}
|
|
1623
|
+
if (!resolvedSourceResult.loadSubset) return true;
|
|
1624
|
+
acquisition.forwarded = true;
|
|
1625
|
+
try {
|
|
1626
|
+
return resolvedSourceResult.loadSubset(loadOptions);
|
|
1627
|
+
} catch (error) {
|
|
1628
|
+
acquisition.forwarded = false;
|
|
1629
|
+
throw error;
|
|
1630
|
+
}
|
|
1631
|
+
});
|
|
1586
1632
|
},
|
|
1587
1633
|
unloadSubset: (options) => {
|
|
1588
|
-
|
|
1589
|
-
|
|
1634
|
+
const acquisition = acquisitions.get(options);
|
|
1635
|
+
acquisitions.delete(options);
|
|
1636
|
+
runtime.unloadSubset(
|
|
1637
|
+
options,
|
|
1638
|
+
acquisition?.forwarded ? sourceResult.unloadSubset : void 0
|
|
1639
|
+
);
|
|
1590
1640
|
}
|
|
1591
1641
|
};
|
|
1592
1642
|
}
|