@tanstack/electron-db-sqlite-persistence 0.2.13 → 1.0.0-rc.1
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/renderer.cjs +29 -2
- package/dist/cjs/renderer.cjs.map +1 -1
- package/dist/esm/renderer.js +29 -2
- package/dist/esm/renderer.js.map +1 -1
- package/package.json +4 -4
- package/src/renderer.ts +36 -0
package/dist/cjs/renderer.cjs
CHANGED
|
@@ -98,7 +98,25 @@ function createRendererRequestExecutor(options) {
|
|
|
98
98
|
return response.result;
|
|
99
99
|
};
|
|
100
100
|
}
|
|
101
|
-
|
|
101
|
+
class RendererQueuedWork {
|
|
102
|
+
constructor() {
|
|
103
|
+
this.unsettled = /* @__PURE__ */ new Set();
|
|
104
|
+
}
|
|
105
|
+
track(work) {
|
|
106
|
+
const done = work.then(
|
|
107
|
+
() => void 0,
|
|
108
|
+
() => void 0
|
|
109
|
+
);
|
|
110
|
+
this.unsettled.add(done);
|
|
111
|
+
void done.then(() => this.unsettled.delete(done));
|
|
112
|
+
return work;
|
|
113
|
+
}
|
|
114
|
+
// Settles once every hydration scope outstanding at the call settles.
|
|
115
|
+
afterQueuedWork() {
|
|
116
|
+
return Promise.all(this.unsettled).then(() => void 0);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
function createResolvedRendererAdapter(executeRequest, claimCollections, managedCacheGenerations, queuedWork, resolution) {
|
|
102
120
|
const adapter = {
|
|
103
121
|
loadSubset: async (target, subsetOptions, ctx) => {
|
|
104
122
|
const access = dbSqlitePersistenceCore.resolvePersistedStorageTarget(
|
|
@@ -302,7 +320,14 @@ function createResolvedRendererAdapter(executeRequest, claimCollections, managed
|
|
|
302
320
|
},
|
|
303
321
|
resolution
|
|
304
322
|
);
|
|
305
|
-
}
|
|
323
|
+
},
|
|
324
|
+
runInHydrationScope: (task) => queuedWork.track(Promise.resolve().then(() => task(adapter))),
|
|
325
|
+
isHydrationScopeScheduled: () => false,
|
|
326
|
+
// Work runs directly; the main process serializes it.
|
|
327
|
+
runInRegularScope: Object.assign(
|
|
328
|
+
(task) => task(adapter),
|
|
329
|
+
{ afterQueuedWork: () => queuedWork.afterQueuedWork() }
|
|
330
|
+
)
|
|
306
331
|
};
|
|
307
332
|
if (!managedCacheGenerations) {
|
|
308
333
|
adapter.claimCacheGeneration = void 0;
|
|
@@ -324,6 +349,7 @@ function resolveInvoke(options) {
|
|
|
324
349
|
);
|
|
325
350
|
}
|
|
326
351
|
function createElectronSQLitePersistence(options) {
|
|
352
|
+
const queuedWork = new RendererQueuedWork();
|
|
327
353
|
const invoke = resolveInvoke(options);
|
|
328
354
|
const coordinator = options.coordinator ?? new dbSqlitePersistenceCore.SingleProcessCoordinator();
|
|
329
355
|
const claimCollections = /* @__PURE__ */ new Map();
|
|
@@ -344,6 +370,7 @@ function createElectronSQLitePersistence(options) {
|
|
|
344
370
|
executeRequest,
|
|
345
371
|
claimCollections,
|
|
346
372
|
options.managedCacheGenerations ?? true,
|
|
373
|
+
queuedWork,
|
|
347
374
|
{ mode, schemaVersion, logicalCollectionId: collectionId }
|
|
348
375
|
);
|
|
349
376
|
adapterCache.set(cacheKey, adapter);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"renderer.cjs","sources":["../../src/renderer.ts"],"sourcesContent":["import {\n InvalidPersistedCollectionConfigError,\n SingleProcessCoordinator,\n resolvePersistedStorageTarget,\n} from '@tanstack/db-sqlite-persistence-core'\nimport { ElectronCollectionCoordinator } from './electron-coordinator'\nimport {\n DEFAULT_ELECTRON_PERSISTENCE_CHANNEL,\n ELECTRON_PERSISTENCE_PROTOCOL_VERSION,\n} from './protocol'\nimport type {\n CommittedTxAnchor,\n PersistedCacheGenerationClaim,\n PersistedCollectionCoordinator,\n PersistedCollectionMode,\n PersistedCollectionPersistence,\n PersistedIndexSpec,\n PersistedStorageTarget,\n PersistedTx,\n ReconciledCommittedTx,\n SQLitePullSinceResult,\n} from '@tanstack/db-sqlite-persistence-core'\nimport type {\n ElectronPersistedKey,\n ElectronPersistedRow,\n ElectronPersistenceInvoke,\n ElectronPersistenceMethod,\n ElectronPersistencePayloadMap,\n ElectronPersistenceRequest,\n ElectronPersistenceRequestEnvelope,\n ElectronPersistenceResolution,\n ElectronPersistenceResponseEnvelope,\n ElectronPersistenceResultMap,\n} from './protocol'\nimport type { LoadSubsetOptions } from '@tanstack/db'\n\nconst DEFAULT_REQUEST_TIMEOUT_MS = 5_000\nlet nextRequestId = 1\n\nfunction createRequestId(): string {\n const requestId = nextRequestId\n nextRequestId++\n return `electron-persistence-${requestId}`\n}\n\nfunction withTimeout<T>(\n promise: Promise<T>,\n timeoutMs: number,\n timeoutMessage: string,\n): Promise<T> {\n if (timeoutMs <= 0) {\n return promise\n }\n\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => {\n reject(new InvalidPersistedCollectionConfigError(timeoutMessage))\n }, timeoutMs)\n\n promise.then(\n (value) => {\n clearTimeout(timer)\n resolve(value)\n },\n (error: unknown) => {\n clearTimeout(timer)\n reject(error)\n },\n )\n })\n}\n\nfunction assertValidResponse(\n response: ElectronPersistenceResponseEnvelope,\n request: ElectronPersistenceRequestEnvelope,\n): void {\n if (response.v !== ELECTRON_PERSISTENCE_PROTOCOL_VERSION) {\n throw new InvalidPersistedCollectionConfigError(\n `Unexpected electron persistence protocol version \"${response.v}\" in response`,\n )\n }\n\n if (response.requestId !== request.requestId) {\n throw new InvalidPersistedCollectionConfigError(\n `Mismatched electron persistence response request id. Expected \"${request.requestId}\", received \"${response.requestId}\"`,\n )\n }\n\n if (response.method !== request.method) {\n throw new InvalidPersistedCollectionConfigError(\n `Mismatched electron persistence response method. Expected \"${request.method}\", received \"${response.method}\"`,\n )\n }\n}\n\nfunction createSerializableLoadSubsetOptions(\n subsetOptions: LoadSubsetOptions,\n): LoadSubsetOptions {\n const { subscription: _subscription, ...serializableOptions } = subsetOptions\n return serializableOptions\n}\n\ntype RendererRequestExecutor = <TMethod extends ElectronPersistenceMethod>(\n method: TMethod,\n target: string | PersistedStorageTarget,\n payload: ElectronPersistencePayloadMap[TMethod],\n resolution?: ElectronPersistenceResolution,\n) => Promise<ElectronPersistenceResultMap[TMethod]>\n\nfunction createRendererRequestExecutor(options: {\n invoke: ElectronPersistenceInvoke\n channel?: string\n timeoutMs?: number\n claimCollections: Map<string, string>\n}): RendererRequestExecutor {\n const channel = options.channel ?? DEFAULT_ELECTRON_PERSISTENCE_CHANNEL\n const timeoutMs = options.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS\n\n return async <TMethod extends ElectronPersistenceMethod>(\n method: TMethod,\n target: string | PersistedStorageTarget,\n payload: ElectronPersistencePayloadMap[TMethod],\n resolution?: ElectronPersistenceResolution,\n ) => {\n const storageTarget = typeof target === `string` ? undefined : target\n const collectionId = storageTarget\n ? resolvePersistedStorageTarget(storageTarget).collectionId\n : target\n const isGenerationRequest =\n method === `claimCacheGeneration` ||\n method === `rotateCacheGeneration` ||\n method === `renewCacheGenerationClaim` ||\n method === `releaseCacheGenerationClaim`\n const managedTarget = storageTarget?.kind === `managed`\n const logicalCollectionId =\n resolution?.logicalCollectionId ??\n (managedTarget\n ? options.claimCollections.get(storageTarget.claimId)\n : isGenerationRequest\n ? collectionId\n : undefined)\n if ((managedTarget || isGenerationRequest) && !logicalCollectionId) {\n throw new InvalidPersistedCollectionConfigError(\n `Electron managed cache request requires a known logical Collection ID`,\n )\n }\n const request = {\n v: ELECTRON_PERSISTENCE_PROTOCOL_VERSION,\n requestId: createRequestId(),\n collectionId,\n storageTarget,\n method,\n resolution:\n managedTarget || isGenerationRequest\n ? { ...resolution, mode: `sync-present`, logicalCollectionId }\n : resolution,\n payload,\n } as ElectronPersistenceRequest\n\n const response = await withTimeout(\n options.invoke(channel, request),\n timeoutMs,\n `Electron persistence request timed out (method=${method}, collection=${collectionId}, timeoutMs=${timeoutMs})`,\n )\n assertValidResponse(response, request)\n\n if (!response.ok) {\n const remoteError = new InvalidPersistedCollectionConfigError(\n `${response.error.name}: ${response.error.message}`,\n )\n if (typeof response.error.stack === `string`) {\n remoteError.stack = response.error.stack\n }\n if (\n typeof response.error.code === `string` ||\n typeof response.error.code === `number`\n ) {\n ;(remoteError as Error & { code?: string | number }).code =\n response.error.code\n }\n if (response.error.path !== undefined) {\n ;(\n remoteError as Error & {\n path?: string | ReadonlyArray<string | number>\n }\n ).path = response.error.path\n }\n throw remoteError\n }\n\n return response.result as ElectronPersistenceResultMap[TMethod]\n }\n}\n\ntype ElectronRendererResolvedAdapter =\n PersistedCollectionPersistence[`adapter`] & {\n loadCollectionMetadata: (\n target: PersistedStorageTarget,\n ctx?: { cacheGenerationClaimId?: string },\n ) => Promise<Array<{ key: string; value: unknown }>>\n scanRows: (\n target: PersistedStorageTarget,\n options?: { metadataOnly?: boolean },\n ctx?: { cacheGenerationClaimId?: string },\n ) => Promise<\n Array<{\n key: string | number\n value: Record<string, unknown>\n metadata?: unknown\n }>\n >\n pullSince: (\n target: PersistedStorageTarget,\n fromRowVersion: number,\n ctx?: { cacheGenerationClaimId?: string },\n ) => Promise<SQLitePullSinceResult<string | number>>\n getStreamPosition: (\n target: PersistedStorageTarget,\n ctx?: { cacheGenerationClaimId?: string },\n ) => Promise<{\n latestTerm: number\n latestSeq: number\n latestRowVersion: number\n }>\n reserveLeadershipTerm: (\n target: PersistedStorageTarget,\n observedTerm: number,\n ctx?: { cacheGenerationClaimId?: string },\n ) => Promise<{\n latestTerm: number\n latestSeq: number\n latestRowVersion: number\n }>\n }\n\nfunction createResolvedRendererAdapter(\n executeRequest: RendererRequestExecutor,\n claimCollections: Map<string, string>,\n managedCacheGenerations: boolean,\n resolution?: ElectronPersistenceResolution,\n): ElectronRendererResolvedAdapter {\n const adapter: ElectronRendererResolvedAdapter = {\n loadSubset: async (\n target: PersistedStorageTarget,\n subsetOptions: LoadSubsetOptions,\n ctx?: {\n requiredIndexSignatures?: ReadonlyArray<string>\n cacheGenerationClaimId?: string\n },\n ) => {\n const access = resolvePersistedStorageTarget(\n target,\n ctx?.cacheGenerationClaimId,\n )\n const result = await executeRequest(\n `loadSubset`,\n target,\n {\n options: createSerializableLoadSubsetOptions(subsetOptions),\n ctx: { ...ctx, cacheGenerationClaimId: access.claimId },\n },\n resolution,\n )\n\n return result as Array<{\n key: string | number\n value: Record<string, unknown>\n }>\n },\n loadResumeSnapshot: async (\n target: PersistedStorageTarget,\n ctx?: {\n requiredIndexSignatures?: ReadonlyArray<string>\n includeRows?: boolean\n cacheGenerationClaimId?: string\n },\n ) => {\n const access = resolvePersistedStorageTarget(\n target,\n ctx?.cacheGenerationClaimId,\n )\n return executeRequest(\n `loadResumeSnapshot`,\n target,\n { ctx: { ...ctx, cacheGenerationClaimId: access.claimId } },\n resolution,\n )\n },\n applyCommittedTx: async (\n target: PersistedStorageTarget,\n tx: PersistedTx<Record<string, unknown>, string | number>,\n ): Promise<void> => {\n const access = resolvePersistedStorageTarget(\n target,\n tx.cacheGenerationClaimId,\n )\n await executeRequest(\n `applyCommittedTx`,\n target,\n {\n tx: { ...tx, cacheGenerationClaimId: access.claimId } as PersistedTx<\n ElectronPersistedRow,\n ElectronPersistedKey\n >,\n },\n resolution,\n )\n },\n reconcileCommittedTx: async (\n target: PersistedStorageTarget,\n tx: PersistedTx<Record<string, unknown>, string | number>,\n anchor: CommittedTxAnchor,\n ): Promise<ReconciledCommittedTx> => {\n const access = resolvePersistedStorageTarget(\n target,\n tx.cacheGenerationClaimId,\n )\n return executeRequest(\n `reconcileCommittedTx`,\n target,\n { tx: { ...tx, cacheGenerationClaimId: access.claimId }, anchor },\n resolution,\n )\n },\n loadCollectionMetadata: async (\n target: PersistedStorageTarget,\n ctx?: { cacheGenerationClaimId?: string },\n ): Promise<Array<{ key: string; value: unknown }>> => {\n const access = resolvePersistedStorageTarget(\n target,\n ctx?.cacheGenerationClaimId,\n )\n return executeRequest(\n `loadCollectionMetadata`,\n target,\n { ctx: { ...ctx, cacheGenerationClaimId: access.claimId } },\n resolution,\n )\n },\n scanRows: async (\n target: PersistedStorageTarget,\n options?: { metadataOnly?: boolean },\n ctx?: { cacheGenerationClaimId?: string },\n ): Promise<\n Array<{\n key: string | number\n value: Record<string, unknown>\n metadata?: unknown\n }>\n > => {\n const access = resolvePersistedStorageTarget(\n target,\n ctx?.cacheGenerationClaimId,\n )\n const result = await executeRequest(\n `scanRows`,\n target,\n { options, ctx: { ...ctx, cacheGenerationClaimId: access.claimId } },\n resolution,\n )\n return result as Array<{\n key: string | number\n value: Record<string, unknown>\n metadata?: unknown\n }>\n },\n ensureIndex: async (\n target: PersistedStorageTarget,\n signature: string,\n spec: PersistedIndexSpec,\n ctx?: { cacheGenerationClaimId?: string },\n ): Promise<void> => {\n const access = resolvePersistedStorageTarget(\n target,\n ctx?.cacheGenerationClaimId,\n )\n await executeRequest(\n `ensureIndex`,\n target,\n {\n signature,\n spec,\n ctx: { ...ctx, cacheGenerationClaimId: access.claimId },\n },\n resolution,\n )\n },\n markIndexRemoved: async (\n target: PersistedStorageTarget,\n signature: string,\n ctx?: { cacheGenerationClaimId?: string },\n ): Promise<void> => {\n const access = resolvePersistedStorageTarget(\n target,\n ctx?.cacheGenerationClaimId,\n )\n await executeRequest(\n `markIndexRemoved`,\n target,\n {\n signature,\n ctx: { ...ctx, cacheGenerationClaimId: access.claimId },\n },\n resolution,\n )\n },\n pullSince: async (\n target: PersistedStorageTarget,\n fromRowVersion: number,\n ctx?: { cacheGenerationClaimId?: string },\n ): Promise<SQLitePullSinceResult<string | number>> => {\n const access = resolvePersistedStorageTarget(\n target,\n ctx?.cacheGenerationClaimId,\n )\n const result = await executeRequest(\n `pullSince`,\n target,\n {\n fromRowVersion,\n ctx: { ...ctx, cacheGenerationClaimId: access.claimId },\n },\n resolution,\n )\n return result as SQLitePullSinceResult<string | number>\n },\n getStreamPosition: async (\n target: PersistedStorageTarget,\n ctx?: { cacheGenerationClaimId?: string },\n ): Promise<{\n latestTerm: number\n latestSeq: number\n latestRowVersion: number\n }> => {\n const access = resolvePersistedStorageTarget(\n target,\n ctx?.cacheGenerationClaimId,\n )\n return executeRequest(\n `getStreamPosition`,\n target,\n { ctx: { ...ctx, cacheGenerationClaimId: access.claimId } },\n resolution,\n )\n },\n claimCacheGeneration: async (\n collectionId: string,\n ): Promise<PersistedCacheGenerationClaim> => {\n const claim = await executeRequest(\n `claimCacheGeneration`,\n collectionId,\n {},\n resolution,\n )\n claimCollections.set(claim.claimId, collectionId)\n return claim\n },\n rotateCacheGeneration: async (\n collectionId: string,\n claimId: string,\n resetMetadata?: { key: string; value: unknown },\n expectedStorageCollectionId?: string,\n ): Promise<PersistedCacheGenerationClaim> => {\n const claim = await executeRequest(\n `rotateCacheGeneration`,\n collectionId,\n { claimId, resetMetadata, expectedStorageCollectionId },\n resolution,\n )\n claimCollections.delete(claimId)\n claimCollections.set(claim.claimId, collectionId)\n return claim\n },\n renewCacheGenerationClaim: (\n storageCollectionId: string,\n claimId: string,\n ): Promise<number | undefined> => {\n const collectionId = claimCollections.get(claimId)\n if (!collectionId) {\n throw new InvalidPersistedCollectionConfigError(\n `Unknown electron persisted cache claim \"${claimId}\"`,\n )\n }\n return executeRequest(\n `renewCacheGenerationClaim`,\n collectionId,\n { storageCollectionId, claimId },\n resolution,\n )\n },\n releaseCacheGenerationClaim: async (claimId: string): Promise<void> => {\n const collectionId = claimCollections.get(claimId)\n if (!collectionId) {\n throw new InvalidPersistedCollectionConfigError(\n `Unknown electron persisted cache claim \"${claimId}\"`,\n )\n }\n await executeRequest(\n `releaseCacheGenerationClaim`,\n collectionId,\n { claimId },\n resolution,\n )\n claimCollections.delete(claimId)\n },\n reserveLeadershipTerm: async (target, observedTerm, ctx) => {\n const access = resolvePersistedStorageTarget(\n target,\n ctx?.cacheGenerationClaimId,\n )\n return executeRequest(\n `reserveLeadershipTerm`,\n target,\n {\n observedTerm,\n ctx: { ...ctx, cacheGenerationClaimId: access.claimId },\n },\n resolution,\n )\n },\n }\n if (!managedCacheGenerations) {\n adapter.claimCacheGeneration = undefined\n adapter.rotateCacheGeneration = undefined\n adapter.renewCacheGenerationClaim = undefined\n adapter.releaseCacheGenerationClaim = undefined\n }\n return adapter\n}\n\nexport type ElectronIpcRendererLike = {\n invoke: (\n channel: string,\n request: ElectronPersistenceRequestEnvelope,\n ) => Promise<ElectronPersistenceResponseEnvelope>\n}\n\nexport type ElectronSQLitePersistenceOptions = {\n invoke?: ElectronPersistenceInvoke\n ipcRenderer?: ElectronIpcRendererLike\n channel?: string\n timeoutMs?: number\n coordinator?: PersistedCollectionCoordinator\n /** Set false when a custom main-process adapter does not manage cache generations. */\n managedCacheGenerations?: boolean\n}\n\nfunction resolveInvoke(\n options: ElectronSQLitePersistenceOptions,\n): ElectronPersistenceInvoke {\n if (options.invoke) {\n return options.invoke\n }\n\n if (options.ipcRenderer) {\n return (channel, request) => options.ipcRenderer!.invoke(channel, request)\n }\n\n throw new InvalidPersistedCollectionConfigError(\n `Electron renderer persistence requires either invoke or ipcRenderer`,\n )\n}\n\nexport function createElectronSQLitePersistence(\n options: ElectronSQLitePersistenceOptions,\n): PersistedCollectionPersistence {\n const invoke = resolveInvoke(options)\n const coordinator = options.coordinator ?? new SingleProcessCoordinator()\n const claimCollections = new Map<string, string>()\n const executeRequest = createRendererRequestExecutor({\n invoke,\n channel: options.channel,\n timeoutMs: options.timeoutMs,\n claimCollections,\n })\n const adapterCache = new Map<string, ElectronRendererResolvedAdapter>()\n\n const getAdapterForCollection = (\n collectionId: string | undefined,\n mode: PersistedCollectionMode,\n schemaVersion: number | undefined,\n ) => {\n const cacheKey = JSON.stringify([collectionId, mode, schemaVersion])\n const cachedAdapter = adapterCache.get(cacheKey)\n if (cachedAdapter) {\n return cachedAdapter\n }\n\n const adapter = createResolvedRendererAdapter(\n executeRequest,\n claimCollections,\n options.managedCacheGenerations ?? true,\n { mode, schemaVersion, logicalCollectionId: collectionId },\n )\n adapterCache.set(cacheKey, adapter)\n return adapter\n }\n\n const createCollectionPersistence = (\n collectionId: string | undefined,\n mode: PersistedCollectionMode,\n schemaVersion: number | undefined,\n ): PersistedCollectionPersistence => {\n const adapter = getAdapterForCollection(collectionId, mode, schemaVersion)\n if (coordinator instanceof ElectronCollectionCoordinator) {\n if (collectionId === undefined) {\n coordinator.setAdapter(adapter)\n } else {\n coordinator.setAdapterForCollection(collectionId, adapter)\n }\n }\n return { adapter, coordinator }\n }\n\n const defaultPersistence = createCollectionPersistence(\n undefined,\n `sync-absent`,\n undefined,\n )\n if (coordinator instanceof ElectronCollectionCoordinator) {\n coordinator.setAdapter(defaultPersistence.adapter)\n }\n\n return {\n ...defaultPersistence,\n resolvePersistenceForCollection: ({ collectionId, mode, schemaVersion }) =>\n createCollectionPersistence(collectionId, mode, schemaVersion),\n // Backward compatible fallback for older callers.\n resolvePersistenceForMode: (mode) =>\n createCollectionPersistence(undefined, mode, undefined),\n }\n}\n"],"names":["InvalidPersistedCollectionConfigError","ELECTRON_PERSISTENCE_PROTOCOL_VERSION","DEFAULT_ELECTRON_PERSISTENCE_CHANNEL","resolvePersistedStorageTarget","SingleProcessCoordinator","ElectronCollectionCoordinator"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"renderer.cjs","sources":["../../src/renderer.ts"],"sourcesContent":["import {\n InvalidPersistedCollectionConfigError,\n SingleProcessCoordinator,\n resolvePersistedStorageTarget,\n} from '@tanstack/db-sqlite-persistence-core'\nimport { ElectronCollectionCoordinator } from './electron-coordinator'\nimport {\n DEFAULT_ELECTRON_PERSISTENCE_CHANNEL,\n ELECTRON_PERSISTENCE_PROTOCOL_VERSION,\n} from './protocol'\nimport type {\n CommittedTxAnchor,\n HydrationPersistenceAdapter,\n PersistedCacheGenerationClaim,\n PersistedCollectionCoordinator,\n PersistedCollectionMode,\n PersistedCollectionPersistence,\n PersistedIndexSpec,\n PersistedStorageTarget,\n PersistedTx,\n ReconciledCommittedTx,\n SQLitePullSinceResult,\n} from '@tanstack/db-sqlite-persistence-core'\nimport type {\n ElectronPersistedKey,\n ElectronPersistedRow,\n ElectronPersistenceInvoke,\n ElectronPersistenceMethod,\n ElectronPersistencePayloadMap,\n ElectronPersistenceRequest,\n ElectronPersistenceRequestEnvelope,\n ElectronPersistenceResolution,\n ElectronPersistenceResponseEnvelope,\n ElectronPersistenceResultMap,\n} from './protocol'\nimport type { LoadSubsetOptions } from '@tanstack/db'\n\nconst DEFAULT_REQUEST_TIMEOUT_MS = 5_000\nlet nextRequestId = 1\n\nfunction createRequestId(): string {\n const requestId = nextRequestId\n nextRequestId++\n return `electron-persistence-${requestId}`\n}\n\nfunction withTimeout<T>(\n promise: Promise<T>,\n timeoutMs: number,\n timeoutMessage: string,\n): Promise<T> {\n if (timeoutMs <= 0) {\n return promise\n }\n\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => {\n reject(new InvalidPersistedCollectionConfigError(timeoutMessage))\n }, timeoutMs)\n\n promise.then(\n (value) => {\n clearTimeout(timer)\n resolve(value)\n },\n (error: unknown) => {\n clearTimeout(timer)\n reject(error)\n },\n )\n })\n}\n\nfunction assertValidResponse(\n response: ElectronPersistenceResponseEnvelope,\n request: ElectronPersistenceRequestEnvelope,\n): void {\n if (response.v !== ELECTRON_PERSISTENCE_PROTOCOL_VERSION) {\n throw new InvalidPersistedCollectionConfigError(\n `Unexpected electron persistence protocol version \"${response.v}\" in response`,\n )\n }\n\n if (response.requestId !== request.requestId) {\n throw new InvalidPersistedCollectionConfigError(\n `Mismatched electron persistence response request id. Expected \"${request.requestId}\", received \"${response.requestId}\"`,\n )\n }\n\n if (response.method !== request.method) {\n throw new InvalidPersistedCollectionConfigError(\n `Mismatched electron persistence response method. Expected \"${request.method}\", received \"${response.method}\"`,\n )\n }\n}\n\nfunction createSerializableLoadSubsetOptions(\n subsetOptions: LoadSubsetOptions,\n): LoadSubsetOptions {\n const { subscription: _subscription, ...serializableOptions } = subsetOptions\n return serializableOptions\n}\n\ntype RendererRequestExecutor = <TMethod extends ElectronPersistenceMethod>(\n method: TMethod,\n target: string | PersistedStorageTarget,\n payload: ElectronPersistencePayloadMap[TMethod],\n resolution?: ElectronPersistenceResolution,\n) => Promise<ElectronPersistenceResultMap[TMethod]>\n\nfunction createRendererRequestExecutor(options: {\n invoke: ElectronPersistenceInvoke\n channel?: string\n timeoutMs?: number\n claimCollections: Map<string, string>\n}): RendererRequestExecutor {\n const channel = options.channel ?? DEFAULT_ELECTRON_PERSISTENCE_CHANNEL\n const timeoutMs = options.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS\n\n return async <TMethod extends ElectronPersistenceMethod>(\n method: TMethod,\n target: string | PersistedStorageTarget,\n payload: ElectronPersistencePayloadMap[TMethod],\n resolution?: ElectronPersistenceResolution,\n ) => {\n const storageTarget = typeof target === `string` ? undefined : target\n const collectionId = storageTarget\n ? resolvePersistedStorageTarget(storageTarget).collectionId\n : target\n const isGenerationRequest =\n method === `claimCacheGeneration` ||\n method === `rotateCacheGeneration` ||\n method === `renewCacheGenerationClaim` ||\n method === `releaseCacheGenerationClaim`\n const managedTarget = storageTarget?.kind === `managed`\n const logicalCollectionId =\n resolution?.logicalCollectionId ??\n (managedTarget\n ? options.claimCollections.get(storageTarget.claimId)\n : isGenerationRequest\n ? collectionId\n : undefined)\n if ((managedTarget || isGenerationRequest) && !logicalCollectionId) {\n throw new InvalidPersistedCollectionConfigError(\n `Electron managed cache request requires a known logical Collection ID`,\n )\n }\n const request = {\n v: ELECTRON_PERSISTENCE_PROTOCOL_VERSION,\n requestId: createRequestId(),\n collectionId,\n storageTarget,\n method,\n resolution:\n managedTarget || isGenerationRequest\n ? { ...resolution, mode: `sync-present`, logicalCollectionId }\n : resolution,\n payload,\n } as ElectronPersistenceRequest\n\n const response = await withTimeout(\n options.invoke(channel, request),\n timeoutMs,\n `Electron persistence request timed out (method=${method}, collection=${collectionId}, timeoutMs=${timeoutMs})`,\n )\n assertValidResponse(response, request)\n\n if (!response.ok) {\n const remoteError = new InvalidPersistedCollectionConfigError(\n `${response.error.name}: ${response.error.message}`,\n )\n if (typeof response.error.stack === `string`) {\n remoteError.stack = response.error.stack\n }\n if (\n typeof response.error.code === `string` ||\n typeof response.error.code === `number`\n ) {\n ;(remoteError as Error & { code?: string | number }).code =\n response.error.code\n }\n if (response.error.path !== undefined) {\n ;(\n remoteError as Error & {\n path?: string | ReadonlyArray<string | number>\n }\n ).path = response.error.path\n }\n throw remoteError\n }\n\n return response.result as ElectronPersistenceResultMap[TMethod]\n }\n}\n\n// The renderer has no shared driver scheduler. Its queued reads are its\n// hydration scopes; its writes take the writer Web Lock, which also orders\n// them against an election term.\nclass RendererQueuedWork {\n private readonly unsettled = new Set<Promise<void>>()\n\n track<T>(work: Promise<T>): Promise<T> {\n const done = work.then(\n () => undefined,\n () => undefined,\n )\n this.unsettled.add(done)\n void done.then(() => this.unsettled.delete(done))\n return work\n }\n\n // Settles once every hydration scope outstanding at the call settles.\n afterQueuedWork(): Promise<void> {\n return Promise.all(this.unsettled).then(() => undefined)\n }\n}\n\ntype ElectronRendererResolvedAdapter =\n PersistedCollectionPersistence[`adapter`] & {\n loadCollectionMetadata: (\n target: PersistedStorageTarget,\n ctx?: { cacheGenerationClaimId?: string },\n ) => Promise<Array<{ key: string; value: unknown }>>\n scanRows: (\n target: PersistedStorageTarget,\n options?: { metadataOnly?: boolean },\n ctx?: { cacheGenerationClaimId?: string },\n ) => Promise<\n Array<{\n key: string | number\n value: Record<string, unknown>\n metadata?: unknown\n }>\n >\n pullSince: (\n target: PersistedStorageTarget,\n fromRowVersion: number,\n ctx?: { cacheGenerationClaimId?: string },\n ) => Promise<SQLitePullSinceResult<string | number>>\n getStreamPosition: (\n target: PersistedStorageTarget,\n ctx?: { cacheGenerationClaimId?: string },\n ) => Promise<{\n latestTerm: number\n latestSeq: number\n latestRowVersion: number\n }>\n reserveLeadershipTerm: (\n target: PersistedStorageTarget,\n observedTerm: number,\n ctx?: { cacheGenerationClaimId?: string },\n ) => Promise<{\n latestTerm: number\n latestSeq: number\n latestRowVersion: number\n }>\n }\n\nfunction createResolvedRendererAdapter(\n executeRequest: RendererRequestExecutor,\n claimCollections: Map<string, string>,\n managedCacheGenerations: boolean,\n queuedWork: RendererQueuedWork,\n resolution?: ElectronPersistenceResolution,\n): ElectronRendererResolvedAdapter {\n const adapter: ElectronRendererResolvedAdapter = {\n loadSubset: async (\n target: PersistedStorageTarget,\n subsetOptions: LoadSubsetOptions,\n ctx?: {\n requiredIndexSignatures?: ReadonlyArray<string>\n cacheGenerationClaimId?: string\n },\n ) => {\n const access = resolvePersistedStorageTarget(\n target,\n ctx?.cacheGenerationClaimId,\n )\n const result = await executeRequest(\n `loadSubset`,\n target,\n {\n options: createSerializableLoadSubsetOptions(subsetOptions),\n ctx: { ...ctx, cacheGenerationClaimId: access.claimId },\n },\n resolution,\n )\n\n return result as Array<{\n key: string | number\n value: Record<string, unknown>\n }>\n },\n loadResumeSnapshot: async (\n target: PersistedStorageTarget,\n ctx?: {\n requiredIndexSignatures?: ReadonlyArray<string>\n includeRows?: boolean\n cacheGenerationClaimId?: string\n },\n ) => {\n const access = resolvePersistedStorageTarget(\n target,\n ctx?.cacheGenerationClaimId,\n )\n return executeRequest(\n `loadResumeSnapshot`,\n target,\n { ctx: { ...ctx, cacheGenerationClaimId: access.claimId } },\n resolution,\n )\n },\n applyCommittedTx: async (\n target: PersistedStorageTarget,\n tx: PersistedTx<Record<string, unknown>, string | number>,\n ): Promise<void> => {\n const access = resolvePersistedStorageTarget(\n target,\n tx.cacheGenerationClaimId,\n )\n await executeRequest(\n `applyCommittedTx`,\n target,\n {\n tx: { ...tx, cacheGenerationClaimId: access.claimId } as PersistedTx<\n ElectronPersistedRow,\n ElectronPersistedKey\n >,\n },\n resolution,\n )\n },\n reconcileCommittedTx: async (\n target: PersistedStorageTarget,\n tx: PersistedTx<Record<string, unknown>, string | number>,\n anchor: CommittedTxAnchor,\n ): Promise<ReconciledCommittedTx> => {\n const access = resolvePersistedStorageTarget(\n target,\n tx.cacheGenerationClaimId,\n )\n return executeRequest(\n `reconcileCommittedTx`,\n target,\n { tx: { ...tx, cacheGenerationClaimId: access.claimId }, anchor },\n resolution,\n )\n },\n loadCollectionMetadata: async (\n target: PersistedStorageTarget,\n ctx?: { cacheGenerationClaimId?: string },\n ): Promise<Array<{ key: string; value: unknown }>> => {\n const access = resolvePersistedStorageTarget(\n target,\n ctx?.cacheGenerationClaimId,\n )\n return executeRequest(\n `loadCollectionMetadata`,\n target,\n { ctx: { ...ctx, cacheGenerationClaimId: access.claimId } },\n resolution,\n )\n },\n scanRows: async (\n target: PersistedStorageTarget,\n options?: { metadataOnly?: boolean },\n ctx?: { cacheGenerationClaimId?: string },\n ): Promise<\n Array<{\n key: string | number\n value: Record<string, unknown>\n metadata?: unknown\n }>\n > => {\n const access = resolvePersistedStorageTarget(\n target,\n ctx?.cacheGenerationClaimId,\n )\n const result = await executeRequest(\n `scanRows`,\n target,\n { options, ctx: { ...ctx, cacheGenerationClaimId: access.claimId } },\n resolution,\n )\n return result as Array<{\n key: string | number\n value: Record<string, unknown>\n metadata?: unknown\n }>\n },\n ensureIndex: async (\n target: PersistedStorageTarget,\n signature: string,\n spec: PersistedIndexSpec,\n ctx?: { cacheGenerationClaimId?: string },\n ): Promise<void> => {\n const access = resolvePersistedStorageTarget(\n target,\n ctx?.cacheGenerationClaimId,\n )\n await executeRequest(\n `ensureIndex`,\n target,\n {\n signature,\n spec,\n ctx: { ...ctx, cacheGenerationClaimId: access.claimId },\n },\n resolution,\n )\n },\n markIndexRemoved: async (\n target: PersistedStorageTarget,\n signature: string,\n ctx?: { cacheGenerationClaimId?: string },\n ): Promise<void> => {\n const access = resolvePersistedStorageTarget(\n target,\n ctx?.cacheGenerationClaimId,\n )\n await executeRequest(\n `markIndexRemoved`,\n target,\n {\n signature,\n ctx: { ...ctx, cacheGenerationClaimId: access.claimId },\n },\n resolution,\n )\n },\n pullSince: async (\n target: PersistedStorageTarget,\n fromRowVersion: number,\n ctx?: { cacheGenerationClaimId?: string },\n ): Promise<SQLitePullSinceResult<string | number>> => {\n const access = resolvePersistedStorageTarget(\n target,\n ctx?.cacheGenerationClaimId,\n )\n const result = await executeRequest(\n `pullSince`,\n target,\n {\n fromRowVersion,\n ctx: { ...ctx, cacheGenerationClaimId: access.claimId },\n },\n resolution,\n )\n return result as SQLitePullSinceResult<string | number>\n },\n getStreamPosition: async (\n target: PersistedStorageTarget,\n ctx?: { cacheGenerationClaimId?: string },\n ): Promise<{\n latestTerm: number\n latestSeq: number\n latestRowVersion: number\n }> => {\n const access = resolvePersistedStorageTarget(\n target,\n ctx?.cacheGenerationClaimId,\n )\n return executeRequest(\n `getStreamPosition`,\n target,\n { ctx: { ...ctx, cacheGenerationClaimId: access.claimId } },\n resolution,\n )\n },\n claimCacheGeneration: async (\n collectionId: string,\n ): Promise<PersistedCacheGenerationClaim> => {\n const claim = await executeRequest(\n `claimCacheGeneration`,\n collectionId,\n {},\n resolution,\n )\n claimCollections.set(claim.claimId, collectionId)\n return claim\n },\n rotateCacheGeneration: async (\n collectionId: string,\n claimId: string,\n resetMetadata?: { key: string; value: unknown },\n expectedStorageCollectionId?: string,\n ): Promise<PersistedCacheGenerationClaim> => {\n const claim = await executeRequest(\n `rotateCacheGeneration`,\n collectionId,\n { claimId, resetMetadata, expectedStorageCollectionId },\n resolution,\n )\n claimCollections.delete(claimId)\n claimCollections.set(claim.claimId, collectionId)\n return claim\n },\n renewCacheGenerationClaim: (\n storageCollectionId: string,\n claimId: string,\n ): Promise<number | undefined> => {\n const collectionId = claimCollections.get(claimId)\n if (!collectionId) {\n throw new InvalidPersistedCollectionConfigError(\n `Unknown electron persisted cache claim \"${claimId}\"`,\n )\n }\n return executeRequest(\n `renewCacheGenerationClaim`,\n collectionId,\n { storageCollectionId, claimId },\n resolution,\n )\n },\n releaseCacheGenerationClaim: async (claimId: string): Promise<void> => {\n const collectionId = claimCollections.get(claimId)\n if (!collectionId) {\n throw new InvalidPersistedCollectionConfigError(\n `Unknown electron persisted cache claim \"${claimId}\"`,\n )\n }\n await executeRequest(\n `releaseCacheGenerationClaim`,\n collectionId,\n { claimId },\n resolution,\n )\n claimCollections.delete(claimId)\n },\n reserveLeadershipTerm: async (target, observedTerm, ctx) => {\n const access = resolvePersistedStorageTarget(\n target,\n ctx?.cacheGenerationClaimId,\n )\n return executeRequest(\n `reserveLeadershipTerm`,\n target,\n {\n observedTerm,\n ctx: { ...ctx, cacheGenerationClaimId: access.claimId },\n },\n resolution,\n )\n },\n runInHydrationScope: <T>(\n task: (scopedAdapter: HydrationPersistenceAdapter) => Promise<T>,\n ) => queuedWork.track(Promise.resolve().then(() => task(adapter))),\n isHydrationScopeScheduled: () => false,\n // Work runs directly; the main process serializes it.\n runInRegularScope: Object.assign(\n <T>(task: (scopedAdapter: HydrationPersistenceAdapter) => Promise<T>) =>\n task(adapter),\n { afterQueuedWork: () => queuedWork.afterQueuedWork() },\n ),\n }\n if (!managedCacheGenerations) {\n adapter.claimCacheGeneration = undefined\n adapter.rotateCacheGeneration = undefined\n adapter.renewCacheGenerationClaim = undefined\n adapter.releaseCacheGenerationClaim = undefined\n }\n return adapter\n}\n\nexport type ElectronIpcRendererLike = {\n invoke: (\n channel: string,\n request: ElectronPersistenceRequestEnvelope,\n ) => Promise<ElectronPersistenceResponseEnvelope>\n}\n\nexport type ElectronSQLitePersistenceOptions = {\n invoke?: ElectronPersistenceInvoke\n ipcRenderer?: ElectronIpcRendererLike\n channel?: string\n timeoutMs?: number\n coordinator?: PersistedCollectionCoordinator\n /** Set false when a custom main-process adapter does not manage cache generations. */\n managedCacheGenerations?: boolean\n}\n\nfunction resolveInvoke(\n options: ElectronSQLitePersistenceOptions,\n): ElectronPersistenceInvoke {\n if (options.invoke) {\n return options.invoke\n }\n\n if (options.ipcRenderer) {\n return (channel, request) => options.ipcRenderer!.invoke(channel, request)\n }\n\n throw new InvalidPersistedCollectionConfigError(\n `Electron renderer persistence requires either invoke or ipcRenderer`,\n )\n}\n\nexport function createElectronSQLitePersistence(\n options: ElectronSQLitePersistenceOptions,\n): PersistedCollectionPersistence {\n const queuedWork = new RendererQueuedWork()\n const invoke = resolveInvoke(options)\n const coordinator = options.coordinator ?? new SingleProcessCoordinator()\n const claimCollections = new Map<string, string>()\n const executeRequest = createRendererRequestExecutor({\n invoke,\n channel: options.channel,\n timeoutMs: options.timeoutMs,\n claimCollections,\n })\n const adapterCache = new Map<string, ElectronRendererResolvedAdapter>()\n\n const getAdapterForCollection = (\n collectionId: string | undefined,\n mode: PersistedCollectionMode,\n schemaVersion: number | undefined,\n ) => {\n const cacheKey = JSON.stringify([collectionId, mode, schemaVersion])\n const cachedAdapter = adapterCache.get(cacheKey)\n if (cachedAdapter) {\n return cachedAdapter\n }\n\n const adapter = createResolvedRendererAdapter(\n executeRequest,\n claimCollections,\n options.managedCacheGenerations ?? true,\n queuedWork,\n { mode, schemaVersion, logicalCollectionId: collectionId },\n )\n adapterCache.set(cacheKey, adapter)\n return adapter\n }\n\n const createCollectionPersistence = (\n collectionId: string | undefined,\n mode: PersistedCollectionMode,\n schemaVersion: number | undefined,\n ): PersistedCollectionPersistence => {\n const adapter = getAdapterForCollection(collectionId, mode, schemaVersion)\n if (coordinator instanceof ElectronCollectionCoordinator) {\n if (collectionId === undefined) {\n coordinator.setAdapter(adapter)\n } else {\n coordinator.setAdapterForCollection(collectionId, adapter)\n }\n }\n return { adapter, coordinator }\n }\n\n const defaultPersistence = createCollectionPersistence(\n undefined,\n `sync-absent`,\n undefined,\n )\n if (coordinator instanceof ElectronCollectionCoordinator) {\n coordinator.setAdapter(defaultPersistence.adapter)\n }\n\n return {\n ...defaultPersistence,\n resolvePersistenceForCollection: ({ collectionId, mode, schemaVersion }) =>\n createCollectionPersistence(collectionId, mode, schemaVersion),\n // Backward compatible fallback for older callers.\n resolvePersistenceForMode: (mode) =>\n createCollectionPersistence(undefined, mode, undefined),\n }\n}\n"],"names":["InvalidPersistedCollectionConfigError","ELECTRON_PERSISTENCE_PROTOCOL_VERSION","DEFAULT_ELECTRON_PERSISTENCE_CHANNEL","resolvePersistedStorageTarget","SingleProcessCoordinator","ElectronCollectionCoordinator"],"mappings":"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"}
|
package/dist/esm/renderer.js
CHANGED
|
@@ -96,7 +96,25 @@ function createRendererRequestExecutor(options) {
|
|
|
96
96
|
return response.result;
|
|
97
97
|
};
|
|
98
98
|
}
|
|
99
|
-
|
|
99
|
+
class RendererQueuedWork {
|
|
100
|
+
constructor() {
|
|
101
|
+
this.unsettled = /* @__PURE__ */ new Set();
|
|
102
|
+
}
|
|
103
|
+
track(work) {
|
|
104
|
+
const done = work.then(
|
|
105
|
+
() => void 0,
|
|
106
|
+
() => void 0
|
|
107
|
+
);
|
|
108
|
+
this.unsettled.add(done);
|
|
109
|
+
void done.then(() => this.unsettled.delete(done));
|
|
110
|
+
return work;
|
|
111
|
+
}
|
|
112
|
+
// Settles once every hydration scope outstanding at the call settles.
|
|
113
|
+
afterQueuedWork() {
|
|
114
|
+
return Promise.all(this.unsettled).then(() => void 0);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
function createResolvedRendererAdapter(executeRequest, claimCollections, managedCacheGenerations, queuedWork, resolution) {
|
|
100
118
|
const adapter = {
|
|
101
119
|
loadSubset: async (target, subsetOptions, ctx) => {
|
|
102
120
|
const access = resolvePersistedStorageTarget(
|
|
@@ -300,7 +318,14 @@ function createResolvedRendererAdapter(executeRequest, claimCollections, managed
|
|
|
300
318
|
},
|
|
301
319
|
resolution
|
|
302
320
|
);
|
|
303
|
-
}
|
|
321
|
+
},
|
|
322
|
+
runInHydrationScope: (task) => queuedWork.track(Promise.resolve().then(() => task(adapter))),
|
|
323
|
+
isHydrationScopeScheduled: () => false,
|
|
324
|
+
// Work runs directly; the main process serializes it.
|
|
325
|
+
runInRegularScope: Object.assign(
|
|
326
|
+
(task) => task(adapter),
|
|
327
|
+
{ afterQueuedWork: () => queuedWork.afterQueuedWork() }
|
|
328
|
+
)
|
|
304
329
|
};
|
|
305
330
|
if (!managedCacheGenerations) {
|
|
306
331
|
adapter.claimCacheGeneration = void 0;
|
|
@@ -322,6 +347,7 @@ function resolveInvoke(options) {
|
|
|
322
347
|
);
|
|
323
348
|
}
|
|
324
349
|
function createElectronSQLitePersistence(options) {
|
|
350
|
+
const queuedWork = new RendererQueuedWork();
|
|
325
351
|
const invoke = resolveInvoke(options);
|
|
326
352
|
const coordinator = options.coordinator ?? new SingleProcessCoordinator();
|
|
327
353
|
const claimCollections = /* @__PURE__ */ new Map();
|
|
@@ -342,6 +368,7 @@ function createElectronSQLitePersistence(options) {
|
|
|
342
368
|
executeRequest,
|
|
343
369
|
claimCollections,
|
|
344
370
|
options.managedCacheGenerations ?? true,
|
|
371
|
+
queuedWork,
|
|
345
372
|
{ mode, schemaVersion, logicalCollectionId: collectionId }
|
|
346
373
|
);
|
|
347
374
|
adapterCache.set(cacheKey, adapter);
|
package/dist/esm/renderer.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"renderer.js","sources":["../../src/renderer.ts"],"sourcesContent":["import {\n InvalidPersistedCollectionConfigError,\n SingleProcessCoordinator,\n resolvePersistedStorageTarget,\n} from '@tanstack/db-sqlite-persistence-core'\nimport { ElectronCollectionCoordinator } from './electron-coordinator'\nimport {\n DEFAULT_ELECTRON_PERSISTENCE_CHANNEL,\n ELECTRON_PERSISTENCE_PROTOCOL_VERSION,\n} from './protocol'\nimport type {\n CommittedTxAnchor,\n PersistedCacheGenerationClaim,\n PersistedCollectionCoordinator,\n PersistedCollectionMode,\n PersistedCollectionPersistence,\n PersistedIndexSpec,\n PersistedStorageTarget,\n PersistedTx,\n ReconciledCommittedTx,\n SQLitePullSinceResult,\n} from '@tanstack/db-sqlite-persistence-core'\nimport type {\n ElectronPersistedKey,\n ElectronPersistedRow,\n ElectronPersistenceInvoke,\n ElectronPersistenceMethod,\n ElectronPersistencePayloadMap,\n ElectronPersistenceRequest,\n ElectronPersistenceRequestEnvelope,\n ElectronPersistenceResolution,\n ElectronPersistenceResponseEnvelope,\n ElectronPersistenceResultMap,\n} from './protocol'\nimport type { LoadSubsetOptions } from '@tanstack/db'\n\nconst DEFAULT_REQUEST_TIMEOUT_MS = 5_000\nlet nextRequestId = 1\n\nfunction createRequestId(): string {\n const requestId = nextRequestId\n nextRequestId++\n return `electron-persistence-${requestId}`\n}\n\nfunction withTimeout<T>(\n promise: Promise<T>,\n timeoutMs: number,\n timeoutMessage: string,\n): Promise<T> {\n if (timeoutMs <= 0) {\n return promise\n }\n\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => {\n reject(new InvalidPersistedCollectionConfigError(timeoutMessage))\n }, timeoutMs)\n\n promise.then(\n (value) => {\n clearTimeout(timer)\n resolve(value)\n },\n (error: unknown) => {\n clearTimeout(timer)\n reject(error)\n },\n )\n })\n}\n\nfunction assertValidResponse(\n response: ElectronPersistenceResponseEnvelope,\n request: ElectronPersistenceRequestEnvelope,\n): void {\n if (response.v !== ELECTRON_PERSISTENCE_PROTOCOL_VERSION) {\n throw new InvalidPersistedCollectionConfigError(\n `Unexpected electron persistence protocol version \"${response.v}\" in response`,\n )\n }\n\n if (response.requestId !== request.requestId) {\n throw new InvalidPersistedCollectionConfigError(\n `Mismatched electron persistence response request id. Expected \"${request.requestId}\", received \"${response.requestId}\"`,\n )\n }\n\n if (response.method !== request.method) {\n throw new InvalidPersistedCollectionConfigError(\n `Mismatched electron persistence response method. Expected \"${request.method}\", received \"${response.method}\"`,\n )\n }\n}\n\nfunction createSerializableLoadSubsetOptions(\n subsetOptions: LoadSubsetOptions,\n): LoadSubsetOptions {\n const { subscription: _subscription, ...serializableOptions } = subsetOptions\n return serializableOptions\n}\n\ntype RendererRequestExecutor = <TMethod extends ElectronPersistenceMethod>(\n method: TMethod,\n target: string | PersistedStorageTarget,\n payload: ElectronPersistencePayloadMap[TMethod],\n resolution?: ElectronPersistenceResolution,\n) => Promise<ElectronPersistenceResultMap[TMethod]>\n\nfunction createRendererRequestExecutor(options: {\n invoke: ElectronPersistenceInvoke\n channel?: string\n timeoutMs?: number\n claimCollections: Map<string, string>\n}): RendererRequestExecutor {\n const channel = options.channel ?? DEFAULT_ELECTRON_PERSISTENCE_CHANNEL\n const timeoutMs = options.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS\n\n return async <TMethod extends ElectronPersistenceMethod>(\n method: TMethod,\n target: string | PersistedStorageTarget,\n payload: ElectronPersistencePayloadMap[TMethod],\n resolution?: ElectronPersistenceResolution,\n ) => {\n const storageTarget = typeof target === `string` ? undefined : target\n const collectionId = storageTarget\n ? resolvePersistedStorageTarget(storageTarget).collectionId\n : target\n const isGenerationRequest =\n method === `claimCacheGeneration` ||\n method === `rotateCacheGeneration` ||\n method === `renewCacheGenerationClaim` ||\n method === `releaseCacheGenerationClaim`\n const managedTarget = storageTarget?.kind === `managed`\n const logicalCollectionId =\n resolution?.logicalCollectionId ??\n (managedTarget\n ? options.claimCollections.get(storageTarget.claimId)\n : isGenerationRequest\n ? collectionId\n : undefined)\n if ((managedTarget || isGenerationRequest) && !logicalCollectionId) {\n throw new InvalidPersistedCollectionConfigError(\n `Electron managed cache request requires a known logical Collection ID`,\n )\n }\n const request = {\n v: ELECTRON_PERSISTENCE_PROTOCOL_VERSION,\n requestId: createRequestId(),\n collectionId,\n storageTarget,\n method,\n resolution:\n managedTarget || isGenerationRequest\n ? { ...resolution, mode: `sync-present`, logicalCollectionId }\n : resolution,\n payload,\n } as ElectronPersistenceRequest\n\n const response = await withTimeout(\n options.invoke(channel, request),\n timeoutMs,\n `Electron persistence request timed out (method=${method}, collection=${collectionId}, timeoutMs=${timeoutMs})`,\n )\n assertValidResponse(response, request)\n\n if (!response.ok) {\n const remoteError = new InvalidPersistedCollectionConfigError(\n `${response.error.name}: ${response.error.message}`,\n )\n if (typeof response.error.stack === `string`) {\n remoteError.stack = response.error.stack\n }\n if (\n typeof response.error.code === `string` ||\n typeof response.error.code === `number`\n ) {\n ;(remoteError as Error & { code?: string | number }).code =\n response.error.code\n }\n if (response.error.path !== undefined) {\n ;(\n remoteError as Error & {\n path?: string | ReadonlyArray<string | number>\n }\n ).path = response.error.path\n }\n throw remoteError\n }\n\n return response.result as ElectronPersistenceResultMap[TMethod]\n }\n}\n\ntype ElectronRendererResolvedAdapter =\n PersistedCollectionPersistence[`adapter`] & {\n loadCollectionMetadata: (\n target: PersistedStorageTarget,\n ctx?: { cacheGenerationClaimId?: string },\n ) => Promise<Array<{ key: string; value: unknown }>>\n scanRows: (\n target: PersistedStorageTarget,\n options?: { metadataOnly?: boolean },\n ctx?: { cacheGenerationClaimId?: string },\n ) => Promise<\n Array<{\n key: string | number\n value: Record<string, unknown>\n metadata?: unknown\n }>\n >\n pullSince: (\n target: PersistedStorageTarget,\n fromRowVersion: number,\n ctx?: { cacheGenerationClaimId?: string },\n ) => Promise<SQLitePullSinceResult<string | number>>\n getStreamPosition: (\n target: PersistedStorageTarget,\n ctx?: { cacheGenerationClaimId?: string },\n ) => Promise<{\n latestTerm: number\n latestSeq: number\n latestRowVersion: number\n }>\n reserveLeadershipTerm: (\n target: PersistedStorageTarget,\n observedTerm: number,\n ctx?: { cacheGenerationClaimId?: string },\n ) => Promise<{\n latestTerm: number\n latestSeq: number\n latestRowVersion: number\n }>\n }\n\nfunction createResolvedRendererAdapter(\n executeRequest: RendererRequestExecutor,\n claimCollections: Map<string, string>,\n managedCacheGenerations: boolean,\n resolution?: ElectronPersistenceResolution,\n): ElectronRendererResolvedAdapter {\n const adapter: ElectronRendererResolvedAdapter = {\n loadSubset: async (\n target: PersistedStorageTarget,\n subsetOptions: LoadSubsetOptions,\n ctx?: {\n requiredIndexSignatures?: ReadonlyArray<string>\n cacheGenerationClaimId?: string\n },\n ) => {\n const access = resolvePersistedStorageTarget(\n target,\n ctx?.cacheGenerationClaimId,\n )\n const result = await executeRequest(\n `loadSubset`,\n target,\n {\n options: createSerializableLoadSubsetOptions(subsetOptions),\n ctx: { ...ctx, cacheGenerationClaimId: access.claimId },\n },\n resolution,\n )\n\n return result as Array<{\n key: string | number\n value: Record<string, unknown>\n }>\n },\n loadResumeSnapshot: async (\n target: PersistedStorageTarget,\n ctx?: {\n requiredIndexSignatures?: ReadonlyArray<string>\n includeRows?: boolean\n cacheGenerationClaimId?: string\n },\n ) => {\n const access = resolvePersistedStorageTarget(\n target,\n ctx?.cacheGenerationClaimId,\n )\n return executeRequest(\n `loadResumeSnapshot`,\n target,\n { ctx: { ...ctx, cacheGenerationClaimId: access.claimId } },\n resolution,\n )\n },\n applyCommittedTx: async (\n target: PersistedStorageTarget,\n tx: PersistedTx<Record<string, unknown>, string | number>,\n ): Promise<void> => {\n const access = resolvePersistedStorageTarget(\n target,\n tx.cacheGenerationClaimId,\n )\n await executeRequest(\n `applyCommittedTx`,\n target,\n {\n tx: { ...tx, cacheGenerationClaimId: access.claimId } as PersistedTx<\n ElectronPersistedRow,\n ElectronPersistedKey\n >,\n },\n resolution,\n )\n },\n reconcileCommittedTx: async (\n target: PersistedStorageTarget,\n tx: PersistedTx<Record<string, unknown>, string | number>,\n anchor: CommittedTxAnchor,\n ): Promise<ReconciledCommittedTx> => {\n const access = resolvePersistedStorageTarget(\n target,\n tx.cacheGenerationClaimId,\n )\n return executeRequest(\n `reconcileCommittedTx`,\n target,\n { tx: { ...tx, cacheGenerationClaimId: access.claimId }, anchor },\n resolution,\n )\n },\n loadCollectionMetadata: async (\n target: PersistedStorageTarget,\n ctx?: { cacheGenerationClaimId?: string },\n ): Promise<Array<{ key: string; value: unknown }>> => {\n const access = resolvePersistedStorageTarget(\n target,\n ctx?.cacheGenerationClaimId,\n )\n return executeRequest(\n `loadCollectionMetadata`,\n target,\n { ctx: { ...ctx, cacheGenerationClaimId: access.claimId } },\n resolution,\n )\n },\n scanRows: async (\n target: PersistedStorageTarget,\n options?: { metadataOnly?: boolean },\n ctx?: { cacheGenerationClaimId?: string },\n ): Promise<\n Array<{\n key: string | number\n value: Record<string, unknown>\n metadata?: unknown\n }>\n > => {\n const access = resolvePersistedStorageTarget(\n target,\n ctx?.cacheGenerationClaimId,\n )\n const result = await executeRequest(\n `scanRows`,\n target,\n { options, ctx: { ...ctx, cacheGenerationClaimId: access.claimId } },\n resolution,\n )\n return result as Array<{\n key: string | number\n value: Record<string, unknown>\n metadata?: unknown\n }>\n },\n ensureIndex: async (\n target: PersistedStorageTarget,\n signature: string,\n spec: PersistedIndexSpec,\n ctx?: { cacheGenerationClaimId?: string },\n ): Promise<void> => {\n const access = resolvePersistedStorageTarget(\n target,\n ctx?.cacheGenerationClaimId,\n )\n await executeRequest(\n `ensureIndex`,\n target,\n {\n signature,\n spec,\n ctx: { ...ctx, cacheGenerationClaimId: access.claimId },\n },\n resolution,\n )\n },\n markIndexRemoved: async (\n target: PersistedStorageTarget,\n signature: string,\n ctx?: { cacheGenerationClaimId?: string },\n ): Promise<void> => {\n const access = resolvePersistedStorageTarget(\n target,\n ctx?.cacheGenerationClaimId,\n )\n await executeRequest(\n `markIndexRemoved`,\n target,\n {\n signature,\n ctx: { ...ctx, cacheGenerationClaimId: access.claimId },\n },\n resolution,\n )\n },\n pullSince: async (\n target: PersistedStorageTarget,\n fromRowVersion: number,\n ctx?: { cacheGenerationClaimId?: string },\n ): Promise<SQLitePullSinceResult<string | number>> => {\n const access = resolvePersistedStorageTarget(\n target,\n ctx?.cacheGenerationClaimId,\n )\n const result = await executeRequest(\n `pullSince`,\n target,\n {\n fromRowVersion,\n ctx: { ...ctx, cacheGenerationClaimId: access.claimId },\n },\n resolution,\n )\n return result as SQLitePullSinceResult<string | number>\n },\n getStreamPosition: async (\n target: PersistedStorageTarget,\n ctx?: { cacheGenerationClaimId?: string },\n ): Promise<{\n latestTerm: number\n latestSeq: number\n latestRowVersion: number\n }> => {\n const access = resolvePersistedStorageTarget(\n target,\n ctx?.cacheGenerationClaimId,\n )\n return executeRequest(\n `getStreamPosition`,\n target,\n { ctx: { ...ctx, cacheGenerationClaimId: access.claimId } },\n resolution,\n )\n },\n claimCacheGeneration: async (\n collectionId: string,\n ): Promise<PersistedCacheGenerationClaim> => {\n const claim = await executeRequest(\n `claimCacheGeneration`,\n collectionId,\n {},\n resolution,\n )\n claimCollections.set(claim.claimId, collectionId)\n return claim\n },\n rotateCacheGeneration: async (\n collectionId: string,\n claimId: string,\n resetMetadata?: { key: string; value: unknown },\n expectedStorageCollectionId?: string,\n ): Promise<PersistedCacheGenerationClaim> => {\n const claim = await executeRequest(\n `rotateCacheGeneration`,\n collectionId,\n { claimId, resetMetadata, expectedStorageCollectionId },\n resolution,\n )\n claimCollections.delete(claimId)\n claimCollections.set(claim.claimId, collectionId)\n return claim\n },\n renewCacheGenerationClaim: (\n storageCollectionId: string,\n claimId: string,\n ): Promise<number | undefined> => {\n const collectionId = claimCollections.get(claimId)\n if (!collectionId) {\n throw new InvalidPersistedCollectionConfigError(\n `Unknown electron persisted cache claim \"${claimId}\"`,\n )\n }\n return executeRequest(\n `renewCacheGenerationClaim`,\n collectionId,\n { storageCollectionId, claimId },\n resolution,\n )\n },\n releaseCacheGenerationClaim: async (claimId: string): Promise<void> => {\n const collectionId = claimCollections.get(claimId)\n if (!collectionId) {\n throw new InvalidPersistedCollectionConfigError(\n `Unknown electron persisted cache claim \"${claimId}\"`,\n )\n }\n await executeRequest(\n `releaseCacheGenerationClaim`,\n collectionId,\n { claimId },\n resolution,\n )\n claimCollections.delete(claimId)\n },\n reserveLeadershipTerm: async (target, observedTerm, ctx) => {\n const access = resolvePersistedStorageTarget(\n target,\n ctx?.cacheGenerationClaimId,\n )\n return executeRequest(\n `reserveLeadershipTerm`,\n target,\n {\n observedTerm,\n ctx: { ...ctx, cacheGenerationClaimId: access.claimId },\n },\n resolution,\n )\n },\n }\n if (!managedCacheGenerations) {\n adapter.claimCacheGeneration = undefined\n adapter.rotateCacheGeneration = undefined\n adapter.renewCacheGenerationClaim = undefined\n adapter.releaseCacheGenerationClaim = undefined\n }\n return adapter\n}\n\nexport type ElectronIpcRendererLike = {\n invoke: (\n channel: string,\n request: ElectronPersistenceRequestEnvelope,\n ) => Promise<ElectronPersistenceResponseEnvelope>\n}\n\nexport type ElectronSQLitePersistenceOptions = {\n invoke?: ElectronPersistenceInvoke\n ipcRenderer?: ElectronIpcRendererLike\n channel?: string\n timeoutMs?: number\n coordinator?: PersistedCollectionCoordinator\n /** Set false when a custom main-process adapter does not manage cache generations. */\n managedCacheGenerations?: boolean\n}\n\nfunction resolveInvoke(\n options: ElectronSQLitePersistenceOptions,\n): ElectronPersistenceInvoke {\n if (options.invoke) {\n return options.invoke\n }\n\n if (options.ipcRenderer) {\n return (channel, request) => options.ipcRenderer!.invoke(channel, request)\n }\n\n throw new InvalidPersistedCollectionConfigError(\n `Electron renderer persistence requires either invoke or ipcRenderer`,\n )\n}\n\nexport function createElectronSQLitePersistence(\n options: ElectronSQLitePersistenceOptions,\n): PersistedCollectionPersistence {\n const invoke = resolveInvoke(options)\n const coordinator = options.coordinator ?? new SingleProcessCoordinator()\n const claimCollections = new Map<string, string>()\n const executeRequest = createRendererRequestExecutor({\n invoke,\n channel: options.channel,\n timeoutMs: options.timeoutMs,\n claimCollections,\n })\n const adapterCache = new Map<string, ElectronRendererResolvedAdapter>()\n\n const getAdapterForCollection = (\n collectionId: string | undefined,\n mode: PersistedCollectionMode,\n schemaVersion: number | undefined,\n ) => {\n const cacheKey = JSON.stringify([collectionId, mode, schemaVersion])\n const cachedAdapter = adapterCache.get(cacheKey)\n if (cachedAdapter) {\n return cachedAdapter\n }\n\n const adapter = createResolvedRendererAdapter(\n executeRequest,\n claimCollections,\n options.managedCacheGenerations ?? true,\n { mode, schemaVersion, logicalCollectionId: collectionId },\n )\n adapterCache.set(cacheKey, adapter)\n return adapter\n }\n\n const createCollectionPersistence = (\n collectionId: string | undefined,\n mode: PersistedCollectionMode,\n schemaVersion: number | undefined,\n ): PersistedCollectionPersistence => {\n const adapter = getAdapterForCollection(collectionId, mode, schemaVersion)\n if (coordinator instanceof ElectronCollectionCoordinator) {\n if (collectionId === undefined) {\n coordinator.setAdapter(adapter)\n } else {\n coordinator.setAdapterForCollection(collectionId, adapter)\n }\n }\n return { adapter, coordinator }\n }\n\n const defaultPersistence = createCollectionPersistence(\n undefined,\n `sync-absent`,\n undefined,\n )\n if (coordinator instanceof ElectronCollectionCoordinator) {\n coordinator.setAdapter(defaultPersistence.adapter)\n }\n\n return {\n ...defaultPersistence,\n resolvePersistenceForCollection: ({ collectionId, mode, schemaVersion }) =>\n createCollectionPersistence(collectionId, mode, schemaVersion),\n // Backward compatible fallback for older callers.\n resolvePersistenceForMode: (mode) =>\n createCollectionPersistence(undefined, mode, undefined),\n }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"renderer.js","sources":["../../src/renderer.ts"],"sourcesContent":["import {\n InvalidPersistedCollectionConfigError,\n SingleProcessCoordinator,\n resolvePersistedStorageTarget,\n} from '@tanstack/db-sqlite-persistence-core'\nimport { ElectronCollectionCoordinator } from './electron-coordinator'\nimport {\n DEFAULT_ELECTRON_PERSISTENCE_CHANNEL,\n ELECTRON_PERSISTENCE_PROTOCOL_VERSION,\n} from './protocol'\nimport type {\n CommittedTxAnchor,\n HydrationPersistenceAdapter,\n PersistedCacheGenerationClaim,\n PersistedCollectionCoordinator,\n PersistedCollectionMode,\n PersistedCollectionPersistence,\n PersistedIndexSpec,\n PersistedStorageTarget,\n PersistedTx,\n ReconciledCommittedTx,\n SQLitePullSinceResult,\n} from '@tanstack/db-sqlite-persistence-core'\nimport type {\n ElectronPersistedKey,\n ElectronPersistedRow,\n ElectronPersistenceInvoke,\n ElectronPersistenceMethod,\n ElectronPersistencePayloadMap,\n ElectronPersistenceRequest,\n ElectronPersistenceRequestEnvelope,\n ElectronPersistenceResolution,\n ElectronPersistenceResponseEnvelope,\n ElectronPersistenceResultMap,\n} from './protocol'\nimport type { LoadSubsetOptions } from '@tanstack/db'\n\nconst DEFAULT_REQUEST_TIMEOUT_MS = 5_000\nlet nextRequestId = 1\n\nfunction createRequestId(): string {\n const requestId = nextRequestId\n nextRequestId++\n return `electron-persistence-${requestId}`\n}\n\nfunction withTimeout<T>(\n promise: Promise<T>,\n timeoutMs: number,\n timeoutMessage: string,\n): Promise<T> {\n if (timeoutMs <= 0) {\n return promise\n }\n\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => {\n reject(new InvalidPersistedCollectionConfigError(timeoutMessage))\n }, timeoutMs)\n\n promise.then(\n (value) => {\n clearTimeout(timer)\n resolve(value)\n },\n (error: unknown) => {\n clearTimeout(timer)\n reject(error)\n },\n )\n })\n}\n\nfunction assertValidResponse(\n response: ElectronPersistenceResponseEnvelope,\n request: ElectronPersistenceRequestEnvelope,\n): void {\n if (response.v !== ELECTRON_PERSISTENCE_PROTOCOL_VERSION) {\n throw new InvalidPersistedCollectionConfigError(\n `Unexpected electron persistence protocol version \"${response.v}\" in response`,\n )\n }\n\n if (response.requestId !== request.requestId) {\n throw new InvalidPersistedCollectionConfigError(\n `Mismatched electron persistence response request id. Expected \"${request.requestId}\", received \"${response.requestId}\"`,\n )\n }\n\n if (response.method !== request.method) {\n throw new InvalidPersistedCollectionConfigError(\n `Mismatched electron persistence response method. Expected \"${request.method}\", received \"${response.method}\"`,\n )\n }\n}\n\nfunction createSerializableLoadSubsetOptions(\n subsetOptions: LoadSubsetOptions,\n): LoadSubsetOptions {\n const { subscription: _subscription, ...serializableOptions } = subsetOptions\n return serializableOptions\n}\n\ntype RendererRequestExecutor = <TMethod extends ElectronPersistenceMethod>(\n method: TMethod,\n target: string | PersistedStorageTarget,\n payload: ElectronPersistencePayloadMap[TMethod],\n resolution?: ElectronPersistenceResolution,\n) => Promise<ElectronPersistenceResultMap[TMethod]>\n\nfunction createRendererRequestExecutor(options: {\n invoke: ElectronPersistenceInvoke\n channel?: string\n timeoutMs?: number\n claimCollections: Map<string, string>\n}): RendererRequestExecutor {\n const channel = options.channel ?? DEFAULT_ELECTRON_PERSISTENCE_CHANNEL\n const timeoutMs = options.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS\n\n return async <TMethod extends ElectronPersistenceMethod>(\n method: TMethod,\n target: string | PersistedStorageTarget,\n payload: ElectronPersistencePayloadMap[TMethod],\n resolution?: ElectronPersistenceResolution,\n ) => {\n const storageTarget = typeof target === `string` ? undefined : target\n const collectionId = storageTarget\n ? resolvePersistedStorageTarget(storageTarget).collectionId\n : target\n const isGenerationRequest =\n method === `claimCacheGeneration` ||\n method === `rotateCacheGeneration` ||\n method === `renewCacheGenerationClaim` ||\n method === `releaseCacheGenerationClaim`\n const managedTarget = storageTarget?.kind === `managed`\n const logicalCollectionId =\n resolution?.logicalCollectionId ??\n (managedTarget\n ? options.claimCollections.get(storageTarget.claimId)\n : isGenerationRequest\n ? collectionId\n : undefined)\n if ((managedTarget || isGenerationRequest) && !logicalCollectionId) {\n throw new InvalidPersistedCollectionConfigError(\n `Electron managed cache request requires a known logical Collection ID`,\n )\n }\n const request = {\n v: ELECTRON_PERSISTENCE_PROTOCOL_VERSION,\n requestId: createRequestId(),\n collectionId,\n storageTarget,\n method,\n resolution:\n managedTarget || isGenerationRequest\n ? { ...resolution, mode: `sync-present`, logicalCollectionId }\n : resolution,\n payload,\n } as ElectronPersistenceRequest\n\n const response = await withTimeout(\n options.invoke(channel, request),\n timeoutMs,\n `Electron persistence request timed out (method=${method}, collection=${collectionId}, timeoutMs=${timeoutMs})`,\n )\n assertValidResponse(response, request)\n\n if (!response.ok) {\n const remoteError = new InvalidPersistedCollectionConfigError(\n `${response.error.name}: ${response.error.message}`,\n )\n if (typeof response.error.stack === `string`) {\n remoteError.stack = response.error.stack\n }\n if (\n typeof response.error.code === `string` ||\n typeof response.error.code === `number`\n ) {\n ;(remoteError as Error & { code?: string | number }).code =\n response.error.code\n }\n if (response.error.path !== undefined) {\n ;(\n remoteError as Error & {\n path?: string | ReadonlyArray<string | number>\n }\n ).path = response.error.path\n }\n throw remoteError\n }\n\n return response.result as ElectronPersistenceResultMap[TMethod]\n }\n}\n\n// The renderer has no shared driver scheduler. Its queued reads are its\n// hydration scopes; its writes take the writer Web Lock, which also orders\n// them against an election term.\nclass RendererQueuedWork {\n private readonly unsettled = new Set<Promise<void>>()\n\n track<T>(work: Promise<T>): Promise<T> {\n const done = work.then(\n () => undefined,\n () => undefined,\n )\n this.unsettled.add(done)\n void done.then(() => this.unsettled.delete(done))\n return work\n }\n\n // Settles once every hydration scope outstanding at the call settles.\n afterQueuedWork(): Promise<void> {\n return Promise.all(this.unsettled).then(() => undefined)\n }\n}\n\ntype ElectronRendererResolvedAdapter =\n PersistedCollectionPersistence[`adapter`] & {\n loadCollectionMetadata: (\n target: PersistedStorageTarget,\n ctx?: { cacheGenerationClaimId?: string },\n ) => Promise<Array<{ key: string; value: unknown }>>\n scanRows: (\n target: PersistedStorageTarget,\n options?: { metadataOnly?: boolean },\n ctx?: { cacheGenerationClaimId?: string },\n ) => Promise<\n Array<{\n key: string | number\n value: Record<string, unknown>\n metadata?: unknown\n }>\n >\n pullSince: (\n target: PersistedStorageTarget,\n fromRowVersion: number,\n ctx?: { cacheGenerationClaimId?: string },\n ) => Promise<SQLitePullSinceResult<string | number>>\n getStreamPosition: (\n target: PersistedStorageTarget,\n ctx?: { cacheGenerationClaimId?: string },\n ) => Promise<{\n latestTerm: number\n latestSeq: number\n latestRowVersion: number\n }>\n reserveLeadershipTerm: (\n target: PersistedStorageTarget,\n observedTerm: number,\n ctx?: { cacheGenerationClaimId?: string },\n ) => Promise<{\n latestTerm: number\n latestSeq: number\n latestRowVersion: number\n }>\n }\n\nfunction createResolvedRendererAdapter(\n executeRequest: RendererRequestExecutor,\n claimCollections: Map<string, string>,\n managedCacheGenerations: boolean,\n queuedWork: RendererQueuedWork,\n resolution?: ElectronPersistenceResolution,\n): ElectronRendererResolvedAdapter {\n const adapter: ElectronRendererResolvedAdapter = {\n loadSubset: async (\n target: PersistedStorageTarget,\n subsetOptions: LoadSubsetOptions,\n ctx?: {\n requiredIndexSignatures?: ReadonlyArray<string>\n cacheGenerationClaimId?: string\n },\n ) => {\n const access = resolvePersistedStorageTarget(\n target,\n ctx?.cacheGenerationClaimId,\n )\n const result = await executeRequest(\n `loadSubset`,\n target,\n {\n options: createSerializableLoadSubsetOptions(subsetOptions),\n ctx: { ...ctx, cacheGenerationClaimId: access.claimId },\n },\n resolution,\n )\n\n return result as Array<{\n key: string | number\n value: Record<string, unknown>\n }>\n },\n loadResumeSnapshot: async (\n target: PersistedStorageTarget,\n ctx?: {\n requiredIndexSignatures?: ReadonlyArray<string>\n includeRows?: boolean\n cacheGenerationClaimId?: string\n },\n ) => {\n const access = resolvePersistedStorageTarget(\n target,\n ctx?.cacheGenerationClaimId,\n )\n return executeRequest(\n `loadResumeSnapshot`,\n target,\n { ctx: { ...ctx, cacheGenerationClaimId: access.claimId } },\n resolution,\n )\n },\n applyCommittedTx: async (\n target: PersistedStorageTarget,\n tx: PersistedTx<Record<string, unknown>, string | number>,\n ): Promise<void> => {\n const access = resolvePersistedStorageTarget(\n target,\n tx.cacheGenerationClaimId,\n )\n await executeRequest(\n `applyCommittedTx`,\n target,\n {\n tx: { ...tx, cacheGenerationClaimId: access.claimId } as PersistedTx<\n ElectronPersistedRow,\n ElectronPersistedKey\n >,\n },\n resolution,\n )\n },\n reconcileCommittedTx: async (\n target: PersistedStorageTarget,\n tx: PersistedTx<Record<string, unknown>, string | number>,\n anchor: CommittedTxAnchor,\n ): Promise<ReconciledCommittedTx> => {\n const access = resolvePersistedStorageTarget(\n target,\n tx.cacheGenerationClaimId,\n )\n return executeRequest(\n `reconcileCommittedTx`,\n target,\n { tx: { ...tx, cacheGenerationClaimId: access.claimId }, anchor },\n resolution,\n )\n },\n loadCollectionMetadata: async (\n target: PersistedStorageTarget,\n ctx?: { cacheGenerationClaimId?: string },\n ): Promise<Array<{ key: string; value: unknown }>> => {\n const access = resolvePersistedStorageTarget(\n target,\n ctx?.cacheGenerationClaimId,\n )\n return executeRequest(\n `loadCollectionMetadata`,\n target,\n { ctx: { ...ctx, cacheGenerationClaimId: access.claimId } },\n resolution,\n )\n },\n scanRows: async (\n target: PersistedStorageTarget,\n options?: { metadataOnly?: boolean },\n ctx?: { cacheGenerationClaimId?: string },\n ): Promise<\n Array<{\n key: string | number\n value: Record<string, unknown>\n metadata?: unknown\n }>\n > => {\n const access = resolvePersistedStorageTarget(\n target,\n ctx?.cacheGenerationClaimId,\n )\n const result = await executeRequest(\n `scanRows`,\n target,\n { options, ctx: { ...ctx, cacheGenerationClaimId: access.claimId } },\n resolution,\n )\n return result as Array<{\n key: string | number\n value: Record<string, unknown>\n metadata?: unknown\n }>\n },\n ensureIndex: async (\n target: PersistedStorageTarget,\n signature: string,\n spec: PersistedIndexSpec,\n ctx?: { cacheGenerationClaimId?: string },\n ): Promise<void> => {\n const access = resolvePersistedStorageTarget(\n target,\n ctx?.cacheGenerationClaimId,\n )\n await executeRequest(\n `ensureIndex`,\n target,\n {\n signature,\n spec,\n ctx: { ...ctx, cacheGenerationClaimId: access.claimId },\n },\n resolution,\n )\n },\n markIndexRemoved: async (\n target: PersistedStorageTarget,\n signature: string,\n ctx?: { cacheGenerationClaimId?: string },\n ): Promise<void> => {\n const access = resolvePersistedStorageTarget(\n target,\n ctx?.cacheGenerationClaimId,\n )\n await executeRequest(\n `markIndexRemoved`,\n target,\n {\n signature,\n ctx: { ...ctx, cacheGenerationClaimId: access.claimId },\n },\n resolution,\n )\n },\n pullSince: async (\n target: PersistedStorageTarget,\n fromRowVersion: number,\n ctx?: { cacheGenerationClaimId?: string },\n ): Promise<SQLitePullSinceResult<string | number>> => {\n const access = resolvePersistedStorageTarget(\n target,\n ctx?.cacheGenerationClaimId,\n )\n const result = await executeRequest(\n `pullSince`,\n target,\n {\n fromRowVersion,\n ctx: { ...ctx, cacheGenerationClaimId: access.claimId },\n },\n resolution,\n )\n return result as SQLitePullSinceResult<string | number>\n },\n getStreamPosition: async (\n target: PersistedStorageTarget,\n ctx?: { cacheGenerationClaimId?: string },\n ): Promise<{\n latestTerm: number\n latestSeq: number\n latestRowVersion: number\n }> => {\n const access = resolvePersistedStorageTarget(\n target,\n ctx?.cacheGenerationClaimId,\n )\n return executeRequest(\n `getStreamPosition`,\n target,\n { ctx: { ...ctx, cacheGenerationClaimId: access.claimId } },\n resolution,\n )\n },\n claimCacheGeneration: async (\n collectionId: string,\n ): Promise<PersistedCacheGenerationClaim> => {\n const claim = await executeRequest(\n `claimCacheGeneration`,\n collectionId,\n {},\n resolution,\n )\n claimCollections.set(claim.claimId, collectionId)\n return claim\n },\n rotateCacheGeneration: async (\n collectionId: string,\n claimId: string,\n resetMetadata?: { key: string; value: unknown },\n expectedStorageCollectionId?: string,\n ): Promise<PersistedCacheGenerationClaim> => {\n const claim = await executeRequest(\n `rotateCacheGeneration`,\n collectionId,\n { claimId, resetMetadata, expectedStorageCollectionId },\n resolution,\n )\n claimCollections.delete(claimId)\n claimCollections.set(claim.claimId, collectionId)\n return claim\n },\n renewCacheGenerationClaim: (\n storageCollectionId: string,\n claimId: string,\n ): Promise<number | undefined> => {\n const collectionId = claimCollections.get(claimId)\n if (!collectionId) {\n throw new InvalidPersistedCollectionConfigError(\n `Unknown electron persisted cache claim \"${claimId}\"`,\n )\n }\n return executeRequest(\n `renewCacheGenerationClaim`,\n collectionId,\n { storageCollectionId, claimId },\n resolution,\n )\n },\n releaseCacheGenerationClaim: async (claimId: string): Promise<void> => {\n const collectionId = claimCollections.get(claimId)\n if (!collectionId) {\n throw new InvalidPersistedCollectionConfigError(\n `Unknown electron persisted cache claim \"${claimId}\"`,\n )\n }\n await executeRequest(\n `releaseCacheGenerationClaim`,\n collectionId,\n { claimId },\n resolution,\n )\n claimCollections.delete(claimId)\n },\n reserveLeadershipTerm: async (target, observedTerm, ctx) => {\n const access = resolvePersistedStorageTarget(\n target,\n ctx?.cacheGenerationClaimId,\n )\n return executeRequest(\n `reserveLeadershipTerm`,\n target,\n {\n observedTerm,\n ctx: { ...ctx, cacheGenerationClaimId: access.claimId },\n },\n resolution,\n )\n },\n runInHydrationScope: <T>(\n task: (scopedAdapter: HydrationPersistenceAdapter) => Promise<T>,\n ) => queuedWork.track(Promise.resolve().then(() => task(adapter))),\n isHydrationScopeScheduled: () => false,\n // Work runs directly; the main process serializes it.\n runInRegularScope: Object.assign(\n <T>(task: (scopedAdapter: HydrationPersistenceAdapter) => Promise<T>) =>\n task(adapter),\n { afterQueuedWork: () => queuedWork.afterQueuedWork() },\n ),\n }\n if (!managedCacheGenerations) {\n adapter.claimCacheGeneration = undefined\n adapter.rotateCacheGeneration = undefined\n adapter.renewCacheGenerationClaim = undefined\n adapter.releaseCacheGenerationClaim = undefined\n }\n return adapter\n}\n\nexport type ElectronIpcRendererLike = {\n invoke: (\n channel: string,\n request: ElectronPersistenceRequestEnvelope,\n ) => Promise<ElectronPersistenceResponseEnvelope>\n}\n\nexport type ElectronSQLitePersistenceOptions = {\n invoke?: ElectronPersistenceInvoke\n ipcRenderer?: ElectronIpcRendererLike\n channel?: string\n timeoutMs?: number\n coordinator?: PersistedCollectionCoordinator\n /** Set false when a custom main-process adapter does not manage cache generations. */\n managedCacheGenerations?: boolean\n}\n\nfunction resolveInvoke(\n options: ElectronSQLitePersistenceOptions,\n): ElectronPersistenceInvoke {\n if (options.invoke) {\n return options.invoke\n }\n\n if (options.ipcRenderer) {\n return (channel, request) => options.ipcRenderer!.invoke(channel, request)\n }\n\n throw new InvalidPersistedCollectionConfigError(\n `Electron renderer persistence requires either invoke or ipcRenderer`,\n )\n}\n\nexport function createElectronSQLitePersistence(\n options: ElectronSQLitePersistenceOptions,\n): PersistedCollectionPersistence {\n const queuedWork = new RendererQueuedWork()\n const invoke = resolveInvoke(options)\n const coordinator = options.coordinator ?? new SingleProcessCoordinator()\n const claimCollections = new Map<string, string>()\n const executeRequest = createRendererRequestExecutor({\n invoke,\n channel: options.channel,\n timeoutMs: options.timeoutMs,\n claimCollections,\n })\n const adapterCache = new Map<string, ElectronRendererResolvedAdapter>()\n\n const getAdapterForCollection = (\n collectionId: string | undefined,\n mode: PersistedCollectionMode,\n schemaVersion: number | undefined,\n ) => {\n const cacheKey = JSON.stringify([collectionId, mode, schemaVersion])\n const cachedAdapter = adapterCache.get(cacheKey)\n if (cachedAdapter) {\n return cachedAdapter\n }\n\n const adapter = createResolvedRendererAdapter(\n executeRequest,\n claimCollections,\n options.managedCacheGenerations ?? true,\n queuedWork,\n { mode, schemaVersion, logicalCollectionId: collectionId },\n )\n adapterCache.set(cacheKey, adapter)\n return adapter\n }\n\n const createCollectionPersistence = (\n collectionId: string | undefined,\n mode: PersistedCollectionMode,\n schemaVersion: number | undefined,\n ): PersistedCollectionPersistence => {\n const adapter = getAdapterForCollection(collectionId, mode, schemaVersion)\n if (coordinator instanceof ElectronCollectionCoordinator) {\n if (collectionId === undefined) {\n coordinator.setAdapter(adapter)\n } else {\n coordinator.setAdapterForCollection(collectionId, adapter)\n }\n }\n return { adapter, coordinator }\n }\n\n const defaultPersistence = createCollectionPersistence(\n undefined,\n `sync-absent`,\n undefined,\n )\n if (coordinator instanceof ElectronCollectionCoordinator) {\n coordinator.setAdapter(defaultPersistence.adapter)\n }\n\n return {\n ...defaultPersistence,\n resolvePersistenceForCollection: ({ collectionId, mode, schemaVersion }) =>\n createCollectionPersistence(collectionId, mode, schemaVersion),\n // Backward compatible fallback for older callers.\n resolvePersistenceForMode: (mode) =>\n createCollectionPersistence(undefined, mode, undefined),\n }\n}\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/electron-db-sqlite-persistence",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0-rc.1",
|
|
4
4
|
"description": "Electron SQLite persisted collection bridge for TanStack DB",
|
|
5
5
|
"author": "TanStack Team",
|
|
6
6
|
"license": "MIT",
|
|
@@ -60,14 +60,14 @@
|
|
|
60
60
|
"src"
|
|
61
61
|
],
|
|
62
62
|
"dependencies": {
|
|
63
|
-
"@tanstack/db-sqlite-persistence-core": "0.
|
|
63
|
+
"@tanstack/db-sqlite-persistence-core": "1.0.0-rc.1"
|
|
64
64
|
},
|
|
65
65
|
"peerDependencies": {
|
|
66
66
|
"typescript": ">=4.7"
|
|
67
67
|
},
|
|
68
68
|
"devDependencies": {
|
|
69
|
-
"@vitest/coverage-istanbul": "^
|
|
70
|
-
"electron": "^
|
|
69
|
+
"@vitest/coverage-istanbul": "^4.1.12",
|
|
70
|
+
"electron": "^42.0.0"
|
|
71
71
|
},
|
|
72
72
|
"scripts": {
|
|
73
73
|
"build": "vite build",
|
package/src/renderer.ts
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
} from './protocol'
|
|
11
11
|
import type {
|
|
12
12
|
CommittedTxAnchor,
|
|
13
|
+
HydrationPersistenceAdapter,
|
|
13
14
|
PersistedCacheGenerationClaim,
|
|
14
15
|
PersistedCollectionCoordinator,
|
|
15
16
|
PersistedCollectionMode,
|
|
@@ -192,6 +193,28 @@ function createRendererRequestExecutor(options: {
|
|
|
192
193
|
}
|
|
193
194
|
}
|
|
194
195
|
|
|
196
|
+
// The renderer has no shared driver scheduler. Its queued reads are its
|
|
197
|
+
// hydration scopes; its writes take the writer Web Lock, which also orders
|
|
198
|
+
// them against an election term.
|
|
199
|
+
class RendererQueuedWork {
|
|
200
|
+
private readonly unsettled = new Set<Promise<void>>()
|
|
201
|
+
|
|
202
|
+
track<T>(work: Promise<T>): Promise<T> {
|
|
203
|
+
const done = work.then(
|
|
204
|
+
() => undefined,
|
|
205
|
+
() => undefined,
|
|
206
|
+
)
|
|
207
|
+
this.unsettled.add(done)
|
|
208
|
+
void done.then(() => this.unsettled.delete(done))
|
|
209
|
+
return work
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Settles once every hydration scope outstanding at the call settles.
|
|
213
|
+
afterQueuedWork(): Promise<void> {
|
|
214
|
+
return Promise.all(this.unsettled).then(() => undefined)
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
195
218
|
type ElectronRendererResolvedAdapter =
|
|
196
219
|
PersistedCollectionPersistence[`adapter`] & {
|
|
197
220
|
loadCollectionMetadata: (
|
|
@@ -237,6 +260,7 @@ function createResolvedRendererAdapter(
|
|
|
237
260
|
executeRequest: RendererRequestExecutor,
|
|
238
261
|
claimCollections: Map<string, string>,
|
|
239
262
|
managedCacheGenerations: boolean,
|
|
263
|
+
queuedWork: RendererQueuedWork,
|
|
240
264
|
resolution?: ElectronPersistenceResolution,
|
|
241
265
|
): ElectronRendererResolvedAdapter {
|
|
242
266
|
const adapter: ElectronRendererResolvedAdapter = {
|
|
@@ -518,6 +542,16 @@ function createResolvedRendererAdapter(
|
|
|
518
542
|
resolution,
|
|
519
543
|
)
|
|
520
544
|
},
|
|
545
|
+
runInHydrationScope: <T>(
|
|
546
|
+
task: (scopedAdapter: HydrationPersistenceAdapter) => Promise<T>,
|
|
547
|
+
) => queuedWork.track(Promise.resolve().then(() => task(adapter))),
|
|
548
|
+
isHydrationScopeScheduled: () => false,
|
|
549
|
+
// Work runs directly; the main process serializes it.
|
|
550
|
+
runInRegularScope: Object.assign(
|
|
551
|
+
<T>(task: (scopedAdapter: HydrationPersistenceAdapter) => Promise<T>) =>
|
|
552
|
+
task(adapter),
|
|
553
|
+
{ afterQueuedWork: () => queuedWork.afterQueuedWork() },
|
|
554
|
+
),
|
|
521
555
|
}
|
|
522
556
|
if (!managedCacheGenerations) {
|
|
523
557
|
adapter.claimCacheGeneration = undefined
|
|
@@ -564,6 +598,7 @@ function resolveInvoke(
|
|
|
564
598
|
export function createElectronSQLitePersistence(
|
|
565
599
|
options: ElectronSQLitePersistenceOptions,
|
|
566
600
|
): PersistedCollectionPersistence {
|
|
601
|
+
const queuedWork = new RendererQueuedWork()
|
|
567
602
|
const invoke = resolveInvoke(options)
|
|
568
603
|
const coordinator = options.coordinator ?? new SingleProcessCoordinator()
|
|
569
604
|
const claimCollections = new Map<string, string>()
|
|
@@ -590,6 +625,7 @@ export function createElectronSQLitePersistence(
|
|
|
590
625
|
executeRequest,
|
|
591
626
|
claimCollections,
|
|
592
627
|
options.managedCacheGenerations ?? true,
|
|
628
|
+
queuedWork,
|
|
593
629
|
{ mode, schemaVersion, logicalCollectionId: collectionId },
|
|
594
630
|
)
|
|
595
631
|
adapterCache.set(cacheKey, adapter)
|