@tanstack/node-db-sqlite-persistence 0.2.32 → 0.2.34

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 +1 @@
1
- {"version":3,"file":"node-driver.cjs","sources":["../../src/node-driver.ts"],"sourcesContent":["import { AsyncLocalStorage } from 'node:async_hooks'\nimport BetterSqlite3 from 'better-sqlite3'\nimport { InvalidPersistedCollectionConfigError } from '@tanstack/db-sqlite-persistence-core'\nimport type { SQLiteDriver } from '@tanstack/db-sqlite-persistence-core'\n\nconst DEFAULT_PRAGMAS = [\n `journal_mode = WAL`,\n `synchronous = NORMAL`,\n `foreign_keys = ON`,\n] as const\n\nconst INVALID_PRAGMA_PATTERN = /(;|--|\\/\\*)/\n\nexport type BetterSqlite3Database = InstanceType<typeof BetterSqlite3>\nexport type BetterSqlite3OpenOptions = ConstructorParameters<\n typeof BetterSqlite3\n>[1]\n\ntype BetterSqlite3ExistingDatabaseOptions = {\n database: BetterSqlite3Database\n pragmas?: ReadonlyArray<string>\n}\n\ntype BetterSqlite3OpenFileOptions = {\n filename: string\n options?: BetterSqlite3OpenOptions\n pragmas?: ReadonlyArray<string>\n}\n\nexport type BetterSqlite3DriverOptions =\n BetterSqlite3ExistingDatabaseOptions | BetterSqlite3OpenFileOptions\n\ntype TransactionContext = {\n depth: number\n}\n\ntype DatabaseExecutionState = {\n transactionContext: AsyncLocalStorage<TransactionContext>\n queue: Promise<void>\n nextSavepointId: number\n}\n\nconst databaseExecutionStates = new WeakMap<\n BetterSqlite3Database,\n DatabaseExecutionState\n>()\n\nfunction getDatabaseExecutionState(\n database: BetterSqlite3Database,\n): DatabaseExecutionState {\n const existing = databaseExecutionStates.get(database)\n if (existing) {\n return existing\n }\n\n const state: DatabaseExecutionState = {\n transactionContext: new AsyncLocalStorage<TransactionContext>(),\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 hasExistingDatabase(\n options: BetterSqlite3DriverOptions,\n): options is BetterSqlite3ExistingDatabaseOptions {\n return `database` in options\n}\n\nexport class BetterSqlite3SQLiteDriver implements SQLiteDriver {\n private readonly database: BetterSqlite3Database\n private readonly ownsDatabase: boolean\n private readonly executionState: DatabaseExecutionState\n\n constructor(options: BetterSqlite3DriverOptions) {\n if (hasExistingDatabase(options)) {\n this.database = options.database\n this.ownsDatabase = false\n this.executionState = getDatabaseExecutionState(this.database)\n this.applyPragmas(options.pragmas ?? DEFAULT_PRAGMAS)\n return\n }\n\n if (options.filename.trim().length === 0) {\n throw new InvalidPersistedCollectionConfigError(\n `Node SQLite driver filename cannot be empty`,\n )\n }\n\n this.database = new BetterSqlite3(options.filename, options.options)\n this.ownsDatabase = true\n this.executionState = getDatabaseExecutionState(this.database)\n this.applyPragmas(options.pragmas ?? DEFAULT_PRAGMAS)\n }\n\n async exec(sql: string): Promise<void> {\n if (this.isInsideTransaction()) {\n this.database.exec(sql)\n return\n }\n\n await this.enqueue(() => {\n this.database.exec(sql)\n })\n }\n\n async query<T>(\n sql: string,\n params: ReadonlyArray<unknown> = [],\n ): Promise<ReadonlyArray<T>> {\n if (this.isInsideTransaction()) {\n return this.executeQuery<T>(sql, params)\n }\n\n return this.enqueue(() => this.executeQuery<T>(sql, params))\n }\n\n async run(sql: string, params: ReadonlyArray<unknown> = []): Promise<void> {\n if (this.isInsideTransaction()) {\n this.executeRun(sql, params)\n return\n }\n\n await this.enqueue(() => {\n this.executeRun(sql, params)\n })\n }\n\n async transaction<T>(\n fn: (transactionDriver: SQLiteDriver) => Promise<T>,\n ): Promise<T> {\n assertTransactionCallbackHasDriverArg(fn)\n\n if (this.isInsideTransaction()) {\n return this.runNestedTransaction(fn)\n }\n\n return this.enqueue(async () => {\n this.database.exec(`BEGIN IMMEDIATE`)\n try {\n const result = await this.executionState.transactionContext.run(\n { depth: 1 },\n async () => fn(this),\n )\n this.database.exec(`COMMIT`)\n return result\n } catch (error) {\n try {\n this.database.exec(`ROLLBACK`)\n } catch {\n // Keep the original transaction error as the primary failure.\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 close(): void {\n if (!this.ownsDatabase) {\n return\n }\n\n this.database.close()\n }\n\n getDatabase(): BetterSqlite3Database {\n return this.database\n }\n\n private applyPragmas(pragmas: ReadonlyArray<string>): void {\n for (const pragma of pragmas) {\n const trimmedPragma = pragma.trim()\n if (trimmedPragma.length === 0) {\n continue\n }\n\n if (INVALID_PRAGMA_PATTERN.test(trimmedPragma)) {\n throw new InvalidPersistedCollectionConfigError(\n `Invalid SQLite PRAGMA: \"${pragma}\"`,\n )\n }\n\n this.database.exec(`PRAGMA ${trimmedPragma}`)\n }\n }\n\n private isInsideTransaction(): boolean {\n return this.executionState.transactionContext.getStore() !== undefined\n }\n\n private executeQuery<T>(\n sql: string,\n params: ReadonlyArray<unknown>,\n ): ReadonlyArray<T> {\n const statement = this.database.prepare(sql)\n if (params.length === 0) {\n return statement.all() as ReadonlyArray<T>\n }\n\n return statement.all(...params) as ReadonlyArray<T>\n }\n\n private executeRun(sql: string, params: ReadonlyArray<unknown>): void {\n const statement = this.database.prepare(sql)\n if (params.length === 0) {\n statement.run()\n return\n }\n\n statement.run(...params)\n }\n\n private enqueue<T>(operation: () => Promise<T> | T): Promise<T> {\n const queuedOperation = this.executionState.queue.then(operation, operation)\n this.executionState.queue = queuedOperation.then(\n () => undefined,\n () => undefined,\n )\n return queuedOperation\n }\n\n private async runNestedTransaction<T>(\n fn: (transactionDriver: SQLiteDriver) => Promise<T>,\n ): Promise<T> {\n const context = this.executionState.transactionContext.getStore()\n if (!context) {\n return fn(this)\n }\n\n const savepointName = `tsdb_sp_${this.executionState.nextSavepointId}`\n this.executionState.nextSavepointId++\n this.database.exec(`SAVEPOINT ${savepointName}`)\n\n try {\n const result = await this.executionState.transactionContext.run(\n { depth: context.depth + 1 },\n async () => fn(this),\n )\n this.database.exec(`RELEASE SAVEPOINT ${savepointName}`)\n return result\n } catch (error) {\n this.database.exec(`ROLLBACK TO SAVEPOINT ${savepointName}`)\n this.database.exec(`RELEASE SAVEPOINT ${savepointName}`)\n throw error\n }\n }\n}\n\nexport function createBetterSqlite3Driver(\n options: BetterSqlite3DriverOptions,\n): BetterSqlite3SQLiteDriver {\n return new BetterSqlite3SQLiteDriver(options)\n}\n"],"names":["AsyncLocalStorage","InvalidPersistedCollectionConfigError"],"mappings":"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"}
1
+ {"version":3,"file":"node-driver.cjs","sources":["../../src/node-driver.ts"],"sourcesContent":["import { AsyncLocalStorage } from 'node:async_hooks'\nimport BetterSqlite3 from 'better-sqlite3'\nimport { InvalidPersistedCollectionConfigError } from '@tanstack/db-sqlite-persistence-core'\nimport type { SQLiteDriver } from '@tanstack/db-sqlite-persistence-core'\n\nconst DEFAULT_PRAGMAS = [\n `journal_mode = WAL`,\n `synchronous = NORMAL`,\n `foreign_keys = ON`,\n] as const\n\nconst INVALID_PRAGMA_PATTERN = /(;|--|\\/\\*)/\n\nexport type BetterSqlite3Database = InstanceType<typeof BetterSqlite3>\nexport type BetterSqlite3OpenOptions = ConstructorParameters<\n typeof BetterSqlite3\n>[1]\n\ntype BetterSqlite3ExistingDatabaseOptions = {\n database: BetterSqlite3Database\n pragmas?: ReadonlyArray<string>\n}\n\ntype BetterSqlite3OpenFileOptions = {\n filename: string\n options?: BetterSqlite3OpenOptions\n pragmas?: ReadonlyArray<string>\n}\n\nexport type BetterSqlite3DriverOptions =\n BetterSqlite3ExistingDatabaseOptions | BetterSqlite3OpenFileOptions\n\ntype TransactionContext = {\n depth: number\n}\n\ntype DatabaseExecutionState = {\n transactionContext: AsyncLocalStorage<TransactionContext>\n queue: Promise<void>\n nextSavepointId: number\n}\n\nconst databaseExecutionStates = new WeakMap<\n BetterSqlite3Database,\n DatabaseExecutionState\n>()\n\nfunction getDatabaseExecutionState(\n database: BetterSqlite3Database,\n): DatabaseExecutionState {\n const existing = databaseExecutionStates.get(database)\n if (existing) {\n return existing\n }\n\n const state: DatabaseExecutionState = {\n transactionContext: new AsyncLocalStorage<TransactionContext>(),\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 hasExistingDatabase(\n options: BetterSqlite3DriverOptions,\n): options is BetterSqlite3ExistingDatabaseOptions {\n return `database` in options\n}\n\nexport class BetterSqlite3SQLiteDriver implements SQLiteDriver {\n private readonly database: BetterSqlite3Database\n private readonly ownsDatabase: boolean\n private readonly executionState: DatabaseExecutionState\n\n constructor(options: BetterSqlite3DriverOptions) {\n if (hasExistingDatabase(options)) {\n this.database = options.database\n this.ownsDatabase = false\n this.executionState = getDatabaseExecutionState(this.database)\n this.applyPragmas(options.pragmas ?? DEFAULT_PRAGMAS)\n return\n }\n\n if (options.filename.trim().length === 0) {\n throw new InvalidPersistedCollectionConfigError(\n `Node SQLite driver filename cannot be empty`,\n )\n }\n\n this.database = new BetterSqlite3(options.filename, options.options)\n this.ownsDatabase = true\n this.executionState = getDatabaseExecutionState(this.database)\n this.applyPragmas(options.pragmas ?? DEFAULT_PRAGMAS)\n }\n\n async exec(sql: string): Promise<void> {\n if (this.isInsideTransaction()) {\n this.database.exec(sql)\n return\n }\n\n await this.enqueue(() => {\n this.database.exec(sql)\n })\n }\n\n async query<T>(\n sql: string,\n params: ReadonlyArray<unknown> = [],\n ): Promise<ReadonlyArray<T>> {\n if (this.isInsideTransaction()) {\n return this.executeQuery<T>(sql, params)\n }\n\n return this.enqueue(() => this.executeQuery<T>(sql, params))\n }\n\n async run(sql: string, params: ReadonlyArray<unknown> = []): Promise<void> {\n if (this.isInsideTransaction()) {\n this.executeRun(sql, params)\n return\n }\n\n await this.enqueue(() => {\n this.executeRun(sql, params)\n })\n }\n\n async transaction<T>(\n fn: (transactionDriver: SQLiteDriver) => Promise<T>,\n ): Promise<T> {\n assertTransactionCallbackHasDriverArg(fn)\n\n if (this.isInsideTransaction()) {\n return this.runNestedTransaction(fn)\n }\n\n return this.enqueue(async () => {\n this.database.exec(`BEGIN IMMEDIATE`)\n try {\n const result = await this.executionState.transactionContext.run(\n { depth: 1 },\n async () => fn(this),\n )\n this.database.exec(`COMMIT`)\n return result\n } catch (error) {\n try {\n this.database.exec(`ROLLBACK`)\n } catch {\n // Keep the original transaction error as the primary failure.\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 close(): void {\n if (!this.ownsDatabase) {\n return\n }\n\n this.database.close()\n }\n\n getDatabase(): BetterSqlite3Database {\n return this.database\n }\n\n private applyPragmas(pragmas: ReadonlyArray<string>): void {\n for (const pragma of pragmas) {\n const trimmedPragma = pragma.trim()\n if (trimmedPragma.length === 0) {\n continue\n }\n\n if (INVALID_PRAGMA_PATTERN.test(trimmedPragma)) {\n throw new InvalidPersistedCollectionConfigError(\n `Invalid SQLite PRAGMA: \"${pragma}\"`,\n )\n }\n\n this.database.exec(`PRAGMA ${trimmedPragma}`)\n }\n }\n\n private isInsideTransaction(): boolean {\n return this.executionState.transactionContext.getStore() !== undefined\n }\n\n private executeQuery<T>(\n sql: string,\n params: ReadonlyArray<unknown>,\n ): ReadonlyArray<T> {\n const statement = this.database.prepare(sql)\n if (params.length === 0) {\n return statement.all() as ReadonlyArray<T>\n }\n\n return statement.all(...params) as ReadonlyArray<T>\n }\n\n private executeRun(sql: string, params: ReadonlyArray<unknown>): void {\n const statement = this.database.prepare(sql)\n if (params.length === 0) {\n statement.run()\n return\n }\n\n statement.run(...params)\n }\n\n private enqueue<T>(operation: () => Promise<T> | T): Promise<T> {\n const queuedOperation = this.executionState.queue.then(operation, operation)\n this.executionState.queue = queuedOperation.then(\n () => undefined,\n () => undefined,\n )\n return queuedOperation\n }\n\n private async runNestedTransaction<T>(\n fn: (transactionDriver: SQLiteDriver) => Promise<T>,\n ): Promise<T> {\n const context = this.executionState.transactionContext.getStore()\n if (!context) {\n return fn(this)\n }\n\n const savepointName = `tsdb_sp_${this.executionState.nextSavepointId}`\n this.executionState.nextSavepointId++\n this.database.exec(`SAVEPOINT ${savepointName}`)\n\n try {\n const result = await this.executionState.transactionContext.run(\n { depth: context.depth + 1 },\n async () => fn(this),\n )\n this.database.exec(`RELEASE SAVEPOINT ${savepointName}`)\n return result\n } catch (error) {\n this.database.exec(`ROLLBACK TO SAVEPOINT ${savepointName}`)\n this.database.exec(`RELEASE SAVEPOINT ${savepointName}`)\n throw error\n }\n }\n}\n"],"names":["AsyncLocalStorage","InvalidPersistedCollectionConfigError"],"mappings":"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"}
@@ -31,5 +31,4 @@ export declare class BetterSqlite3SQLiteDriver implements SQLiteDriver {
31
31
  private enqueue;
32
32
  private runNestedTransaction;
33
33
  }
34
- export declare function createBetterSqlite3Driver(options: BetterSqlite3DriverOptions): BetterSqlite3SQLiteDriver;
35
34
  export {};
@@ -30,7 +30,9 @@ function resolveAdapterBaseOptions(options) {
30
30
  return {
31
31
  appliedTxPruneMaxRows: options.appliedTxPruneMaxRows ?? dbSqlitePersistenceCore.DEFAULT_APPLIED_TX_PRUNE_MAX_ROWS,
32
32
  appliedTxPruneMaxAgeSeconds: options.appliedTxPruneMaxAgeSeconds ?? dbSqlitePersistenceCore.DEFAULT_APPLIED_TX_PRUNE_MAX_AGE_SECONDS,
33
- pullSinceReloadThreshold: options.pullSinceReloadThreshold
33
+ pullSinceReloadThreshold: options.pullSinceReloadThreshold,
34
+ cacheGenerationClaimTtlMs: options.cacheGenerationClaimTtlMs,
35
+ now: options.now
34
36
  };
35
37
  }
36
38
  function createNodeSQLitePersistence(options) {
@@ -1 +1 @@
1
- {"version":3,"file":"node-persistence.cjs","sources":["../../src/node-persistence.ts"],"sourcesContent":["import {\n DEFAULT_APPLIED_TX_PRUNE_MAX_AGE_SECONDS as CORE_DEFAULT_APPLIED_TX_PRUNE_MAX_AGE_SECONDS,\n DEFAULT_APPLIED_TX_PRUNE_MAX_ROWS as CORE_DEFAULT_APPLIED_TX_PRUNE_MAX_ROWS,\n SingleProcessCoordinator,\n createSQLiteCorePersistenceAdapter,\n} from '@tanstack/db-sqlite-persistence-core'\nimport { BetterSqlite3SQLiteDriver } from './node-driver'\nimport type {\n PersistedCollectionCoordinator,\n PersistedCollectionMode,\n PersistedCollectionPersistence,\n SQLiteCoreAdapterOptions,\n SQLiteDriver,\n} from '@tanstack/db-sqlite-persistence-core'\nimport type { BetterSqlite3Database } from './node-driver'\n\nexport type { BetterSqlite3Database } from './node-driver'\n\ntype NodeSQLiteCoreSchemaMismatchPolicy =\n `sync-present-reset` | `sync-absent-error` | `reset`\n\nexport type NodeSQLiteSchemaMismatchPolicy =\n NodeSQLiteCoreSchemaMismatchPolicy | `throw`\n\ntype NodeSQLitePersistenceBaseOptions = Omit<\n SQLiteCoreAdapterOptions,\n `driver` | `schemaVersion` | `schemaMismatchPolicy`\n> & {\n database: BetterSqlite3Database\n pragmas?: ReadonlyArray<string>\n coordinator?: PersistedCollectionCoordinator\n schemaMismatchPolicy?: NodeSQLiteSchemaMismatchPolicy\n}\n\nexport type NodeSQLitePersistenceOptions = NodeSQLitePersistenceBaseOptions\n\n/**\n * Default cap on retained `applied_tx` rows per collection. The log is a\n * replayable cache, so a bounded row count keeps SQLite files from growing\n * without limit. Pass `appliedTxPruneMaxRows: 0` to disable the row cap.\n */\nexport const DEFAULT_APPLIED_TX_PRUNE_MAX_ROWS =\n CORE_DEFAULT_APPLIED_TX_PRUNE_MAX_ROWS\n\n/**\n * Default age backstop for retained `applied_tx` rows, in seconds (24h). Rows\n * older than this are pruned on the next write. Pass\n * `appliedTxPruneMaxAgeSeconds: 0` to disable the age backstop.\n */\nexport const DEFAULT_APPLIED_TX_PRUNE_MAX_AGE_SECONDS =\n CORE_DEFAULT_APPLIED_TX_PRUNE_MAX_AGE_SECONDS\n\nfunction normalizeSchemaMismatchPolicy(\n policy: NodeSQLiteSchemaMismatchPolicy,\n): NodeSQLiteCoreSchemaMismatchPolicy {\n if (policy === `throw`) {\n return `sync-absent-error`\n }\n\n return policy\n}\n\nfunction resolveSchemaMismatchPolicy(\n explicitPolicy: NodeSQLiteSchemaMismatchPolicy | undefined,\n mode: PersistedCollectionMode,\n): NodeSQLiteCoreSchemaMismatchPolicy {\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: NodeSQLiteCoreSchemaMismatchPolicy,\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: NodeSQLitePersistenceOptions,\n): SQLiteDriver {\n return new BetterSqlite3SQLiteDriver({\n database: options.database,\n ...(options.pragmas ? { pragmas: options.pragmas } : {}),\n })\n}\n\nfunction resolveAdapterBaseOptions(\n options: NodeSQLitePersistenceOptions,\n): Omit<\n SQLiteCoreAdapterOptions,\n `driver` | `schemaVersion` | `schemaMismatchPolicy`\n> {\n return {\n appliedTxPruneMaxRows:\n options.appliedTxPruneMaxRows ?? CORE_DEFAULT_APPLIED_TX_PRUNE_MAX_ROWS,\n appliedTxPruneMaxAgeSeconds:\n options.appliedTxPruneMaxAgeSeconds ??\n CORE_DEFAULT_APPLIED_TX_PRUNE_MAX_AGE_SECONDS,\n pullSinceReloadThreshold: options.pullSinceReloadThreshold,\n }\n}\n\n/**\n * Creates a shared SQLite persistence instance that can be reused by many\n * collections on the same database. Collection-specific schema versions are\n * resolved by `persistedCollectionOptions` via `resolvePersistenceForCollection`.\n */\nexport function createNodeSQLitePersistence(\n options: NodeSQLitePersistenceOptions,\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 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 // Backward compatible fallback for older callers.\n resolvePersistenceForMode: (mode) =>\n createCollectionPersistence(mode, undefined),\n }\n}\n"],"names":["CORE_DEFAULT_APPLIED_TX_PRUNE_MAX_ROWS","CORE_DEFAULT_APPLIED_TX_PRUNE_MAX_AGE_SECONDS","BetterSqlite3SQLiteDriver","SingleProcessCoordinator","createSQLiteCorePersistenceAdapter"],"mappings":";;;;AAyCO,MAAM,oCACXA,wBAAAA;AAOK,MAAM,2CACXC,wBAAAA;AAEF,SAAS,8BACP,QACoC;AACpC,MAAI,WAAW,SAAS;AACtB,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEA,SAAS,4BACP,gBACA,MACoC;AACpC,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,IAAIC,WAAAA,0BAA0B;AAAA,IACnC,UAAU,QAAQ;AAAA,IAClB,GAAI,QAAQ,UAAU,EAAE,SAAS,QAAQ,QAAA,IAAY,CAAA;AAAA,EAAC,CACvD;AACH;AAEA,SAAS,0BACP,SAIA;AACA,SAAO;AAAA,IACL,uBACE,QAAQ,yBAAyBF,wBAAAA;AAAAA,IACnC,6BACE,QAAQ,+BACRC,wBAAAA;AAAAA,IACF,0BAA0B,QAAQ;AAAA,EAAA;AAEtC;AAOO,SAAS,4BACd,SACgC;AAChC,QAAM,EAAE,aAAa,qBAAA,IAAyB;AAC9C,QAAM,SAAS,2BAA2B,OAAO;AACjD,QAAM,qBAAqB,0BAA0B,OAAO;AAC5D,QAAM,sBAAsB,eAAe,IAAIE,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,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;AAAA,IAEjD,2BAA2B,CAAC,SAC1B,4BAA4B,MAAM,MAAS;AAAA,EAAA;AAEjD;;;;"}
1
+ {"version":3,"file":"node-persistence.cjs","sources":["../../src/node-persistence.ts"],"sourcesContent":["import {\n DEFAULT_APPLIED_TX_PRUNE_MAX_AGE_SECONDS as CORE_DEFAULT_APPLIED_TX_PRUNE_MAX_AGE_SECONDS,\n DEFAULT_APPLIED_TX_PRUNE_MAX_ROWS as CORE_DEFAULT_APPLIED_TX_PRUNE_MAX_ROWS,\n SingleProcessCoordinator,\n createSQLiteCorePersistenceAdapter,\n} from '@tanstack/db-sqlite-persistence-core'\nimport { BetterSqlite3SQLiteDriver } from './node-driver'\nimport type {\n PersistedCollectionCoordinator,\n PersistedCollectionMode,\n PersistedCollectionPersistence,\n SQLiteCoreAdapterOptions,\n SQLiteDriver,\n} from '@tanstack/db-sqlite-persistence-core'\nimport type { BetterSqlite3Database } from './node-driver'\n\nexport type { BetterSqlite3Database } from './node-driver'\n\ntype NodeSQLiteCoreSchemaMismatchPolicy =\n `sync-present-reset` | `sync-absent-error` | `reset`\n\nexport type NodeSQLiteSchemaMismatchPolicy =\n NodeSQLiteCoreSchemaMismatchPolicy | `throw`\n\ntype NodeSQLitePersistenceBaseOptions = Omit<\n SQLiteCoreAdapterOptions,\n `driver` | `schemaVersion` | `schemaMismatchPolicy`\n> & {\n database: BetterSqlite3Database\n pragmas?: ReadonlyArray<string>\n coordinator?: PersistedCollectionCoordinator\n schemaMismatchPolicy?: NodeSQLiteSchemaMismatchPolicy\n}\n\nexport type NodeSQLitePersistenceOptions = NodeSQLitePersistenceBaseOptions\n\n/**\n * Default cap on retained `applied_tx` rows per collection. The log is a\n * replayable cache, so a bounded row count keeps SQLite files from growing\n * without limit. Pass `appliedTxPruneMaxRows: 0` to disable the row cap.\n */\nexport const DEFAULT_APPLIED_TX_PRUNE_MAX_ROWS =\n CORE_DEFAULT_APPLIED_TX_PRUNE_MAX_ROWS\n\n/**\n * Default age backstop for retained `applied_tx` rows, in seconds (24h). Rows\n * older than this are pruned on the next write. Pass\n * `appliedTxPruneMaxAgeSeconds: 0` to disable the age backstop.\n */\nexport const DEFAULT_APPLIED_TX_PRUNE_MAX_AGE_SECONDS =\n CORE_DEFAULT_APPLIED_TX_PRUNE_MAX_AGE_SECONDS\n\nfunction normalizeSchemaMismatchPolicy(\n policy: NodeSQLiteSchemaMismatchPolicy,\n): NodeSQLiteCoreSchemaMismatchPolicy {\n if (policy === `throw`) {\n return `sync-absent-error`\n }\n\n return policy\n}\n\nfunction resolveSchemaMismatchPolicy(\n explicitPolicy: NodeSQLiteSchemaMismatchPolicy | undefined,\n mode: PersistedCollectionMode,\n): NodeSQLiteCoreSchemaMismatchPolicy {\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: NodeSQLiteCoreSchemaMismatchPolicy,\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: NodeSQLitePersistenceOptions,\n): SQLiteDriver {\n return new BetterSqlite3SQLiteDriver({\n database: options.database,\n ...(options.pragmas ? { pragmas: options.pragmas } : {}),\n })\n}\n\nfunction resolveAdapterBaseOptions(\n options: NodeSQLitePersistenceOptions,\n): Omit<\n SQLiteCoreAdapterOptions,\n `driver` | `schemaVersion` | `schemaMismatchPolicy`\n> {\n return {\n appliedTxPruneMaxRows:\n options.appliedTxPruneMaxRows ?? CORE_DEFAULT_APPLIED_TX_PRUNE_MAX_ROWS,\n appliedTxPruneMaxAgeSeconds:\n options.appliedTxPruneMaxAgeSeconds ??\n CORE_DEFAULT_APPLIED_TX_PRUNE_MAX_AGE_SECONDS,\n pullSinceReloadThreshold: options.pullSinceReloadThreshold,\n cacheGenerationClaimTtlMs: options.cacheGenerationClaimTtlMs,\n now: options.now,\n }\n}\n\n/**\n * Creates a shared SQLite persistence instance that can be reused by many\n * collections on the same database. Collection-specific schema versions are\n * resolved by `persistedCollectionOptions` via `resolvePersistenceForCollection`.\n */\nexport function createNodeSQLitePersistence(\n options: NodeSQLitePersistenceOptions,\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 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 // Backward compatible fallback for older callers.\n resolvePersistenceForMode: (mode) =>\n createCollectionPersistence(mode, undefined),\n }\n}\n"],"names":["CORE_DEFAULT_APPLIED_TX_PRUNE_MAX_ROWS","CORE_DEFAULT_APPLIED_TX_PRUNE_MAX_AGE_SECONDS","BetterSqlite3SQLiteDriver","SingleProcessCoordinator","createSQLiteCorePersistenceAdapter"],"mappings":";;;;AAyCO,MAAM,oCACXA,wBAAAA;AAOK,MAAM,2CACXC,wBAAAA;AAEF,SAAS,8BACP,QACoC;AACpC,MAAI,WAAW,SAAS;AACtB,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEA,SAAS,4BACP,gBACA,MACoC;AACpC,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,IAAIC,WAAAA,0BAA0B;AAAA,IACnC,UAAU,QAAQ;AAAA,IAClB,GAAI,QAAQ,UAAU,EAAE,SAAS,QAAQ,QAAA,IAAY,CAAA;AAAA,EAAC,CACvD;AACH;AAEA,SAAS,0BACP,SAIA;AACA,SAAO;AAAA,IACL,uBACE,QAAQ,yBAAyBF,wBAAAA;AAAAA,IACnC,6BACE,QAAQ,+BACRC,wBAAAA;AAAAA,IACF,0BAA0B,QAAQ;AAAA,IAClC,2BAA2B,QAAQ;AAAA,IACnC,KAAK,QAAQ;AAAA,EAAA;AAEjB;AAOO,SAAS,4BACd,SACgC;AAChC,QAAM,EAAE,aAAa,qBAAA,IAAyB;AAC9C,QAAM,SAAS,2BAA2B,OAAO;AACjD,QAAM,qBAAqB,0BAA0B,OAAO;AAC5D,QAAM,sBAAsB,eAAe,IAAIE,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,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;AAAA,IAEjD,2BAA2B,CAAC,SAC1B,4BAA4B,MAAM,MAAS;AAAA,EAAA;AAEjD;;;;"}
@@ -31,5 +31,4 @@ export declare class BetterSqlite3SQLiteDriver implements SQLiteDriver {
31
31
  private enqueue;
32
32
  private runNestedTransaction;
33
33
  }
34
- export declare function createBetterSqlite3Driver(options: BetterSqlite3DriverOptions): BetterSqlite3SQLiteDriver;
35
34
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"node-driver.js","sources":["../../src/node-driver.ts"],"sourcesContent":["import { AsyncLocalStorage } from 'node:async_hooks'\nimport BetterSqlite3 from 'better-sqlite3'\nimport { InvalidPersistedCollectionConfigError } from '@tanstack/db-sqlite-persistence-core'\nimport type { SQLiteDriver } from '@tanstack/db-sqlite-persistence-core'\n\nconst DEFAULT_PRAGMAS = [\n `journal_mode = WAL`,\n `synchronous = NORMAL`,\n `foreign_keys = ON`,\n] as const\n\nconst INVALID_PRAGMA_PATTERN = /(;|--|\\/\\*)/\n\nexport type BetterSqlite3Database = InstanceType<typeof BetterSqlite3>\nexport type BetterSqlite3OpenOptions = ConstructorParameters<\n typeof BetterSqlite3\n>[1]\n\ntype BetterSqlite3ExistingDatabaseOptions = {\n database: BetterSqlite3Database\n pragmas?: ReadonlyArray<string>\n}\n\ntype BetterSqlite3OpenFileOptions = {\n filename: string\n options?: BetterSqlite3OpenOptions\n pragmas?: ReadonlyArray<string>\n}\n\nexport type BetterSqlite3DriverOptions =\n BetterSqlite3ExistingDatabaseOptions | BetterSqlite3OpenFileOptions\n\ntype TransactionContext = {\n depth: number\n}\n\ntype DatabaseExecutionState = {\n transactionContext: AsyncLocalStorage<TransactionContext>\n queue: Promise<void>\n nextSavepointId: number\n}\n\nconst databaseExecutionStates = new WeakMap<\n BetterSqlite3Database,\n DatabaseExecutionState\n>()\n\nfunction getDatabaseExecutionState(\n database: BetterSqlite3Database,\n): DatabaseExecutionState {\n const existing = databaseExecutionStates.get(database)\n if (existing) {\n return existing\n }\n\n const state: DatabaseExecutionState = {\n transactionContext: new AsyncLocalStorage<TransactionContext>(),\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 hasExistingDatabase(\n options: BetterSqlite3DriverOptions,\n): options is BetterSqlite3ExistingDatabaseOptions {\n return `database` in options\n}\n\nexport class BetterSqlite3SQLiteDriver implements SQLiteDriver {\n private readonly database: BetterSqlite3Database\n private readonly ownsDatabase: boolean\n private readonly executionState: DatabaseExecutionState\n\n constructor(options: BetterSqlite3DriverOptions) {\n if (hasExistingDatabase(options)) {\n this.database = options.database\n this.ownsDatabase = false\n this.executionState = getDatabaseExecutionState(this.database)\n this.applyPragmas(options.pragmas ?? DEFAULT_PRAGMAS)\n return\n }\n\n if (options.filename.trim().length === 0) {\n throw new InvalidPersistedCollectionConfigError(\n `Node SQLite driver filename cannot be empty`,\n )\n }\n\n this.database = new BetterSqlite3(options.filename, options.options)\n this.ownsDatabase = true\n this.executionState = getDatabaseExecutionState(this.database)\n this.applyPragmas(options.pragmas ?? DEFAULT_PRAGMAS)\n }\n\n async exec(sql: string): Promise<void> {\n if (this.isInsideTransaction()) {\n this.database.exec(sql)\n return\n }\n\n await this.enqueue(() => {\n this.database.exec(sql)\n })\n }\n\n async query<T>(\n sql: string,\n params: ReadonlyArray<unknown> = [],\n ): Promise<ReadonlyArray<T>> {\n if (this.isInsideTransaction()) {\n return this.executeQuery<T>(sql, params)\n }\n\n return this.enqueue(() => this.executeQuery<T>(sql, params))\n }\n\n async run(sql: string, params: ReadonlyArray<unknown> = []): Promise<void> {\n if (this.isInsideTransaction()) {\n this.executeRun(sql, params)\n return\n }\n\n await this.enqueue(() => {\n this.executeRun(sql, params)\n })\n }\n\n async transaction<T>(\n fn: (transactionDriver: SQLiteDriver) => Promise<T>,\n ): Promise<T> {\n assertTransactionCallbackHasDriverArg(fn)\n\n if (this.isInsideTransaction()) {\n return this.runNestedTransaction(fn)\n }\n\n return this.enqueue(async () => {\n this.database.exec(`BEGIN IMMEDIATE`)\n try {\n const result = await this.executionState.transactionContext.run(\n { depth: 1 },\n async () => fn(this),\n )\n this.database.exec(`COMMIT`)\n return result\n } catch (error) {\n try {\n this.database.exec(`ROLLBACK`)\n } catch {\n // Keep the original transaction error as the primary failure.\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 close(): void {\n if (!this.ownsDatabase) {\n return\n }\n\n this.database.close()\n }\n\n getDatabase(): BetterSqlite3Database {\n return this.database\n }\n\n private applyPragmas(pragmas: ReadonlyArray<string>): void {\n for (const pragma of pragmas) {\n const trimmedPragma = pragma.trim()\n if (trimmedPragma.length === 0) {\n continue\n }\n\n if (INVALID_PRAGMA_PATTERN.test(trimmedPragma)) {\n throw new InvalidPersistedCollectionConfigError(\n `Invalid SQLite PRAGMA: \"${pragma}\"`,\n )\n }\n\n this.database.exec(`PRAGMA ${trimmedPragma}`)\n }\n }\n\n private isInsideTransaction(): boolean {\n return this.executionState.transactionContext.getStore() !== undefined\n }\n\n private executeQuery<T>(\n sql: string,\n params: ReadonlyArray<unknown>,\n ): ReadonlyArray<T> {\n const statement = this.database.prepare(sql)\n if (params.length === 0) {\n return statement.all() as ReadonlyArray<T>\n }\n\n return statement.all(...params) as ReadonlyArray<T>\n }\n\n private executeRun(sql: string, params: ReadonlyArray<unknown>): void {\n const statement = this.database.prepare(sql)\n if (params.length === 0) {\n statement.run()\n return\n }\n\n statement.run(...params)\n }\n\n private enqueue<T>(operation: () => Promise<T> | T): Promise<T> {\n const queuedOperation = this.executionState.queue.then(operation, operation)\n this.executionState.queue = queuedOperation.then(\n () => undefined,\n () => undefined,\n )\n return queuedOperation\n }\n\n private async runNestedTransaction<T>(\n fn: (transactionDriver: SQLiteDriver) => Promise<T>,\n ): Promise<T> {\n const context = this.executionState.transactionContext.getStore()\n if (!context) {\n return fn(this)\n }\n\n const savepointName = `tsdb_sp_${this.executionState.nextSavepointId}`\n this.executionState.nextSavepointId++\n this.database.exec(`SAVEPOINT ${savepointName}`)\n\n try {\n const result = await this.executionState.transactionContext.run(\n { depth: context.depth + 1 },\n async () => fn(this),\n )\n this.database.exec(`RELEASE SAVEPOINT ${savepointName}`)\n return result\n } catch (error) {\n this.database.exec(`ROLLBACK TO SAVEPOINT ${savepointName}`)\n this.database.exec(`RELEASE SAVEPOINT ${savepointName}`)\n throw error\n }\n }\n}\n\nexport function createBetterSqlite3Driver(\n options: BetterSqlite3DriverOptions,\n): BetterSqlite3SQLiteDriver {\n return new BetterSqlite3SQLiteDriver(options)\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"node-driver.js","sources":["../../src/node-driver.ts"],"sourcesContent":["import { AsyncLocalStorage } from 'node:async_hooks'\nimport BetterSqlite3 from 'better-sqlite3'\nimport { InvalidPersistedCollectionConfigError } from '@tanstack/db-sqlite-persistence-core'\nimport type { SQLiteDriver } from '@tanstack/db-sqlite-persistence-core'\n\nconst DEFAULT_PRAGMAS = [\n `journal_mode = WAL`,\n `synchronous = NORMAL`,\n `foreign_keys = ON`,\n] as const\n\nconst INVALID_PRAGMA_PATTERN = /(;|--|\\/\\*)/\n\nexport type BetterSqlite3Database = InstanceType<typeof BetterSqlite3>\nexport type BetterSqlite3OpenOptions = ConstructorParameters<\n typeof BetterSqlite3\n>[1]\n\ntype BetterSqlite3ExistingDatabaseOptions = {\n database: BetterSqlite3Database\n pragmas?: ReadonlyArray<string>\n}\n\ntype BetterSqlite3OpenFileOptions = {\n filename: string\n options?: BetterSqlite3OpenOptions\n pragmas?: ReadonlyArray<string>\n}\n\nexport type BetterSqlite3DriverOptions =\n BetterSqlite3ExistingDatabaseOptions | BetterSqlite3OpenFileOptions\n\ntype TransactionContext = {\n depth: number\n}\n\ntype DatabaseExecutionState = {\n transactionContext: AsyncLocalStorage<TransactionContext>\n queue: Promise<void>\n nextSavepointId: number\n}\n\nconst databaseExecutionStates = new WeakMap<\n BetterSqlite3Database,\n DatabaseExecutionState\n>()\n\nfunction getDatabaseExecutionState(\n database: BetterSqlite3Database,\n): DatabaseExecutionState {\n const existing = databaseExecutionStates.get(database)\n if (existing) {\n return existing\n }\n\n const state: DatabaseExecutionState = {\n transactionContext: new AsyncLocalStorage<TransactionContext>(),\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 hasExistingDatabase(\n options: BetterSqlite3DriverOptions,\n): options is BetterSqlite3ExistingDatabaseOptions {\n return `database` in options\n}\n\nexport class BetterSqlite3SQLiteDriver implements SQLiteDriver {\n private readonly database: BetterSqlite3Database\n private readonly ownsDatabase: boolean\n private readonly executionState: DatabaseExecutionState\n\n constructor(options: BetterSqlite3DriverOptions) {\n if (hasExistingDatabase(options)) {\n this.database = options.database\n this.ownsDatabase = false\n this.executionState = getDatabaseExecutionState(this.database)\n this.applyPragmas(options.pragmas ?? DEFAULT_PRAGMAS)\n return\n }\n\n if (options.filename.trim().length === 0) {\n throw new InvalidPersistedCollectionConfigError(\n `Node SQLite driver filename cannot be empty`,\n )\n }\n\n this.database = new BetterSqlite3(options.filename, options.options)\n this.ownsDatabase = true\n this.executionState = getDatabaseExecutionState(this.database)\n this.applyPragmas(options.pragmas ?? DEFAULT_PRAGMAS)\n }\n\n async exec(sql: string): Promise<void> {\n if (this.isInsideTransaction()) {\n this.database.exec(sql)\n return\n }\n\n await this.enqueue(() => {\n this.database.exec(sql)\n })\n }\n\n async query<T>(\n sql: string,\n params: ReadonlyArray<unknown> = [],\n ): Promise<ReadonlyArray<T>> {\n if (this.isInsideTransaction()) {\n return this.executeQuery<T>(sql, params)\n }\n\n return this.enqueue(() => this.executeQuery<T>(sql, params))\n }\n\n async run(sql: string, params: ReadonlyArray<unknown> = []): Promise<void> {\n if (this.isInsideTransaction()) {\n this.executeRun(sql, params)\n return\n }\n\n await this.enqueue(() => {\n this.executeRun(sql, params)\n })\n }\n\n async transaction<T>(\n fn: (transactionDriver: SQLiteDriver) => Promise<T>,\n ): Promise<T> {\n assertTransactionCallbackHasDriverArg(fn)\n\n if (this.isInsideTransaction()) {\n return this.runNestedTransaction(fn)\n }\n\n return this.enqueue(async () => {\n this.database.exec(`BEGIN IMMEDIATE`)\n try {\n const result = await this.executionState.transactionContext.run(\n { depth: 1 },\n async () => fn(this),\n )\n this.database.exec(`COMMIT`)\n return result\n } catch (error) {\n try {\n this.database.exec(`ROLLBACK`)\n } catch {\n // Keep the original transaction error as the primary failure.\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 close(): void {\n if (!this.ownsDatabase) {\n return\n }\n\n this.database.close()\n }\n\n getDatabase(): BetterSqlite3Database {\n return this.database\n }\n\n private applyPragmas(pragmas: ReadonlyArray<string>): void {\n for (const pragma of pragmas) {\n const trimmedPragma = pragma.trim()\n if (trimmedPragma.length === 0) {\n continue\n }\n\n if (INVALID_PRAGMA_PATTERN.test(trimmedPragma)) {\n throw new InvalidPersistedCollectionConfigError(\n `Invalid SQLite PRAGMA: \"${pragma}\"`,\n )\n }\n\n this.database.exec(`PRAGMA ${trimmedPragma}`)\n }\n }\n\n private isInsideTransaction(): boolean {\n return this.executionState.transactionContext.getStore() !== undefined\n }\n\n private executeQuery<T>(\n sql: string,\n params: ReadonlyArray<unknown>,\n ): ReadonlyArray<T> {\n const statement = this.database.prepare(sql)\n if (params.length === 0) {\n return statement.all() as ReadonlyArray<T>\n }\n\n return statement.all(...params) as ReadonlyArray<T>\n }\n\n private executeRun(sql: string, params: ReadonlyArray<unknown>): void {\n const statement = this.database.prepare(sql)\n if (params.length === 0) {\n statement.run()\n return\n }\n\n statement.run(...params)\n }\n\n private enqueue<T>(operation: () => Promise<T> | T): Promise<T> {\n const queuedOperation = this.executionState.queue.then(operation, operation)\n this.executionState.queue = queuedOperation.then(\n () => undefined,\n () => undefined,\n )\n return queuedOperation\n }\n\n private async runNestedTransaction<T>(\n fn: (transactionDriver: SQLiteDriver) => Promise<T>,\n ): Promise<T> {\n const context = this.executionState.transactionContext.getStore()\n if (!context) {\n return fn(this)\n }\n\n const savepointName = `tsdb_sp_${this.executionState.nextSavepointId}`\n this.executionState.nextSavepointId++\n this.database.exec(`SAVEPOINT ${savepointName}`)\n\n try {\n const result = await this.executionState.transactionContext.run(\n { depth: context.depth + 1 },\n async () => fn(this),\n )\n this.database.exec(`RELEASE SAVEPOINT ${savepointName}`)\n return result\n } catch (error) {\n this.database.exec(`ROLLBACK TO SAVEPOINT ${savepointName}`)\n this.database.exec(`RELEASE SAVEPOINT ${savepointName}`)\n throw error\n }\n }\n}\n"],"names":[],"mappings":"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"}
@@ -28,7 +28,9 @@ function resolveAdapterBaseOptions(options) {
28
28
  return {
29
29
  appliedTxPruneMaxRows: options.appliedTxPruneMaxRows ?? DEFAULT_APPLIED_TX_PRUNE_MAX_ROWS$1,
30
30
  appliedTxPruneMaxAgeSeconds: options.appliedTxPruneMaxAgeSeconds ?? DEFAULT_APPLIED_TX_PRUNE_MAX_AGE_SECONDS$1,
31
- pullSinceReloadThreshold: options.pullSinceReloadThreshold
31
+ pullSinceReloadThreshold: options.pullSinceReloadThreshold,
32
+ cacheGenerationClaimTtlMs: options.cacheGenerationClaimTtlMs,
33
+ now: options.now
32
34
  };
33
35
  }
34
36
  function createNodeSQLitePersistence(options) {
@@ -1 +1 @@
1
- {"version":3,"file":"node-persistence.js","sources":["../../src/node-persistence.ts"],"sourcesContent":["import {\n DEFAULT_APPLIED_TX_PRUNE_MAX_AGE_SECONDS as CORE_DEFAULT_APPLIED_TX_PRUNE_MAX_AGE_SECONDS,\n DEFAULT_APPLIED_TX_PRUNE_MAX_ROWS as CORE_DEFAULT_APPLIED_TX_PRUNE_MAX_ROWS,\n SingleProcessCoordinator,\n createSQLiteCorePersistenceAdapter,\n} from '@tanstack/db-sqlite-persistence-core'\nimport { BetterSqlite3SQLiteDriver } from './node-driver'\nimport type {\n PersistedCollectionCoordinator,\n PersistedCollectionMode,\n PersistedCollectionPersistence,\n SQLiteCoreAdapterOptions,\n SQLiteDriver,\n} from '@tanstack/db-sqlite-persistence-core'\nimport type { BetterSqlite3Database } from './node-driver'\n\nexport type { BetterSqlite3Database } from './node-driver'\n\ntype NodeSQLiteCoreSchemaMismatchPolicy =\n `sync-present-reset` | `sync-absent-error` | `reset`\n\nexport type NodeSQLiteSchemaMismatchPolicy =\n NodeSQLiteCoreSchemaMismatchPolicy | `throw`\n\ntype NodeSQLitePersistenceBaseOptions = Omit<\n SQLiteCoreAdapterOptions,\n `driver` | `schemaVersion` | `schemaMismatchPolicy`\n> & {\n database: BetterSqlite3Database\n pragmas?: ReadonlyArray<string>\n coordinator?: PersistedCollectionCoordinator\n schemaMismatchPolicy?: NodeSQLiteSchemaMismatchPolicy\n}\n\nexport type NodeSQLitePersistenceOptions = NodeSQLitePersistenceBaseOptions\n\n/**\n * Default cap on retained `applied_tx` rows per collection. The log is a\n * replayable cache, so a bounded row count keeps SQLite files from growing\n * without limit. Pass `appliedTxPruneMaxRows: 0` to disable the row cap.\n */\nexport const DEFAULT_APPLIED_TX_PRUNE_MAX_ROWS =\n CORE_DEFAULT_APPLIED_TX_PRUNE_MAX_ROWS\n\n/**\n * Default age backstop for retained `applied_tx` rows, in seconds (24h). Rows\n * older than this are pruned on the next write. Pass\n * `appliedTxPruneMaxAgeSeconds: 0` to disable the age backstop.\n */\nexport const DEFAULT_APPLIED_TX_PRUNE_MAX_AGE_SECONDS =\n CORE_DEFAULT_APPLIED_TX_PRUNE_MAX_AGE_SECONDS\n\nfunction normalizeSchemaMismatchPolicy(\n policy: NodeSQLiteSchemaMismatchPolicy,\n): NodeSQLiteCoreSchemaMismatchPolicy {\n if (policy === `throw`) {\n return `sync-absent-error`\n }\n\n return policy\n}\n\nfunction resolveSchemaMismatchPolicy(\n explicitPolicy: NodeSQLiteSchemaMismatchPolicy | undefined,\n mode: PersistedCollectionMode,\n): NodeSQLiteCoreSchemaMismatchPolicy {\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: NodeSQLiteCoreSchemaMismatchPolicy,\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: NodeSQLitePersistenceOptions,\n): SQLiteDriver {\n return new BetterSqlite3SQLiteDriver({\n database: options.database,\n ...(options.pragmas ? { pragmas: options.pragmas } : {}),\n })\n}\n\nfunction resolveAdapterBaseOptions(\n options: NodeSQLitePersistenceOptions,\n): Omit<\n SQLiteCoreAdapterOptions,\n `driver` | `schemaVersion` | `schemaMismatchPolicy`\n> {\n return {\n appliedTxPruneMaxRows:\n options.appliedTxPruneMaxRows ?? CORE_DEFAULT_APPLIED_TX_PRUNE_MAX_ROWS,\n appliedTxPruneMaxAgeSeconds:\n options.appliedTxPruneMaxAgeSeconds ??\n CORE_DEFAULT_APPLIED_TX_PRUNE_MAX_AGE_SECONDS,\n pullSinceReloadThreshold: options.pullSinceReloadThreshold,\n }\n}\n\n/**\n * Creates a shared SQLite persistence instance that can be reused by many\n * collections on the same database. Collection-specific schema versions are\n * resolved by `persistedCollectionOptions` via `resolvePersistenceForCollection`.\n */\nexport function createNodeSQLitePersistence(\n options: NodeSQLitePersistenceOptions,\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 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 // Backward compatible fallback for older callers.\n resolvePersistenceForMode: (mode) =>\n createCollectionPersistence(mode, undefined),\n }\n}\n"],"names":["CORE_DEFAULT_APPLIED_TX_PRUNE_MAX_ROWS","CORE_DEFAULT_APPLIED_TX_PRUNE_MAX_AGE_SECONDS"],"mappings":";;AAyCO,MAAM,oCACXA;AAOK,MAAM,2CACXC;AAEF,SAAS,8BACP,QACoC;AACpC,MAAI,WAAW,SAAS;AACtB,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEA,SAAS,4BACP,gBACA,MACoC;AACpC,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,IAAI,0BAA0B;AAAA,IACnC,UAAU,QAAQ;AAAA,IAClB,GAAI,QAAQ,UAAU,EAAE,SAAS,QAAQ,QAAA,IAAY,CAAA;AAAA,EAAC,CACvD;AACH;AAEA,SAAS,0BACP,SAIA;AACA,SAAO;AAAA,IACL,uBACE,QAAQ,yBAAyBD;AAAAA,IACnC,6BACE,QAAQ,+BACRC;AAAAA,IACF,0BAA0B,QAAQ;AAAA,EAAA;AAEtC;AAOO,SAAS,4BACd,SACgC;AAChC,QAAM,EAAE,aAAa,qBAAA,IAAyB;AAC9C,QAAM,SAAS,2BAA2B,OAAO;AACjD,QAAM,qBAAqB,0BAA0B,OAAO;AAC5D,QAAM,sBAAsB,eAAe,IAAI,yBAAA;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,UAAU,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,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;AAAA,IAEjD,2BAA2B,CAAC,SAC1B,4BAA4B,MAAM,MAAS;AAAA,EAAA;AAEjD;"}
1
+ {"version":3,"file":"node-persistence.js","sources":["../../src/node-persistence.ts"],"sourcesContent":["import {\n DEFAULT_APPLIED_TX_PRUNE_MAX_AGE_SECONDS as CORE_DEFAULT_APPLIED_TX_PRUNE_MAX_AGE_SECONDS,\n DEFAULT_APPLIED_TX_PRUNE_MAX_ROWS as CORE_DEFAULT_APPLIED_TX_PRUNE_MAX_ROWS,\n SingleProcessCoordinator,\n createSQLiteCorePersistenceAdapter,\n} from '@tanstack/db-sqlite-persistence-core'\nimport { BetterSqlite3SQLiteDriver } from './node-driver'\nimport type {\n PersistedCollectionCoordinator,\n PersistedCollectionMode,\n PersistedCollectionPersistence,\n SQLiteCoreAdapterOptions,\n SQLiteDriver,\n} from '@tanstack/db-sqlite-persistence-core'\nimport type { BetterSqlite3Database } from './node-driver'\n\nexport type { BetterSqlite3Database } from './node-driver'\n\ntype NodeSQLiteCoreSchemaMismatchPolicy =\n `sync-present-reset` | `sync-absent-error` | `reset`\n\nexport type NodeSQLiteSchemaMismatchPolicy =\n NodeSQLiteCoreSchemaMismatchPolicy | `throw`\n\ntype NodeSQLitePersistenceBaseOptions = Omit<\n SQLiteCoreAdapterOptions,\n `driver` | `schemaVersion` | `schemaMismatchPolicy`\n> & {\n database: BetterSqlite3Database\n pragmas?: ReadonlyArray<string>\n coordinator?: PersistedCollectionCoordinator\n schemaMismatchPolicy?: NodeSQLiteSchemaMismatchPolicy\n}\n\nexport type NodeSQLitePersistenceOptions = NodeSQLitePersistenceBaseOptions\n\n/**\n * Default cap on retained `applied_tx` rows per collection. The log is a\n * replayable cache, so a bounded row count keeps SQLite files from growing\n * without limit. Pass `appliedTxPruneMaxRows: 0` to disable the row cap.\n */\nexport const DEFAULT_APPLIED_TX_PRUNE_MAX_ROWS =\n CORE_DEFAULT_APPLIED_TX_PRUNE_MAX_ROWS\n\n/**\n * Default age backstop for retained `applied_tx` rows, in seconds (24h). Rows\n * older than this are pruned on the next write. Pass\n * `appliedTxPruneMaxAgeSeconds: 0` to disable the age backstop.\n */\nexport const DEFAULT_APPLIED_TX_PRUNE_MAX_AGE_SECONDS =\n CORE_DEFAULT_APPLIED_TX_PRUNE_MAX_AGE_SECONDS\n\nfunction normalizeSchemaMismatchPolicy(\n policy: NodeSQLiteSchemaMismatchPolicy,\n): NodeSQLiteCoreSchemaMismatchPolicy {\n if (policy === `throw`) {\n return `sync-absent-error`\n }\n\n return policy\n}\n\nfunction resolveSchemaMismatchPolicy(\n explicitPolicy: NodeSQLiteSchemaMismatchPolicy | undefined,\n mode: PersistedCollectionMode,\n): NodeSQLiteCoreSchemaMismatchPolicy {\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: NodeSQLiteCoreSchemaMismatchPolicy,\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: NodeSQLitePersistenceOptions,\n): SQLiteDriver {\n return new BetterSqlite3SQLiteDriver({\n database: options.database,\n ...(options.pragmas ? { pragmas: options.pragmas } : {}),\n })\n}\n\nfunction resolveAdapterBaseOptions(\n options: NodeSQLitePersistenceOptions,\n): Omit<\n SQLiteCoreAdapterOptions,\n `driver` | `schemaVersion` | `schemaMismatchPolicy`\n> {\n return {\n appliedTxPruneMaxRows:\n options.appliedTxPruneMaxRows ?? CORE_DEFAULT_APPLIED_TX_PRUNE_MAX_ROWS,\n appliedTxPruneMaxAgeSeconds:\n options.appliedTxPruneMaxAgeSeconds ??\n CORE_DEFAULT_APPLIED_TX_PRUNE_MAX_AGE_SECONDS,\n pullSinceReloadThreshold: options.pullSinceReloadThreshold,\n cacheGenerationClaimTtlMs: options.cacheGenerationClaimTtlMs,\n now: options.now,\n }\n}\n\n/**\n * Creates a shared SQLite persistence instance that can be reused by many\n * collections on the same database. Collection-specific schema versions are\n * resolved by `persistedCollectionOptions` via `resolvePersistenceForCollection`.\n */\nexport function createNodeSQLitePersistence(\n options: NodeSQLitePersistenceOptions,\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 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 // Backward compatible fallback for older callers.\n resolvePersistenceForMode: (mode) =>\n createCollectionPersistence(mode, undefined),\n }\n}\n"],"names":["CORE_DEFAULT_APPLIED_TX_PRUNE_MAX_ROWS","CORE_DEFAULT_APPLIED_TX_PRUNE_MAX_AGE_SECONDS"],"mappings":";;AAyCO,MAAM,oCACXA;AAOK,MAAM,2CACXC;AAEF,SAAS,8BACP,QACoC;AACpC,MAAI,WAAW,SAAS;AACtB,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEA,SAAS,4BACP,gBACA,MACoC;AACpC,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,IAAI,0BAA0B;AAAA,IACnC,UAAU,QAAQ;AAAA,IAClB,GAAI,QAAQ,UAAU,EAAE,SAAS,QAAQ,QAAA,IAAY,CAAA;AAAA,EAAC,CACvD;AACH;AAEA,SAAS,0BACP,SAIA;AACA,SAAO;AAAA,IACL,uBACE,QAAQ,yBAAyBD;AAAAA,IACnC,6BACE,QAAQ,+BACRC;AAAAA,IACF,0BAA0B,QAAQ;AAAA,IAClC,2BAA2B,QAAQ;AAAA,IACnC,KAAK,QAAQ;AAAA,EAAA;AAEjB;AAOO,SAAS,4BACd,SACgC;AAChC,QAAM,EAAE,aAAa,qBAAA,IAAyB;AAC9C,QAAM,SAAS,2BAA2B,OAAO;AACjD,QAAM,qBAAqB,0BAA0B,OAAO;AAC5D,QAAM,sBAAsB,eAAe,IAAI,yBAAA;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,UAAU,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,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;AAAA,IAEjD,2BAA2B,CAAC,SAC1B,4BAA4B,MAAM,MAAS;AAAA,EAAA;AAEjD;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/node-db-sqlite-persistence",
3
- "version": "0.2.32",
3
+ "version": "0.2.34",
4
4
  "description": "Node SQLite persisted collection adapter for TanStack DB",
5
5
  "author": "TanStack Team",
6
6
  "license": "MIT",
@@ -41,7 +41,7 @@
41
41
  ],
42
42
  "dependencies": {
43
43
  "better-sqlite3": "^12.6.2",
44
- "@tanstack/db-sqlite-persistence-core": "0.4.7"
44
+ "@tanstack/db-sqlite-persistence-core": "0.4.9"
45
45
  },
46
46
  "peerDependencies": {
47
47
  "typescript": ">=4.7"
@@ -264,9 +264,3 @@ export class BetterSqlite3SQLiteDriver implements SQLiteDriver {
264
264
  }
265
265
  }
266
266
  }
267
-
268
- export function createBetterSqlite3Driver(
269
- options: BetterSqlite3DriverOptions,
270
- ): BetterSqlite3SQLiteDriver {
271
- return new BetterSqlite3SQLiteDriver(options)
272
- }
@@ -102,6 +102,8 @@ function resolveAdapterBaseOptions(
102
102
  options.appliedTxPruneMaxAgeSeconds ??
103
103
  CORE_DEFAULT_APPLIED_TX_PRUNE_MAX_AGE_SECONDS,
104
104
  pullSinceReloadThreshold: options.pullSinceReloadThreshold,
105
+ cacheGenerationClaimTtlMs: options.cacheGenerationClaimTtlMs,
106
+ now: options.now,
105
107
  }
106
108
  }
107
109