@tanstack/electron-db-sqlite-persistence 0.2.8 → 0.2.10

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.
@@ -1,4 +1,4 @@
1
- import { SingleProcessCoordinator, InvalidPersistedCollectionConfigError } from "@tanstack/db-sqlite-persistence-core";
1
+ import { SingleProcessCoordinator, InvalidPersistedCollectionConfigError, resolvePersistedStorageTarget } from "@tanstack/db-sqlite-persistence-core";
2
2
  import { ElectronCollectionCoordinator } from "./electron-coordinator.js";
3
3
  import { DEFAULT_ELECTRON_PERSISTENCE_CHANNEL, ELECTRON_PERSISTENCE_PROTOCOL_VERSION } from "./protocol.js";
4
4
  const DEFAULT_REQUEST_TIMEOUT_MS = 5e3;
@@ -52,13 +52,24 @@ function createSerializableLoadSubsetOptions(subsetOptions) {
52
52
  function createRendererRequestExecutor(options) {
53
53
  const channel = options.channel ?? DEFAULT_ELECTRON_PERSISTENCE_CHANNEL;
54
54
  const timeoutMs = options.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
55
- return async (method, collectionId, payload, resolution) => {
55
+ return async (method, target, payload, resolution) => {
56
+ const storageTarget = typeof target === `string` ? void 0 : target;
57
+ const collectionId = storageTarget ? resolvePersistedStorageTarget(storageTarget).collectionId : target;
58
+ const isGenerationRequest = method === `claimCacheGeneration` || method === `rotateCacheGeneration` || method === `renewCacheGenerationClaim` || method === `releaseCacheGenerationClaim`;
59
+ const managedTarget = storageTarget?.kind === `managed`;
60
+ const logicalCollectionId = resolution?.logicalCollectionId ?? (managedTarget ? options.claimCollections.get(storageTarget.claimId) : isGenerationRequest ? collectionId : void 0);
61
+ if ((managedTarget || isGenerationRequest) && !logicalCollectionId) {
62
+ throw new InvalidPersistedCollectionConfigError(
63
+ `Electron managed cache request requires a known logical Collection ID`
64
+ );
65
+ }
56
66
  const request = {
57
67
  v: ELECTRON_PERSISTENCE_PROTOCOL_VERSION,
58
68
  requestId: createRequestId(),
59
69
  collectionId,
70
+ storageTarget,
60
71
  method,
61
- resolution,
72
+ resolution: managedTarget || isGenerationRequest ? { ...resolution, mode: `sync-present`, logicalCollectionId } : resolution,
62
73
  payload
63
74
  };
64
75
  const response = await withTimeout(
@@ -74,99 +85,230 @@ function createRendererRequestExecutor(options) {
74
85
  if (typeof response.error.stack === `string`) {
75
86
  remoteError.stack = response.error.stack;
76
87
  }
77
- if (typeof response.error.code === `string`) {
88
+ if (typeof response.error.code === `string` || typeof response.error.code === `number`) {
78
89
  remoteError.code = response.error.code;
79
90
  }
91
+ if (response.error.path !== void 0) {
92
+ remoteError.path = response.error.path;
93
+ }
80
94
  throw remoteError;
81
95
  }
82
96
  return response.result;
83
97
  };
84
98
  }
85
- function createResolvedRendererAdapter(executeRequest, resolution) {
86
- return {
87
- loadSubset: async (collectionId, subsetOptions, ctx) => {
99
+ function createResolvedRendererAdapter(executeRequest, claimCollections, managedCacheGenerations, resolution) {
100
+ const adapter = {
101
+ loadSubset: async (target, subsetOptions, ctx) => {
102
+ const access = resolvePersistedStorageTarget(
103
+ target,
104
+ ctx?.cacheGenerationClaimId
105
+ );
88
106
  const result = await executeRequest(
89
107
  `loadSubset`,
90
- collectionId,
108
+ target,
91
109
  {
92
110
  options: createSerializableLoadSubsetOptions(subsetOptions),
93
- ctx
111
+ ctx: { ...ctx, cacheGenerationClaimId: access.claimId }
94
112
  },
95
113
  resolution
96
114
  );
97
115
  return result;
98
116
  },
99
- loadResumeSnapshot: async (collectionId, ctx) => {
117
+ loadResumeSnapshot: async (target, ctx) => {
118
+ const access = resolvePersistedStorageTarget(
119
+ target,
120
+ ctx?.cacheGenerationClaimId
121
+ );
100
122
  return executeRequest(
101
123
  `loadResumeSnapshot`,
102
- collectionId,
103
- { ctx },
124
+ target,
125
+ { ctx: { ...ctx, cacheGenerationClaimId: access.claimId } },
104
126
  resolution
105
127
  );
106
128
  },
107
- applyCommittedTx: async (collectionId, tx) => {
129
+ applyCommittedTx: async (target, tx) => {
130
+ const access = resolvePersistedStorageTarget(
131
+ target,
132
+ tx.cacheGenerationClaimId
133
+ );
108
134
  await executeRequest(
109
135
  `applyCommittedTx`,
110
- collectionId,
136
+ target,
111
137
  {
112
- tx
138
+ tx: { ...tx, cacheGenerationClaimId: access.claimId }
113
139
  },
114
140
  resolution
115
141
  );
116
142
  },
117
- loadCollectionMetadata: async (collectionId) => {
143
+ reconcileCommittedTx: async (target, tx, anchor) => {
144
+ const access = resolvePersistedStorageTarget(
145
+ target,
146
+ tx.cacheGenerationClaimId
147
+ );
148
+ return executeRequest(
149
+ `reconcileCommittedTx`,
150
+ target,
151
+ { tx: { ...tx, cacheGenerationClaimId: access.claimId }, anchor },
152
+ resolution
153
+ );
154
+ },
155
+ loadCollectionMetadata: async (target, ctx) => {
156
+ const access = resolvePersistedStorageTarget(
157
+ target,
158
+ ctx?.cacheGenerationClaimId
159
+ );
118
160
  return executeRequest(
119
161
  `loadCollectionMetadata`,
120
- collectionId,
121
- {},
162
+ target,
163
+ { ctx: { ...ctx, cacheGenerationClaimId: access.claimId } },
122
164
  resolution
123
165
  );
124
166
  },
125
- scanRows: async (collectionId, options) => {
167
+ scanRows: async (target, options, ctx) => {
168
+ const access = resolvePersistedStorageTarget(
169
+ target,
170
+ ctx?.cacheGenerationClaimId
171
+ );
126
172
  const result = await executeRequest(
127
173
  `scanRows`,
128
- collectionId,
129
- { options },
174
+ target,
175
+ { options, ctx: { ...ctx, cacheGenerationClaimId: access.claimId } },
130
176
  resolution
131
177
  );
132
178
  return result;
133
179
  },
134
- ensureIndex: async (collectionId, signature, spec) => {
180
+ ensureIndex: async (target, signature, spec, ctx) => {
181
+ const access = resolvePersistedStorageTarget(
182
+ target,
183
+ ctx?.cacheGenerationClaimId
184
+ );
135
185
  await executeRequest(
136
186
  `ensureIndex`,
137
- collectionId,
187
+ target,
138
188
  {
139
189
  signature,
140
- spec
190
+ spec,
191
+ ctx: { ...ctx, cacheGenerationClaimId: access.claimId }
141
192
  },
142
193
  resolution
143
194
  );
144
195
  },
145
- markIndexRemoved: async (collectionId, signature) => {
196
+ markIndexRemoved: async (target, signature, ctx) => {
197
+ const access = resolvePersistedStorageTarget(
198
+ target,
199
+ ctx?.cacheGenerationClaimId
200
+ );
146
201
  await executeRequest(
147
202
  `markIndexRemoved`,
148
- collectionId,
203
+ target,
149
204
  {
150
- signature
205
+ signature,
206
+ ctx: { ...ctx, cacheGenerationClaimId: access.claimId }
151
207
  },
152
208
  resolution
153
209
  );
154
210
  },
155
- pullSince: async (collectionId, fromRowVersion) => {
211
+ pullSince: async (target, fromRowVersion, ctx) => {
212
+ const access = resolvePersistedStorageTarget(
213
+ target,
214
+ ctx?.cacheGenerationClaimId
215
+ );
156
216
  const result = await executeRequest(
157
217
  `pullSince`,
158
- collectionId,
218
+ target,
159
219
  {
160
- fromRowVersion
220
+ fromRowVersion,
221
+ ctx: { ...ctx, cacheGenerationClaimId: access.claimId }
161
222
  },
162
223
  resolution
163
224
  );
164
225
  return result;
165
226
  },
166
- getStreamPosition: async (collectionId) => {
167
- return executeRequest(`getStreamPosition`, collectionId, {}, resolution);
227
+ getStreamPosition: async (target, ctx) => {
228
+ const access = resolvePersistedStorageTarget(
229
+ target,
230
+ ctx?.cacheGenerationClaimId
231
+ );
232
+ return executeRequest(
233
+ `getStreamPosition`,
234
+ target,
235
+ { ctx: { ...ctx, cacheGenerationClaimId: access.claimId } },
236
+ resolution
237
+ );
238
+ },
239
+ claimCacheGeneration: async (collectionId) => {
240
+ const claim = await executeRequest(
241
+ `claimCacheGeneration`,
242
+ collectionId,
243
+ {},
244
+ resolution
245
+ );
246
+ claimCollections.set(claim.claimId, collectionId);
247
+ return claim;
248
+ },
249
+ rotateCacheGeneration: async (collectionId, claimId, resetMetadata, expectedStorageCollectionId) => {
250
+ const claim = await executeRequest(
251
+ `rotateCacheGeneration`,
252
+ collectionId,
253
+ { claimId, resetMetadata, expectedStorageCollectionId },
254
+ resolution
255
+ );
256
+ claimCollections.delete(claimId);
257
+ claimCollections.set(claim.claimId, collectionId);
258
+ return claim;
259
+ },
260
+ renewCacheGenerationClaim: (storageCollectionId, claimId) => {
261
+ const collectionId = claimCollections.get(claimId);
262
+ if (!collectionId) {
263
+ throw new InvalidPersistedCollectionConfigError(
264
+ `Unknown electron persisted cache claim "${claimId}"`
265
+ );
266
+ }
267
+ return executeRequest(
268
+ `renewCacheGenerationClaim`,
269
+ collectionId,
270
+ { storageCollectionId, claimId },
271
+ resolution
272
+ );
273
+ },
274
+ releaseCacheGenerationClaim: async (claimId) => {
275
+ const collectionId = claimCollections.get(claimId);
276
+ if (!collectionId) {
277
+ throw new InvalidPersistedCollectionConfigError(
278
+ `Unknown electron persisted cache claim "${claimId}"`
279
+ );
280
+ }
281
+ await executeRequest(
282
+ `releaseCacheGenerationClaim`,
283
+ collectionId,
284
+ { claimId },
285
+ resolution
286
+ );
287
+ claimCollections.delete(claimId);
288
+ },
289
+ reserveLeadershipTerm: async (target, observedTerm, ctx) => {
290
+ const access = resolvePersistedStorageTarget(
291
+ target,
292
+ ctx?.cacheGenerationClaimId
293
+ );
294
+ return executeRequest(
295
+ `reserveLeadershipTerm`,
296
+ target,
297
+ {
298
+ observedTerm,
299
+ ctx: { ...ctx, cacheGenerationClaimId: access.claimId }
300
+ },
301
+ resolution
302
+ );
168
303
  }
169
304
  };
305
+ if (!managedCacheGenerations) {
306
+ adapter.claimCacheGeneration = void 0;
307
+ adapter.rotateCacheGeneration = void 0;
308
+ adapter.renewCacheGenerationClaim = void 0;
309
+ adapter.releaseCacheGenerationClaim = void 0;
310
+ }
311
+ return adapter;
170
312
  }
171
313
  function resolveInvoke(options) {
172
314
  if (options.invoke) {
@@ -182,28 +324,31 @@ function resolveInvoke(options) {
182
324
  function createElectronSQLitePersistence(options) {
183
325
  const invoke = resolveInvoke(options);
184
326
  const coordinator = options.coordinator ?? new SingleProcessCoordinator();
327
+ const claimCollections = /* @__PURE__ */ new Map();
185
328
  const executeRequest = createRendererRequestExecutor({
186
329
  invoke,
187
330
  channel: options.channel,
188
- timeoutMs: options.timeoutMs
331
+ timeoutMs: options.timeoutMs,
332
+ claimCollections
189
333
  });
190
334
  const adapterCache = /* @__PURE__ */ new Map();
191
- const getAdapterForCollection = (mode, schemaVersion) => {
192
- const schemaVersionKey = schemaVersion === void 0 ? `schema:default` : `schema:${schemaVersion}`;
193
- const cacheKey = `mode:${mode}|${schemaVersionKey}`;
335
+ const getAdapterForCollection = (collectionId, mode, schemaVersion) => {
336
+ const cacheKey = JSON.stringify([collectionId, mode, schemaVersion]);
194
337
  const cachedAdapter = adapterCache.get(cacheKey);
195
338
  if (cachedAdapter) {
196
339
  return cachedAdapter;
197
340
  }
198
- const adapter = createResolvedRendererAdapter(executeRequest, {
199
- mode,
200
- schemaVersion
201
- });
341
+ const adapter = createResolvedRendererAdapter(
342
+ executeRequest,
343
+ claimCollections,
344
+ options.managedCacheGenerations ?? true,
345
+ { mode, schemaVersion, logicalCollectionId: collectionId }
346
+ );
202
347
  adapterCache.set(cacheKey, adapter);
203
348
  return adapter;
204
349
  };
205
350
  const createCollectionPersistence = (collectionId, mode, schemaVersion) => {
206
- const adapter = getAdapterForCollection(mode, schemaVersion);
351
+ const adapter = getAdapterForCollection(collectionId, mode, schemaVersion);
207
352
  if (coordinator instanceof ElectronCollectionCoordinator) {
208
353
  if (collectionId === void 0) {
209
354
  coordinator.setAdapter(adapter);
@@ -1 +1 @@
1
- {"version":3,"file":"renderer.js","sources":["../../src/renderer.ts"],"sourcesContent":["import {\n InvalidPersistedCollectionConfigError,\n SingleProcessCoordinator,\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 PersistedCollectionCoordinator,\n PersistedCollectionMode,\n PersistedCollectionPersistence,\n PersistedIndexSpec,\n PersistedTx,\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 collectionId: string,\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}): 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 collectionId: string,\n payload: ElectronPersistencePayloadMap[TMethod],\n resolution?: ElectronPersistenceResolution,\n ) => {\n const request = {\n v: ELECTRON_PERSISTENCE_PROTOCOL_VERSION,\n requestId: createRequestId(),\n collectionId,\n method,\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 (typeof response.error.code === `string`) {\n ;(remoteError as Error & { code?: string }).code = response.error.code\n }\n throw remoteError\n }\n\n return response.result as ElectronPersistenceResultMap[TMethod]\n }\n}\n\ntype ElectronRendererResolvedAdapter =\n PersistedCollectionPersistence[`adapter`] & {\n loadCollectionMetadata: (\n collectionId: string,\n ) => Promise<Array<{ key: string; value: unknown }>>\n scanRows: (\n collectionId: string,\n options?: { metadataOnly?: boolean },\n ) => Promise<\n Array<{\n key: string | number\n value: Record<string, unknown>\n metadata?: unknown\n }>\n >\n pullSince: (\n collectionId: string,\n fromRowVersion: number,\n ) => Promise<SQLitePullSinceResult<string | number>>\n getStreamPosition: (collectionId: string) => Promise<{\n latestTerm: number\n latestSeq: number\n latestRowVersion: number\n }>\n }\n\nfunction createResolvedRendererAdapter(\n executeRequest: RendererRequestExecutor,\n resolution?: ElectronPersistenceResolution,\n): ElectronRendererResolvedAdapter {\n return {\n loadSubset: async (\n collectionId: string,\n subsetOptions: LoadSubsetOptions,\n ctx?: { requiredIndexSignatures?: ReadonlyArray<string> },\n ) => {\n const result = await executeRequest(\n `loadSubset`,\n collectionId,\n {\n options: createSerializableLoadSubsetOptions(subsetOptions),\n ctx,\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 collectionId: string,\n ctx?: {\n requiredIndexSignatures?: ReadonlyArray<string>\n includeRows?: boolean\n },\n ) => {\n return executeRequest(\n `loadResumeSnapshot`,\n collectionId,\n { ctx },\n resolution,\n )\n },\n applyCommittedTx: async (\n collectionId: string,\n tx: PersistedTx<Record<string, unknown>, string | number>,\n ): Promise<void> => {\n await executeRequest(\n `applyCommittedTx`,\n collectionId,\n {\n tx: tx as PersistedTx<ElectronPersistedRow, ElectronPersistedKey>,\n },\n resolution,\n )\n },\n loadCollectionMetadata: async (\n collectionId: string,\n ): Promise<Array<{ key: string; value: unknown }>> => {\n return executeRequest(\n `loadCollectionMetadata`,\n collectionId,\n {},\n resolution,\n )\n },\n scanRows: async (\n collectionId: string,\n options?: { metadataOnly?: boolean },\n ): Promise<\n Array<{\n key: string | number\n value: Record<string, unknown>\n metadata?: unknown\n }>\n > => {\n const result = await executeRequest(\n `scanRows`,\n collectionId,\n { options },\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 collectionId: string,\n signature: string,\n spec: PersistedIndexSpec,\n ): Promise<void> => {\n await executeRequest(\n `ensureIndex`,\n collectionId,\n {\n signature,\n spec,\n },\n resolution,\n )\n },\n markIndexRemoved: async (\n collectionId: string,\n signature: string,\n ): Promise<void> => {\n await executeRequest(\n `markIndexRemoved`,\n collectionId,\n {\n signature,\n },\n resolution,\n )\n },\n pullSince: async (\n collectionId: string,\n fromRowVersion: number,\n ): Promise<SQLitePullSinceResult<string | number>> => {\n const result = await executeRequest(\n `pullSince`,\n collectionId,\n {\n fromRowVersion,\n },\n resolution,\n )\n return result as SQLitePullSinceResult<string | number>\n },\n getStreamPosition: async (\n collectionId: string,\n ): Promise<{\n latestTerm: number\n latestSeq: number\n latestRowVersion: number\n }> => {\n return executeRequest(`getStreamPosition`, collectionId, {}, resolution)\n },\n }\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}\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 executeRequest = createRendererRequestExecutor({\n invoke,\n channel: options.channel,\n timeoutMs: options.timeoutMs,\n })\n const adapterCache = new Map<string, ElectronRendererResolvedAdapter>()\n\n const getAdapterForCollection = (\n mode: PersistedCollectionMode,\n schemaVersion: number | undefined,\n ) => {\n const schemaVersionKey =\n schemaVersion === undefined ? `schema:default` : `schema:${schemaVersion}`\n const cacheKey = `mode:${mode}|${schemaVersionKey}`\n const cachedAdapter = adapterCache.get(cacheKey)\n if (cachedAdapter) {\n return cachedAdapter\n }\n\n const adapter = createResolvedRendererAdapter(executeRequest, {\n mode,\n schemaVersion,\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(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 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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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/electron-db-sqlite-persistence",
3
- "version": "0.2.8",
3
+ "version": "0.2.10",
4
4
  "description": "Electron SQLite persisted collection bridge for TanStack DB",
5
5
  "author": "TanStack Team",
6
6
  "license": "MIT",
@@ -60,7 +60,7 @@
60
60
  "src"
61
61
  ],
62
62
  "dependencies": {
63
- "@tanstack/db-sqlite-persistence-core": "0.4.7"
63
+ "@tanstack/db-sqlite-persistence-core": "0.4.9"
64
64
  },
65
65
  "peerDependencies": {
66
66
  "typescript": ">=4.7"