@tanstack/db-sqlite-persistence-core 0.2.21 → 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 +100 -47
- 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 +100 -47
- package/dist/esm/persisted.js.map +1 -1
- package/package.json +2 -2
- package/src/persisted.ts +123 -52
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/db-sqlite-persistence-core",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.23",
|
|
4
4
|
"description": "SQLite persisted collection core for TanStack DB",
|
|
5
5
|
"author": "TanStack Team",
|
|
6
6
|
"license": "MIT",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
],
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"@standard-schema/spec": "^1.1.0",
|
|
43
|
-
"@tanstack/db": "0.9.
|
|
43
|
+
"@tanstack/db": "0.9.2"
|
|
44
44
|
},
|
|
45
45
|
"peerDependencies": {
|
|
46
46
|
"typescript": ">=4.7"
|
package/src/persisted.ts
CHANGED
|
@@ -352,6 +352,7 @@ export interface PersistedCollectionUtils extends UtilsRecord {
|
|
|
352
352
|
mutations: Array<PendingMutation<Record<string, unknown>>>
|
|
353
353
|
}) => Promise<void> | void
|
|
354
354
|
getLeadershipState?: () => PersistedCollectionLeadershipState
|
|
355
|
+
/** Hydrate once without acquiring a new ongoing subset lease. */
|
|
355
356
|
forceReloadSubset?: (options: LoadSubsetOptions) => Promise<void> | void
|
|
356
357
|
}
|
|
357
358
|
|
|
@@ -707,18 +708,6 @@ function stableSerialize(value: unknown): string {
|
|
|
707
708
|
return JSON.stringify(toStableSerializable(value) ?? null)
|
|
708
709
|
}
|
|
709
710
|
|
|
710
|
-
function normalizeSubsetOptionsForKey(
|
|
711
|
-
options: LoadSubsetOptions,
|
|
712
|
-
): Record<string, unknown> {
|
|
713
|
-
return {
|
|
714
|
-
where: toStableSerializable(options.where),
|
|
715
|
-
orderBy: toStableSerializable(options.orderBy),
|
|
716
|
-
limit: options.limit,
|
|
717
|
-
cursor: toStableSerializable(options.cursor),
|
|
718
|
-
offset: options.offset,
|
|
719
|
-
}
|
|
720
|
-
}
|
|
721
|
-
|
|
722
711
|
function normalizeSyncFnResult(result: void | (() => void) | SyncConfigRes) {
|
|
723
712
|
if (typeof result === `function`) {
|
|
724
713
|
return { cleanup: result } satisfies SyncConfigRes
|
|
@@ -802,7 +791,7 @@ class PersistedCollectionRuntime<
|
|
|
802
791
|
BufferedSyncTransaction<T, TKey>
|
|
803
792
|
> = []
|
|
804
793
|
private readonly queuedTxCommitted: Array<TxCommitted> = []
|
|
805
|
-
private readonly
|
|
794
|
+
private readonly requestIds = new WeakMap<LoadSubsetOptions, string>()
|
|
806
795
|
|
|
807
796
|
private collection: Collection<T, TKey, PersistedCollectionUtils> | null =
|
|
808
797
|
null
|
|
@@ -816,15 +805,17 @@ class PersistedCollectionRuntime<
|
|
|
816
805
|
private started = false
|
|
817
806
|
private startupMetadataPromise: Promise<void> | null = null
|
|
818
807
|
private startPromise: Promise<void> | null = null
|
|
808
|
+
private resumeBaselinePromise: Promise<void> | null = null
|
|
809
|
+
private lifecycleGeneration = 0
|
|
819
810
|
private internalApplyDepth = 0
|
|
820
811
|
private appliedReceiptSequence = 0
|
|
821
812
|
private readonly pendingAppliedReceipts = new Map<number, Promise<void>>()
|
|
822
|
-
private
|
|
813
|
+
private hydratingGeneration: number | null = null
|
|
823
814
|
private coordinatorUnsubscribe: (() => void) | null = null
|
|
824
815
|
private indexAddedUnsubscribe: (() => void) | null = null
|
|
825
816
|
private indexRemovedUnsubscribe: (() => void) | null = null
|
|
826
817
|
private remoteEnsureRetryTimer: ReturnType<typeof setTimeout> | null = null
|
|
827
|
-
private
|
|
818
|
+
private nextRequestId = 0
|
|
828
819
|
|
|
829
820
|
private latestTerm = 0
|
|
830
821
|
private latestSeq = 0
|
|
@@ -842,6 +833,8 @@ class PersistedCollectionRuntime<
|
|
|
842
833
|
) {}
|
|
843
834
|
|
|
844
835
|
setSyncControls(syncControls: SyncControlFns<T, TKey>): void {
|
|
836
|
+
this.advanceLifecycle()
|
|
837
|
+
|
|
845
838
|
const commit = syncControls.commit
|
|
846
839
|
this.syncControls = {
|
|
847
840
|
...syncControls,
|
|
@@ -881,7 +874,7 @@ class PersistedCollectionRuntime<
|
|
|
881
874
|
}
|
|
882
875
|
|
|
883
876
|
isHydratingNow(): boolean {
|
|
884
|
-
return this.
|
|
877
|
+
return this.hydratingGeneration === this.lifecycleGeneration
|
|
885
878
|
}
|
|
886
879
|
|
|
887
880
|
isApplyingInternally(): boolean {
|
|
@@ -911,20 +904,56 @@ class PersistedCollectionRuntime<
|
|
|
911
904
|
return this.startPromise
|
|
912
905
|
}
|
|
913
906
|
|
|
914
|
-
|
|
907
|
+
const lifecycleGeneration = this.lifecycleGeneration
|
|
908
|
+
this.startPromise = this.startInternal(lifecycleGeneration)
|
|
915
909
|
return this.startPromise
|
|
916
910
|
}
|
|
917
911
|
|
|
912
|
+
ensureResumeBaselineHydrated(): Promise<void> {
|
|
913
|
+
if (this.resumeBaselinePromise) {
|
|
914
|
+
return this.resumeBaselinePromise
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
const lifecycleGeneration = this.lifecycleGeneration
|
|
918
|
+
this.resumeBaselinePromise = (async () => {
|
|
919
|
+
await this.ensureStarted()
|
|
920
|
+
if (lifecycleGeneration !== this.lifecycleGeneration) return
|
|
921
|
+
if (this.syncMode !== `on-demand`) return
|
|
922
|
+
|
|
923
|
+
await this.hydrateBaseline(lifecycleGeneration)
|
|
924
|
+
})()
|
|
925
|
+
return this.resumeBaselinePromise
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
private async hydrateBaseline(lifecycleGeneration: number): Promise<void> {
|
|
929
|
+
if (lifecycleGeneration !== this.lifecycleGeneration) return
|
|
930
|
+
|
|
931
|
+
const baseline = {}
|
|
932
|
+
this.activeSubsets.set(this.getSubsetKey(baseline), baseline)
|
|
933
|
+
const appliedCursor = this.appliedReceiptSequence
|
|
934
|
+
await this.applyMutex.run(async () => {
|
|
935
|
+
if (lifecycleGeneration !== this.lifecycleGeneration) return
|
|
936
|
+
await this.hydrateSubsetUnsafe(baseline, {
|
|
937
|
+
requestRemoteEnsure: false,
|
|
938
|
+
lifecycleGeneration,
|
|
939
|
+
})
|
|
940
|
+
})
|
|
941
|
+
if (lifecycleGeneration !== this.lifecycleGeneration) return
|
|
942
|
+
await this.waitForAppliedReceiptsAfter(appliedCursor)
|
|
943
|
+
}
|
|
944
|
+
|
|
918
945
|
async ensureStartupMetadataLoaded(): Promise<void> {
|
|
919
946
|
if (this.startupMetadataPromise) {
|
|
920
947
|
return this.startupMetadataPromise
|
|
921
948
|
}
|
|
922
949
|
|
|
923
|
-
|
|
950
|
+
const lifecycleGeneration = this.lifecycleGeneration
|
|
951
|
+
this.startupMetadataPromise =
|
|
952
|
+
this.loadStartupMetadataInternal(lifecycleGeneration)
|
|
924
953
|
return this.startupMetadataPromise
|
|
925
954
|
}
|
|
926
955
|
|
|
927
|
-
private async startInternal(): Promise<void> {
|
|
956
|
+
private async startInternal(lifecycleGeneration: number): Promise<void> {
|
|
928
957
|
if (this.started) {
|
|
929
958
|
return
|
|
930
959
|
}
|
|
@@ -932,28 +961,28 @@ class PersistedCollectionRuntime<
|
|
|
932
961
|
this.started = true
|
|
933
962
|
|
|
934
963
|
await this.ensureStartupMetadataLoaded()
|
|
964
|
+
if (lifecycleGeneration !== this.lifecycleGeneration) return
|
|
935
965
|
|
|
936
966
|
const indexBootstrapSnapshot = this.collection?.getIndexMetadata() ?? []
|
|
937
967
|
this.attachIndexLifecycleListeners()
|
|
938
968
|
await this.bootstrapPersistedIndexes(indexBootstrapSnapshot)
|
|
969
|
+
if (lifecycleGeneration !== this.lifecycleGeneration) return
|
|
939
970
|
|
|
940
971
|
if (this.syncMode !== `on-demand`) {
|
|
941
|
-
this.
|
|
942
|
-
const appliedCursor = this.appliedReceiptSequence
|
|
943
|
-
await this.applyMutex.run(() =>
|
|
944
|
-
this.hydrateSubsetUnsafe({}, { requestRemoteEnsure: false }),
|
|
945
|
-
)
|
|
946
|
-
await this.waitForAppliedReceiptsAfter(appliedCursor)
|
|
972
|
+
await this.hydrateBaseline(lifecycleGeneration)
|
|
947
973
|
}
|
|
948
974
|
}
|
|
949
975
|
|
|
950
|
-
private async loadStartupMetadataInternal(
|
|
976
|
+
private async loadStartupMetadataInternal(
|
|
977
|
+
lifecycleGeneration: number,
|
|
978
|
+
): Promise<void> {
|
|
951
979
|
// Restore stream position from the database so that new mutations
|
|
952
980
|
// don't collide with previously applied transactions.
|
|
953
981
|
if (this.persistence.adapter.getStreamPosition) {
|
|
954
982
|
const position = await this.persistence.adapter.getStreamPosition(
|
|
955
983
|
this.collectionId,
|
|
956
984
|
)
|
|
985
|
+
if (lifecycleGeneration !== this.lifecycleGeneration) return
|
|
957
986
|
this.observeStreamPosition(
|
|
958
987
|
position.latestTerm,
|
|
959
988
|
position.latestSeq,
|
|
@@ -961,11 +990,8 @@ class PersistedCollectionRuntime<
|
|
|
961
990
|
)
|
|
962
991
|
}
|
|
963
992
|
|
|
964
|
-
await this.loadCollectionMetadataIntoCollection()
|
|
965
|
-
}
|
|
966
|
-
|
|
967
|
-
private async loadCollectionMetadataIntoCollection(): Promise<void> {
|
|
968
993
|
const collectionMetadata = await this.loadCollectionMetadataSnapshot()
|
|
994
|
+
if (lifecycleGeneration !== this.lifecycleGeneration) return
|
|
969
995
|
this.replaceCollectionMetadataSnapshot(collectionMetadata)
|
|
970
996
|
}
|
|
971
997
|
|
|
@@ -1018,14 +1044,17 @@ class PersistedCollectionRuntime<
|
|
|
1018
1044
|
options: LoadSubsetOptions,
|
|
1019
1045
|
upstreamLoadSubset?: LoadSubsetFn,
|
|
1020
1046
|
): Promise<void> {
|
|
1047
|
+
const lifecycleGeneration = this.lifecycleGeneration
|
|
1021
1048
|
this.activeSubsets.set(this.getSubsetKey(options), options)
|
|
1022
1049
|
|
|
1023
1050
|
const appliedCursor = this.appliedReceiptSequence
|
|
1024
1051
|
await this.applyMutex.run(() =>
|
|
1025
1052
|
this.hydrateSubsetUnsafe(options, {
|
|
1026
1053
|
requestRemoteEnsure: this.mode === `sync-present`,
|
|
1054
|
+
lifecycleGeneration,
|
|
1027
1055
|
}),
|
|
1028
1056
|
)
|
|
1057
|
+
if (lifecycleGeneration !== this.lifecycleGeneration) return
|
|
1029
1058
|
await this.waitForAppliedReceiptsAfter(appliedCursor)
|
|
1030
1059
|
|
|
1031
1060
|
if (upstreamLoadSubset) {
|
|
@@ -1044,6 +1073,8 @@ class PersistedCollectionRuntime<
|
|
|
1044
1073
|
}
|
|
1045
1074
|
console.warn(`Failed to trigger remote subset load:`, error)
|
|
1046
1075
|
this.queueRemoteSubsetEnsure(options)
|
|
1076
|
+
// Hydration remains readable, but it does not satisfy remote demand.
|
|
1077
|
+
throw error
|
|
1047
1078
|
}
|
|
1048
1079
|
}
|
|
1049
1080
|
}
|
|
@@ -1058,9 +1089,13 @@ class PersistedCollectionRuntime<
|
|
|
1058
1089
|
}
|
|
1059
1090
|
|
|
1060
1091
|
async forceReloadSubset(options: LoadSubsetOptions): Promise<void> {
|
|
1061
|
-
this.
|
|
1092
|
+
const lifecycleGeneration = this.lifecycleGeneration
|
|
1093
|
+
// A one-shot refresh does not acquire an enduring subscription lease.
|
|
1062
1094
|
await this.applyMutex.run(() =>
|
|
1063
|
-
this.hydrateSubsetUnsafe(options, {
|
|
1095
|
+
this.hydrateSubsetUnsafe(options, {
|
|
1096
|
+
requestRemoteEnsure: false,
|
|
1097
|
+
lifecycleGeneration,
|
|
1098
|
+
}),
|
|
1064
1099
|
)
|
|
1065
1100
|
}
|
|
1066
1101
|
|
|
@@ -1179,6 +1214,8 @@ class PersistedCollectionRuntime<
|
|
|
1179
1214
|
}
|
|
1180
1215
|
|
|
1181
1216
|
cleanup(): void {
|
|
1217
|
+
this.advanceLifecycle()
|
|
1218
|
+
|
|
1182
1219
|
this.coordinatorUnsubscribe?.()
|
|
1183
1220
|
this.coordinatorUnsubscribe = null
|
|
1184
1221
|
|
|
@@ -1201,6 +1238,15 @@ class PersistedCollectionRuntime<
|
|
|
1201
1238
|
this.queuedHydrationTransactions.length = 0
|
|
1202
1239
|
this.queuedTxCommitted.length = 0
|
|
1203
1240
|
this.clearSyncControls()
|
|
1241
|
+
this.collection = null
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1244
|
+
private advanceLifecycle(): void {
|
|
1245
|
+
this.lifecycleGeneration++
|
|
1246
|
+
this.started = false
|
|
1247
|
+
this.startupMetadataPromise = null
|
|
1248
|
+
this.startPromise = null
|
|
1249
|
+
this.resumeBaselinePromise = null
|
|
1204
1250
|
}
|
|
1205
1251
|
|
|
1206
1252
|
private withInternalApply<TResult>(task: () => TResult): TResult {
|
|
@@ -1253,15 +1299,19 @@ class PersistedCollectionRuntime<
|
|
|
1253
1299
|
options: LoadSubsetOptions,
|
|
1254
1300
|
config: {
|
|
1255
1301
|
requestRemoteEnsure: boolean
|
|
1302
|
+
lifecycleGeneration: number
|
|
1256
1303
|
},
|
|
1257
1304
|
): Promise<void> {
|
|
1258
|
-
this.
|
|
1305
|
+
this.hydratingGeneration = config.lifecycleGeneration
|
|
1259
1306
|
try {
|
|
1260
1307
|
const rows = await this.loadSubsetRowsUnsafe(options)
|
|
1308
|
+
if (config.lifecycleGeneration !== this.lifecycleGeneration) return
|
|
1261
1309
|
|
|
1262
1310
|
this.applyRowsToCollection(rows)
|
|
1263
1311
|
} finally {
|
|
1264
|
-
this.
|
|
1312
|
+
if (this.hydratingGeneration === config.lifecycleGeneration) {
|
|
1313
|
+
this.hydratingGeneration = null
|
|
1314
|
+
}
|
|
1265
1315
|
}
|
|
1266
1316
|
|
|
1267
1317
|
await this.flushQueuedHydrationTransactionsUnsafe()
|
|
@@ -1808,20 +1858,14 @@ class PersistedCollectionRuntime<
|
|
|
1808
1858
|
}
|
|
1809
1859
|
|
|
1810
1860
|
private getSubsetKey(options: LoadSubsetOptions): string {
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
this.nextSubscriptionId++
|
|
1819
|
-
const id = `sub:${this.nextSubscriptionId}`
|
|
1820
|
-
this.subscriptionIds.set(subscription, id)
|
|
1821
|
-
return id
|
|
1861
|
+
// A subscription can own several independent acquisitions, including
|
|
1862
|
+
// identical requests. Only releasing this options object ends its lease.
|
|
1863
|
+
let id = this.requestIds.get(options)
|
|
1864
|
+
if (id === undefined) {
|
|
1865
|
+
id = `request:${++this.nextRequestId}`
|
|
1866
|
+
this.requestIds.set(options, id)
|
|
1822
1867
|
}
|
|
1823
|
-
|
|
1824
|
-
return `opts:${stableSerialize(normalizeSubsetOptionsForKey(options))}`
|
|
1868
|
+
return id
|
|
1825
1869
|
}
|
|
1826
1870
|
|
|
1827
1871
|
private queueRemoteSubsetEnsure(options: LoadSubsetOptions): void {
|
|
@@ -1911,7 +1955,7 @@ class PersistedCollectionRuntime<
|
|
|
1911
1955
|
// of both local and remote mutations. The seq dedup in
|
|
1912
1956
|
// processCommittedTxUnsafe prevents double-processing of our own writes.
|
|
1913
1957
|
if (isTxCommittedPayload(payload)) {
|
|
1914
|
-
if (this.
|
|
1958
|
+
if (this.isHydratingNow()) {
|
|
1915
1959
|
this.queuedTxCommitted.push(payload)
|
|
1916
1960
|
return
|
|
1917
1961
|
}
|
|
@@ -2136,17 +2180,20 @@ class PersistedCollectionRuntime<
|
|
|
2136
2180
|
}
|
|
2137
2181
|
|
|
2138
2182
|
private async reloadActiveSubsetsUnsafe(): Promise<void> {
|
|
2183
|
+
const lifecycleGeneration = this.lifecycleGeneration
|
|
2139
2184
|
const activeSubsetOptions =
|
|
2140
2185
|
this.activeSubsets.size > 0
|
|
2141
2186
|
? Array.from(this.activeSubsets.values())
|
|
2142
2187
|
: [{}]
|
|
2143
2188
|
|
|
2144
|
-
this.
|
|
2189
|
+
this.hydratingGeneration = lifecycleGeneration
|
|
2145
2190
|
try {
|
|
2146
2191
|
const mergedRows = new Map<TKey, { value: T; metadata?: unknown }>()
|
|
2147
2192
|
const collectionMetadata = await this.loadCollectionMetadataSnapshot()
|
|
2193
|
+
if (lifecycleGeneration !== this.lifecycleGeneration) return
|
|
2148
2194
|
for (const options of activeSubsetOptions) {
|
|
2149
2195
|
const subsetRows = await this.loadSubsetRowsUnsafe(options)
|
|
2196
|
+
if (lifecycleGeneration !== this.lifecycleGeneration) return
|
|
2150
2197
|
for (const row of subsetRows) {
|
|
2151
2198
|
mergedRows.set(row.key, {
|
|
2152
2199
|
value: row.value,
|
|
@@ -2164,7 +2211,9 @@ class PersistedCollectionRuntime<
|
|
|
2164
2211
|
collectionMetadata,
|
|
2165
2212
|
)
|
|
2166
2213
|
} finally {
|
|
2167
|
-
this.
|
|
2214
|
+
if (this.hydratingGeneration === lifecycleGeneration) {
|
|
2215
|
+
this.hydratingGeneration = null
|
|
2216
|
+
}
|
|
2168
2217
|
}
|
|
2169
2218
|
|
|
2170
2219
|
await this.flushQueuedHydrationTransactionsUnsafe()
|
|
@@ -2280,6 +2329,7 @@ function createWrappedSyncConfig<
|
|
|
2280
2329
|
const getOpenTransaction = () =>
|
|
2281
2330
|
transactionStack[transactionStack.length - 1]
|
|
2282
2331
|
let fullStartPromise: Promise<void> | null = null
|
|
2332
|
+
const startupState = { cleanedUp: false }
|
|
2283
2333
|
const acquisitions = new Map<LoadSubsetOptions, { forwarded: boolean }>()
|
|
2284
2334
|
runtime.setSyncControls({
|
|
2285
2335
|
begin: params.begin,
|
|
@@ -2295,11 +2345,14 @@ function createWrappedSyncConfig<
|
|
|
2295
2345
|
const wrappedParams = {
|
|
2296
2346
|
...params,
|
|
2297
2347
|
markReady: () => {
|
|
2348
|
+
if (startupState.cleanedUp) return
|
|
2298
2349
|
void (fullStartPromise ?? runtime.ensureStarted())
|
|
2299
2350
|
.then(() => {
|
|
2351
|
+
if (startupState.cleanedUp) return
|
|
2300
2352
|
params.markReady()
|
|
2301
2353
|
})
|
|
2302
2354
|
.catch((error) => {
|
|
2355
|
+
if (startupState.cleanedUp) return
|
|
2303
2356
|
console.warn(
|
|
2304
2357
|
`Failed persisted sync startup before markReady:`,
|
|
2305
2358
|
error,
|
|
@@ -2308,6 +2361,7 @@ function createWrappedSyncConfig<
|
|
|
2308
2361
|
})
|
|
2309
2362
|
},
|
|
2310
2363
|
begin: (options?: { immediate?: boolean }) => {
|
|
2364
|
+
if (startupState.cleanedUp) return
|
|
2311
2365
|
const transaction: OpenSyncTransaction<T, TKey> = {
|
|
2312
2366
|
operations: [],
|
|
2313
2367
|
rowMetadataWrites: new Map(),
|
|
@@ -2324,6 +2378,7 @@ function createWrappedSyncConfig<
|
|
|
2324
2378
|
}
|
|
2325
2379
|
},
|
|
2326
2380
|
write: (message: ChangeMessageOrDeleteKeyMessage<T, TKey>) => {
|
|
2381
|
+
if (startupState.cleanedUp) return
|
|
2327
2382
|
const normalization = runtime.normalizeSyncWriteMessage(message)
|
|
2328
2383
|
const openTransaction = getOpenTransaction()
|
|
2329
2384
|
|
|
@@ -2369,7 +2424,12 @@ function createWrappedSyncConfig<
|
|
|
2369
2424
|
metadata: params.metadata
|
|
2370
2425
|
? {
|
|
2371
2426
|
row: {
|
|
2427
|
+
whenHydrated: () =>
|
|
2428
|
+
startupState.cleanedUp
|
|
2429
|
+
? Promise.resolve()
|
|
2430
|
+
: runtime.ensureResumeBaselineHydrated(),
|
|
2372
2431
|
get: (key: TKey) => {
|
|
2432
|
+
if (startupState.cleanedUp) return undefined
|
|
2373
2433
|
const openTransaction = getOpenTransaction()
|
|
2374
2434
|
const pendingWrite =
|
|
2375
2435
|
openTransaction?.rowMetadataWrites.get(key)
|
|
@@ -2384,8 +2444,11 @@ function createWrappedSyncConfig<
|
|
|
2384
2444
|
return params.metadata!.row.get(key)
|
|
2385
2445
|
},
|
|
2386
2446
|
scanPersisted: (options?: PersistedRowScanOptions) =>
|
|
2387
|
-
|
|
2447
|
+
startupState.cleanedUp
|
|
2448
|
+
? Promise.resolve([])
|
|
2449
|
+
: runtime.scanPersistedRows(options),
|
|
2388
2450
|
set: (key: TKey, value: unknown) => {
|
|
2451
|
+
if (startupState.cleanedUp) return
|
|
2389
2452
|
const openTransaction = getOpenTransaction()
|
|
2390
2453
|
if (!openTransaction) {
|
|
2391
2454
|
throw new InvalidPersistedCollectionConfigError(
|
|
@@ -2401,6 +2464,7 @@ function createWrappedSyncConfig<
|
|
|
2401
2464
|
}
|
|
2402
2465
|
},
|
|
2403
2466
|
delete: (key: TKey) => {
|
|
2467
|
+
if (startupState.cleanedUp) return
|
|
2404
2468
|
const openTransaction = getOpenTransaction()
|
|
2405
2469
|
if (!openTransaction) {
|
|
2406
2470
|
throw new InvalidPersistedCollectionConfigError(
|
|
@@ -2417,6 +2481,7 @@ function createWrappedSyncConfig<
|
|
|
2417
2481
|
},
|
|
2418
2482
|
collection: {
|
|
2419
2483
|
get: (key: string) => {
|
|
2484
|
+
if (startupState.cleanedUp) return undefined
|
|
2420
2485
|
const openTransaction = getOpenTransaction()
|
|
2421
2486
|
const pendingWrite =
|
|
2422
2487
|
openTransaction?.collectionMetadataWrites.get(key)
|
|
@@ -2428,6 +2493,7 @@ function createWrappedSyncConfig<
|
|
|
2428
2493
|
return params.metadata!.collection.get(key)
|
|
2429
2494
|
},
|
|
2430
2495
|
set: (key: string, value: unknown) => {
|
|
2496
|
+
if (startupState.cleanedUp) return
|
|
2431
2497
|
const openTransaction = getOpenTransaction()
|
|
2432
2498
|
if (!openTransaction) {
|
|
2433
2499
|
throw new InvalidPersistedCollectionConfigError(
|
|
@@ -2443,6 +2509,7 @@ function createWrappedSyncConfig<
|
|
|
2443
2509
|
}
|
|
2444
2510
|
},
|
|
2445
2511
|
delete: (key: string) => {
|
|
2512
|
+
if (startupState.cleanedUp) return
|
|
2446
2513
|
const openTransaction = getOpenTransaction()
|
|
2447
2514
|
if (!openTransaction) {
|
|
2448
2515
|
throw new InvalidPersistedCollectionConfigError(
|
|
@@ -2457,6 +2524,7 @@ function createWrappedSyncConfig<
|
|
|
2457
2524
|
}
|
|
2458
2525
|
},
|
|
2459
2526
|
list: (prefix?: string) => {
|
|
2527
|
+
if (startupState.cleanedUp) return []
|
|
2460
2528
|
const merged = new Map(
|
|
2461
2529
|
params
|
|
2462
2530
|
.metadata!.collection.list()
|
|
@@ -2487,6 +2555,7 @@ function createWrappedSyncConfig<
|
|
|
2487
2555
|
}
|
|
2488
2556
|
: undefined,
|
|
2489
2557
|
truncate: () => {
|
|
2558
|
+
if (startupState.cleanedUp) return
|
|
2490
2559
|
const openTransaction = getOpenTransaction()
|
|
2491
2560
|
if (!openTransaction) {
|
|
2492
2561
|
params.truncate()
|
|
@@ -2505,6 +2574,7 @@ function createWrappedSyncConfig<
|
|
|
2505
2574
|
}
|
|
2506
2575
|
},
|
|
2507
2576
|
commit: (signal?: AbortSignal) => {
|
|
2577
|
+
if (startupState.cleanedUp) return true
|
|
2508
2578
|
const openTransaction = transactionStack.pop()
|
|
2509
2579
|
if (!openTransaction) {
|
|
2510
2580
|
return params.commit(signal)
|
|
@@ -2559,7 +2629,6 @@ function createWrappedSyncConfig<
|
|
|
2559
2629
|
}
|
|
2560
2630
|
|
|
2561
2631
|
let sourceResult: SyncConfigRes = {}
|
|
2562
|
-
const startupState = { cleanedUp: false }
|
|
2563
2632
|
fullStartPromise = runtime.ensureStarted()
|
|
2564
2633
|
const sourceResultPromise = (async () => {
|
|
2565
2634
|
await runtime.ensureStartupMetadataLoaded()
|
|
@@ -2605,6 +2674,8 @@ function createWrappedSyncConfig<
|
|
|
2605
2674
|
if (!resolvedSourceResult.loadSubset) return true
|
|
2606
2675
|
acquisition.forwarded = true
|
|
2607
2676
|
try {
|
|
2677
|
+
// Returning a promise transfers its lease even if it rejects.
|
|
2678
|
+
// Only a synchronous throw leaves no upstream lease to release.
|
|
2608
2679
|
return resolvedSourceResult.loadSubset(loadOptions)
|
|
2609
2680
|
} catch (error) {
|
|
2610
2681
|
acquisition.forwarded = false
|