@tanstack/db-sqlite-persistence-core 0.4.3 → 0.4.5
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/README.md +14 -6
- package/dist/cjs/errors.cjs.map +1 -1
- package/dist/cjs/index.cjs +5 -0
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/persisted.cjs +59 -62
- package/dist/cjs/persisted.cjs.map +1 -1
- package/dist/cjs/persisted.d.cts +7 -1
- package/dist/cjs/remote-subset-wire.cjs +100 -73
- package/dist/cjs/remote-subset-wire.cjs.map +1 -1
- package/dist/cjs/remote-subset-wire.d.cts +2 -0
- package/dist/cjs/sqlite-core-adapter.cjs +433 -184
- package/dist/cjs/sqlite-core-adapter.cjs.map +1 -1
- package/dist/cjs/sqlite-value.cjs +51 -0
- package/dist/cjs/sqlite-value.cjs.map +1 -1
- package/dist/cjs/sqlite-value.d.cts +12 -0
- package/dist/esm/errors.js.map +1 -1
- package/dist/esm/index.js +8 -3
- package/dist/esm/persisted.d.ts +7 -1
- package/dist/esm/persisted.js +63 -66
- package/dist/esm/persisted.js.map +1 -1
- package/dist/esm/remote-subset-wire.d.ts +2 -0
- package/dist/esm/remote-subset-wire.js +101 -74
- package/dist/esm/remote-subset-wire.js.map +1 -1
- package/dist/esm/sqlite-core-adapter.js +435 -186
- package/dist/esm/sqlite-core-adapter.js.map +1 -1
- package/dist/esm/sqlite-value.d.ts +12 -0
- package/dist/esm/sqlite-value.js +53 -2
- package/dist/esm/sqlite-value.js.map +1 -1
- package/package.json +4 -3
- package/src/errors.ts +1 -2
- package/src/persisted.ts +111 -91
- package/src/remote-subset-wire.ts +150 -85
- package/src/sqlite-core-adapter.ts +686 -235
- package/src/sqlite-value.ts +98 -1
package/README.md
CHANGED
|
@@ -260,12 +260,20 @@ source publication and its durable suffix. A source may mark a transaction
|
|
|
260
260
|
optimistic layer. The wrapper still gives that transaction one FIFO turn and
|
|
261
261
|
writes its durable suffix before admitting the next source turn.
|
|
262
262
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
in
|
|
263
|
+
Persisted rows establish a baseline for newer changes from the sync adapter.
|
|
264
|
+
Once an ordinary sync transaction is accepted at `commit()`, queued reads of
|
|
265
|
+
that baseline cannot revoke acceptance. This includes subset reads and rereads
|
|
266
|
+
requested by coordinator reset or full-reload notifications. This rule assumes
|
|
267
|
+
a compatible baseline; it does not authorize using an invalidated resume point.
|
|
268
|
+
A truncate replay replaces earlier source rows in the same sync run. Sync
|
|
269
|
+
transactions ordered after that replacement apply to the replacement.
|
|
270
|
+
|
|
271
|
+
An `immediate` sync transaction cannot enter while an earlier normal source
|
|
272
|
+
publication is waiting. The wrapper also currently rejects a sync transaction
|
|
273
|
+
that remains open across another persistence read. These admission restrictions
|
|
274
|
+
throw `InvalidPersistedCollectionConfigError`; an internal wait after accepted
|
|
275
|
+
`commit()` is not an admission failure. The open-transaction restriction is
|
|
276
|
+
separate from the accepted-transaction precedence rule.
|
|
269
277
|
|
|
270
278
|
### Atomic resume snapshots
|
|
271
279
|
|
package/dist/cjs/errors.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.cjs","sources":["../../src/errors.ts"],"sourcesContent":["import { TanStackDBError } from '@tanstack/db'\n\nexport class PersistedCollectionCoreError extends TanStackDBError {\n constructor(message: string) {\n super(message)\n this.name = `PersistedCollectionCoreError`\n }\n}\n\nexport class InvalidPersistedCollectionConfigError extends PersistedCollectionCoreError {\n constructor(message: string) {\n super(message)\n this.name = `InvalidPersistedCollectionConfigError`\n }\n}\n\nexport class InvalidSyncConfigError extends InvalidPersistedCollectionConfigError {\n constructor(details?: string) {\n super(\n details\n ? `Invalid sync config: ${details}`\n : `Invalid sync config: expected an object with a callable sync function`,\n )\n this.name = `InvalidSyncConfigError`\n }\n}\n\nexport class InvalidPersistedCollectionCoordinatorError extends InvalidPersistedCollectionConfigError {\n constructor(methodName: string) {\n super(\n `Invalid persisted collection coordinator: missing required \"${methodName}\" method`,\n )\n this.name = `InvalidPersistedCollectionCoordinatorError`\n }\n}\n\nexport class InvalidPersistenceAdapterError extends InvalidPersistedCollectionConfigError {\n constructor(methodName: string) {\n super(\n `Invalid persistence adapter: missing required \"${methodName}\" method`,\n )\n this.name = `InvalidPersistenceAdapterError`\n }\n}\n\nexport type PersistedCollectionDurabilityErrorOptions = {\n cause?: unknown\n code?: unknown\n path?: unknown\n}\n\nexport class PersistedCollectionDurabilityError extends PersistedCollectionCoreError {\n override readonly cause: unknown\n readonly code: unknown\n readonly path: unknown\n\n constructor(\n message: string,\n options: PersistedCollectionDurabilityErrorOptions = {},\n ) {\n super(message)\n this.name = `PersistedCollectionDurabilityError`\n this.cause = options.cause\n this.code = options.code\n this.path = options.path\n }\n}\n\nexport function toPersistedCollectionDurabilityError(\n collectionId: string,\n cause: unknown,\n): PersistedCollectionDurabilityError {\n if (cause instanceof PersistedCollectionDurabilityError) {\n return cause\n }\n\n const details =\n typeof cause === `object` && cause !== null\n ? (cause as Record<string, unknown>)\n : undefined\n const message = cause instanceof Error ? cause.message : String(cause)\n return new PersistedCollectionDurabilityError(\n `Failed to durably persist collection \"${collectionId}\": ${message}`,\n {\n cause,\n code: details?.code,\n path: details?.path,\n },\n )\n}\n\nexport type IndeterminateCommitRequestType =\n
|
|
1
|
+
{"version":3,"file":"errors.cjs","sources":["../../src/errors.ts"],"sourcesContent":["import { TanStackDBError } from '@tanstack/db'\n\nexport class PersistedCollectionCoreError extends TanStackDBError {\n constructor(message: string) {\n super(message)\n this.name = `PersistedCollectionCoreError`\n }\n}\n\nexport class InvalidPersistedCollectionConfigError extends PersistedCollectionCoreError {\n constructor(message: string) {\n super(message)\n this.name = `InvalidPersistedCollectionConfigError`\n }\n}\n\nexport class InvalidSyncConfigError extends InvalidPersistedCollectionConfigError {\n constructor(details?: string) {\n super(\n details\n ? `Invalid sync config: ${details}`\n : `Invalid sync config: expected an object with a callable sync function`,\n )\n this.name = `InvalidSyncConfigError`\n }\n}\n\nexport class InvalidPersistedCollectionCoordinatorError extends InvalidPersistedCollectionConfigError {\n constructor(methodName: string) {\n super(\n `Invalid persisted collection coordinator: missing required \"${methodName}\" method`,\n )\n this.name = `InvalidPersistedCollectionCoordinatorError`\n }\n}\n\nexport class InvalidPersistenceAdapterError extends InvalidPersistedCollectionConfigError {\n constructor(methodName: string) {\n super(\n `Invalid persistence adapter: missing required \"${methodName}\" method`,\n )\n this.name = `InvalidPersistenceAdapterError`\n }\n}\n\nexport type PersistedCollectionDurabilityErrorOptions = {\n cause?: unknown\n code?: unknown\n path?: unknown\n}\n\nexport class PersistedCollectionDurabilityError extends PersistedCollectionCoreError {\n override readonly cause: unknown\n readonly code: unknown\n readonly path: unknown\n\n constructor(\n message: string,\n options: PersistedCollectionDurabilityErrorOptions = {},\n ) {\n super(message)\n this.name = `PersistedCollectionDurabilityError`\n this.cause = options.cause\n this.code = options.code\n this.path = options.path\n }\n}\n\nexport function toPersistedCollectionDurabilityError(\n collectionId: string,\n cause: unknown,\n): PersistedCollectionDurabilityError {\n if (cause instanceof PersistedCollectionDurabilityError) {\n return cause\n }\n\n const details =\n typeof cause === `object` && cause !== null\n ? (cause as Record<string, unknown>)\n : undefined\n const message = cause instanceof Error ? cause.message : String(cause)\n return new PersistedCollectionDurabilityError(\n `Failed to durably persist collection \"${collectionId}\": ${message}`,\n {\n cause,\n code: details?.code,\n path: details?.path,\n },\n )\n}\n\nexport type IndeterminateCommitRequestType =\n `rpc:applyLocalMutations:req` | `rpc:applyCommittedTx:req`\n\nexport type IndeterminateCommitErrorOptions = {\n collectionId: string\n requestType: IndeterminateCommitRequestType\n previousLeaderId: string | null\n previousTerm: number | null\n currentLeaderId: string | null\n currentTerm: number | null\n cause: unknown\n}\n\nexport class IndeterminateCommitError extends PersistedCollectionCoreError {\n readonly code: `INDETERMINATE_COMMIT` = `INDETERMINATE_COMMIT`\n readonly collectionId: string\n readonly requestType: IndeterminateCommitRequestType\n readonly previousLeaderId: string | null\n readonly previousTerm: number | null\n readonly currentLeaderId: string | null\n readonly currentTerm: number | null\n override readonly cause: unknown\n\n constructor(options: IndeterminateCommitErrorOptions) {\n super(\n `Commit outcome is indeterminate for collection \"${options.collectionId}\": ${options.requestType} crossed leadership from ${formatLeader(options.previousLeaderId, options.previousTerm)} to ${formatLeader(options.currentLeaderId, options.currentTerm)}`,\n )\n this.name = `IndeterminateCommitError`\n this.collectionId = options.collectionId\n this.requestType = options.requestType\n this.previousLeaderId = options.previousLeaderId\n this.previousTerm = options.previousTerm\n this.currentLeaderId = options.currentLeaderId\n this.currentTerm = options.currentTerm\n this.cause = options.cause\n }\n}\n\nfunction formatLeader(leaderId: string | null, term: number | null): string {\n return `${leaderId ?? `unknown leader`} (term ${term ?? `unknown`})`\n}\n\nexport class DuplicateRemoteSubsetOwnerError extends PersistedCollectionCoreError {\n readonly collectionId: string\n\n constructor(collectionId: string) {\n super(\n `A remote subset owner is already registered for collection \"${collectionId}\"`,\n )\n this.name = `DuplicateRemoteSubsetOwnerError`\n this.collectionId = collectionId\n }\n}\n\nexport class RetryableRemoteSubsetAcquisitionError extends PersistedCollectionCoreError {\n override readonly cause: unknown\n\n constructor(message: string, cause?: unknown) {\n super(message)\n this.name = `RetryableRemoteSubsetAcquisitionError`\n this.cause = cause\n }\n}\n\nexport class InvalidPersistedStorageKeyError extends InvalidPersistedCollectionConfigError {\n constructor(key: string | number) {\n super(\n `Invalid persisted storage key \"${String(key)}\": numeric keys must be finite`,\n )\n this.name = `InvalidPersistedStorageKeyError`\n }\n}\n\nexport class InvalidPersistedStorageKeyEncodingError extends InvalidPersistedCollectionConfigError {\n constructor(encoded: string) {\n super(\n `Invalid persisted storage key encoding \"${encoded}\": expected prefix \"n:\" or \"s:\"`,\n )\n this.name = `InvalidPersistedStorageKeyEncodingError`\n }\n}\n\nexport class SQLiteBigIntOutOfRangeError extends PersistedCollectionCoreError {\n constructor(value: bigint, minimum: bigint, maximum: bigint) {\n super(\n `SQLite BigInt value ${value} is outside the signed 64-bit range [${minimum}, ${maximum}]`,\n )\n this.name = `SQLiteBigIntOutOfRangeError`\n }\n}\n\nexport class PersistenceUnavailableError extends PersistedCollectionCoreError {\n constructor(details?: string) {\n super(\n details\n ? `Persistence unavailable: ${details}`\n : `Persistence unavailable in this runtime`,\n )\n this.name = `PersistenceUnavailableError`\n }\n}\n"],"names":["TanStackDBError"],"mappings":"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"}
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -37,10 +37,15 @@ exports.PERSISTED_VALUE_TAG = sqliteValue.PERSISTED_VALUE_TAG;
|
|
|
37
37
|
exports.SQLITE_BIGINT_MAX = sqliteValue.SQLITE_BIGINT_MAX;
|
|
38
38
|
exports.SQLITE_BIGINT_MIN = sqliteValue.SQLITE_BIGINT_MIN;
|
|
39
39
|
exports.assertSQLiteBigIntInRange = sqliteValue.assertSQLiteBigIntInRange;
|
|
40
|
+
exports.reviveSQLiteTemporal = sqliteValue.reviveSQLiteTemporal;
|
|
40
41
|
exports.serializeSQLiteBigInt = sqliteValue.serializeSQLiteBigInt;
|
|
42
|
+
exports.serializeSQLiteTemporal = sqliteValue.serializeSQLiteTemporal;
|
|
43
|
+
exports.sqliteTemporalIdentity = sqliteValue.sqliteTemporalIdentity;
|
|
44
|
+
exports.sqliteTemporalKind = sqliteValue.sqliteTemporalKind;
|
|
41
45
|
exports.RemoteSubsetWireValueError = remoteSubsetWire.RemoteSubsetWireValueError;
|
|
42
46
|
exports.toProcessLocalLoadSubsetOptions = remoteSubsetWire.toProcessLocalLoadSubsetOptions;
|
|
43
47
|
exports.toTransportedLoadSubsetOptions = remoteSubsetWire.toTransportedLoadSubsetOptions;
|
|
48
|
+
exports.validateRemoteSubsetOptions = remoteSubsetWire.validateRemoteSubsetOptions;
|
|
44
49
|
Object.defineProperty(exports, "safeRandomUUID", {
|
|
45
50
|
enumerable: true,
|
|
46
51
|
get: () => db.safeRandomUUID
|
package/dist/cjs/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
package/dist/cjs/persisted.cjs
CHANGED
|
@@ -178,8 +178,8 @@ class SingleProcessCoordinator {
|
|
|
178
178
|
setAdapterForCollection(collectionId, adapter) {
|
|
179
179
|
this.collectionAdapters.set(collectionId, adapter);
|
|
180
180
|
}
|
|
181
|
-
async requestApplyCommittedTx(collectionId, tx) {
|
|
182
|
-
const adapter = this.collectionAdapters.get(collectionId);
|
|
181
|
+
async requestApplyCommittedTx(collectionId, tx, scopedAdapter) {
|
|
182
|
+
const adapter = scopedAdapter ?? this.collectionAdapters.get(collectionId);
|
|
183
183
|
if (!adapter) {
|
|
184
184
|
throw new errors.InvalidPersistedCollectionConfigError(
|
|
185
185
|
`SingleProcessCoordinator has no persistence adapter configured for collection "${collectionId}"`
|
|
@@ -335,6 +335,8 @@ function toStableSerializable(value) {
|
|
|
335
335
|
case `undefined`:
|
|
336
336
|
return void 0;
|
|
337
337
|
}
|
|
338
|
+
const temporal = sqliteValue.serializeSQLiteTemporal(value);
|
|
339
|
+
if (temporal) return temporal;
|
|
338
340
|
if (value instanceof Date) {
|
|
339
341
|
return value.toISOString();
|
|
340
342
|
}
|
|
@@ -442,7 +444,6 @@ class PersistedCollectionRuntime {
|
|
|
442
444
|
this.resumeGenerationOwner = /* @__PURE__ */ Symbol(`persisted resume generation owner`);
|
|
443
445
|
this.lifecycleGeneration = 0;
|
|
444
446
|
this.internalApplyDepth = 0;
|
|
445
|
-
this.sourcePublicationWaitDepth = 0;
|
|
446
447
|
this.appliedReceiptSequence = 0;
|
|
447
448
|
this.syncErrorReported = false;
|
|
448
449
|
this.pendingAppliedReceipts = /* @__PURE__ */ new Map();
|
|
@@ -501,11 +502,14 @@ class PersistedCollectionRuntime {
|
|
|
501
502
|
void receipt.then(removeReceipt, removeReceipt);
|
|
502
503
|
return receipt;
|
|
503
504
|
}
|
|
504
|
-
|
|
505
|
+
// Startup waits for acceptance: a local mutation's handler can wait for
|
|
506
|
+
// startup, and the rows publish when that mutation settles. Readiness waits
|
|
507
|
+
// for them in core. A subset load waits for visibility.
|
|
508
|
+
async waitForAppliedReceiptsAfter(cursor, until = `visible`) {
|
|
505
509
|
await Promise.all(
|
|
506
510
|
Array.from(
|
|
507
511
|
this.pendingAppliedReceipts,
|
|
508
|
-
([sequence, receipt]) => sequence
|
|
512
|
+
([sequence, receipt]) => sequence <= cursor ? void 0 : until === `accepted` ? db.whenSyncAccepted(receipt) : receipt
|
|
509
513
|
)
|
|
510
514
|
);
|
|
511
515
|
}
|
|
@@ -666,7 +670,10 @@ class PersistedCollectionRuntime {
|
|
|
666
670
|
startup.completedLocalIndexSignatures
|
|
667
671
|
);
|
|
668
672
|
if (startup.appliedCursor !== void 0 && lifecycleGeneration === this.lifecycleGeneration) {
|
|
669
|
-
await this.waitForAppliedReceiptsAfter(
|
|
673
|
+
await this.waitForAppliedReceiptsAfter(
|
|
674
|
+
startup.appliedCursor,
|
|
675
|
+
`accepted`
|
|
676
|
+
);
|
|
670
677
|
}
|
|
671
678
|
}
|
|
672
679
|
if (lifecycleGeneration === this.lifecycleGeneration) {
|
|
@@ -701,7 +708,7 @@ class PersistedCollectionRuntime {
|
|
|
701
708
|
return result;
|
|
702
709
|
});
|
|
703
710
|
if (appliedCursor !== void 0 && lifecycleGeneration === this.lifecycleGeneration) {
|
|
704
|
-
await this.waitForAppliedReceiptsAfter(appliedCursor);
|
|
711
|
+
await this.waitForAppliedReceiptsAfter(appliedCursor, `accepted`);
|
|
705
712
|
}
|
|
706
713
|
})().catch((error) => {
|
|
707
714
|
throw this.markTerminalFailure(error, lifecycleGeneration);
|
|
@@ -742,7 +749,6 @@ class PersistedCollectionRuntime {
|
|
|
742
749
|
await this.hydrateSubsetUnsafe(
|
|
743
750
|
baseline,
|
|
744
751
|
{
|
|
745
|
-
requestRemoteEnsure: false,
|
|
746
752
|
lifecycleGeneration,
|
|
747
753
|
bindKeySetEvidence: true
|
|
748
754
|
},
|
|
@@ -790,7 +796,7 @@ class PersistedCollectionRuntime {
|
|
|
790
796
|
const applied = this.replaceCollectionMetadataSnapshot(
|
|
791
797
|
snapshot.collectionMetadata
|
|
792
798
|
);
|
|
793
|
-
|
|
799
|
+
await db.whenSyncAccepted(applied);
|
|
794
800
|
}
|
|
795
801
|
async loadCollectionMetadataSnapshot(adapter) {
|
|
796
802
|
if (!adapter.loadCollectionMetadata) {
|
|
@@ -807,7 +813,7 @@ class PersistedCollectionRuntime {
|
|
|
807
813
|
);
|
|
808
814
|
const currentKeys = this.syncControls.metadata.collection.list().map(({ key }) => key);
|
|
809
815
|
return this.withInternalApply(() => {
|
|
810
|
-
this.syncControls.begin?.(
|
|
816
|
+
this.syncControls.begin?.();
|
|
811
817
|
currentKeys.forEach((key) => {
|
|
812
818
|
if (!nextMetadata.has(key)) {
|
|
813
819
|
this.syncControls.metadata?.collection.delete(key);
|
|
@@ -825,6 +831,7 @@ class PersistedCollectionRuntime {
|
|
|
825
831
|
const subsetKey = this.getSubsetKey(options);
|
|
826
832
|
const truncateGeneration = this.sourceTruncateGeneration;
|
|
827
833
|
const routeRemoteDemandDuringHydration = this.canRouteRemoteDemandThroughCoordinator();
|
|
834
|
+
if (routeRemoteDemandDuringHydration) remoteSubsetWire.validateRemoteSubsetOptions(options);
|
|
828
835
|
this.activeSubsets.set(subsetKey, options);
|
|
829
836
|
const appliedCursor = this.appliedReceiptSequence;
|
|
830
837
|
try {
|
|
@@ -834,7 +841,6 @@ class PersistedCollectionRuntime {
|
|
|
834
841
|
(adapter) => this.hydrateSubsetUnsafe(
|
|
835
842
|
options,
|
|
836
843
|
{
|
|
837
|
-
requestRemoteEnsure: this.mode === `sync-present` && !routeRemoteDemandDuringHydration,
|
|
838
844
|
lifecycleGeneration,
|
|
839
845
|
requestLocalLoadFailure: true,
|
|
840
846
|
rejectBufferedReplayFailure: true
|
|
@@ -850,6 +856,9 @@ class PersistedCollectionRuntime {
|
|
|
850
856
|
});
|
|
851
857
|
if (lifecycleGeneration !== this.lifecycleGeneration) return;
|
|
852
858
|
await this.waitForAppliedReceiptsAfter(appliedCursor);
|
|
859
|
+
if (!routeRemoteDemandDuringHydration && this.canRouteRemoteDemandThroughCoordinator()) {
|
|
860
|
+
remoteSubsetWire.validateRemoteSubsetOptions(options);
|
|
861
|
+
}
|
|
853
862
|
} catch (error) {
|
|
854
863
|
if (this.activeSubsets.get(subsetKey) === options) {
|
|
855
864
|
this.activeSubsets.delete(subsetKey);
|
|
@@ -959,7 +968,6 @@ class PersistedCollectionRuntime {
|
|
|
959
968
|
(adapter) => this.hydrateSubsetUnsafe(
|
|
960
969
|
options,
|
|
961
970
|
{
|
|
962
|
-
requestRemoteEnsure: false,
|
|
963
971
|
lifecycleGeneration,
|
|
964
972
|
rejectBufferedReplayFailure: true
|
|
965
973
|
},
|
|
@@ -982,13 +990,6 @@ class PersistedCollectionRuntime {
|
|
|
982
990
|
applyHydrationBufferedTransaction(transaction) {
|
|
983
991
|
const failure = this.getCurrentTerminalFailure();
|
|
984
992
|
if (failure) return Promise.reject(failure.error);
|
|
985
|
-
if (transaction.beginOptions?.immediate && this.sourcePublicationWaitDepth > 0) {
|
|
986
|
-
return Promise.reject(
|
|
987
|
-
new errors.InvalidPersistedCollectionConfigError(
|
|
988
|
-
`immediate persisted source replay cannot enter while an earlier source publication is waiting`
|
|
989
|
-
)
|
|
990
|
-
);
|
|
991
|
-
}
|
|
992
993
|
return this.applyMutex.run(async () => {
|
|
993
994
|
await this.applyBufferedSyncTransactionUnsafe(transaction);
|
|
994
995
|
});
|
|
@@ -1209,7 +1210,7 @@ class PersistedCollectionRuntime {
|
|
|
1209
1210
|
hydrationContext.suppliedRowKeys.add(row.key);
|
|
1210
1211
|
}
|
|
1211
1212
|
const applied = this.applyRowsToCollection(rows);
|
|
1212
|
-
|
|
1213
|
+
await db.whenSyncAccepted(applied);
|
|
1213
1214
|
}
|
|
1214
1215
|
} finally {
|
|
1215
1216
|
if (this.activeHydrationContext === hydrationContext && this.hydratingGeneration === config.lifecycleGeneration) {
|
|
@@ -1219,9 +1220,6 @@ class PersistedCollectionRuntime {
|
|
|
1219
1220
|
if (config.lifecycleGeneration !== this.lifecycleGeneration) return;
|
|
1220
1221
|
replayFailure = await this.flushQueuedHydrationTransactionsUnsafe(adapter);
|
|
1221
1222
|
if (config.lifecycleGeneration !== this.lifecycleGeneration) return;
|
|
1222
|
-
if (config.requestRemoteEnsure && !replayFailure) {
|
|
1223
|
-
this.queueRemoteSubsetEnsure(options);
|
|
1224
|
-
}
|
|
1225
1223
|
} catch (error) {
|
|
1226
1224
|
if (config.requestLocalLoadFailure && !rowsLoaded) {
|
|
1227
1225
|
this.hydratingGeneration = config.lifecycleGeneration;
|
|
@@ -1352,7 +1350,7 @@ class PersistedCollectionRuntime {
|
|
|
1352
1350
|
return true;
|
|
1353
1351
|
}
|
|
1354
1352
|
return this.withInternalApply(() => {
|
|
1355
|
-
this.syncControls.begin?.(
|
|
1353
|
+
this.syncControls.begin?.();
|
|
1356
1354
|
for (const row of rows) {
|
|
1357
1355
|
if (this.collection?._hasHydratedKey(row.key)) {
|
|
1358
1356
|
continue;
|
|
@@ -1398,7 +1396,7 @@ class PersistedCollectionRuntime {
|
|
|
1398
1396
|
);
|
|
1399
1397
|
const currentKeys = this.syncControls.metadata.collection.list().map(({ key }) => key);
|
|
1400
1398
|
return this.withInternalApply(() => {
|
|
1401
|
-
this.syncControls.begin?.(
|
|
1399
|
+
this.syncControls.begin?.();
|
|
1402
1400
|
this.syncControls.truncate?.();
|
|
1403
1401
|
for (const row of rows) {
|
|
1404
1402
|
this.syncControls.write?.({
|
|
@@ -1452,14 +1450,9 @@ class PersistedCollectionRuntime {
|
|
|
1452
1450
|
const applied = transaction.internal ? this.withInternalApply(transaction.applyToCollection) : transaction.applyToCollection();
|
|
1453
1451
|
applicationReturned = true;
|
|
1454
1452
|
abortedDuringApplication = transaction.signal?.aborted === true;
|
|
1455
|
-
if (
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
await applied;
|
|
1459
|
-
} finally {
|
|
1460
|
-
this.sourcePublicationWaitDepth--;
|
|
1461
|
-
}
|
|
1462
|
-
}
|
|
1453
|
+
if (transaction.internal) await db.whenSyncAccepted(applied);
|
|
1454
|
+
else if (applied !== true && !this.collection?._state.hasPersistingTransaction())
|
|
1455
|
+
await applied;
|
|
1463
1456
|
this.throwIfLifecycleReplaced(transaction.lifecycleGeneration);
|
|
1464
1457
|
if (!transaction.internal) {
|
|
1465
1458
|
await this.persistAndBroadcastExternalSyncTransactionUnsafe(
|
|
@@ -1629,7 +1622,7 @@ class PersistedCollectionRuntime {
|
|
|
1629
1622
|
return;
|
|
1630
1623
|
}
|
|
1631
1624
|
const applied = this.withInternalApply(() => {
|
|
1632
|
-
this.syncControls.begin?.(
|
|
1625
|
+
this.syncControls.begin?.();
|
|
1633
1626
|
for (const mutation of mutations) {
|
|
1634
1627
|
if (mutation.type === `delete`) {
|
|
1635
1628
|
this.syncControls.write?.({
|
|
@@ -1645,9 +1638,8 @@ class PersistedCollectionRuntime {
|
|
|
1645
1638
|
}
|
|
1646
1639
|
return this.syncControls.commit?.() ?? true;
|
|
1647
1640
|
});
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
}
|
|
1641
|
+
const accepted = db.whenSyncAccepted(applied);
|
|
1642
|
+
if (accepted !== true) await accepted;
|
|
1651
1643
|
}
|
|
1652
1644
|
filterMutationsForCollection(mutations) {
|
|
1653
1645
|
const collection = this.collection;
|
|
@@ -1820,6 +1812,7 @@ class PersistedCollectionRuntime {
|
|
|
1820
1812
|
}
|
|
1821
1813
|
const subsetKey = this.getSubsetKey(options);
|
|
1822
1814
|
if (this.activeSubsets.get(subsetKey) !== options) return;
|
|
1815
|
+
remoteSubsetWire.validateRemoteSubsetOptions(options);
|
|
1823
1816
|
this.pendingRemoteSubsetEnsures.set(subsetKey, options);
|
|
1824
1817
|
void this.flushPendingRemoteSubsetEnsures();
|
|
1825
1818
|
}
|
|
@@ -2035,11 +2028,11 @@ class PersistedCollectionRuntime {
|
|
|
2035
2028
|
this.resetSequence++;
|
|
2036
2029
|
if (this.syncControls.begin && this.syncControls.commit) {
|
|
2037
2030
|
const applied = this.withInternalApply(() => {
|
|
2038
|
-
this.syncControls.begin?.(
|
|
2031
|
+
this.syncControls.begin?.();
|
|
2039
2032
|
this.syncControls.truncate?.();
|
|
2040
2033
|
return this.syncControls.commit?.() ?? true;
|
|
2041
2034
|
});
|
|
2042
|
-
|
|
2035
|
+
await db.whenSyncAccepted(applied);
|
|
2043
2036
|
}
|
|
2044
2037
|
if (lifecycleGeneration !== this.lifecycleGeneration) return;
|
|
2045
2038
|
await this.reloadActiveSubsetsUnsafe(adapter);
|
|
@@ -2072,7 +2065,7 @@ class PersistedCollectionRuntime {
|
|
|
2072
2065
|
(opt) => opt.where ? db.compileSingleRowExpression(opt.where) : null
|
|
2073
2066
|
);
|
|
2074
2067
|
const applied = this.withInternalApply(() => {
|
|
2075
|
-
this.syncControls.begin?.(
|
|
2068
|
+
this.syncControls.begin?.();
|
|
2076
2069
|
for (const {
|
|
2077
2070
|
key: changedKey,
|
|
2078
2071
|
value: newValue
|
|
@@ -2112,7 +2105,7 @@ class PersistedCollectionRuntime {
|
|
|
2112
2105
|
});
|
|
2113
2106
|
return this.syncControls.commit?.() ?? true;
|
|
2114
2107
|
});
|
|
2115
|
-
|
|
2108
|
+
await db.whenSyncAccepted(applied);
|
|
2116
2109
|
}
|
|
2117
2110
|
async reloadActiveSubsetsUnsafe(adapter) {
|
|
2118
2111
|
const lifecycleGeneration = this.lifecycleGeneration;
|
|
@@ -2148,7 +2141,7 @@ class PersistedCollectionRuntime {
|
|
|
2148
2141
|
})),
|
|
2149
2142
|
collectionMetadata
|
|
2150
2143
|
);
|
|
2151
|
-
|
|
2144
|
+
await db.whenSyncAccepted(applied);
|
|
2152
2145
|
} finally {
|
|
2153
2146
|
if (this.activeHydrationContext === hydrationContext && this.hydratingGeneration === lifecycleGeneration) {
|
|
2154
2147
|
this.hydratingGeneration = null;
|
|
@@ -2222,8 +2215,8 @@ class PersistedCollectionRuntime {
|
|
|
2222
2215
|
await this.requestCoordinatorPersistedIndex(indexMetadata, completedLocally);
|
|
2223
2216
|
}
|
|
2224
2217
|
async ensureLocalPersistedIndex(indexMetadata, adapter) {
|
|
2225
|
-
const spec = this.buildPersistedIndexSpec(indexMetadata);
|
|
2226
2218
|
try {
|
|
2219
|
+
const spec = this.buildPersistedIndexSpec(indexMetadata);
|
|
2227
2220
|
await adapter.ensureIndex(
|
|
2228
2221
|
this.collectionId,
|
|
2229
2222
|
indexMetadata.signature,
|
|
@@ -2236,8 +2229,8 @@ class PersistedCollectionRuntime {
|
|
|
2236
2229
|
}
|
|
2237
2230
|
}
|
|
2238
2231
|
async requestCoordinatorPersistedIndex(indexMetadata, completedLocally) {
|
|
2239
|
-
const spec = this.buildPersistedIndexSpec(indexMetadata);
|
|
2240
2232
|
try {
|
|
2233
|
+
const spec = this.buildPersistedIndexSpec(indexMetadata);
|
|
2241
2234
|
await this.persistence.coordinator.requestEnsurePersistedIndex(
|
|
2242
2235
|
this.collectionId,
|
|
2243
2236
|
indexMetadata.signature,
|
|
@@ -2314,6 +2307,14 @@ function createWrappedSyncConfig(sourceSyncConfig, runtime, persistedReadiness)
|
|
|
2314
2307
|
const settlePendingTransaction = (transaction) => {
|
|
2315
2308
|
removePendingPublicationTransaction(transaction);
|
|
2316
2309
|
};
|
|
2310
|
+
const visibleAfterDurable = (transaction, durable) => {
|
|
2311
|
+
const visible = durable.then(async () => {
|
|
2312
|
+
const receipt = transaction.applicationReceipt;
|
|
2313
|
+
if (receipt !== void 0 && receipt !== true) await receipt;
|
|
2314
|
+
});
|
|
2315
|
+
void visible.catch(() => void 0);
|
|
2316
|
+
return db.withAcceptedReceipt(visible, durable);
|
|
2317
|
+
};
|
|
2317
2318
|
const settleRuntimeTransaction = (transaction, applied) => {
|
|
2318
2319
|
void applied.then(
|
|
2319
2320
|
() => settlePendingTransaction(transaction),
|
|
@@ -2421,9 +2422,7 @@ function createWrappedSyncConfig(sourceSyncConfig, runtime, persistedReadiness)
|
|
|
2421
2422
|
}
|
|
2422
2423
|
}
|
|
2423
2424
|
transaction.deferredHydrationMetadataDeleteKeys.clear();
|
|
2424
|
-
params.begin(
|
|
2425
|
-
transaction.queuedBecauseHydrating ? { immediate: true } : transaction.beginOptions
|
|
2426
|
-
);
|
|
2425
|
+
params.begin();
|
|
2427
2426
|
if (transaction.truncate) params.truncate();
|
|
2428
2427
|
for (const operation of transaction.operations) {
|
|
2429
2428
|
if (operation.type === `delete`) {
|
|
@@ -2449,14 +2448,8 @@ function createWrappedSyncConfig(sourceSyncConfig, runtime, persistedReadiness)
|
|
|
2449
2448
|
}
|
|
2450
2449
|
const applied = params.commit(signal);
|
|
2451
2450
|
transaction.applicationReceipt = applied;
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
} else {
|
|
2455
|
-
void applied.then(
|
|
2456
|
-
() => removePendingPublicationTransaction(transaction),
|
|
2457
|
-
() => removePendingPublicationTransaction(transaction)
|
|
2458
|
-
);
|
|
2459
|
-
}
|
|
2451
|
+
removePendingPublicationTransaction(transaction);
|
|
2452
|
+
if (applied !== true) void applied.catch(() => void 0);
|
|
2460
2453
|
return applied;
|
|
2461
2454
|
} catch (error) {
|
|
2462
2455
|
removePendingPublicationTransaction(transaction);
|
|
@@ -2477,6 +2470,11 @@ function createWrappedSyncConfig(sourceSyncConfig, runtime, persistedReadiness)
|
|
|
2477
2470
|
const persistenceCapability = {
|
|
2478
2471
|
protocol: db.SYNC_PERSISTENCE_PROTOCOL,
|
|
2479
2472
|
version: db.SYNC_PERSISTENCE_VERSION,
|
|
2473
|
+
reserveCommitTurn: () => {
|
|
2474
|
+
const openTransaction = getOpenTransaction();
|
|
2475
|
+
if (openTransaction && !openTransaction.internal)
|
|
2476
|
+
openTransaction.reservesCommitTurn = true;
|
|
2477
|
+
},
|
|
2480
2478
|
hydrateBaseline: async () => {
|
|
2481
2479
|
if (startupState.cleanedUp) return;
|
|
2482
2480
|
try {
|
|
@@ -2526,7 +2524,7 @@ function createWrappedSyncConfig(sourceSyncConfig, runtime, persistedReadiness)
|
|
|
2526
2524
|
params.markReady();
|
|
2527
2525
|
}).catch(() => void 0);
|
|
2528
2526
|
},
|
|
2529
|
-
begin: (
|
|
2527
|
+
begin: () => {
|
|
2530
2528
|
if (startupState.cleanedUp) return void 0;
|
|
2531
2529
|
const terminalFailure = getTerminalFailure();
|
|
2532
2530
|
const internal = runtime.isApplyingInternally();
|
|
@@ -2539,7 +2537,6 @@ function createWrappedSyncConfig(sourceSyncConfig, runtime, persistedReadiness)
|
|
|
2539
2537
|
truncate: false,
|
|
2540
2538
|
internal,
|
|
2541
2539
|
lifecycleGeneration: runtime.getLifecycleGeneration(),
|
|
2542
|
-
beginOptions: options,
|
|
2543
2540
|
operationKeys: /* @__PURE__ */ new Set(),
|
|
2544
2541
|
hasDependentSuccessor: false,
|
|
2545
2542
|
queuedBecauseHydrating: terminalFailure === void 0 && !internal && runtime.isHydratingNow(),
|
|
@@ -2798,7 +2795,6 @@ function createWrappedSyncConfig(sourceSyncConfig, runtime, persistedReadiness)
|
|
|
2798
2795
|
truncate: openTransaction.truncate,
|
|
2799
2796
|
internal: false,
|
|
2800
2797
|
lifecycleGeneration: openTransaction.lifecycleGeneration,
|
|
2801
|
-
beginOptions: openTransaction.beginOptions,
|
|
2802
2798
|
expectedResumeGenerationOwner: openTransaction.expectedResumeGenerationOwner,
|
|
2803
2799
|
signal,
|
|
2804
2800
|
prependHydrationRows: (rows) => {
|
|
@@ -2840,8 +2836,9 @@ function createWrappedSyncConfig(sourceSyncConfig, runtime, persistedReadiness)
|
|
|
2840
2836
|
});
|
|
2841
2837
|
settlePublicationAdmissionWaiters(openTransaction);
|
|
2842
2838
|
settleRuntimeTransaction(openTransaction, applied2);
|
|
2843
|
-
return applied2;
|
|
2839
|
+
return visibleAfterDurable(openTransaction, applied2);
|
|
2844
2840
|
}
|
|
2841
|
+
openTransaction.hydrationSequence = void 0;
|
|
2845
2842
|
let applied;
|
|
2846
2843
|
try {
|
|
2847
2844
|
applied = runtime.applyHydrationBufferedTransaction(transaction);
|
|
@@ -2851,7 +2848,7 @@ function createWrappedSyncConfig(sourceSyncConfig, runtime, persistedReadiness)
|
|
|
2851
2848
|
}
|
|
2852
2849
|
settlePublicationAdmissionWaiters(openTransaction);
|
|
2853
2850
|
settleRuntimeTransaction(openTransaction, applied);
|
|
2854
|
-
return applied;
|
|
2851
|
+
return visibleAfterDurable(openTransaction, applied);
|
|
2855
2852
|
}
|
|
2856
2853
|
};
|
|
2857
2854
|
let sourceResult = {};
|
|
@@ -2959,7 +2956,7 @@ function createWrappedSyncConfig(sourceSyncConfig, runtime, persistedReadiness)
|
|
|
2959
2956
|
}
|
|
2960
2957
|
};
|
|
2961
2958
|
const openTransaction = getOpenTransaction();
|
|
2962
|
-
const needsPublicationAdmission = openTransaction
|
|
2959
|
+
const needsPublicationAdmission = openTransaction?.reservesCommitTurn === true;
|
|
2963
2960
|
const hydrated = sourceResultSettled && !needsPublicationAdmission ? runtime.loadHydratedSubset(
|
|
2964
2961
|
options,
|
|
2965
2962
|
(loadOptions) => forwardUpstream(sourceResult, loadOptions)
|
|
@@ -2974,7 +2971,7 @@ function createWrappedSyncConfig(sourceSyncConfig, runtime, persistedReadiness)
|
|
|
2974
2971
|
return;
|
|
2975
2972
|
}
|
|
2976
2973
|
const currentTransaction = getOpenTransaction();
|
|
2977
|
-
if (currentTransaction
|
|
2974
|
+
if (currentTransaction?.reservesCommitTurn) {
|
|
2978
2975
|
await waitForPublicationAdmission(
|
|
2979
2976
|
currentTransaction,
|
|
2980
2977
|
options,
|