@tanstack/browser-db-sqlite-persistence 0.2.23 → 0.2.26

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.
Files changed (40) hide show
  1. package/README.md +75 -1
  2. package/dist/assets/{opfs-worker-uyjx5Rus.js → opfs-worker-accoEoax.js} +17 -6
  3. package/dist/assets/{opfs-worker-uyjx5Rus.js.map → opfs-worker-accoEoax.js.map} +1 -1
  4. package/dist/cjs/browser-coordinator.cjs +5 -534
  5. package/dist/cjs/browser-coordinator.cjs.map +1 -1
  6. package/dist/cjs/browser-coordinator.d.cts +3 -65
  7. package/dist/cjs/browser-persistence.cjs +19 -8
  8. package/dist/cjs/browser-persistence.cjs.map +1 -1
  9. package/dist/cjs/index.cjs +16 -0
  10. package/dist/cjs/index.cjs.map +1 -1
  11. package/dist/cjs/index.d.cts +2 -2
  12. package/dist/cjs/opfs-database.cjs +58 -1
  13. package/dist/cjs/opfs-database.cjs.map +1 -1
  14. package/dist/cjs/opfs-database.d.cts +4 -0
  15. package/dist/cjs/opfs-worker.cjs +1 -1
  16. package/dist/cjs/wa-sqlite-driver.cjs +38 -14
  17. package/dist/cjs/wa-sqlite-driver.cjs.map +1 -1
  18. package/dist/cjs/wa-sqlite-driver.d.cts +3 -3
  19. package/dist/esm/browser-coordinator.d.ts +3 -65
  20. package/dist/esm/browser-coordinator.js +5 -534
  21. package/dist/esm/browser-coordinator.js.map +1 -1
  22. package/dist/esm/browser-persistence.js +19 -8
  23. package/dist/esm/browser-persistence.js.map +1 -1
  24. package/dist/esm/index.d.ts +2 -2
  25. package/dist/esm/index.js +5 -1
  26. package/dist/esm/opfs-database.d.ts +4 -0
  27. package/dist/esm/opfs-database.js +58 -1
  28. package/dist/esm/opfs-database.js.map +1 -1
  29. package/dist/esm/opfs-worker.js +1 -1
  30. package/dist/esm/wa-sqlite-driver.d.ts +3 -3
  31. package/dist/esm/wa-sqlite-driver.js +39 -15
  32. package/dist/esm/wa-sqlite-driver.js.map +1 -1
  33. package/package.json +9 -3
  34. package/src/browser-coordinator.ts +10 -834
  35. package/src/browser-persistence.ts +22 -14
  36. package/src/index.ts +9 -0
  37. package/src/opfs-database.ts +76 -1
  38. package/src/opfs-worker.ts +16 -5
  39. package/src/wa-sqlite-driver.ts +57 -15
  40. package/src/wa-sqlite-examples.d.ts +1 -0
@@ -1,67 +1,5 @@
1
- import { ApplyLocalMutationsResponse, PersistedCollectionCoordinator, PersistedIndexSpec, PersistedMutationEnvelope, PersistenceAdapter, ProtocolEnvelope, PullSinceResponse } from '@tanstack/db-sqlite-persistence-core';
2
- import { LoadSubsetOptions } from '@tanstack/db';
3
- type AdapterWithPullSince = PersistenceAdapter & {
4
- pullSince?: (collectionId: string, fromRowVersion: number) => Promise<{
5
- latestRowVersion: number;
6
- requiresFullReload: true;
7
- } | {
8
- latestRowVersion: number;
9
- requiresFullReload: false;
10
- changedKeys: Array<string | number>;
11
- deletedKeys: Array<string | number>;
12
- }>;
13
- getStreamPosition?: (collectionId: string) => Promise<{
14
- latestTerm: number;
15
- latestSeq: number;
16
- latestRowVersion: number;
17
- }>;
18
- };
19
- export type BrowserCollectionCoordinatorOptions = {
20
- dbName: string;
21
- adapter?: AdapterWithPullSince;
22
- };
23
- export declare class BrowserCollectionCoordinator implements PersistedCollectionCoordinator {
24
- private readonly nodeId;
25
- private readonly dbName;
26
- private adapter;
27
- private readonly channel;
28
- private readonly collections;
29
- private readonly pendingRPCs;
30
- private readonly appliedEnvelopeIds;
31
- private disposed;
32
- /** Method indirection to prevent TypeScript from narrowing `disposed` across awaits */
33
- private isDisposed;
34
- private requireAdapter;
1
+ import { BroadcastCollectionCoordinator, BroadcastCollectionCoordinatorOptions } from '@tanstack/db-sqlite-persistence-core/broadcast-coordinator';
2
+ export type BrowserCollectionCoordinatorOptions = Omit<BroadcastCollectionCoordinatorOptions, `coordinatorName`>;
3
+ export declare class BrowserCollectionCoordinator extends BroadcastCollectionCoordinator {
35
4
  constructor(options: BrowserCollectionCoordinatorOptions);
36
- /**
37
- * Set or replace the persistence adapter used for leader-side RPC handling.
38
- * Called by `createBrowserWASQLitePersistence` to wire the internally-created
39
- * adapter into the coordinator.
40
- */
41
- setAdapter(adapter: AdapterWithPullSince): void;
42
- getNodeId(): string;
43
- subscribe(collectionId: string, onMessage: (message: ProtocolEnvelope<unknown>) => void): () => void;
44
- publish(_collectionId: string, message: ProtocolEnvelope<unknown>): void;
45
- isLeader(collectionId: string): boolean;
46
- ensureLeadership(collectionId: string): Promise<void>;
47
- requestEnsureRemoteSubset(collectionId: string, options: LoadSubsetOptions): Promise<void>;
48
- requestEnsurePersistedIndex(collectionId: string, signature: string, spec: PersistedIndexSpec): Promise<void>;
49
- requestApplyLocalMutations(collectionId: string, mutations: Array<PersistedMutationEnvelope>): Promise<ApplyLocalMutationsResponse>;
50
- pullSince(collectionId: string, fromRowVersion: number): Promise<PullSinceResponse>;
51
- dispose(): void;
52
- private ensureCollectionState;
53
- private acquireLeadership;
54
- private releaseLeadership;
55
- private emitHeartbeat;
56
- private onChannelMessage;
57
- private sendRPC;
58
- private sendRPCOnce;
59
- private handleRPCRequest;
60
- private handleEnsureRemoteSubset;
61
- private handleEnsurePersistedIndex;
62
- private handleApplyLocalMutations;
63
- private handlePullSince;
64
- private withWriterLock;
65
- private pruneAppliedEnvelopeIds;
66
5
  }
67
- export {};
@@ -57,23 +57,34 @@ function createBrowserWASQLitePersistence(options) {
57
57
  ...schemaVersion === void 0 ? {} : { schemaVersion }
58
58
  });
59
59
  adapterCache.set(cacheKey, adapter);
60
+ return adapter;
61
+ };
62
+ const createCollectionPersistence = (collectionId, mode, schemaVersion) => {
63
+ const adapter = getAdapterForCollection(mode, schemaVersion);
60
64
  if (resolvedCoordinator instanceof browserCoordinator.BrowserCollectionCoordinator) {
61
- resolvedCoordinator.setAdapter(adapter);
65
+ if (collectionId === void 0) {
66
+ resolvedCoordinator.setAdapter(adapter);
67
+ } else {
68
+ resolvedCoordinator.setAdapterForCollection(collectionId, adapter);
69
+ }
62
70
  }
63
- return adapter;
71
+ return {
72
+ adapter,
73
+ coordinator: resolvedCoordinator
74
+ };
64
75
  };
65
- const createCollectionPersistence = (mode, schemaVersion) => ({
66
- adapter: getAdapterForCollection(mode, schemaVersion),
67
- coordinator: resolvedCoordinator
68
- });
69
76
  const defaultPersistence = createCollectionPersistence(
77
+ void 0,
70
78
  `sync-absent`,
71
79
  void 0
72
80
  );
81
+ if (resolvedCoordinator instanceof browserCoordinator.BrowserCollectionCoordinator) {
82
+ resolvedCoordinator.setAdapter(defaultPersistence.adapter);
83
+ }
73
84
  return {
74
85
  ...defaultPersistence,
75
- resolvePersistenceForCollection: ({ mode, schemaVersion }) => createCollectionPersistence(mode, schemaVersion),
76
- resolvePersistenceForMode: (mode) => createCollectionPersistence(mode, void 0)
86
+ resolvePersistenceForCollection: ({ collectionId, mode, schemaVersion }) => createCollectionPersistence(collectionId, mode, schemaVersion),
87
+ resolvePersistenceForMode: (mode) => createCollectionPersistence(void 0, mode, void 0)
77
88
  };
78
89
  }
79
90
  exports.createBrowserWASQLitePersistence = createBrowserWASQLitePersistence;
@@ -1 +1 @@
1
- {"version":3,"file":"browser-persistence.cjs","sources":["../../src/browser-persistence.ts"],"sourcesContent":["import {\n DEFAULT_APPLIED_TX_PRUNE_MAX_AGE_SECONDS,\n DEFAULT_APPLIED_TX_PRUNE_MAX_ROWS,\n SingleProcessCoordinator,\n createSQLiteCorePersistenceAdapter,\n} from '@tanstack/db-sqlite-persistence-core'\nimport { BrowserCollectionCoordinator } from './browser-coordinator'\nimport { BrowserWASQLiteDriver } from './wa-sqlite-driver'\nimport type {\n PersistedCollectionCoordinator,\n PersistedCollectionMode,\n PersistedCollectionPersistence,\n SQLiteCoreAdapterOptions,\n SQLiteDriver,\n} from '@tanstack/db-sqlite-persistence-core'\nimport type { BrowserWASQLiteDatabase } from './wa-sqlite-driver'\n\nexport type { BrowserWASQLiteDatabase } from './wa-sqlite-driver'\n\ntype BrowserSQLiteCoreSchemaMismatchPolicy =\n | `sync-present-reset`\n | `sync-absent-error`\n | `reset`\n\nexport type BrowserWASQLiteSchemaMismatchPolicy =\n | BrowserSQLiteCoreSchemaMismatchPolicy\n | `throw`\n\nexport type BrowserWASQLitePersistenceOptions = Omit<\n SQLiteCoreAdapterOptions,\n `driver` | `schemaVersion` | `schemaMismatchPolicy`\n> & {\n database: BrowserWASQLiteDatabase\n coordinator?: PersistedCollectionCoordinator\n schemaMismatchPolicy?: BrowserWASQLiteSchemaMismatchPolicy\n}\n\nfunction normalizeSchemaMismatchPolicy(\n policy: BrowserWASQLiteSchemaMismatchPolicy,\n): BrowserSQLiteCoreSchemaMismatchPolicy {\n if (policy === `throw`) {\n return `sync-absent-error`\n }\n\n return policy\n}\n\nfunction resolveSchemaMismatchPolicy(\n explicitPolicy: BrowserWASQLiteSchemaMismatchPolicy | undefined,\n mode: PersistedCollectionMode,\n): BrowserSQLiteCoreSchemaMismatchPolicy {\n if (explicitPolicy) {\n return normalizeSchemaMismatchPolicy(explicitPolicy)\n }\n\n return mode === `sync-present` ? `sync-present-reset` : `sync-absent-error`\n}\n\nfunction createAdapterCacheKey(\n schemaMismatchPolicy: BrowserSQLiteCoreSchemaMismatchPolicy,\n schemaVersion: number | undefined,\n): string {\n const schemaVersionKey =\n schemaVersion === undefined ? `schema:default` : `schema:${schemaVersion}`\n return `${schemaMismatchPolicy}|${schemaVersionKey}`\n}\n\nfunction createInternalSQLiteDriver(\n options: BrowserWASQLitePersistenceOptions,\n): SQLiteDriver {\n return new BrowserWASQLiteDriver({\n database: options.database,\n })\n}\n\nfunction resolveAdapterBaseOptions(\n options: BrowserWASQLitePersistenceOptions,\n): Omit<\n SQLiteCoreAdapterOptions,\n `driver` | `schemaVersion` | `schemaMismatchPolicy`\n> {\n return {\n appliedTxPruneMaxRows:\n options.appliedTxPruneMaxRows ?? DEFAULT_APPLIED_TX_PRUNE_MAX_ROWS,\n appliedTxPruneMaxAgeSeconds:\n options.appliedTxPruneMaxAgeSeconds ??\n DEFAULT_APPLIED_TX_PRUNE_MAX_AGE_SECONDS,\n pullSinceReloadThreshold: options.pullSinceReloadThreshold,\n }\n}\n\n/**\n * Creates a shared browser wa-sqlite persistence instance that can be reused by\n * many collections on the same database. This is single-tab wiring using\n * SingleProcessCoordinator semantics (no election required).\n */\nexport function createBrowserWASQLitePersistence(\n options: BrowserWASQLitePersistenceOptions,\n): PersistedCollectionPersistence {\n const { coordinator, schemaMismatchPolicy } = options\n const driver = createInternalSQLiteDriver(options)\n const adapterBaseOptions = resolveAdapterBaseOptions(options)\n const resolvedCoordinator = coordinator ?? new SingleProcessCoordinator()\n const adapterCache = new Map<\n string,\n ReturnType<typeof createSQLiteCorePersistenceAdapter>\n >()\n\n const getAdapterForCollection = (\n mode: PersistedCollectionMode,\n schemaVersion: number | undefined,\n ) => {\n const resolvedSchemaMismatchPolicy = resolveSchemaMismatchPolicy(\n schemaMismatchPolicy,\n mode,\n )\n const cacheKey = createAdapterCacheKey(\n resolvedSchemaMismatchPolicy,\n schemaVersion,\n )\n const cachedAdapter = adapterCache.get(cacheKey)\n if (cachedAdapter) {\n return cachedAdapter\n }\n\n const adapter = createSQLiteCorePersistenceAdapter({\n ...adapterBaseOptions,\n driver,\n schemaMismatchPolicy: resolvedSchemaMismatchPolicy,\n ...(schemaVersion === undefined ? {} : { schemaVersion }),\n })\n adapterCache.set(cacheKey, adapter)\n\n // Wire the adapter into the multi-tab coordinator so it can handle\n // leader-side RPCs (applyCommittedTx, pullSince, ensureIndex, etc.)\n if (resolvedCoordinator instanceof BrowserCollectionCoordinator) {\n resolvedCoordinator.setAdapter(adapter)\n }\n\n return adapter\n }\n\n const createCollectionPersistence = (\n mode: PersistedCollectionMode,\n schemaVersion: number | undefined,\n ): PersistedCollectionPersistence => ({\n adapter: getAdapterForCollection(mode, schemaVersion),\n coordinator: resolvedCoordinator,\n })\n\n const defaultPersistence = createCollectionPersistence(\n `sync-absent`,\n undefined,\n )\n\n return {\n ...defaultPersistence,\n resolvePersistenceForCollection: ({ mode, schemaVersion }) =>\n createCollectionPersistence(mode, schemaVersion),\n resolvePersistenceForMode: (mode) =>\n createCollectionPersistence(mode, undefined),\n }\n}\n"],"names":["BrowserWASQLiteDriver","DEFAULT_APPLIED_TX_PRUNE_MAX_ROWS","DEFAULT_APPLIED_TX_PRUNE_MAX_AGE_SECONDS","SingleProcessCoordinator","createSQLiteCorePersistenceAdapter","BrowserCollectionCoordinator"],"mappings":";;;;;AAqCA,SAAS,8BACP,QACuC;AACvC,MAAI,WAAW,SAAS;AACtB,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEA,SAAS,4BACP,gBACA,MACuC;AACvC,MAAI,gBAAgB;AAClB,WAAO,8BAA8B,cAAc;AAAA,EACrD;AAEA,SAAO,SAAS,iBAAiB,uBAAuB;AAC1D;AAEA,SAAS,sBACP,sBACA,eACQ;AACR,QAAM,mBACJ,kBAAkB,SAAY,mBAAmB,UAAU,aAAa;AAC1E,SAAO,GAAG,oBAAoB,IAAI,gBAAgB;AACpD;AAEA,SAAS,2BACP,SACc;AACd,SAAO,IAAIA,eAAAA,sBAAsB;AAAA,IAC/B,UAAU,QAAQ;AAAA,EAAA,CACnB;AACH;AAEA,SAAS,0BACP,SAIA;AACA,SAAO;AAAA,IACL,uBACE,QAAQ,yBAAyBC,wBAAAA;AAAAA,IACnC,6BACE,QAAQ,+BACRC,wBAAAA;AAAAA,IACF,0BAA0B,QAAQ;AAAA,EAAA;AAEtC;AAOO,SAAS,iCACd,SACgC;AAChC,QAAM,EAAE,aAAa,qBAAA,IAAyB;AAC9C,QAAM,SAAS,2BAA2B,OAAO;AACjD,QAAM,qBAAqB,0BAA0B,OAAO;AAC5D,QAAM,sBAAsB,eAAe,IAAIC,iDAAA;AAC/C,QAAM,mCAAmB,IAAA;AAKzB,QAAM,0BAA0B,CAC9B,MACA,kBACG;AACH,UAAM,+BAA+B;AAAA,MACnC;AAAA,MACA;AAAA,IAAA;AAEF,UAAM,WAAW;AAAA,MACf;AAAA,MACA;AAAA,IAAA;AAEF,UAAM,gBAAgB,aAAa,IAAI,QAAQ;AAC/C,QAAI,eAAe;AACjB,aAAO;AAAA,IACT;AAEA,UAAM,UAAUC,wBAAAA,mCAAmC;AAAA,MACjD,GAAG;AAAA,MACH;AAAA,MACA,sBAAsB;AAAA,MACtB,GAAI,kBAAkB,SAAY,CAAA,IAAK,EAAE,cAAA;AAAA,IAAc,CACxD;AACD,iBAAa,IAAI,UAAU,OAAO;AAIlC,QAAI,+BAA+BC,mBAAAA,8BAA8B;AAC/D,0BAAoB,WAAW,OAAO;AAAA,IACxC;AAEA,WAAO;AAAA,EACT;AAEA,QAAM,8BAA8B,CAClC,MACA,mBACoC;AAAA,IACpC,SAAS,wBAAwB,MAAM,aAAa;AAAA,IACpD,aAAa;AAAA,EAAA;AAGf,QAAM,qBAAqB;AAAA,IACzB;AAAA,IACA;AAAA,EAAA;AAGF,SAAO;AAAA,IACL,GAAG;AAAA,IACH,iCAAiC,CAAC,EAAE,MAAM,oBACxC,4BAA4B,MAAM,aAAa;AAAA,IACjD,2BAA2B,CAAC,SAC1B,4BAA4B,MAAM,MAAS;AAAA,EAAA;AAEjD;;"}
1
+ {"version":3,"file":"browser-persistence.cjs","sources":["../../src/browser-persistence.ts"],"sourcesContent":["import {\n DEFAULT_APPLIED_TX_PRUNE_MAX_AGE_SECONDS,\n DEFAULT_APPLIED_TX_PRUNE_MAX_ROWS,\n SingleProcessCoordinator,\n createSQLiteCorePersistenceAdapter,\n} from '@tanstack/db-sqlite-persistence-core'\nimport { BrowserCollectionCoordinator } from './browser-coordinator'\nimport { BrowserWASQLiteDriver } from './wa-sqlite-driver'\nimport type {\n PersistedCollectionCoordinator,\n PersistedCollectionMode,\n PersistedCollectionPersistence,\n SQLiteCoreAdapterOptions,\n SQLiteDriver,\n} from '@tanstack/db-sqlite-persistence-core'\nimport type { BrowserWASQLiteDatabase } from './wa-sqlite-driver'\n\nexport type { BrowserWASQLiteDatabase } from './wa-sqlite-driver'\n\ntype BrowserSQLiteCoreSchemaMismatchPolicy =\n | `sync-present-reset`\n | `sync-absent-error`\n | `reset`\n\nexport type BrowserWASQLiteSchemaMismatchPolicy =\n | BrowserSQLiteCoreSchemaMismatchPolicy\n | `throw`\n\nexport type BrowserWASQLitePersistenceOptions = Omit<\n SQLiteCoreAdapterOptions,\n `driver` | `schemaVersion` | `schemaMismatchPolicy`\n> & {\n database: BrowserWASQLiteDatabase\n coordinator?: PersistedCollectionCoordinator\n schemaMismatchPolicy?: BrowserWASQLiteSchemaMismatchPolicy\n}\n\nfunction normalizeSchemaMismatchPolicy(\n policy: BrowserWASQLiteSchemaMismatchPolicy,\n): BrowserSQLiteCoreSchemaMismatchPolicy {\n if (policy === `throw`) {\n return `sync-absent-error`\n }\n\n return policy\n}\n\nfunction resolveSchemaMismatchPolicy(\n explicitPolicy: BrowserWASQLiteSchemaMismatchPolicy | undefined,\n mode: PersistedCollectionMode,\n): BrowserSQLiteCoreSchemaMismatchPolicy {\n if (explicitPolicy) {\n return normalizeSchemaMismatchPolicy(explicitPolicy)\n }\n\n return mode === `sync-present` ? `sync-present-reset` : `sync-absent-error`\n}\n\nfunction createAdapterCacheKey(\n schemaMismatchPolicy: BrowserSQLiteCoreSchemaMismatchPolicy,\n schemaVersion: number | undefined,\n): string {\n const schemaVersionKey =\n schemaVersion === undefined ? `schema:default` : `schema:${schemaVersion}`\n return `${schemaMismatchPolicy}|${schemaVersionKey}`\n}\n\nfunction createInternalSQLiteDriver(\n options: BrowserWASQLitePersistenceOptions,\n): SQLiteDriver {\n return new BrowserWASQLiteDriver({\n database: options.database,\n })\n}\n\nfunction resolveAdapterBaseOptions(\n options: BrowserWASQLitePersistenceOptions,\n): Omit<\n SQLiteCoreAdapterOptions,\n `driver` | `schemaVersion` | `schemaMismatchPolicy`\n> {\n return {\n appliedTxPruneMaxRows:\n options.appliedTxPruneMaxRows ?? DEFAULT_APPLIED_TX_PRUNE_MAX_ROWS,\n appliedTxPruneMaxAgeSeconds:\n options.appliedTxPruneMaxAgeSeconds ??\n DEFAULT_APPLIED_TX_PRUNE_MAX_AGE_SECONDS,\n pullSinceReloadThreshold: options.pullSinceReloadThreshold,\n }\n}\n\n/**\n * Creates a shared browser wa-sqlite persistence instance that can be reused by\n * many collections on the same database. This is single-tab wiring using\n * SingleProcessCoordinator semantics (no election required).\n */\nexport function createBrowserWASQLitePersistence(\n options: BrowserWASQLitePersistenceOptions,\n): PersistedCollectionPersistence {\n const { coordinator, schemaMismatchPolicy } = options\n const driver = createInternalSQLiteDriver(options)\n const adapterBaseOptions = resolveAdapterBaseOptions(options)\n const resolvedCoordinator = coordinator ?? new SingleProcessCoordinator()\n const adapterCache = new Map<\n string,\n ReturnType<typeof createSQLiteCorePersistenceAdapter>\n >()\n\n const getAdapterForCollection = (\n mode: PersistedCollectionMode,\n schemaVersion: number | undefined,\n ) => {\n const resolvedSchemaMismatchPolicy = resolveSchemaMismatchPolicy(\n schemaMismatchPolicy,\n mode,\n )\n const cacheKey = createAdapterCacheKey(\n resolvedSchemaMismatchPolicy,\n schemaVersion,\n )\n const cachedAdapter = adapterCache.get(cacheKey)\n if (cachedAdapter) {\n return cachedAdapter\n }\n\n const adapter = createSQLiteCorePersistenceAdapter({\n ...adapterBaseOptions,\n driver,\n schemaMismatchPolicy: resolvedSchemaMismatchPolicy,\n ...(schemaVersion === undefined ? {} : { 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 (resolvedCoordinator instanceof BrowserCollectionCoordinator) {\n if (collectionId === undefined) {\n resolvedCoordinator.setAdapter(adapter)\n } else {\n resolvedCoordinator.setAdapterForCollection(collectionId, adapter)\n }\n }\n return {\n adapter,\n coordinator: resolvedCoordinator,\n }\n }\n\n const defaultPersistence = createCollectionPersistence(\n undefined,\n `sync-absent`,\n undefined,\n )\n if (resolvedCoordinator instanceof BrowserCollectionCoordinator) {\n resolvedCoordinator.setAdapter(defaultPersistence.adapter)\n }\n\n return {\n ...defaultPersistence,\n resolvePersistenceForCollection: ({ collectionId, mode, schemaVersion }) =>\n createCollectionPersistence(collectionId, mode, schemaVersion),\n resolvePersistenceForMode: (mode) =>\n createCollectionPersistence(undefined, mode, undefined),\n }\n}\n"],"names":["BrowserWASQLiteDriver","DEFAULT_APPLIED_TX_PRUNE_MAX_ROWS","DEFAULT_APPLIED_TX_PRUNE_MAX_AGE_SECONDS","SingleProcessCoordinator","createSQLiteCorePersistenceAdapter","BrowserCollectionCoordinator"],"mappings":";;;;;AAqCA,SAAS,8BACP,QACuC;AACvC,MAAI,WAAW,SAAS;AACtB,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEA,SAAS,4BACP,gBACA,MACuC;AACvC,MAAI,gBAAgB;AAClB,WAAO,8BAA8B,cAAc;AAAA,EACrD;AAEA,SAAO,SAAS,iBAAiB,uBAAuB;AAC1D;AAEA,SAAS,sBACP,sBACA,eACQ;AACR,QAAM,mBACJ,kBAAkB,SAAY,mBAAmB,UAAU,aAAa;AAC1E,SAAO,GAAG,oBAAoB,IAAI,gBAAgB;AACpD;AAEA,SAAS,2BACP,SACc;AACd,SAAO,IAAIA,eAAAA,sBAAsB;AAAA,IAC/B,UAAU,QAAQ;AAAA,EAAA,CACnB;AACH;AAEA,SAAS,0BACP,SAIA;AACA,SAAO;AAAA,IACL,uBACE,QAAQ,yBAAyBC,wBAAAA;AAAAA,IACnC,6BACE,QAAQ,+BACRC,wBAAAA;AAAAA,IACF,0BAA0B,QAAQ;AAAA,EAAA;AAEtC;AAOO,SAAS,iCACd,SACgC;AAChC,QAAM,EAAE,aAAa,qBAAA,IAAyB;AAC9C,QAAM,SAAS,2BAA2B,OAAO;AACjD,QAAM,qBAAqB,0BAA0B,OAAO;AAC5D,QAAM,sBAAsB,eAAe,IAAIC,iDAAA;AAC/C,QAAM,mCAAmB,IAAA;AAKzB,QAAM,0BAA0B,CAC9B,MACA,kBACG;AACH,UAAM,+BAA+B;AAAA,MACnC;AAAA,MACA;AAAA,IAAA;AAEF,UAAM,WAAW;AAAA,MACf;AAAA,MACA;AAAA,IAAA;AAEF,UAAM,gBAAgB,aAAa,IAAI,QAAQ;AAC/C,QAAI,eAAe;AACjB,aAAO;AAAA,IACT;AAEA,UAAM,UAAUC,wBAAAA,mCAAmC;AAAA,MACjD,GAAG;AAAA,MACH;AAAA,MACA,sBAAsB;AAAA,MACtB,GAAI,kBAAkB,SAAY,CAAA,IAAK,EAAE,cAAA;AAAA,IAAc,CACxD;AACD,iBAAa,IAAI,UAAU,OAAO;AAClC,WAAO;AAAA,EACT;AAEA,QAAM,8BAA8B,CAClC,cACA,MACA,kBACmC;AACnC,UAAM,UAAU,wBAAwB,MAAM,aAAa;AAC3D,QAAI,+BAA+BC,mBAAAA,8BAA8B;AAC/D,UAAI,iBAAiB,QAAW;AAC9B,4BAAoB,WAAW,OAAO;AAAA,MACxC,OAAO;AACL,4BAAoB,wBAAwB,cAAc,OAAO;AAAA,MACnE;AAAA,IACF;AACA,WAAO;AAAA,MACL;AAAA,MACA,aAAa;AAAA,IAAA;AAAA,EAEjB;AAEA,QAAM,qBAAqB;AAAA,IACzB;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAEF,MAAI,+BAA+BA,mBAAAA,8BAA8B;AAC/D,wBAAoB,WAAW,mBAAmB,OAAO;AAAA,EAC3D;AAEA,SAAO;AAAA,IACL,GAAG;AAAA,IACH,iCAAiC,CAAC,EAAE,cAAc,MAAM,oBACtD,4BAA4B,cAAc,MAAM,aAAa;AAAA,IAC/D,2BAA2B,CAAC,SAC1B,4BAA4B,QAAW,MAAM,MAAS;AAAA,EAAA;AAE5D;;"}
@@ -15,6 +15,22 @@ Object.defineProperty(exports, "DEFAULT_APPLIED_TX_PRUNE_MAX_ROWS", {
15
15
  enumerable: true,
16
16
  get: () => dbSqlitePersistenceCore.DEFAULT_APPLIED_TX_PRUNE_MAX_ROWS
17
17
  });
18
+ Object.defineProperty(exports, "DuplicateRemoteSubsetOwnerError", {
19
+ enumerable: true,
20
+ get: () => dbSqlitePersistenceCore.DuplicateRemoteSubsetOwnerError
21
+ });
22
+ Object.defineProperty(exports, "IndeterminateCommitError", {
23
+ enumerable: true,
24
+ get: () => dbSqlitePersistenceCore.IndeterminateCommitError
25
+ });
26
+ Object.defineProperty(exports, "PersistedCollectionDurabilityError", {
27
+ enumerable: true,
28
+ get: () => dbSqlitePersistenceCore.PersistedCollectionDurabilityError
29
+ });
30
+ Object.defineProperty(exports, "RemoteSubsetWireValueError", {
31
+ enumerable: true,
32
+ get: () => dbSqlitePersistenceCore.RemoteSubsetWireValueError
33
+ });
18
34
  Object.defineProperty(exports, "persistedCollectionOptions", {
19
35
  enumerable: true,
20
36
  get: () => dbSqlitePersistenceCore.persistedCollectionOptions
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -4,5 +4,5 @@ export { BrowserCollectionCoordinator } from './browser-coordinator.cjs';
4
4
  export type { BrowserWASQLiteDatabase, BrowserWASQLitePersistenceOptions, BrowserWASQLiteSchemaMismatchPolicy, } from './browser-persistence.cjs';
5
5
  export type { OpenBrowserWASQLiteOPFSDatabaseOptions } from './opfs-database.cjs';
6
6
  export type { BrowserCollectionCoordinatorOptions } from './browser-coordinator.cjs';
7
- export { DEFAULT_APPLIED_TX_PRUNE_MAX_AGE_SECONDS, DEFAULT_APPLIED_TX_PRUNE_MAX_ROWS, persistedCollectionOptions, } from '@tanstack/db-sqlite-persistence-core';
8
- export type { PersistedCollectionCoordinator, PersistedCollectionPersistence, } from '@tanstack/db-sqlite-persistence-core';
7
+ export { DEFAULT_APPLIED_TX_PRUNE_MAX_AGE_SECONDS, DEFAULT_APPLIED_TX_PRUNE_MAX_ROWS, DuplicateRemoteSubsetOwnerError, IndeterminateCommitError, PersistedCollectionDurabilityError, RemoteSubsetWireValueError, persistedCollectionOptions, } from '@tanstack/db-sqlite-persistence-core';
8
+ export type { PersistedCollectionCoordinator, PersistedCollectionPersistence, IndeterminateCommitRequestType, RemoteSubsetOwner, RemoteSubsetWireExpression, RemoteSubsetWireValue, TransportedLoadSubsetOptions, } from '@tanstack/db-sqlite-persistence-core';
@@ -3,6 +3,8 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const dbSqlitePersistenceCore = require("@tanstack/db-sqlite-persistence-core");
4
4
  const opfsWorker = require("./opfs-worker.cjs");
5
5
  const DEFAULT_VFS_NAME = `opfs`;
6
+ const DEFAULT_OPEN_TIMEOUT_MS = 3e4;
7
+ const MAX_OPEN_TIMEOUT_MS = 2147483647;
6
8
  class OPFSWorkerRequestError extends Error {
7
9
  constructor(code, message) {
8
10
  super(message);
@@ -42,6 +44,13 @@ function createOPFSWorkerInstance() {
42
44
  }
43
45
  return new opfsWorker();
44
46
  }
47
+ function getOpenAbortError(signal) {
48
+ const reason = signal.reason;
49
+ return reason instanceof Error ? reason : new DOMException(
50
+ `Opening browser OPFS database was aborted`,
51
+ `AbortError`
52
+ );
53
+ }
45
54
  async function openBrowserWASQLiteOPFSDatabase(options) {
46
55
  const databaseName = options.databaseName.trim();
47
56
  if (databaseName.length === 0) {
@@ -49,6 +58,16 @@ async function openBrowserWASQLiteOPFSDatabase(options) {
49
58
  `Browser wa-sqlite databaseName cannot be empty`
50
59
  );
51
60
  }
61
+ const timeoutMs = options.timeoutMs ?? DEFAULT_OPEN_TIMEOUT_MS;
62
+ if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 0 || timeoutMs > MAX_OPEN_TIMEOUT_MS) {
63
+ throw new dbSqlitePersistenceCore.InvalidPersistedCollectionConfigError(
64
+ `Browser wa-sqlite timeoutMs must be an integer between 0 and ${MAX_OPEN_TIMEOUT_MS}`
65
+ );
66
+ }
67
+ const signal = options.signal;
68
+ if (signal?.aborted) {
69
+ throw getOpenAbortError(signal);
70
+ }
52
71
  if (!hasOPFSBrowserPrerequisites(globalThis)) {
53
72
  throw new dbSqlitePersistenceCore.PersistenceUnavailableError(
54
73
  `Browser OPFS prerequisites are not available in this runtime`
@@ -64,6 +83,7 @@ async function openBrowserWASQLiteOPFSDatabase(options) {
64
83
  return;
65
84
  }
66
85
  disposed = true;
86
+ globalThis.removeEventListener(`pagehide`, onPageHide);
67
87
  worker.removeEventListener(`message`, onMessage);
68
88
  worker.removeEventListener(`error`, onError);
69
89
  worker.removeEventListener(`messageerror`, onMessageError);
@@ -103,9 +123,19 @@ async function openBrowserWASQLiteOPFSDatabase(options) {
103
123
  );
104
124
  disposeWorker();
105
125
  };
126
+ const onPageHide = () => {
127
+ rejectAllPendingRequests(
128
+ new DOMException(
129
+ `The page is closing its SQLite connection`,
130
+ `AbortError`
131
+ )
132
+ );
133
+ disposeWorker();
134
+ };
106
135
  worker.addEventListener(`message`, onMessage);
107
136
  worker.addEventListener(`error`, onError);
108
137
  worker.addEventListener(`messageerror`, onMessageError);
138
+ globalThis.addEventListener(`pagehide`, onPageHide);
109
139
  const sendWorkerRequest = (request) => {
110
140
  if (disposed) {
111
141
  return Promise.reject(
@@ -138,15 +168,39 @@ async function openBrowserWASQLiteOPFSDatabase(options) {
138
168
  }
139
169
  });
140
170
  };
171
+ let openTimeout;
172
+ const onAbort = () => {
173
+ if (!signal) return;
174
+ rejectAllPendingRequests(getOpenAbortError(signal));
175
+ disposeWorker();
176
+ };
177
+ const onTimeout = () => {
178
+ rejectAllPendingRequests(
179
+ new DOMException(
180
+ `Opening browser OPFS database timed out after ${timeoutMs} ms`,
181
+ `TimeoutError`
182
+ )
183
+ );
184
+ disposeWorker();
185
+ };
141
186
  try {
142
- await sendWorkerRequest({
187
+ const initialization = sendWorkerRequest({
143
188
  type: `init`,
144
189
  databaseName,
145
190
  vfsName
146
191
  });
192
+ signal?.addEventListener(`abort`, onAbort, { once: true });
193
+ if (signal?.aborted) onAbort();
194
+ if (timeoutMs > 0) {
195
+ openTimeout = setTimeout(onTimeout, timeoutMs);
196
+ }
197
+ await initialization;
147
198
  } catch (error) {
148
199
  disposeWorker();
149
200
  throw error;
201
+ } finally {
202
+ if (openTimeout !== void 0) clearTimeout(openTimeout);
203
+ signal?.removeEventListener(`abort`, onAbort);
150
204
  }
151
205
  return {
152
206
  execute: (sql, params = []) => sendWorkerRequest({
@@ -155,6 +209,9 @@ async function openBrowserWASQLiteOPFSDatabase(options) {
155
209
  params
156
210
  }),
157
211
  close: async () => {
212
+ if (disposed) {
213
+ return;
214
+ }
158
215
  let closeError;
159
216
  try {
160
217
  await sendWorkerRequest({
@@ -1 +1 @@
1
- {"version":3,"file":"opfs-database.cjs","sources":["../../src/opfs-database.ts"],"sourcesContent":["import {\n InvalidPersistedCollectionConfigError,\n PersistenceUnavailableError,\n} from '@tanstack/db-sqlite-persistence-core'\nimport OPFSWorkerConstructor from './opfs-worker?worker'\nimport type { BrowserWASQLiteDatabase } from './wa-sqlite-driver'\nimport type {\n BrowserOPFSWorkerErrorCode,\n BrowserOPFSWorkerRequest,\n BrowserOPFSWorkerResponse,\n} from './opfs-worker-protocol'\n\nconst DEFAULT_VFS_NAME = `opfs`\ntype BrowserOPFSFeatureGlobal = {\n navigator?: {\n storage?: {\n getDirectory?: () => Promise<unknown>\n }\n }\n Worker?: typeof Worker\n}\n\nexport type OpenBrowserWASQLiteOPFSDatabaseOptions = {\n databaseName: string\n vfsName?: string\n}\n\ntype BrowserOPFSWorkerLike = Pick<\n Worker,\n `postMessage` | `terminate` | `addEventListener` | `removeEventListener`\n>\n\ntype PendingWorkerRequest = {\n resolve: (value: unknown) => void\n reject: (error: Error) => void\n}\n\ntype BrowserOPFSWorkerRequestWithoutId =\n BrowserOPFSWorkerRequest extends infer TRequest\n ? TRequest extends { requestId: string }\n ? Omit<TRequest, `requestId`>\n : never\n : never\n\nclass OPFSWorkerRequestError extends Error {\n constructor(\n readonly code: BrowserOPFSWorkerErrorCode,\n message: string,\n ) {\n super(message)\n this.name = `OPFSWorkerRequestError`\n }\n}\n\nfunction hasOPFSBrowserPrerequisites(globalObject: unknown): boolean {\n const candidate = globalObject as BrowserOPFSFeatureGlobal\n const getDirectory = candidate.navigator?.storage?.getDirectory\n const WorkerConstructor = candidate.Worker\n\n return (\n typeof getDirectory === `function` &&\n typeof WorkerConstructor === `function`\n )\n}\n\nfunction createWorkerError(\n code: BrowserOPFSWorkerErrorCode,\n message: string,\n): Error {\n if (code === `PERSISTENCE_UNAVAILABLE`) {\n return new PersistenceUnavailableError(message)\n }\n if (code === `INVALID_CONFIG`) {\n return new InvalidPersistedCollectionConfigError(message)\n }\n return new OPFSWorkerRequestError(code, message)\n}\n\nfunction createWorkerRequestIdFactory(): () => string {\n let sequence = 0\n const prefix = `opfs-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`\n\n return () => {\n sequence++\n return `${prefix}-${sequence}`\n }\n}\n\nfunction createOPFSWorkerInstance(): BrowserOPFSWorkerLike {\n const WorkerConstructor = (\n globalThis as typeof globalThis & { Worker?: typeof Worker }\n ).Worker\n if (typeof WorkerConstructor !== `function`) {\n throw new PersistenceUnavailableError(\n `Web Worker support is required for browser OPFS persistence`,\n )\n }\n\n return new (OPFSWorkerConstructor as unknown as new () => BrowserOPFSWorkerLike)()\n}\n\n/**\n * Creates a browser wa-sqlite database handle backed by OPFS and\n * OPFSCoopSyncVFS.\n */\nexport async function openBrowserWASQLiteOPFSDatabase(\n options: OpenBrowserWASQLiteOPFSDatabaseOptions,\n): Promise<BrowserWASQLiteDatabase> {\n const databaseName = options.databaseName.trim()\n if (databaseName.length === 0) {\n throw new InvalidPersistedCollectionConfigError(\n `Browser wa-sqlite databaseName cannot be empty`,\n )\n }\n\n if (!hasOPFSBrowserPrerequisites(globalThis)) {\n throw new PersistenceUnavailableError(\n `Browser OPFS prerequisites are not available in this runtime`,\n )\n }\n\n const vfsName = options.vfsName ?? DEFAULT_VFS_NAME\n const worker = createOPFSWorkerInstance()\n const nextRequestId = createWorkerRequestIdFactory()\n const pendingRequests = new Map<string, PendingWorkerRequest>()\n let disposed = false\n\n const disposeWorker = (): void => {\n if (disposed) {\n return\n }\n disposed = true\n worker.removeEventListener(`message`, onMessage)\n worker.removeEventListener(`error`, onError)\n worker.removeEventListener(`messageerror`, onMessageError)\n worker.terminate()\n }\n\n const rejectAllPendingRequests = (error: Error): void => {\n for (const pendingRequest of pendingRequests.values()) {\n pendingRequest.reject(error)\n }\n pendingRequests.clear()\n }\n\n const onMessage = (event: Event): void => {\n const messageEvent = event as MessageEvent<BrowserOPFSWorkerResponse>\n const response = messageEvent.data\n\n const pendingRequest = pendingRequests.get(response.requestId)\n if (!pendingRequest) {\n return\n }\n pendingRequests.delete(response.requestId)\n\n if (response.ok) {\n pendingRequest.resolve(response.rows ?? [])\n return\n }\n\n pendingRequest.reject(createWorkerError(response.code, response.error))\n }\n\n const onError = (): void => {\n rejectAllPendingRequests(\n new PersistenceUnavailableError(`OPFS worker terminated unexpectedly`),\n )\n disposeWorker()\n }\n\n const onMessageError = (): void => {\n rejectAllPendingRequests(\n new PersistenceUnavailableError(\n `OPFS worker message serialization failed`,\n ),\n )\n disposeWorker()\n }\n\n worker.addEventListener(`message`, onMessage)\n worker.addEventListener(`error`, onError)\n worker.addEventListener(`messageerror`, onMessageError)\n\n const sendWorkerRequest = <T>(\n request: BrowserOPFSWorkerRequestWithoutId,\n ): Promise<T> => {\n if (disposed) {\n return Promise.reject(\n new InvalidPersistedCollectionConfigError(\n `Browser OPFS worker connection is closed`,\n ),\n )\n }\n\n const requestId = nextRequestId()\n return new Promise<T>((resolve, reject) => {\n pendingRequests.set(requestId, {\n resolve: (value) => {\n resolve(value as T)\n },\n reject,\n })\n try {\n const payload = {\n ...request,\n requestId,\n } as BrowserOPFSWorkerRequest\n worker.postMessage(payload)\n } catch (error) {\n pendingRequests.delete(requestId)\n reject(\n new PersistenceUnavailableError(\n `Failed to send message to OPFS worker: ${(error as Error).message}`,\n ),\n )\n }\n })\n }\n\n try {\n await sendWorkerRequest<void>({\n type: `init`,\n databaseName,\n vfsName,\n })\n } catch (error) {\n disposeWorker()\n throw error\n }\n\n return {\n execute: <TRow = unknown>(\n sql: string,\n params: ReadonlyArray<unknown> = [],\n ) =>\n sendWorkerRequest<ReadonlyArray<TRow>>({\n type: `execute`,\n sql,\n params,\n }),\n close: async () => {\n let closeError: unknown\n try {\n await sendWorkerRequest<void>({\n type: `close`,\n })\n } catch (error) {\n closeError = error\n } finally {\n disposeWorker()\n }\n\n if (closeError) {\n throw closeError\n }\n },\n }\n}\n"],"names":["PersistenceUnavailableError","InvalidPersistedCollectionConfigError","OPFSWorkerConstructor"],"mappings":"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"}
1
+ {"version":3,"file":"opfs-database.cjs","sources":["../../src/opfs-database.ts"],"sourcesContent":["import {\n InvalidPersistedCollectionConfigError,\n PersistenceUnavailableError,\n} from '@tanstack/db-sqlite-persistence-core'\nimport OPFSWorkerConstructor from './opfs-worker?worker'\nimport type { BrowserWASQLiteDatabase } from './wa-sqlite-driver'\nimport type {\n BrowserOPFSWorkerErrorCode,\n BrowserOPFSWorkerRequest,\n BrowserOPFSWorkerResponse,\n} from './opfs-worker-protocol'\n\nconst DEFAULT_VFS_NAME = `opfs`\nconst DEFAULT_OPEN_TIMEOUT_MS = 30_000\nconst MAX_OPEN_TIMEOUT_MS = 2_147_483_647\ntype BrowserOPFSFeatureGlobal = {\n navigator?: {\n storage?: {\n getDirectory?: () => Promise<unknown>\n }\n }\n Worker?: typeof Worker\n}\n\nexport type OpenBrowserWASQLiteOPFSDatabaseOptions = {\n databaseName: string\n vfsName?: string\n /** Defaults to 30 seconds. Set to 0 to wait without a deadline. */\n timeoutMs?: number\n /** Cancels only the database open, not an established connection. */\n signal?: AbortSignal\n}\n\ntype BrowserOPFSWorkerLike = Pick<\n Worker,\n `postMessage` | `terminate` | `addEventListener` | `removeEventListener`\n>\n\ntype PendingWorkerRequest = {\n resolve: (value: unknown) => void\n reject: (error: Error) => void\n}\n\ntype BrowserOPFSWorkerRequestWithoutId =\n BrowserOPFSWorkerRequest extends infer TRequest\n ? TRequest extends { requestId: string }\n ? Omit<TRequest, `requestId`>\n : never\n : never\n\nclass OPFSWorkerRequestError extends Error {\n constructor(\n readonly code: BrowserOPFSWorkerErrorCode,\n message: string,\n ) {\n super(message)\n this.name = `OPFSWorkerRequestError`\n }\n}\n\nfunction hasOPFSBrowserPrerequisites(globalObject: unknown): boolean {\n const candidate = globalObject as BrowserOPFSFeatureGlobal\n const getDirectory = candidate.navigator?.storage?.getDirectory\n const WorkerConstructor = candidate.Worker\n\n return (\n typeof getDirectory === `function` &&\n typeof WorkerConstructor === `function`\n )\n}\n\nfunction createWorkerError(\n code: BrowserOPFSWorkerErrorCode,\n message: string,\n): Error {\n if (code === `PERSISTENCE_UNAVAILABLE`) {\n return new PersistenceUnavailableError(message)\n }\n if (code === `INVALID_CONFIG`) {\n return new InvalidPersistedCollectionConfigError(message)\n }\n return new OPFSWorkerRequestError(code, message)\n}\n\nfunction createWorkerRequestIdFactory(): () => string {\n let sequence = 0\n const prefix = `opfs-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`\n\n return () => {\n sequence++\n return `${prefix}-${sequence}`\n }\n}\n\nfunction createOPFSWorkerInstance(): BrowserOPFSWorkerLike {\n const WorkerConstructor = (\n globalThis as typeof globalThis & { Worker?: typeof Worker }\n ).Worker\n if (typeof WorkerConstructor !== `function`) {\n throw new PersistenceUnavailableError(\n `Web Worker support is required for browser OPFS persistence`,\n )\n }\n\n return new (OPFSWorkerConstructor as unknown as new () => BrowserOPFSWorkerLike)()\n}\n\nfunction getOpenAbortError(signal: AbortSignal): Error {\n const reason: unknown = signal.reason\n return reason instanceof Error\n ? reason\n : new DOMException(\n `Opening browser OPFS database was aborted`,\n `AbortError`,\n )\n}\n\n/**\n * Creates a browser wa-sqlite database handle backed by OPFS and\n * OPFSCoopSyncVFS.\n */\nexport async function openBrowserWASQLiteOPFSDatabase(\n options: OpenBrowserWASQLiteOPFSDatabaseOptions,\n): Promise<BrowserWASQLiteDatabase> {\n const databaseName = options.databaseName.trim()\n if (databaseName.length === 0) {\n throw new InvalidPersistedCollectionConfigError(\n `Browser wa-sqlite databaseName cannot be empty`,\n )\n }\n\n const timeoutMs = options.timeoutMs ?? DEFAULT_OPEN_TIMEOUT_MS\n if (\n !Number.isSafeInteger(timeoutMs) ||\n timeoutMs < 0 ||\n timeoutMs > MAX_OPEN_TIMEOUT_MS\n ) {\n throw new InvalidPersistedCollectionConfigError(\n `Browser wa-sqlite timeoutMs must be an integer between 0 and ${MAX_OPEN_TIMEOUT_MS}`,\n )\n }\n\n const signal = options.signal\n if (signal?.aborted) {\n throw getOpenAbortError(signal)\n }\n\n if (!hasOPFSBrowserPrerequisites(globalThis)) {\n throw new PersistenceUnavailableError(\n `Browser OPFS prerequisites are not available in this runtime`,\n )\n }\n\n const vfsName = options.vfsName ?? DEFAULT_VFS_NAME\n const worker = createOPFSWorkerInstance()\n const nextRequestId = createWorkerRequestIdFactory()\n const pendingRequests = new Map<string, PendingWorkerRequest>()\n let disposed = false\n\n const disposeWorker = (): void => {\n if (disposed) {\n return\n }\n disposed = true\n globalThis.removeEventListener(`pagehide`, onPageHide)\n worker.removeEventListener(`message`, onMessage)\n worker.removeEventListener(`error`, onError)\n worker.removeEventListener(`messageerror`, onMessageError)\n worker.terminate()\n }\n\n const rejectAllPendingRequests = (error: Error): void => {\n for (const pendingRequest of pendingRequests.values()) {\n pendingRequest.reject(error)\n }\n pendingRequests.clear()\n }\n\n const onMessage = (event: Event): void => {\n const messageEvent = event as MessageEvent<BrowserOPFSWorkerResponse>\n const response = messageEvent.data\n\n const pendingRequest = pendingRequests.get(response.requestId)\n if (!pendingRequest) {\n return\n }\n pendingRequests.delete(response.requestId)\n\n if (response.ok) {\n pendingRequest.resolve(response.rows ?? [])\n return\n }\n\n pendingRequest.reject(createWorkerError(response.code, response.error))\n }\n\n const onError = (): void => {\n rejectAllPendingRequests(\n new PersistenceUnavailableError(`OPFS worker terminated unexpectedly`),\n )\n disposeWorker()\n }\n\n const onMessageError = (): void => {\n rejectAllPendingRequests(\n new PersistenceUnavailableError(\n `OPFS worker message serialization failed`,\n ),\n )\n disposeWorker()\n }\n\n const onPageHide = (): void => {\n // A document entering the back/forward cache can be frozen before an\n // asynchronous close completes, including while initialization is pending.\n rejectAllPendingRequests(\n new DOMException(\n `The page is closing its SQLite connection`,\n `AbortError`,\n ),\n )\n disposeWorker()\n }\n\n worker.addEventListener(`message`, onMessage)\n worker.addEventListener(`error`, onError)\n worker.addEventListener(`messageerror`, onMessageError)\n globalThis.addEventListener(`pagehide`, onPageHide)\n\n const sendWorkerRequest = <T>(\n request: BrowserOPFSWorkerRequestWithoutId,\n ): Promise<T> => {\n if (disposed) {\n return Promise.reject(\n new InvalidPersistedCollectionConfigError(\n `Browser OPFS worker connection is closed`,\n ),\n )\n }\n\n const requestId = nextRequestId()\n return new Promise<T>((resolve, reject) => {\n pendingRequests.set(requestId, {\n resolve: (value) => {\n resolve(value as T)\n },\n reject,\n })\n try {\n const payload = {\n ...request,\n requestId,\n } as BrowserOPFSWorkerRequest\n worker.postMessage(payload)\n } catch (error) {\n pendingRequests.delete(requestId)\n reject(\n new PersistenceUnavailableError(\n `Failed to send message to OPFS worker: ${(error as Error).message}`,\n ),\n )\n }\n })\n }\n\n let openTimeout: ReturnType<typeof setTimeout> | undefined\n const onAbort = (): void => {\n if (!signal) return\n rejectAllPendingRequests(getOpenAbortError(signal))\n disposeWorker()\n }\n const onTimeout = (): void => {\n rejectAllPendingRequests(\n new DOMException(\n `Opening browser OPFS database timed out after ${timeoutMs} ms`,\n `TimeoutError`,\n ),\n )\n disposeWorker()\n }\n\n try {\n const initialization = sendWorkerRequest<void>({\n type: `init`,\n databaseName,\n vfsName,\n })\n signal?.addEventListener(`abort`, onAbort, { once: true })\n if (signal?.aborted) onAbort()\n if (timeoutMs > 0) {\n openTimeout = setTimeout(onTimeout, timeoutMs)\n }\n await initialization\n } catch (error) {\n disposeWorker()\n throw error\n } finally {\n if (openTimeout !== undefined) clearTimeout(openTimeout)\n signal?.removeEventListener(`abort`, onAbort)\n }\n\n return {\n execute: <TRow = unknown>(\n sql: string,\n params: ReadonlyArray<unknown> = [],\n ) =>\n sendWorkerRequest<ReadonlyArray<TRow>>({\n type: `execute`,\n sql,\n params,\n }),\n close: async () => {\n if (disposed) {\n return\n }\n\n let closeError: unknown\n try {\n await sendWorkerRequest<void>({\n type: `close`,\n })\n } catch (error) {\n closeError = error\n } finally {\n disposeWorker()\n }\n\n if (closeError) {\n throw closeError\n }\n },\n }\n}\n"],"names":["PersistenceUnavailableError","InvalidPersistedCollectionConfigError","OPFSWorkerConstructor"],"mappings":"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"}
@@ -2,6 +2,10 @@ import { BrowserWASQLiteDatabase } from './wa-sqlite-driver.cjs';
2
2
  export type OpenBrowserWASQLiteOPFSDatabaseOptions = {
3
3
  databaseName: string;
4
4
  vfsName?: string;
5
+ /** Defaults to 30 seconds. Set to 0 to wait without a deadline. */
6
+ timeoutMs?: number;
7
+ /** Cancels only the database open, not an established connection. */
8
+ signal?: AbortSignal;
5
9
  };
6
10
  /**
7
11
  * Creates a browser wa-sqlite database handle backed by OPFS and
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  function WorkerWrapper(options) {
3
3
  return new Worker(
4
- "" + (typeof document === "undefined" ? require("url").pathToFileURL(__dirname + "/../assets/opfs-worker-uyjx5Rus.js").href : new URL("../assets/opfs-worker-uyjx5Rus.js", document.currentScript && document.currentScript.tagName.toUpperCase() === "SCRIPT" && document.currentScript.src || document.baseURI).href),
4
+ "" + (typeof document === "undefined" ? require("url").pathToFileURL(__dirname + "/../assets/opfs-worker-accoEoax.js").href : new URL("../assets/opfs-worker-accoEoax.js", document.currentScript && document.currentScript.tagName.toUpperCase() === "SCRIPT" && document.currentScript.src || document.baseURI).href),
5
5
  {
6
6
  name: options?.name
7
7
  }
@@ -1,6 +1,20 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const dbSqlitePersistenceCore = require("@tanstack/db-sqlite-persistence-core");
4
+ var _a;
5
+ const databaseExecutionStates = /* @__PURE__ */ new WeakMap();
6
+ function getDatabaseExecutionState(database) {
7
+ const existing = databaseExecutionStates.get(database);
8
+ if (existing) {
9
+ return existing;
10
+ }
11
+ const state = {
12
+ queue: Promise.resolve(),
13
+ nextSavepointId: 1
14
+ };
15
+ databaseExecutionStates.set(database, state);
16
+ return state;
17
+ }
4
18
  function assertTransactionCallbackHasDriverArg(fn) {
5
19
  if (fn.length > 0) {
6
20
  return;
@@ -16,29 +30,34 @@ function assertDatabaseShape(database) {
16
30
  );
17
31
  }
18
32
  }
33
+ _a = dbSqlitePersistenceCore.SQLITE_DRIVER_SHARED_LOGICAL_SCHEDULING_KEY;
19
34
  class BrowserWASQLiteDriver {
20
35
  constructor(options) {
21
- this.queue = Promise.resolve();
22
- this.nextSavepointId = 1;
36
+ this[_a] = {};
23
37
  this.closed = false;
24
38
  assertDatabaseShape(options.database);
25
39
  this.database = options.database;
40
+ this.executionState = getDatabaseExecutionState(this.database);
26
41
  }
27
- async exec(sql) {
28
- await this.enqueue(async () => {
42
+ exec(sql) {
43
+ return this.enqueue(async () => {
29
44
  await this.database.execute(sql);
30
45
  });
31
46
  }
32
- async query(sql, params = []) {
47
+ query(sql, params = []) {
33
48
  return this.enqueue(() => this.database.execute(sql, params));
34
49
  }
35
- async run(sql, params = []) {
36
- await this.enqueue(async () => {
50
+ run(sql, params = []) {
51
+ return this.enqueue(async () => {
37
52
  await this.database.execute(sql, params);
38
53
  });
39
54
  }
40
- async transaction(fn) {
41
- assertTransactionCallbackHasDriverArg(fn);
55
+ transaction(fn) {
56
+ try {
57
+ assertTransactionCallbackHasDriverArg(fn);
58
+ } catch (error) {
59
+ return Promise.reject(error);
60
+ }
42
61
  return this.enqueue(async () => {
43
62
  await this.database.execute(`BEGIN IMMEDIATE`);
44
63
  try {
@@ -54,7 +73,7 @@ class BrowserWASQLiteDriver {
54
73
  }
55
74
  });
56
75
  }
57
- async transactionWithDriver(fn) {
76
+ transactionWithDriver(fn) {
58
77
  return this.transaction(fn);
59
78
  }
60
79
  async close() {
@@ -80,8 +99,8 @@ class BrowserWASQLiteDriver {
80
99
  }
81
100
  async runNestedTransaction(fn) {
82
101
  assertTransactionCallbackHasDriverArg(fn);
83
- const savepointName = `tsdb_sp_${this.nextSavepointId}`;
84
- this.nextSavepointId++;
102
+ const savepointName = `tsdb_sp_${this.executionState.nextSavepointId}`;
103
+ this.executionState.nextSavepointId++;
85
104
  await this.database.execute(`SAVEPOINT ${savepointName}`);
86
105
  try {
87
106
  const result = await fn(this.createTransactionDriver());
@@ -94,8 +113,13 @@ class BrowserWASQLiteDriver {
94
113
  }
95
114
  }
96
115
  enqueue(operation) {
97
- const queuedOperation = this.queue.then(operation, operation);
98
- this.queue = queuedOperation.then(
116
+ const queuedOperation = this.executionState.queue.then(operation, operation);
117
+ Object.defineProperty(
118
+ queuedOperation,
119
+ dbSqlitePersistenceCore.SQLITE_DRIVER_SHARED_LOGICAL_SCHEDULING_KEY,
120
+ { value: this[dbSqlitePersistenceCore.SQLITE_DRIVER_SHARED_LOGICAL_SCHEDULING_KEY] }
121
+ );
122
+ this.executionState.queue = queuedOperation.then(
99
123
  () => void 0,
100
124
  () => void 0
101
125
  );
@@ -1 +1 @@
1
- {"version":3,"file":"wa-sqlite-driver.cjs","sources":["../../src/wa-sqlite-driver.ts"],"sourcesContent":["import { InvalidPersistedCollectionConfigError } from '@tanstack/db-sqlite-persistence-core'\nimport type { SQLiteDriver } from '@tanstack/db-sqlite-persistence-core'\n\nexport type BrowserWASQLiteDatabase = {\n execute: <TRow = unknown>(\n sql: string,\n params?: ReadonlyArray<unknown>,\n ) => Promise<ReadonlyArray<TRow>>\n close?: () => Promise<void> | void\n}\n\nexport type BrowserWASQLiteDriverOptions = {\n database: BrowserWASQLiteDatabase\n}\n\nfunction assertTransactionCallbackHasDriverArg(\n fn: (transactionDriver: SQLiteDriver) => Promise<unknown>,\n): void {\n if (fn.length > 0) {\n return\n }\n\n throw new InvalidPersistedCollectionConfigError(\n `SQLiteDriver.transaction callback must accept the transaction driver argument`,\n )\n}\n\nfunction assertDatabaseShape(\n database: BrowserWASQLiteDatabase,\n): asserts database is BrowserWASQLiteDatabase {\n if (typeof database.execute !== `function`) {\n throw new InvalidPersistedCollectionConfigError(\n `Browser wa-sqlite database handle must provide execute(sql, params?)`,\n )\n }\n}\n\nexport class BrowserWASQLiteDriver implements SQLiteDriver {\n private readonly database: BrowserWASQLiteDatabase\n private queue: Promise<void> = Promise.resolve()\n private nextSavepointId = 1\n private closed = false\n\n constructor(options: BrowserWASQLiteDriverOptions) {\n assertDatabaseShape(options.database)\n this.database = options.database\n }\n\n async exec(sql: string): Promise<void> {\n await this.enqueue(async () => {\n await this.database.execute(sql)\n })\n }\n\n async query<T>(\n sql: string,\n params: ReadonlyArray<unknown> = [],\n ): Promise<ReadonlyArray<T>> {\n return this.enqueue(() => this.database.execute<T>(sql, params))\n }\n\n async run(sql: string, params: ReadonlyArray<unknown> = []): Promise<void> {\n await this.enqueue(async () => {\n await this.database.execute(sql, params)\n })\n }\n\n async transaction<T>(\n fn: (transactionDriver: SQLiteDriver) => Promise<T>,\n ): Promise<T> {\n assertTransactionCallbackHasDriverArg(fn)\n\n return this.enqueue(async () => {\n await this.database.execute(`BEGIN IMMEDIATE`)\n try {\n const result = await fn(this.createTransactionDriver())\n await this.database.execute(`COMMIT`)\n return result\n } catch (error) {\n try {\n await this.database.execute(`ROLLBACK`)\n } catch {\n // Preserve original transaction error.\n }\n throw error\n }\n })\n }\n\n async transactionWithDriver<T>(\n fn: (transactionDriver: SQLiteDriver) => Promise<T>,\n ): Promise<T> {\n return this.transaction(fn)\n }\n\n async close(): Promise<void> {\n if (this.closed) {\n return\n }\n this.closed = true\n\n if (typeof this.database.close === `function`) {\n await Promise.resolve(this.database.close())\n }\n }\n\n getDatabase(): BrowserWASQLiteDatabase {\n return this.database\n }\n\n private createTransactionDriver(): SQLiteDriver {\n return {\n exec: (sql) => this.database.execute(sql).then(() => undefined),\n query: <T>(sql: string, params: ReadonlyArray<unknown> = []) =>\n this.database.execute<T>(sql, params),\n run: (sql: string, params: ReadonlyArray<unknown> = []) =>\n this.database.execute(sql, params).then(() => undefined),\n transaction: <T>(fn: (transactionDriver: SQLiteDriver) => Promise<T>) =>\n this.runNestedTransaction(fn),\n transactionWithDriver: <T>(\n fn: (transactionDriver: SQLiteDriver) => Promise<T>,\n ) => this.runNestedTransaction(fn),\n }\n }\n\n private async runNestedTransaction<T>(\n fn: (transactionDriver: SQLiteDriver) => Promise<T>,\n ): Promise<T> {\n assertTransactionCallbackHasDriverArg(fn)\n\n const savepointName = `tsdb_sp_${this.nextSavepointId}`\n this.nextSavepointId++\n await this.database.execute(`SAVEPOINT ${savepointName}`)\n try {\n const result = await fn(this.createTransactionDriver())\n await this.database.execute(`RELEASE SAVEPOINT ${savepointName}`)\n return result\n } catch (error) {\n await this.database.execute(`ROLLBACK TO SAVEPOINT ${savepointName}`)\n await this.database.execute(`RELEASE SAVEPOINT ${savepointName}`)\n throw error\n }\n }\n\n private enqueue<T>(operation: () => Promise<T> | T): Promise<T> {\n const queuedOperation = this.queue.then(operation, operation)\n this.queue = queuedOperation.then(\n () => undefined,\n () => undefined,\n )\n return queuedOperation\n }\n}\n"],"names":["InvalidPersistedCollectionConfigError"],"mappings":";;;AAeA,SAAS,sCACP,IACM;AACN,MAAI,GAAG,SAAS,GAAG;AACjB;AAAA,EACF;AAEA,QAAM,IAAIA,wBAAAA;AAAAA,IACR;AAAA,EAAA;AAEJ;AAEA,SAAS,oBACP,UAC6C;AAC7C,MAAI,OAAO,SAAS,YAAY,YAAY;AAC1C,UAAM,IAAIA,wBAAAA;AAAAA,MACR;AAAA,IAAA;AAAA,EAEJ;AACF;AAEO,MAAM,sBAA8C;AAAA,EAMzD,YAAY,SAAuC;AAJnD,SAAQ,QAAuB,QAAQ,QAAA;AACvC,SAAQ,kBAAkB;AAC1B,SAAQ,SAAS;AAGf,wBAAoB,QAAQ,QAAQ;AACpC,SAAK,WAAW,QAAQ;AAAA,EAC1B;AAAA,EAEA,MAAM,KAAK,KAA4B;AACrC,UAAM,KAAK,QAAQ,YAAY;AAC7B,YAAM,KAAK,SAAS,QAAQ,GAAG;AAAA,IACjC,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,MACJ,KACA,SAAiC,IACN;AAC3B,WAAO,KAAK,QAAQ,MAAM,KAAK,SAAS,QAAW,KAAK,MAAM,CAAC;AAAA,EACjE;AAAA,EAEA,MAAM,IAAI,KAAa,SAAiC,IAAmB;AACzE,UAAM,KAAK,QAAQ,YAAY;AAC7B,YAAM,KAAK,SAAS,QAAQ,KAAK,MAAM;AAAA,IACzC,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,YACJ,IACY;AACZ,0CAAsC,EAAE;AAExC,WAAO,KAAK,QAAQ,YAAY;AAC9B,YAAM,KAAK,SAAS,QAAQ,iBAAiB;AAC7C,UAAI;AACF,cAAM,SAAS,MAAM,GAAG,KAAK,yBAAyB;AACtD,cAAM,KAAK,SAAS,QAAQ,QAAQ;AACpC,eAAO;AAAA,MACT,SAAS,OAAO;AACd,YAAI;AACF,gBAAM,KAAK,SAAS,QAAQ,UAAU;AAAA,QACxC,QAAQ;AAAA,QAER;AACA,cAAM;AAAA,MACR;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,sBACJ,IACY;AACZ,WAAO,KAAK,YAAY,EAAE;AAAA,EAC5B;AAAA,EAEA,MAAM,QAAuB;AAC3B,QAAI,KAAK,QAAQ;AACf;AAAA,IACF;AACA,SAAK,SAAS;AAEd,QAAI,OAAO,KAAK,SAAS,UAAU,YAAY;AAC7C,YAAM,QAAQ,QAAQ,KAAK,SAAS,OAAO;AAAA,IAC7C;AAAA,EACF;AAAA,EAEA,cAAuC;AACrC,WAAO,KAAK;AAAA,EACd;AAAA,EAEQ,0BAAwC;AAC9C,WAAO;AAAA,MACL,MAAM,CAAC,QAAQ,KAAK,SAAS,QAAQ,GAAG,EAAE,KAAK,MAAM,MAAS;AAAA,MAC9D,OAAO,CAAI,KAAa,SAAiC,CAAA,MACvD,KAAK,SAAS,QAAW,KAAK,MAAM;AAAA,MACtC,KAAK,CAAC,KAAa,SAAiC,CAAA,MAClD,KAAK,SAAS,QAAQ,KAAK,MAAM,EAAE,KAAK,MAAM,MAAS;AAAA,MACzD,aAAa,CAAI,OACf,KAAK,qBAAqB,EAAE;AAAA,MAC9B,uBAAuB,CACrB,OACG,KAAK,qBAAqB,EAAE;AAAA,IAAA;AAAA,EAErC;AAAA,EAEA,MAAc,qBACZ,IACY;AACZ,0CAAsC,EAAE;AAExC,UAAM,gBAAgB,WAAW,KAAK,eAAe;AACrD,SAAK;AACL,UAAM,KAAK,SAAS,QAAQ,aAAa,aAAa,EAAE;AACxD,QAAI;AACF,YAAM,SAAS,MAAM,GAAG,KAAK,yBAAyB;AACtD,YAAM,KAAK,SAAS,QAAQ,qBAAqB,aAAa,EAAE;AAChE,aAAO;AAAA,IACT,SAAS,OAAO;AACd,YAAM,KAAK,SAAS,QAAQ,yBAAyB,aAAa,EAAE;AACpE,YAAM,KAAK,SAAS,QAAQ,qBAAqB,aAAa,EAAE;AAChE,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEQ,QAAW,WAA6C;AAC9D,UAAM,kBAAkB,KAAK,MAAM,KAAK,WAAW,SAAS;AAC5D,SAAK,QAAQ,gBAAgB;AAAA,MAC3B,MAAM;AAAA,MACN,MAAM;AAAA,IAAA;AAER,WAAO;AAAA,EACT;AACF;;"}
1
+ {"version":3,"file":"wa-sqlite-driver.cjs","sources":["../../src/wa-sqlite-driver.ts"],"sourcesContent":["import {\n InvalidPersistedCollectionConfigError,\n SQLITE_DRIVER_SHARED_LOGICAL_SCHEDULING_KEY,\n} from '@tanstack/db-sqlite-persistence-core'\nimport type { SQLiteDriver } from '@tanstack/db-sqlite-persistence-core'\n\nexport type BrowserWASQLiteDatabase = {\n execute: <TRow = unknown>(\n sql: string,\n params?: ReadonlyArray<unknown>,\n ) => Promise<ReadonlyArray<TRow>>\n close?: () => Promise<void> | void\n}\n\nexport type BrowserWASQLiteDriverOptions = {\n database: BrowserWASQLiteDatabase\n}\n\ntype DatabaseExecutionState = {\n queue: Promise<void>\n nextSavepointId: number\n}\n\nconst databaseExecutionStates = new WeakMap<\n BrowserWASQLiteDatabase,\n DatabaseExecutionState\n>()\n\nfunction getDatabaseExecutionState(\n database: BrowserWASQLiteDatabase,\n): DatabaseExecutionState {\n const existing = databaseExecutionStates.get(database)\n if (existing) {\n return existing\n }\n\n const state: DatabaseExecutionState = {\n queue: Promise.resolve(),\n nextSavepointId: 1,\n }\n databaseExecutionStates.set(database, state)\n return state\n}\n\nfunction assertTransactionCallbackHasDriverArg(\n fn: (transactionDriver: SQLiteDriver) => Promise<unknown>,\n): void {\n if (fn.length > 0) {\n return\n }\n\n throw new InvalidPersistedCollectionConfigError(\n `SQLiteDriver.transaction callback must accept the transaction driver argument`,\n )\n}\n\nfunction assertDatabaseShape(\n database: BrowserWASQLiteDatabase,\n): asserts database is BrowserWASQLiteDatabase {\n if (typeof database.execute !== `function`) {\n throw new InvalidPersistedCollectionConfigError(\n `Browser wa-sqlite database handle must provide execute(sql, params?)`,\n )\n }\n}\n\nexport class BrowserWASQLiteDriver implements SQLiteDriver {\n readonly [SQLITE_DRIVER_SHARED_LOGICAL_SCHEDULING_KEY] = {}\n private readonly database: BrowserWASQLiteDatabase\n private readonly executionState: DatabaseExecutionState\n private closed = false\n\n constructor(options: BrowserWASQLiteDriverOptions) {\n assertDatabaseShape(options.database)\n this.database = options.database\n this.executionState = getDatabaseExecutionState(this.database)\n }\n\n exec(sql: string): Promise<void> {\n return this.enqueue(async () => {\n await this.database.execute(sql)\n })\n }\n\n query<T>(\n sql: string,\n params: ReadonlyArray<unknown> = [],\n ): Promise<ReadonlyArray<T>> {\n return this.enqueue(() => this.database.execute<T>(sql, params))\n }\n\n run(sql: string, params: ReadonlyArray<unknown> = []): Promise<void> {\n return this.enqueue(async () => {\n await this.database.execute(sql, params)\n })\n }\n\n transaction<T>(\n fn: (transactionDriver: SQLiteDriver) => Promise<T>,\n ): Promise<T> {\n try {\n assertTransactionCallbackHasDriverArg(fn)\n } catch (error) {\n return Promise.reject(error)\n }\n\n return this.enqueue(async () => {\n await this.database.execute(`BEGIN IMMEDIATE`)\n try {\n const result = await fn(this.createTransactionDriver())\n await this.database.execute(`COMMIT`)\n return result\n } catch (error) {\n try {\n await this.database.execute(`ROLLBACK`)\n } catch {\n // Preserve original transaction error.\n }\n throw error\n }\n })\n }\n\n transactionWithDriver<T>(\n fn: (transactionDriver: SQLiteDriver) => Promise<T>,\n ): Promise<T> {\n return this.transaction(fn)\n }\n\n async close(): Promise<void> {\n if (this.closed) {\n return\n }\n this.closed = true\n\n if (typeof this.database.close === `function`) {\n await Promise.resolve(this.database.close())\n }\n }\n\n getDatabase(): BrowserWASQLiteDatabase {\n return this.database\n }\n\n private createTransactionDriver(): SQLiteDriver {\n return {\n exec: (sql) => this.database.execute(sql).then(() => undefined),\n query: <T>(sql: string, params: ReadonlyArray<unknown> = []) =>\n this.database.execute<T>(sql, params),\n run: (sql: string, params: ReadonlyArray<unknown> = []) =>\n this.database.execute(sql, params).then(() => undefined),\n transaction: <T>(fn: (transactionDriver: SQLiteDriver) => Promise<T>) =>\n this.runNestedTransaction(fn),\n transactionWithDriver: <T>(\n fn: (transactionDriver: SQLiteDriver) => Promise<T>,\n ) => this.runNestedTransaction(fn),\n }\n }\n\n private async runNestedTransaction<T>(\n fn: (transactionDriver: SQLiteDriver) => Promise<T>,\n ): Promise<T> {\n assertTransactionCallbackHasDriverArg(fn)\n\n const savepointName = `tsdb_sp_${this.executionState.nextSavepointId}`\n this.executionState.nextSavepointId++\n await this.database.execute(`SAVEPOINT ${savepointName}`)\n try {\n const result = await fn(this.createTransactionDriver())\n await this.database.execute(`RELEASE SAVEPOINT ${savepointName}`)\n return result\n } catch (error) {\n await this.database.execute(`ROLLBACK TO SAVEPOINT ${savepointName}`)\n await this.database.execute(`RELEASE SAVEPOINT ${savepointName}`)\n throw error\n }\n }\n\n private enqueue<T>(operation: () => Promise<T> | T): Promise<T> {\n const queuedOperation = this.executionState.queue.then(operation, operation)\n // Brand the exact Promise returned to callers. Transparent wrappers may\n // preserve this identity for late discovery; wrappers that create a new\n // Promise must forward the driver key before adapter construction.\n Object.defineProperty(\n queuedOperation,\n SQLITE_DRIVER_SHARED_LOGICAL_SCHEDULING_KEY,\n { value: this[SQLITE_DRIVER_SHARED_LOGICAL_SCHEDULING_KEY] },\n )\n this.executionState.queue = queuedOperation.then(\n () => undefined,\n () => undefined,\n )\n return queuedOperation\n }\n}\n"],"names":["InvalidPersistedCollectionConfigError","SQLITE_DRIVER_SHARED_LOGICAL_SCHEDULING_KEY"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { SQLiteDriver } from '@tanstack/db-sqlite-persistence-core';
1
+ import { SQLITE_DRIVER_SHARED_LOGICAL_SCHEDULING_KEY, SQLiteDriver } from '@tanstack/db-sqlite-persistence-core';
2
2
  export type BrowserWASQLiteDatabase = {
3
3
  execute: <TRow = unknown>(sql: string, params?: ReadonlyArray<unknown>) => Promise<ReadonlyArray<TRow>>;
4
4
  close?: () => Promise<void> | void;
@@ -7,9 +7,9 @@ export type BrowserWASQLiteDriverOptions = {
7
7
  database: BrowserWASQLiteDatabase;
8
8
  };
9
9
  export declare class BrowserWASQLiteDriver implements SQLiteDriver {
10
+ readonly [SQLITE_DRIVER_SHARED_LOGICAL_SCHEDULING_KEY]: {};
10
11
  private readonly database;
11
- private queue;
12
- private nextSavepointId;
12
+ private readonly executionState;
13
13
  private closed;
14
14
  constructor(options: BrowserWASQLiteDriverOptions);
15
15
  exec(sql: string): Promise<void>;
@@ -1,67 +1,5 @@
1
- import { ApplyLocalMutationsResponse, PersistedCollectionCoordinator, PersistedIndexSpec, PersistedMutationEnvelope, PersistenceAdapter, ProtocolEnvelope, PullSinceResponse } from '@tanstack/db-sqlite-persistence-core';
2
- import { LoadSubsetOptions } from '@tanstack/db';
3
- type AdapterWithPullSince = PersistenceAdapter & {
4
- pullSince?: (collectionId: string, fromRowVersion: number) => Promise<{
5
- latestRowVersion: number;
6
- requiresFullReload: true;
7
- } | {
8
- latestRowVersion: number;
9
- requiresFullReload: false;
10
- changedKeys: Array<string | number>;
11
- deletedKeys: Array<string | number>;
12
- }>;
13
- getStreamPosition?: (collectionId: string) => Promise<{
14
- latestTerm: number;
15
- latestSeq: number;
16
- latestRowVersion: number;
17
- }>;
18
- };
19
- export type BrowserCollectionCoordinatorOptions = {
20
- dbName: string;
21
- adapter?: AdapterWithPullSince;
22
- };
23
- export declare class BrowserCollectionCoordinator implements PersistedCollectionCoordinator {
24
- private readonly nodeId;
25
- private readonly dbName;
26
- private adapter;
27
- private readonly channel;
28
- private readonly collections;
29
- private readonly pendingRPCs;
30
- private readonly appliedEnvelopeIds;
31
- private disposed;
32
- /** Method indirection to prevent TypeScript from narrowing `disposed` across awaits */
33
- private isDisposed;
34
- private requireAdapter;
1
+ import { BroadcastCollectionCoordinator, BroadcastCollectionCoordinatorOptions } from '@tanstack/db-sqlite-persistence-core/broadcast-coordinator';
2
+ export type BrowserCollectionCoordinatorOptions = Omit<BroadcastCollectionCoordinatorOptions, `coordinatorName`>;
3
+ export declare class BrowserCollectionCoordinator extends BroadcastCollectionCoordinator {
35
4
  constructor(options: BrowserCollectionCoordinatorOptions);
36
- /**
37
- * Set or replace the persistence adapter used for leader-side RPC handling.
38
- * Called by `createBrowserWASQLitePersistence` to wire the internally-created
39
- * adapter into the coordinator.
40
- */
41
- setAdapter(adapter: AdapterWithPullSince): void;
42
- getNodeId(): string;
43
- subscribe(collectionId: string, onMessage: (message: ProtocolEnvelope<unknown>) => void): () => void;
44
- publish(_collectionId: string, message: ProtocolEnvelope<unknown>): void;
45
- isLeader(collectionId: string): boolean;
46
- ensureLeadership(collectionId: string): Promise<void>;
47
- requestEnsureRemoteSubset(collectionId: string, options: LoadSubsetOptions): Promise<void>;
48
- requestEnsurePersistedIndex(collectionId: string, signature: string, spec: PersistedIndexSpec): Promise<void>;
49
- requestApplyLocalMutations(collectionId: string, mutations: Array<PersistedMutationEnvelope>): Promise<ApplyLocalMutationsResponse>;
50
- pullSince(collectionId: string, fromRowVersion: number): Promise<PullSinceResponse>;
51
- dispose(): void;
52
- private ensureCollectionState;
53
- private acquireLeadership;
54
- private releaseLeadership;
55
- private emitHeartbeat;
56
- private onChannelMessage;
57
- private sendRPC;
58
- private sendRPCOnce;
59
- private handleRPCRequest;
60
- private handleEnsureRemoteSubset;
61
- private handleEnsurePersistedIndex;
62
- private handleApplyLocalMutations;
63
- private handlePullSince;
64
- private withWriterLock;
65
- private pruneAppliedEnvelopeIds;
66
5
  }
67
- export {};