@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.
@@ -248,6 +248,7 @@ export interface PersistedCollectionUtils extends UtilsRecord {
248
248
  mutations: Array<PendingMutation<Record<string, unknown>>>;
249
249
  }) => Promise<void> | void;
250
250
  getLeadershipState?: () => PersistedCollectionLeadershipState;
251
+ /** Hydrate once without acquiring a new ongoing subset lease. */
251
252
  forceReloadSubset?: (options: LoadSubsetOptions) => Promise<void> | void;
252
253
  }
253
254
  export type PersistedSyncWrappedOptions<T extends object, TKey extends string | number, TSchema extends StandardSchemaV1 = never, TUtils extends UtilsRecord = UtilsRecord> = CollectionConfig<T, TKey, TSchema, TUtils> & {
@@ -248,6 +248,7 @@ export interface PersistedCollectionUtils extends UtilsRecord {
248
248
  mutations: Array<PendingMutation<Record<string, unknown>>>;
249
249
  }) => Promise<void> | void;
250
250
  getLeadershipState?: () => PersistedCollectionLeadershipState;
251
+ /** Hydrate once without acquiring a new ongoing subset lease. */
251
252
  forceReloadSubset?: (options: LoadSubsetOptions) => Promise<void> | void;
252
253
  }
253
254
  export type PersistedSyncWrappedOptions<T extends object, TKey extends string | number, TSchema extends StandardSchemaV1 = never, TUtils extends UtilsRecord = UtilsRecord> = CollectionConfig<T, TKey, TSchema, TUtils> & {
@@ -163,15 +163,6 @@ function toStableSerializable(value) {
163
163
  function stableSerialize(value) {
164
164
  return JSON.stringify(toStableSerializable(value) ?? null);
165
165
  }
166
- function normalizeSubsetOptionsForKey(options) {
167
- return {
168
- where: toStableSerializable(options.where),
169
- orderBy: toStableSerializable(options.orderBy),
170
- limit: options.limit,
171
- cursor: toStableSerializable(options.cursor),
172
- offset: options.offset
173
- };
174
- }
175
166
  function normalizeSyncFnResult(result) {
176
167
  if (typeof result === `function`) {
177
168
  return { cleanup: result };
@@ -218,7 +209,7 @@ class PersistedCollectionRuntime {
218
209
  this.pendingRemoteSubsetEnsures = /* @__PURE__ */ new Map();
219
210
  this.queuedHydrationTransactions = [];
220
211
  this.queuedTxCommitted = [];
221
- this.subscriptionIds = /* @__PURE__ */ new WeakMap();
212
+ this.requestIds = /* @__PURE__ */ new WeakMap();
222
213
  this.collection = null;
223
214
  this.syncControls = {
224
215
  begin: null,
@@ -230,15 +221,17 @@ class PersistedCollectionRuntime {
230
221
  this.started = false;
231
222
  this.startupMetadataPromise = null;
232
223
  this.startPromise = null;
224
+ this.resumeBaselinePromise = null;
225
+ this.lifecycleGeneration = 0;
233
226
  this.internalApplyDepth = 0;
234
227
  this.appliedReceiptSequence = 0;
235
228
  this.pendingAppliedReceipts = /* @__PURE__ */ new Map();
236
- this.isHydrating = false;
229
+ this.hydratingGeneration = null;
237
230
  this.coordinatorUnsubscribe = null;
238
231
  this.indexAddedUnsubscribe = null;
239
232
  this.indexRemovedUnsubscribe = null;
240
233
  this.remoteEnsureRetryTimer = null;
241
- this.nextSubscriptionId = 0;
234
+ this.nextRequestId = 0;
242
235
  this.latestTerm = 0;
243
236
  this.latestSeq = 0;
244
237
  this.latestRowVersion = 0;
@@ -247,6 +240,7 @@ class PersistedCollectionRuntime {
247
240
  this.localRowVersion = 0;
248
241
  }
249
242
  setSyncControls(syncControls) {
243
+ this.advanceLifecycle();
250
244
  const commit = syncControls.commit;
251
245
  this.syncControls = {
252
246
  ...syncControls,
@@ -281,7 +275,7 @@ class PersistedCollectionRuntime {
281
275
  };
282
276
  }
283
277
  isHydratingNow() {
284
- return this.isHydrating;
278
+ return this.hydratingGeneration === this.lifecycleGeneration;
285
279
  }
286
280
  isApplyingInternally() {
287
281
  return this.internalApplyDepth > 0;
@@ -303,49 +297,75 @@ class PersistedCollectionRuntime {
303
297
  if (this.startPromise) {
304
298
  return this.startPromise;
305
299
  }
306
- this.startPromise = this.startInternal();
300
+ const lifecycleGeneration = this.lifecycleGeneration;
301
+ this.startPromise = this.startInternal(lifecycleGeneration);
307
302
  return this.startPromise;
308
303
  }
304
+ ensureResumeBaselineHydrated() {
305
+ if (this.resumeBaselinePromise) {
306
+ return this.resumeBaselinePromise;
307
+ }
308
+ const lifecycleGeneration = this.lifecycleGeneration;
309
+ this.resumeBaselinePromise = (async () => {
310
+ await this.ensureStarted();
311
+ if (lifecycleGeneration !== this.lifecycleGeneration) return;
312
+ if (this.syncMode !== `on-demand`) return;
313
+ await this.hydrateBaseline(lifecycleGeneration);
314
+ })();
315
+ return this.resumeBaselinePromise;
316
+ }
317
+ async hydrateBaseline(lifecycleGeneration) {
318
+ if (lifecycleGeneration !== this.lifecycleGeneration) return;
319
+ const baseline = {};
320
+ this.activeSubsets.set(this.getSubsetKey(baseline), baseline);
321
+ const appliedCursor = this.appliedReceiptSequence;
322
+ await this.applyMutex.run(async () => {
323
+ if (lifecycleGeneration !== this.lifecycleGeneration) return;
324
+ await this.hydrateSubsetUnsafe(baseline, {
325
+ requestRemoteEnsure: false,
326
+ lifecycleGeneration
327
+ });
328
+ });
329
+ if (lifecycleGeneration !== this.lifecycleGeneration) return;
330
+ await this.waitForAppliedReceiptsAfter(appliedCursor);
331
+ }
309
332
  async ensureStartupMetadataLoaded() {
310
333
  if (this.startupMetadataPromise) {
311
334
  return this.startupMetadataPromise;
312
335
  }
313
- this.startupMetadataPromise = this.loadStartupMetadataInternal();
336
+ const lifecycleGeneration = this.lifecycleGeneration;
337
+ this.startupMetadataPromise = this.loadStartupMetadataInternal(lifecycleGeneration);
314
338
  return this.startupMetadataPromise;
315
339
  }
316
- async startInternal() {
340
+ async startInternal(lifecycleGeneration) {
317
341
  if (this.started) {
318
342
  return;
319
343
  }
320
344
  this.started = true;
321
345
  await this.ensureStartupMetadataLoaded();
346
+ if (lifecycleGeneration !== this.lifecycleGeneration) return;
322
347
  const indexBootstrapSnapshot = this.collection?.getIndexMetadata() ?? [];
323
348
  this.attachIndexLifecycleListeners();
324
349
  await this.bootstrapPersistedIndexes(indexBootstrapSnapshot);
350
+ if (lifecycleGeneration !== this.lifecycleGeneration) return;
325
351
  if (this.syncMode !== `on-demand`) {
326
- this.activeSubsets.set(this.getSubsetKey({}), {});
327
- const appliedCursor = this.appliedReceiptSequence;
328
- await this.applyMutex.run(
329
- () => this.hydrateSubsetUnsafe({}, { requestRemoteEnsure: false })
330
- );
331
- await this.waitForAppliedReceiptsAfter(appliedCursor);
352
+ await this.hydrateBaseline(lifecycleGeneration);
332
353
  }
333
354
  }
334
- async loadStartupMetadataInternal() {
355
+ async loadStartupMetadataInternal(lifecycleGeneration) {
335
356
  if (this.persistence.adapter.getStreamPosition) {
336
357
  const position = await this.persistence.adapter.getStreamPosition(
337
358
  this.collectionId
338
359
  );
360
+ if (lifecycleGeneration !== this.lifecycleGeneration) return;
339
361
  this.observeStreamPosition(
340
362
  position.latestTerm,
341
363
  position.latestSeq,
342
364
  position.latestRowVersion
343
365
  );
344
366
  }
345
- await this.loadCollectionMetadataIntoCollection();
346
- }
347
- async loadCollectionMetadataIntoCollection() {
348
367
  const collectionMetadata = await this.loadCollectionMetadataSnapshot();
368
+ if (lifecycleGeneration !== this.lifecycleGeneration) return;
349
369
  this.replaceCollectionMetadataSnapshot(collectionMetadata);
350
370
  }
351
371
  async loadCollectionMetadataSnapshot() {
@@ -376,40 +396,43 @@ class PersistedCollectionRuntime {
376
396
  });
377
397
  }
378
398
  async loadSubset(options, upstreamLoadSubset) {
399
+ const lifecycleGeneration = this.lifecycleGeneration;
379
400
  this.activeSubsets.set(this.getSubsetKey(options), options);
380
401
  const appliedCursor = this.appliedReceiptSequence;
381
402
  await this.applyMutex.run(
382
403
  () => this.hydrateSubsetUnsafe(options, {
383
- requestRemoteEnsure: this.mode === `sync-present`
404
+ requestRemoteEnsure: this.mode === `sync-present`,
405
+ lifecycleGeneration
384
406
  })
385
407
  );
408
+ if (lifecycleGeneration !== this.lifecycleGeneration) return;
386
409
  await this.waitForAppliedReceiptsAfter(appliedCursor);
387
410
  if (upstreamLoadSubset) {
388
411
  try {
389
- const maybePromise = upstreamLoadSubset(options);
390
- if (maybePromise instanceof Promise) {
391
- await maybePromise.catch((error) => {
392
- console.warn(
393
- `Failed to load remote subset in persisted wrapper:`,
394
- error
395
- );
396
- this.queueRemoteSubsetEnsure(options);
397
- });
398
- }
412
+ await upstreamLoadSubset(options);
399
413
  } catch (error) {
414
+ if (options.signal?.aborted || typeof error === `object` && error !== null && `name` in error && error.name === `AbortError`) {
415
+ this.pendingRemoteSubsetEnsures.delete(this.getSubsetKey(options));
416
+ throw error;
417
+ }
400
418
  console.warn(`Failed to trigger remote subset load:`, error);
401
419
  this.queueRemoteSubsetEnsure(options);
420
+ throw error;
402
421
  }
403
422
  }
404
423
  }
405
424
  unloadSubset(options, upstreamUnloadSubset) {
406
425
  this.activeSubsets.delete(this.getSubsetKey(options));
426
+ this.pendingRemoteSubsetEnsures.delete(this.getSubsetKey(options));
407
427
  upstreamUnloadSubset?.(options);
408
428
  }
409
429
  async forceReloadSubset(options) {
410
- this.activeSubsets.set(this.getSubsetKey(options), options);
430
+ const lifecycleGeneration = this.lifecycleGeneration;
411
431
  await this.applyMutex.run(
412
- () => this.hydrateSubsetUnsafe(options, { requestRemoteEnsure: false })
432
+ () => this.hydrateSubsetUnsafe(options, {
433
+ requestRemoteEnsure: false,
434
+ lifecycleGeneration
435
+ })
413
436
  );
414
437
  }
415
438
  queueHydrationBufferedTransaction(transaction) {
@@ -499,6 +522,7 @@ class PersistedCollectionRuntime {
499
522
  await this.persistAndConfirmCollectionMutations(collectionMutations);
500
523
  }
501
524
  cleanup() {
525
+ this.advanceLifecycle();
502
526
  this.coordinatorUnsubscribe?.();
503
527
  this.coordinatorUnsubscribe = null;
504
528
  this.indexAddedUnsubscribe?.();
@@ -517,6 +541,14 @@ class PersistedCollectionRuntime {
517
541
  this.queuedHydrationTransactions.length = 0;
518
542
  this.queuedTxCommitted.length = 0;
519
543
  this.clearSyncControls();
544
+ this.collection = null;
545
+ }
546
+ advanceLifecycle() {
547
+ this.lifecycleGeneration++;
548
+ this.started = false;
549
+ this.startupMetadataPromise = null;
550
+ this.startPromise = null;
551
+ this.resumeBaselinePromise = null;
520
552
  }
521
553
  withInternalApply(task) {
522
554
  this.internalApplyDepth++;
@@ -550,12 +582,15 @@ class PersistedCollectionRuntime {
550
582
  return this.applyMutex.run(() => this.scanPersistedRowsUnsafe(options));
551
583
  }
552
584
  async hydrateSubsetUnsafe(options, config) {
553
- this.isHydrating = true;
585
+ this.hydratingGeneration = config.lifecycleGeneration;
554
586
  try {
555
587
  const rows = await this.loadSubsetRowsUnsafe(options);
588
+ if (config.lifecycleGeneration !== this.lifecycleGeneration) return;
556
589
  this.applyRowsToCollection(rows);
557
590
  } finally {
558
- this.isHydrating = false;
591
+ if (this.hydratingGeneration === config.lifecycleGeneration) {
592
+ this.hydratingGeneration = null;
593
+ }
559
594
  }
560
595
  await this.flushQueuedHydrationTransactionsUnsafe();
561
596
  await this.flushQueuedTxCommittedUnsafe();
@@ -949,21 +984,15 @@ class PersistedCollectionRuntime {
949
984
  };
950
985
  }
951
986
  getSubsetKey(options) {
952
- const subscription = options.subscription;
953
- if (subscription && typeof subscription === `object`) {
954
- const existingId = this.subscriptionIds.get(subscription);
955
- if (existingId) {
956
- return existingId;
957
- }
958
- this.nextSubscriptionId++;
959
- const id = `sub:${this.nextSubscriptionId}`;
960
- this.subscriptionIds.set(subscription, id);
961
- return id;
987
+ let id = this.requestIds.get(options);
988
+ if (id === void 0) {
989
+ id = `request:${++this.nextRequestId}`;
990
+ this.requestIds.set(options, id);
962
991
  }
963
- return `opts:${stableSerialize(normalizeSubsetOptionsForKey(options))}`;
992
+ return id;
964
993
  }
965
994
  queueRemoteSubsetEnsure(options) {
966
- if (this.mode !== `sync-present` || !this.persistence.coordinator.requestEnsureRemoteSubset) {
995
+ if (this.mode !== `sync-present` || !this.persistence.coordinator.requestEnsureRemoteSubset || this.activeSubsets.get(this.getSubsetKey(options)) !== options) {
967
996
  return;
968
997
  }
969
998
  this.pendingRemoteSubsetEnsures.set(this.getSubsetKey(options), options);
@@ -1020,7 +1049,7 @@ class PersistedCollectionRuntime {
1020
1049
  const { payload } = message;
1021
1050
  const isSelf = message.senderId === this.persistence.coordinator.getNodeId();
1022
1051
  if (isTxCommittedPayload(payload)) {
1023
- if (this.isHydrating) {
1052
+ if (this.isHydratingNow()) {
1024
1053
  this.queuedTxCommitted.push(payload);
1025
1054
  return;
1026
1055
  }
@@ -1190,13 +1219,16 @@ class PersistedCollectionRuntime {
1190
1219
  });
1191
1220
  }
1192
1221
  async reloadActiveSubsetsUnsafe() {
1222
+ const lifecycleGeneration = this.lifecycleGeneration;
1193
1223
  const activeSubsetOptions = this.activeSubsets.size > 0 ? Array.from(this.activeSubsets.values()) : [{}];
1194
- this.isHydrating = true;
1224
+ this.hydratingGeneration = lifecycleGeneration;
1195
1225
  try {
1196
1226
  const mergedRows = /* @__PURE__ */ new Map();
1197
1227
  const collectionMetadata = await this.loadCollectionMetadataSnapshot();
1228
+ if (lifecycleGeneration !== this.lifecycleGeneration) return;
1198
1229
  for (const options of activeSubsetOptions) {
1199
1230
  const subsetRows = await this.loadSubsetRowsUnsafe(options);
1231
+ if (lifecycleGeneration !== this.lifecycleGeneration) return;
1200
1232
  for (const row of subsetRows) {
1201
1233
  mergedRows.set(row.key, {
1202
1234
  value: row.value,
@@ -1213,7 +1245,9 @@ class PersistedCollectionRuntime {
1213
1245
  collectionMetadata
1214
1246
  );
1215
1247
  } finally {
1216
- this.isHydrating = false;
1248
+ if (this.hydratingGeneration === lifecycleGeneration) {
1249
+ this.hydratingGeneration = null;
1250
+ }
1217
1251
  }
1218
1252
  await this.flushQueuedHydrationTransactionsUnsafe();
1219
1253
  await this.flushQueuedTxCommittedUnsafe();
@@ -1297,23 +1331,8 @@ function createWrappedSyncConfig(sourceSyncConfig, runtime) {
1297
1331
  const transactionStack = [];
1298
1332
  const getOpenTransaction = () => transactionStack[transactionStack.length - 1];
1299
1333
  let fullStartPromise = null;
1300
- const cancelledLoadKeys = /* @__PURE__ */ new Set();
1301
- const loadSubscriptionIds = /* @__PURE__ */ new WeakMap();
1302
- let nextLoadSubscriptionId = 0;
1303
- const getLoadKey = (options) => {
1304
- const subscription = options.subscription;
1305
- if (subscription && typeof subscription === `object`) {
1306
- const existingId = loadSubscriptionIds.get(subscription);
1307
- if (existingId) {
1308
- return `sub:${existingId}`;
1309
- }
1310
- nextLoadSubscriptionId++;
1311
- const nextId = String(nextLoadSubscriptionId);
1312
- loadSubscriptionIds.set(subscription, nextId);
1313
- return `sub:${nextId}`;
1314
- }
1315
- return `opts:${stableSerialize(normalizeSubsetOptionsForKey(options))}`;
1316
- };
1334
+ const startupState = { cleanedUp: false };
1335
+ const acquisitions = /* @__PURE__ */ new Map();
1317
1336
  runtime.setSyncControls({
1318
1337
  begin: params.begin,
1319
1338
  write: params.write,
@@ -1327,9 +1346,12 @@ function createWrappedSyncConfig(sourceSyncConfig, runtime) {
1327
1346
  const wrappedParams = {
1328
1347
  ...params,
1329
1348
  markReady: () => {
1349
+ if (startupState.cleanedUp) return;
1330
1350
  void (fullStartPromise ?? runtime.ensureStarted()).then(() => {
1351
+ if (startupState.cleanedUp) return;
1331
1352
  params.markReady();
1332
1353
  }).catch((error) => {
1354
+ if (startupState.cleanedUp) return;
1333
1355
  console.warn(
1334
1356
  `Failed persisted sync startup before markReady:`,
1335
1357
  error
@@ -1338,6 +1360,7 @@ function createWrappedSyncConfig(sourceSyncConfig, runtime) {
1338
1360
  });
1339
1361
  },
1340
1362
  begin: (options) => {
1363
+ if (startupState.cleanedUp) return;
1341
1364
  const transaction = {
1342
1365
  operations: [],
1343
1366
  rowMetadataWrites: /* @__PURE__ */ new Map(),
@@ -1352,6 +1375,7 @@ function createWrappedSyncConfig(sourceSyncConfig, runtime) {
1352
1375
  }
1353
1376
  },
1354
1377
  write: (message) => {
1378
+ if (startupState.cleanedUp) return;
1355
1379
  const normalization = runtime.normalizeSyncWriteMessage(message);
1356
1380
  const openTransaction = getOpenTransaction();
1357
1381
  if (!openTransaction) {
@@ -1386,7 +1410,9 @@ function createWrappedSyncConfig(sourceSyncConfig, runtime) {
1386
1410
  },
1387
1411
  metadata: params.metadata ? {
1388
1412
  row: {
1413
+ whenHydrated: () => startupState.cleanedUp ? Promise.resolve() : runtime.ensureResumeBaselineHydrated(),
1389
1414
  get: (key) => {
1415
+ if (startupState.cleanedUp) return void 0;
1390
1416
  const openTransaction = getOpenTransaction();
1391
1417
  const pendingWrite = openTransaction?.rowMetadataWrites.get(key);
1392
1418
  if (pendingWrite) {
@@ -1397,8 +1423,9 @@ function createWrappedSyncConfig(sourceSyncConfig, runtime) {
1397
1423
  }
1398
1424
  return params.metadata.row.get(key);
1399
1425
  },
1400
- scanPersisted: (options) => runtime.scanPersistedRows(options),
1426
+ scanPersisted: (options) => startupState.cleanedUp ? Promise.resolve([]) : runtime.scanPersistedRows(options),
1401
1427
  set: (key, value) => {
1428
+ if (startupState.cleanedUp) return;
1402
1429
  const openTransaction = getOpenTransaction();
1403
1430
  if (!openTransaction) {
1404
1431
  throw new InvalidPersistedCollectionConfigError(
@@ -1414,6 +1441,7 @@ function createWrappedSyncConfig(sourceSyncConfig, runtime) {
1414
1441
  }
1415
1442
  },
1416
1443
  delete: (key) => {
1444
+ if (startupState.cleanedUp) return;
1417
1445
  const openTransaction = getOpenTransaction();
1418
1446
  if (!openTransaction) {
1419
1447
  throw new InvalidPersistedCollectionConfigError(
@@ -1430,6 +1458,7 @@ function createWrappedSyncConfig(sourceSyncConfig, runtime) {
1430
1458
  },
1431
1459
  collection: {
1432
1460
  get: (key) => {
1461
+ if (startupState.cleanedUp) return void 0;
1433
1462
  const openTransaction = getOpenTransaction();
1434
1463
  const pendingWrite = openTransaction?.collectionMetadataWrites.get(key);
1435
1464
  if (pendingWrite) {
@@ -1438,6 +1467,7 @@ function createWrappedSyncConfig(sourceSyncConfig, runtime) {
1438
1467
  return params.metadata.collection.get(key);
1439
1468
  },
1440
1469
  set: (key, value) => {
1470
+ if (startupState.cleanedUp) return;
1441
1471
  const openTransaction = getOpenTransaction();
1442
1472
  if (!openTransaction) {
1443
1473
  throw new InvalidPersistedCollectionConfigError(
@@ -1453,6 +1483,7 @@ function createWrappedSyncConfig(sourceSyncConfig, runtime) {
1453
1483
  }
1454
1484
  },
1455
1485
  delete: (key) => {
1486
+ if (startupState.cleanedUp) return;
1456
1487
  const openTransaction = getOpenTransaction();
1457
1488
  if (!openTransaction) {
1458
1489
  throw new InvalidPersistedCollectionConfigError(
@@ -1467,6 +1498,7 @@ function createWrappedSyncConfig(sourceSyncConfig, runtime) {
1467
1498
  }
1468
1499
  },
1469
1500
  list: (prefix) => {
1501
+ if (startupState.cleanedUp) return [];
1470
1502
  const merged = new Map(
1471
1503
  params.metadata.collection.list().map(({ key, value }) => [key, value])
1472
1504
  );
@@ -1491,6 +1523,7 @@ function createWrappedSyncConfig(sourceSyncConfig, runtime) {
1491
1523
  }
1492
1524
  } : void 0,
1493
1525
  truncate: () => {
1526
+ if (startupState.cleanedUp) return;
1494
1527
  const openTransaction = getOpenTransaction();
1495
1528
  if (!openTransaction) {
1496
1529
  params.truncate();
@@ -1504,6 +1537,7 @@ function createWrappedSyncConfig(sourceSyncConfig, runtime) {
1504
1537
  }
1505
1538
  },
1506
1539
  commit: (signal) => {
1540
+ if (startupState.cleanedUp) return true;
1507
1541
  const openTransaction = transactionStack.pop();
1508
1542
  if (!openTransaction) {
1509
1543
  return params.commit(signal);
@@ -1553,7 +1587,6 @@ function createWrappedSyncConfig(sourceSyncConfig, runtime) {
1553
1587
  }
1554
1588
  };
1555
1589
  let sourceResult = {};
1556
- const startupState = { cleanedUp: false };
1557
1590
  fullStartPromise = runtime.ensureStarted();
1558
1591
  const sourceResultPromise = (async () => {
1559
1592
  await runtime.ensureStartupMetadataLoaded();
@@ -1568,23 +1601,40 @@ function createWrappedSyncConfig(sourceSyncConfig, runtime) {
1568
1601
  return {
1569
1602
  cleanup: () => {
1570
1603
  startupState.cleanedUp = true;
1604
+ acquisitions.clear();
1571
1605
  sourceResult.cleanup?.();
1572
1606
  runtime.cleanup();
1573
1607
  runtime.clearSyncControls();
1574
1608
  },
1575
1609
  loadSubset: async (options) => {
1576
- const loadKey = getLoadKey(options);
1577
- cancelledLoadKeys.delete(loadKey);
1610
+ const acquisition = { forwarded: false };
1611
+ acquisitions.set(options, acquisition);
1578
1612
  await fullStartPromise;
1579
1613
  const resolvedSourceResult = await sourceResultPromise;
1580
- if (startupState.cleanedUp || cancelledLoadKeys.has(loadKey)) {
1614
+ if (startupState.cleanedUp || acquisitions.get(options) !== acquisition) {
1581
1615
  return;
1582
1616
  }
1583
- await runtime.loadSubset(options, resolvedSourceResult.loadSubset);
1617
+ return runtime.loadSubset(options, (loadOptions) => {
1618
+ if (startupState.cleanedUp || acquisitions.get(options) !== acquisition) {
1619
+ return true;
1620
+ }
1621
+ if (!resolvedSourceResult.loadSubset) return true;
1622
+ acquisition.forwarded = true;
1623
+ try {
1624
+ return resolvedSourceResult.loadSubset(loadOptions);
1625
+ } catch (error) {
1626
+ acquisition.forwarded = false;
1627
+ throw error;
1628
+ }
1629
+ });
1584
1630
  },
1585
1631
  unloadSubset: (options) => {
1586
- cancelledLoadKeys.add(getLoadKey(options));
1587
- runtime.unloadSubset(options, sourceResult.unloadSubset);
1632
+ const acquisition = acquisitions.get(options);
1633
+ acquisitions.delete(options);
1634
+ runtime.unloadSubset(
1635
+ options,
1636
+ acquisition?.forwarded ? sourceResult.unloadSubset : void 0
1637
+ );
1588
1638
  }
1589
1639
  };
1590
1640
  }