@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.
@@ -98,7 +98,25 @@ function createRendererRequestExecutor(options) {
98
98
  return response.result;
99
99
  };
100
100
  }
101
- function createResolvedRendererAdapter(executeRequest, claimCollections, managedCacheGenerations, resolution) {
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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"}
@@ -96,7 +96,25 @@ function createRendererRequestExecutor(options) {
96
96
  return response.result;
97
97
  };
98
98
  }
99
- function createResolvedRendererAdapter(executeRequest, claimCollections, managedCacheGenerations, resolution) {
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);
@@ -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":";;;AAqCA,MAAM,6BAA6B;AACnC,IAAI,gBAAgB;AAEpB,SAAS,kBAA0B;AACjC,QAAM,YAAY;AAClB;AACA,SAAO,wBAAwB,SAAS;AAC1C;AAEA,SAAS,YACP,SACA,WACA,gBACY;AACZ,MAAI,aAAa,GAAG;AAClB,WAAO;AAAA,EACT;AAEA,SAAO,IAAI,QAAW,CAAC,SAAS,WAAW;AACzC,UAAM,QAAQ,WAAW,MAAM;AAC7B,aAAO,IAAI,sCAAsC,cAAc,CAAC;AAAA,IAClE,GAAG,SAAS;AAEZ,YAAQ;AAAA,MACN,CAAC,UAAU;AACT,qBAAa,KAAK;AAClB,gBAAQ,KAAK;AAAA,MACf;AAAA,MACA,CAAC,UAAmB;AAClB,qBAAa,KAAK;AAClB,eAAO,KAAK;AAAA,MACd;AAAA,IAAA;AAAA,EAEJ,CAAC;AACH;AAEA,SAAS,oBACP,UACA,SACM;AACN,MAAI,SAAS,MAAM,uCAAuC;AACxD,UAAM,IAAI;AAAA,MACR,qDAAqD,SAAS,CAAC;AAAA,IAAA;AAAA,EAEnE;AAEA,MAAI,SAAS,cAAc,QAAQ,WAAW;AAC5C,UAAM,IAAI;AAAA,MACR,kEAAkE,QAAQ,SAAS,gBAAgB,SAAS,SAAS;AAAA,IAAA;AAAA,EAEzH;AAEA,MAAI,SAAS,WAAW,QAAQ,QAAQ;AACtC,UAAM,IAAI;AAAA,MACR,8DAA8D,QAAQ,MAAM,gBAAgB,SAAS,MAAM;AAAA,IAAA;AAAA,EAE/G;AACF;AAEA,SAAS,oCACP,eACmB;AACnB,QAAM,EAAE,cAAc,eAAe,GAAG,wBAAwB;AAChE,SAAO;AACT;AASA,SAAS,8BAA8B,SAKX;AAC1B,QAAM,UAAU,QAAQ,WAAW;AACnC,QAAM,YAAY,QAAQ,aAAa;AAEvC,SAAO,OACL,QACA,QACA,SACA,eACG;AACH,UAAM,gBAAgB,OAAO,WAAW,WAAW,SAAY;AAC/D,UAAM,eAAe,gBACjB,8BAA8B,aAAa,EAAE,eAC7C;AACJ,UAAM,sBACJ,WAAW,0BACX,WAAW,2BACX,WAAW,+BACX,WAAW;AACb,UAAM,gBAAgB,eAAe,SAAS;AAC9C,UAAM,sBACJ,YAAY,wBACX,gBACG,QAAQ,iBAAiB,IAAI,cAAc,OAAO,IAClD,sBACE,eACA;AACR,SAAK,iBAAiB,wBAAwB,CAAC,qBAAqB;AAClE,YAAM,IAAI;AAAA,QACR;AAAA,MAAA;AAAA,IAEJ;AACA,UAAM,UAAU;AAAA,MACd,GAAG;AAAA,MACH,WAAW,gBAAA;AAAA,MACX;AAAA,MACA;AAAA,MACA;AAAA,MACA,YACE,iBAAiB,sBACb,EAAE,GAAG,YAAY,MAAM,gBAAgB,oBAAA,IACvC;AAAA,MACN;AAAA,IAAA;AAGF,UAAM,WAAW,MAAM;AAAA,MACrB,QAAQ,OAAO,SAAS,OAAO;AAAA,MAC/B;AAAA,MACA,kDAAkD,MAAM,gBAAgB,YAAY,eAAe,SAAS;AAAA,IAAA;AAE9G,wBAAoB,UAAU,OAAO;AAErC,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,cAAc,IAAI;AAAA,QACtB,GAAG,SAAS,MAAM,IAAI,KAAK,SAAS,MAAM,OAAO;AAAA,MAAA;AAEnD,UAAI,OAAO,SAAS,MAAM,UAAU,UAAU;AAC5C,oBAAY,QAAQ,SAAS,MAAM;AAAA,MACrC;AACA,UACE,OAAO,SAAS,MAAM,SAAS,YAC/B,OAAO,SAAS,MAAM,SAAS,UAC/B;AACE,oBAAmD,OACnD,SAAS,MAAM;AAAA,MACnB;AACA,UAAI,SAAS,MAAM,SAAS,QAAW;AAEnC,oBAGA,OAAO,SAAS,MAAM;AAAA,MAC1B;AACA,YAAM;AAAA,IACR;AAEA,WAAO,SAAS;AAAA,EAClB;AACF;AAKA,MAAM,mBAAmB;AAAA,EAAzB,cAAA;AACE,SAAiB,gCAAgB,IAAA;AAAA,EAAmB;AAAA,EAEpD,MAAS,MAA8B;AACrC,UAAM,OAAO,KAAK;AAAA,MAChB,MAAM;AAAA,MACN,MAAM;AAAA,IAAA;AAER,SAAK,UAAU,IAAI,IAAI;AACvB,SAAK,KAAK,KAAK,MAAM,KAAK,UAAU,OAAO,IAAI,CAAC;AAChD,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,kBAAiC;AAC/B,WAAO,QAAQ,IAAI,KAAK,SAAS,EAAE,KAAK,MAAM,MAAS;AAAA,EACzD;AACF;AA2CA,SAAS,8BACP,gBACA,kBACA,yBACA,YACA,YACiC;AACjC,QAAM,UAA2C;AAAA,IAC/C,YAAY,OACV,QACA,eACA,QAIG;AACH,YAAM,SAAS;AAAA,QACb;AAAA,QACA,KAAK;AAAA,MAAA;AAEP,YAAM,SAAS,MAAM;AAAA,QACnB;AAAA,QACA;AAAA,QACA;AAAA,UACE,SAAS,oCAAoC,aAAa;AAAA,UAC1D,KAAK,EAAE,GAAG,KAAK,wBAAwB,OAAO,QAAA;AAAA,QAAQ;AAAA,QAExD;AAAA,MAAA;AAGF,aAAO;AAAA,IAIT;AAAA,IACA,oBAAoB,OAClB,QACA,QAKG;AACH,YAAM,SAAS;AAAA,QACb;AAAA,QACA,KAAK;AAAA,MAAA;AAEP,aAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA,EAAE,KAAK,EAAE,GAAG,KAAK,wBAAwB,OAAO,UAAQ;AAAA,QACxD;AAAA,MAAA;AAAA,IAEJ;AAAA,IACA,kBAAkB,OAChB,QACA,OACkB;AAClB,YAAM,SAAS;AAAA,QACb;AAAA,QACA,GAAG;AAAA,MAAA;AAEL,YAAM;AAAA,QACJ;AAAA,QACA;AAAA,QACA;AAAA,UACE,IAAI,EAAE,GAAG,IAAI,wBAAwB,OAAO,QAAA;AAAA,QAAQ;AAAA,QAKtD;AAAA,MAAA;AAAA,IAEJ;AAAA,IACA,sBAAsB,OACpB,QACA,IACA,WACmC;AACnC,YAAM,SAAS;AAAA,QACb;AAAA,QACA,GAAG;AAAA,MAAA;AAEL,aAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA,EAAE,IAAI,EAAE,GAAG,IAAI,wBAAwB,OAAO,QAAA,GAAW,OAAA;AAAA,QACzD;AAAA,MAAA;AAAA,IAEJ;AAAA,IACA,wBAAwB,OACtB,QACA,QACoD;AACpD,YAAM,SAAS;AAAA,QACb;AAAA,QACA,KAAK;AAAA,MAAA;AAEP,aAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA,EAAE,KAAK,EAAE,GAAG,KAAK,wBAAwB,OAAO,UAAQ;AAAA,QACxD;AAAA,MAAA;AAAA,IAEJ;AAAA,IACA,UAAU,OACR,QACA,SACA,QAOG;AACH,YAAM,SAAS;AAAA,QACb;AAAA,QACA,KAAK;AAAA,MAAA;AAEP,YAAM,SAAS,MAAM;AAAA,QACnB;AAAA,QACA;AAAA,QACA,EAAE,SAAS,KAAK,EAAE,GAAG,KAAK,wBAAwB,OAAO,UAAQ;AAAA,QACjE;AAAA,MAAA;AAEF,aAAO;AAAA,IAKT;AAAA,IACA,aAAa,OACX,QACA,WACA,MACA,QACkB;AAClB,YAAM,SAAS;AAAA,QACb;AAAA,QACA,KAAK;AAAA,MAAA;AAEP,YAAM;AAAA,QACJ;AAAA,QACA;AAAA,QACA;AAAA,UACE;AAAA,UACA;AAAA,UACA,KAAK,EAAE,GAAG,KAAK,wBAAwB,OAAO,QAAA;AAAA,QAAQ;AAAA,QAExD;AAAA,MAAA;AAAA,IAEJ;AAAA,IACA,kBAAkB,OAChB,QACA,WACA,QACkB;AAClB,YAAM,SAAS;AAAA,QACb;AAAA,QACA,KAAK;AAAA,MAAA;AAEP,YAAM;AAAA,QACJ;AAAA,QACA;AAAA,QACA;AAAA,UACE;AAAA,UACA,KAAK,EAAE,GAAG,KAAK,wBAAwB,OAAO,QAAA;AAAA,QAAQ;AAAA,QAExD;AAAA,MAAA;AAAA,IAEJ;AAAA,IACA,WAAW,OACT,QACA,gBACA,QACoD;AACpD,YAAM,SAAS;AAAA,QACb;AAAA,QACA,KAAK;AAAA,MAAA;AAEP,YAAM,SAAS,MAAM;AAAA,QACnB;AAAA,QACA;AAAA,QACA;AAAA,UACE;AAAA,UACA,KAAK,EAAE,GAAG,KAAK,wBAAwB,OAAO,QAAA;AAAA,QAAQ;AAAA,QAExD;AAAA,MAAA;AAEF,aAAO;AAAA,IACT;AAAA,IACA,mBAAmB,OACjB,QACA,QAKI;AACJ,YAAM,SAAS;AAAA,QACb;AAAA,QACA,KAAK;AAAA,MAAA;AAEP,aAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA,EAAE,KAAK,EAAE,GAAG,KAAK,wBAAwB,OAAO,UAAQ;AAAA,QACxD;AAAA,MAAA;AAAA,IAEJ;AAAA,IACA,sBAAsB,OACpB,iBAC2C;AAC3C,YAAM,QAAQ,MAAM;AAAA,QAClB;AAAA,QACA;AAAA,QACA,CAAA;AAAA,QACA;AAAA,MAAA;AAEF,uBAAiB,IAAI,MAAM,SAAS,YAAY;AAChD,aAAO;AAAA,IACT;AAAA,IACA,uBAAuB,OACrB,cACA,SACA,eACA,gCAC2C;AAC3C,YAAM,QAAQ,MAAM;AAAA,QAClB;AAAA,QACA;AAAA,QACA,EAAE,SAAS,eAAe,4BAAA;AAAA,QAC1B;AAAA,MAAA;AAEF,uBAAiB,OAAO,OAAO;AAC/B,uBAAiB,IAAI,MAAM,SAAS,YAAY;AAChD,aAAO;AAAA,IACT;AAAA,IACA,2BAA2B,CACzB,qBACA,YACgC;AAChC,YAAM,eAAe,iBAAiB,IAAI,OAAO;AACjD,UAAI,CAAC,cAAc;AACjB,cAAM,IAAI;AAAA,UACR,2CAA2C,OAAO;AAAA,QAAA;AAAA,MAEtD;AACA,aAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA,EAAE,qBAAqB,QAAA;AAAA,QACvB;AAAA,MAAA;AAAA,IAEJ;AAAA,IACA,6BAA6B,OAAO,YAAmC;AACrE,YAAM,eAAe,iBAAiB,IAAI,OAAO;AACjD,UAAI,CAAC,cAAc;AACjB,cAAM,IAAI;AAAA,UACR,2CAA2C,OAAO;AAAA,QAAA;AAAA,MAEtD;AACA,YAAM;AAAA,QACJ;AAAA,QACA;AAAA,QACA,EAAE,QAAA;AAAA,QACF;AAAA,MAAA;AAEF,uBAAiB,OAAO,OAAO;AAAA,IACjC;AAAA,IACA,uBAAuB,OAAO,QAAQ,cAAc,QAAQ;AAC1D,YAAM,SAAS;AAAA,QACb;AAAA,QACA,KAAK;AAAA,MAAA;AAEP,aAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA;AAAA,UACE;AAAA,UACA,KAAK,EAAE,GAAG,KAAK,wBAAwB,OAAO,QAAA;AAAA,QAAQ;AAAA,QAExD;AAAA,MAAA;AAAA,IAEJ;AAAA,IACA,qBAAqB,CACnB,SACG,WAAW,MAAM,QAAQ,QAAA,EAAU,KAAK,MAAM,KAAK,OAAO,CAAC,CAAC;AAAA,IACjE,2BAA2B,MAAM;AAAA;AAAA,IAEjC,mBAAmB,OAAO;AAAA,MACxB,CAAI,SACF,KAAK,OAAO;AAAA,MACd,EAAE,iBAAiB,MAAM,WAAW,kBAAgB;AAAA,IAAE;AAAA,EACxD;AAEF,MAAI,CAAC,yBAAyB;AAC5B,YAAQ,uBAAuB;AAC/B,YAAQ,wBAAwB;AAChC,YAAQ,4BAA4B;AACpC,YAAQ,8BAA8B;AAAA,EACxC;AACA,SAAO;AACT;AAmBA,SAAS,cACP,SAC2B;AAC3B,MAAI,QAAQ,QAAQ;AAClB,WAAO,QAAQ;AAAA,EACjB;AAEA,MAAI,QAAQ,aAAa;AACvB,WAAO,CAAC,SAAS,YAAY,QAAQ,YAAa,OAAO,SAAS,OAAO;AAAA,EAC3E;AAEA,QAAM,IAAI;AAAA,IACR;AAAA,EAAA;AAEJ;AAEO,SAAS,gCACd,SACgC;AAChC,QAAM,aAAa,IAAI,mBAAA;AACvB,QAAM,SAAS,cAAc,OAAO;AACpC,QAAM,cAAc,QAAQ,eAAe,IAAI,yBAAA;AAC/C,QAAM,uCAAuB,IAAA;AAC7B,QAAM,iBAAiB,8BAA8B;AAAA,IACnD;AAAA,IACA,SAAS,QAAQ;AAAA,IACjB,WAAW,QAAQ;AAAA,IACnB;AAAA,EAAA,CACD;AACD,QAAM,mCAAmB,IAAA;AAEzB,QAAM,0BAA0B,CAC9B,cACA,MACA,kBACG;AACH,UAAM,WAAW,KAAK,UAAU,CAAC,cAAc,MAAM,aAAa,CAAC;AACnE,UAAM,gBAAgB,aAAa,IAAI,QAAQ;AAC/C,QAAI,eAAe;AACjB,aAAO;AAAA,IACT;AAEA,UAAM,UAAU;AAAA,MACd;AAAA,MACA;AAAA,MACA,QAAQ,2BAA2B;AAAA,MACnC;AAAA,MACA,EAAE,MAAM,eAAe,qBAAqB,aAAA;AAAA,IAAa;AAE3D,iBAAa,IAAI,UAAU,OAAO;AAClC,WAAO;AAAA,EACT;AAEA,QAAM,8BAA8B,CAClC,cACA,MACA,kBACmC;AACnC,UAAM,UAAU,wBAAwB,cAAc,MAAM,aAAa;AACzE,QAAI,uBAAuB,+BAA+B;AACxD,UAAI,iBAAiB,QAAW;AAC9B,oBAAY,WAAW,OAAO;AAAA,MAChC,OAAO;AACL,oBAAY,wBAAwB,cAAc,OAAO;AAAA,MAC3D;AAAA,IACF;AACA,WAAO,EAAE,SAAS,YAAA;AAAA,EACpB;AAEA,QAAM,qBAAqB;AAAA,IACzB;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAEF,MAAI,uBAAuB,+BAA+B;AACxD,gBAAY,WAAW,mBAAmB,OAAO;AAAA,EACnD;AAEA,SAAO;AAAA,IACL,GAAG;AAAA,IACH,iCAAiC,CAAC,EAAE,cAAc,MAAM,oBACtD,4BAA4B,cAAc,MAAM,aAAa;AAAA;AAAA,IAE/D,2BAA2B,CAAC,SAC1B,4BAA4B,QAAW,MAAM,MAAS;AAAA,EAAA;AAE5D;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/electron-db-sqlite-persistence",
3
- "version": "0.2.13",
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.4.12"
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": "^3.2.4",
70
- "electron": "^41.0.0"
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)