@tanstack/cloudflare-durable-objects-db-sqlite-persistence 0.2.28 → 0.2.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/do-driver.cjs +1 -0
- package/dist/cjs/do-driver.cjs.map +1 -1
- package/dist/cjs/do-persistence.cjs.map +1 -1
- package/dist/esm/do-driver.js +1 -0
- package/dist/esm/do-driver.js.map +1 -1
- package/dist/esm/do-persistence.js +1 -1
- package/dist/esm/do-persistence.js.map +1 -1
- package/package.json +2 -2
- package/src/do-driver.ts +2 -2
- package/src/do-persistence.ts +2 -5
package/dist/cjs/do-driver.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"do-driver.cjs","sources":["../../src/do-driver.ts"],"sourcesContent":["import { InvalidPersistedCollectionConfigError } from '@tanstack/db-sqlite-persistence-core'\nimport type { SQLiteDriver } from '@tanstack/db-sqlite-persistence-core'\n\ntype DurableObjectSqlRow = Record<string, unknown>\n\ntype DurableObjectSqlCursorLike = Iterable<DurableObjectSqlRow> & {\n toArray?: () => Array<DurableObjectSqlRow>\n}\n\nexport type DurableObjectSqlStorageLike = {\n exec: (\n sql: string,\n ...params: ReadonlyArray<unknown>\n ) => DurableObjectSqlCursorLike | ReadonlyArray<DurableObjectSqlRow> | null\n}\n\nexport type DurableObjectTransactionExecutor = <T>(\n fn: () => Promise<T>,\n) => Promise<T>\n\nexport type DurableObjectStorageLike = {\n sql: DurableObjectSqlStorageLike\n transaction?: DurableObjectTransactionExecutor\n}\n\ntype CloudflareDOProvidedSqlOptions = {\n sql: DurableObjectSqlStorageLike\n transaction?: DurableObjectTransactionExecutor\n}\n\ntype CloudflareDOProvidedStorageOptions = {\n storage: DurableObjectStorageLike\n}\n\nexport type CloudflareDOSQLiteDriverOptions =\n | CloudflareDOProvidedSqlOptions\n | CloudflareDOProvidedStorageOptions\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 isIterableRecord(\n value: unknown,\n): value is Iterable<DurableObjectSqlRow> {\n if (!value || typeof value !== `object`) {\n return false\n }\n\n const iterator = (value as { [Symbol.iterator]?: unknown })[Symbol.iterator]\n return typeof iterator === `function`\n}\n\nfunction toRowArray<T>(\n result: ReturnType<DurableObjectSqlStorageLike[`exec`]>,\n sql: string,\n): ReadonlyArray<T> {\n if (result == null) {\n return []\n }\n\n if (Array.isArray(result)) {\n return result as ReadonlyArray<T>\n }\n\n const cursorResult = result as DurableObjectSqlCursorLike\n if (typeof cursorResult.toArray === `function`) {\n return cursorResult.toArray() as ReadonlyArray<T>\n }\n\n if (isIterableRecord(cursorResult)) {\n return Array.from(cursorResult as Iterable<T>)\n }\n\n throw new InvalidPersistedCollectionConfigError(\n `Unsupported Durable Object SQL result shape for query \"${sql}\"`,\n )\n}\n\nexport class CloudflareDOSQLiteDriver implements SQLiteDriver {\n // https://developers.cloudflare.com/durable-objects/platform/limits/\n // Durable Object SQL storage permits at most 100 bound parameters per query.\n readonly maxBoundParameters = 100\n private readonly sqlStorage: DurableObjectSqlStorageLike\n private readonly storage: DurableObjectStorageLike\n private readonly transactionExecutor: DurableObjectTransactionExecutor | null\n private queue: Promise<void> = Promise.resolve()\n private nextSavepointId = 1\n\n constructor(options: CloudflareDOSQLiteDriverOptions) {\n const resolvedStorage: DurableObjectStorageLike =\n `storage` in options\n ? options.storage\n : {\n sql: options.sql,\n ...(typeof options.transaction === `function`\n ? { transaction: options.transaction }\n : {}),\n }\n const resolvedSqlStorage = resolvedStorage.sql\n if (typeof resolvedSqlStorage.exec !== `function`) {\n throw new InvalidPersistedCollectionConfigError(\n `Cloudflare DO SQL driver requires a sql.exec function`,\n )\n }\n this.storage = resolvedStorage\n this.sqlStorage = resolvedSqlStorage\n if (typeof resolvedStorage.transaction === `function`) {\n const transactionMethod = resolvedStorage.transaction\n this.transactionExecutor = <T>(fn: () => Promise<T>) =>\n Promise.resolve(\n transactionMethod.call(resolvedStorage, fn) as Promise<T> | T,\n )\n } else {\n this.transactionExecutor = null\n }\n }\n\n async exec(sql: string): Promise<void> {\n await this.enqueue(() => {\n this.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.executeQuery<T>(sql, params))\n }\n\n async run(sql: string, params: ReadonlyArray<unknown> = []): Promise<void> {\n await this.enqueue(() => {\n this.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 const transactionDriver = this.createTransactionDriver()\n if (this.transactionExecutor) {\n return this.transactionExecutor(() => fn(transactionDriver))\n }\n\n this.execute(`BEGIN IMMEDIATE`)\n try {\n const result = await fn(transactionDriver)\n this.execute(`COMMIT`)\n return result\n } catch (error) {\n try {\n this.execute(`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 getStorage(): DurableObjectStorageLike {\n return this.storage\n }\n\n private execute(sql: string, params: ReadonlyArray<unknown> = []): unknown {\n return this.sqlStorage.exec(sql, ...params)\n }\n\n private executeQuery<T>(\n sql: string,\n params: ReadonlyArray<unknown>,\n ): ReadonlyArray<T> {\n const result = this.execute(sql, params)\n return toRowArray<T>(\n result as ReturnType<DurableObjectSqlStorageLike[`exec`]>,\n sql,\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 private createTransactionDriver(): SQLiteDriver {\n const transactionDriver: SQLiteDriver = {\n exec: (sql) => {\n this.execute(sql)\n return Promise.resolve()\n },\n query: <T>(\n sql: string,\n params: ReadonlyArray<unknown> = [],\n ): Promise<ReadonlyArray<T>> =>\n Promise.resolve(this.executeQuery<T>(sql, params)),\n run: (sql, params = []) => {\n this.execute(sql, params)\n return Promise.resolve()\n },\n transaction: <T>(\n fn: (nestedDriver: SQLiteDriver) => Promise<T>,\n ): Promise<T> => {\n assertTransactionCallbackHasDriverArg(fn)\n return this.runNestedTransaction(transactionDriver, fn)\n },\n transactionWithDriver: <T>(\n fn: (nestedDriver: SQLiteDriver) => Promise<T>,\n ): Promise<T> => this.runNestedTransaction(transactionDriver, fn),\n }\n\n return transactionDriver\n }\n\n private async runNestedTransaction<T>(\n transactionDriver: SQLiteDriver,\n fn: (nestedDriver: SQLiteDriver) => Promise<T>,\n ): Promise<T> {\n if (this.transactionExecutor) {\n throw new InvalidPersistedCollectionConfigError(\n `Nested SQL savepoints are not supported when using Durable Object transaction API`,\n )\n }\n\n const savepointName = `tsdb_sp_${this.nextSavepointId}`\n this.nextSavepointId++\n this.execute(`SAVEPOINT ${savepointName}`)\n\n try {\n const result = await fn(transactionDriver)\n this.execute(`RELEASE SAVEPOINT ${savepointName}`)\n return result\n } catch (error) {\n this.execute(`ROLLBACK TO SAVEPOINT ${savepointName}`)\n this.execute(`RELEASE SAVEPOINT ${savepointName}`)\n throw error\n }\n }\n}\n\nexport function createCloudflareDOSQLiteDriver(\n options: CloudflareDOSQLiteDriverOptions,\n): CloudflareDOSQLiteDriver {\n return new CloudflareDOSQLiteDriver(options)\n}\n"],"names":["InvalidPersistedCollectionConfigError"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"do-driver.cjs","sources":["../../src/do-driver.ts"],"sourcesContent":["import { InvalidPersistedCollectionConfigError } from '@tanstack/db-sqlite-persistence-core'\nimport type { SQLiteDriver } from '@tanstack/db-sqlite-persistence-core'\n\ntype DurableObjectSqlRow = Record<string, unknown>\n\ntype DurableObjectSqlCursorLike = Iterable<DurableObjectSqlRow> & {\n toArray?: () => Array<DurableObjectSqlRow>\n}\n\nexport type DurableObjectSqlStorageLike = {\n exec: (\n sql: string,\n ...params: ReadonlyArray<unknown>\n ) => DurableObjectSqlCursorLike | ReadonlyArray<DurableObjectSqlRow> | null\n}\n\nexport type DurableObjectTransactionExecutor = <T>(\n fn: () => Promise<T>,\n) => Promise<T>\n\nexport type DurableObjectStorageLike = {\n sql: DurableObjectSqlStorageLike\n transaction?: DurableObjectTransactionExecutor\n}\n\ntype CloudflareDOProvidedSqlOptions = {\n sql: DurableObjectSqlStorageLike\n transaction?: DurableObjectTransactionExecutor\n}\n\ntype CloudflareDOProvidedStorageOptions = {\n storage: DurableObjectStorageLike\n}\n\nexport type CloudflareDOSQLiteDriverOptions =\n CloudflareDOProvidedSqlOptions | CloudflareDOProvidedStorageOptions\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 isIterableRecord(\n value: unknown,\n): value is Iterable<DurableObjectSqlRow> {\n if (!value || typeof value !== `object`) {\n return false\n }\n\n const iterator = (value as { [Symbol.iterator]?: unknown })[Symbol.iterator]\n return typeof iterator === `function`\n}\n\nfunction toRowArray<T>(\n result: ReturnType<DurableObjectSqlStorageLike[`exec`]>,\n sql: string,\n): ReadonlyArray<T> {\n if (result == null) {\n return []\n }\n\n if (Array.isArray(result)) {\n return result as ReadonlyArray<T>\n }\n\n const cursorResult = result as DurableObjectSqlCursorLike\n if (typeof cursorResult.toArray === `function`) {\n return cursorResult.toArray() as ReadonlyArray<T>\n }\n\n if (isIterableRecord(cursorResult)) {\n return Array.from(cursorResult as Iterable<T>)\n }\n\n throw new InvalidPersistedCollectionConfigError(\n `Unsupported Durable Object SQL result shape for query \"${sql}\"`,\n )\n}\n\nexport class CloudflareDOSQLiteDriver implements SQLiteDriver {\n // https://developers.cloudflare.com/durable-objects/platform/limits/\n // Durable Object SQL storage permits at most 100 bound parameters per query.\n readonly maxBoundParameters = 100\n private readonly sqlStorage: DurableObjectSqlStorageLike\n private readonly storage: DurableObjectStorageLike\n private readonly transactionExecutor: DurableObjectTransactionExecutor | null\n private queue: Promise<void> = Promise.resolve()\n private nextSavepointId = 1\n\n constructor(options: CloudflareDOSQLiteDriverOptions) {\n const resolvedStorage: DurableObjectStorageLike =\n `storage` in options\n ? options.storage\n : {\n sql: options.sql,\n ...(typeof options.transaction === `function`\n ? { transaction: options.transaction }\n : {}),\n }\n const resolvedSqlStorage = resolvedStorage.sql\n if (typeof resolvedSqlStorage.exec !== `function`) {\n throw new InvalidPersistedCollectionConfigError(\n `Cloudflare DO SQL driver requires a sql.exec function`,\n )\n }\n this.storage = resolvedStorage\n this.sqlStorage = resolvedSqlStorage\n if (typeof resolvedStorage.transaction === `function`) {\n const transactionMethod = resolvedStorage.transaction\n this.transactionExecutor = <T>(fn: () => Promise<T>) =>\n Promise.resolve(\n transactionMethod.call(resolvedStorage, fn) as Promise<T> | T,\n )\n } else {\n this.transactionExecutor = null\n }\n }\n\n async exec(sql: string): Promise<void> {\n await this.enqueue(() => {\n this.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.executeQuery<T>(sql, params))\n }\n\n async run(sql: string, params: ReadonlyArray<unknown> = []): Promise<void> {\n await this.enqueue(() => {\n this.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 const transactionDriver = this.createTransactionDriver()\n if (this.transactionExecutor) {\n return this.transactionExecutor(() => fn(transactionDriver))\n }\n\n this.execute(`BEGIN IMMEDIATE`)\n try {\n const result = await fn(transactionDriver)\n this.execute(`COMMIT`)\n return result\n } catch (error) {\n try {\n this.execute(`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 getStorage(): DurableObjectStorageLike {\n return this.storage\n }\n\n private execute(sql: string, params: ReadonlyArray<unknown> = []): unknown {\n return this.sqlStorage.exec(sql, ...params)\n }\n\n private executeQuery<T>(\n sql: string,\n params: ReadonlyArray<unknown>,\n ): ReadonlyArray<T> {\n const result = this.execute(sql, params)\n return toRowArray<T>(\n result as ReturnType<DurableObjectSqlStorageLike[`exec`]>,\n sql,\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 private createTransactionDriver(): SQLiteDriver {\n const transactionDriver: SQLiteDriver = {\n maxBoundParameters: this.maxBoundParameters,\n exec: (sql) => {\n this.execute(sql)\n return Promise.resolve()\n },\n query: <T>(\n sql: string,\n params: ReadonlyArray<unknown> = [],\n ): Promise<ReadonlyArray<T>> =>\n Promise.resolve(this.executeQuery<T>(sql, params)),\n run: (sql, params = []) => {\n this.execute(sql, params)\n return Promise.resolve()\n },\n transaction: <T>(\n fn: (nestedDriver: SQLiteDriver) => Promise<T>,\n ): Promise<T> => {\n assertTransactionCallbackHasDriverArg(fn)\n return this.runNestedTransaction(transactionDriver, fn)\n },\n transactionWithDriver: <T>(\n fn: (nestedDriver: SQLiteDriver) => Promise<T>,\n ): Promise<T> => this.runNestedTransaction(transactionDriver, fn),\n }\n\n return transactionDriver\n }\n\n private async runNestedTransaction<T>(\n transactionDriver: SQLiteDriver,\n fn: (nestedDriver: SQLiteDriver) => Promise<T>,\n ): Promise<T> {\n if (this.transactionExecutor) {\n throw new InvalidPersistedCollectionConfigError(\n `Nested SQL savepoints are not supported when using Durable Object transaction API`,\n )\n }\n\n const savepointName = `tsdb_sp_${this.nextSavepointId}`\n this.nextSavepointId++\n this.execute(`SAVEPOINT ${savepointName}`)\n\n try {\n const result = await fn(transactionDriver)\n this.execute(`RELEASE SAVEPOINT ${savepointName}`)\n return result\n } catch (error) {\n this.execute(`ROLLBACK TO SAVEPOINT ${savepointName}`)\n this.execute(`RELEASE SAVEPOINT ${savepointName}`)\n throw error\n }\n }\n}\n\nexport function createCloudflareDOSQLiteDriver(\n options: CloudflareDOSQLiteDriverOptions,\n): CloudflareDOSQLiteDriver {\n return new CloudflareDOSQLiteDriver(options)\n}\n"],"names":["InvalidPersistedCollectionConfigError"],"mappings":";;;AAqCA,SAAS,sCACP,IACM;AACN,MAAI,GAAG,SAAS,GAAG;AACjB;AAAA,EACF;AAEA,QAAM,IAAIA,wBAAAA;AAAAA,IACR;AAAA,EAAA;AAEJ;AAEA,SAAS,iBACP,OACwC;AACxC,MAAI,CAAC,SAAS,OAAO,UAAU,UAAU;AACvC,WAAO;AAAA,EACT;AAEA,QAAM,WAAY,MAA0C,OAAO,QAAQ;AAC3E,SAAO,OAAO,aAAa;AAC7B;AAEA,SAAS,WACP,QACA,KACkB;AAClB,MAAI,UAAU,MAAM;AAClB,WAAO,CAAA;AAAA,EACT;AAEA,MAAI,MAAM,QAAQ,MAAM,GAAG;AACzB,WAAO;AAAA,EACT;AAEA,QAAM,eAAe;AACrB,MAAI,OAAO,aAAa,YAAY,YAAY;AAC9C,WAAO,aAAa,QAAA;AAAA,EACtB;AAEA,MAAI,iBAAiB,YAAY,GAAG;AAClC,WAAO,MAAM,KAAK,YAA2B;AAAA,EAC/C;AAEA,QAAM,IAAIA,wBAAAA;AAAAA,IACR,0DAA0D,GAAG;AAAA,EAAA;AAEjE;AAEO,MAAM,yBAAiD;AAAA,EAU5D,YAAY,SAA0C;AAPtD,SAAS,qBAAqB;AAI9B,SAAQ,QAAuB,QAAQ,QAAA;AACvC,SAAQ,kBAAkB;AAGxB,UAAM,kBACJ,aAAa,UACT,QAAQ,UACR;AAAA,MACE,KAAK,QAAQ;AAAA,MACb,GAAI,OAAO,QAAQ,gBAAgB,aAC/B,EAAE,aAAa,QAAQ,gBACvB,CAAA;AAAA,IAAC;AAEb,UAAM,qBAAqB,gBAAgB;AAC3C,QAAI,OAAO,mBAAmB,SAAS,YAAY;AACjD,YAAM,IAAIA,wBAAAA;AAAAA,QACR;AAAA,MAAA;AAAA,IAEJ;AACA,SAAK,UAAU;AACf,SAAK,aAAa;AAClB,QAAI,OAAO,gBAAgB,gBAAgB,YAAY;AACrD,YAAM,oBAAoB,gBAAgB;AAC1C,WAAK,sBAAsB,CAAI,OAC7B,QAAQ;AAAA,QACN,kBAAkB,KAAK,iBAAiB,EAAE;AAAA,MAAA;AAAA,IAEhD,OAAO;AACL,WAAK,sBAAsB;AAAA,IAC7B;AAAA,EACF;AAAA,EAEA,MAAM,KAAK,KAA4B;AACrC,UAAM,KAAK,QAAQ,MAAM;AACvB,WAAK,QAAQ,GAAG;AAAA,IAClB,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,MACJ,KACA,SAAiC,IACN;AAC3B,WAAO,KAAK,QAAQ,MAAM,KAAK,aAAgB,KAAK,MAAM,CAAC;AAAA,EAC7D;AAAA,EAEA,MAAM,IAAI,KAAa,SAAiC,IAAmB;AACzE,UAAM,KAAK,QAAQ,MAAM;AACvB,WAAK,QAAQ,KAAK,MAAM;AAAA,IAC1B,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,YACJ,IACY;AACZ,0CAAsC,EAAE;AAExC,WAAO,KAAK,QAAQ,YAAY;AAC9B,YAAM,oBAAoB,KAAK,wBAAA;AAC/B,UAAI,KAAK,qBAAqB;AAC5B,eAAO,KAAK,oBAAoB,MAAM,GAAG,iBAAiB,CAAC;AAAA,MAC7D;AAEA,WAAK,QAAQ,iBAAiB;AAC9B,UAAI;AACF,cAAM,SAAS,MAAM,GAAG,iBAAiB;AACzC,aAAK,QAAQ,QAAQ;AACrB,eAAO;AAAA,MACT,SAAS,OAAO;AACd,YAAI;AACF,eAAK,QAAQ,UAAU;AAAA,QACzB,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,aAAuC;AACrC,WAAO,KAAK;AAAA,EACd;AAAA,EAEQ,QAAQ,KAAa,SAAiC,IAAa;AACzE,WAAO,KAAK,WAAW,KAAK,KAAK,GAAG,MAAM;AAAA,EAC5C;AAAA,EAEQ,aACN,KACA,QACkB;AAClB,UAAM,SAAS,KAAK,QAAQ,KAAK,MAAM;AACvC,WAAO;AAAA,MACL;AAAA,MACA;AAAA,IAAA;AAAA,EAEJ;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;AAAA,EAEQ,0BAAwC;AAC9C,UAAM,oBAAkC;AAAA,MACtC,oBAAoB,KAAK;AAAA,MACzB,MAAM,CAAC,QAAQ;AACb,aAAK,QAAQ,GAAG;AAChB,eAAO,QAAQ,QAAA;AAAA,MACjB;AAAA,MACA,OAAO,CACL,KACA,SAAiC,OAEjC,QAAQ,QAAQ,KAAK,aAAgB,KAAK,MAAM,CAAC;AAAA,MACnD,KAAK,CAAC,KAAK,SAAS,OAAO;AACzB,aAAK,QAAQ,KAAK,MAAM;AACxB,eAAO,QAAQ,QAAA;AAAA,MACjB;AAAA,MACA,aAAa,CACX,OACe;AACf,8CAAsC,EAAE;AACxC,eAAO,KAAK,qBAAqB,mBAAmB,EAAE;AAAA,MACxD;AAAA,MACA,uBAAuB,CACrB,OACe,KAAK,qBAAqB,mBAAmB,EAAE;AAAA,IAAA;AAGlE,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,qBACZ,mBACA,IACY;AACZ,QAAI,KAAK,qBAAqB;AAC5B,YAAM,IAAIA,wBAAAA;AAAAA,QACR;AAAA,MAAA;AAAA,IAEJ;AAEA,UAAM,gBAAgB,WAAW,KAAK,eAAe;AACrD,SAAK;AACL,SAAK,QAAQ,aAAa,aAAa,EAAE;AAEzC,QAAI;AACF,YAAM,SAAS,MAAM,GAAG,iBAAiB;AACzC,WAAK,QAAQ,qBAAqB,aAAa,EAAE;AACjD,aAAO;AAAA,IACT,SAAS,OAAO;AACd,WAAK,QAAQ,yBAAyB,aAAa,EAAE;AACrD,WAAK,QAAQ,qBAAqB,aAAa,EAAE;AACjD,YAAM;AAAA,IACR;AAAA,EACF;AACF;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"do-persistence.cjs","sources":["../../src/do-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 { CloudflareDOSQLiteDriver } from './do-driver'\nimport type {\n PersistedCollectionCoordinator,\n PersistedCollectionMode,\n PersistedCollectionPersistence,\n SQLiteCoreAdapterOptions,\n SQLiteDriver,\n} from '@tanstack/db-sqlite-persistence-core'\nimport type { DurableObjectStorageLike } from './do-driver'\n\nexport type { DurableObjectStorageLike } from './do-driver'\n\ntype CloudflareDOCoreSchemaMismatchPolicy =\n
|
|
1
|
+
{"version":3,"file":"do-persistence.cjs","sources":["../../src/do-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 { CloudflareDOSQLiteDriver } from './do-driver'\nimport type {\n PersistedCollectionCoordinator,\n PersistedCollectionMode,\n PersistedCollectionPersistence,\n SQLiteCoreAdapterOptions,\n SQLiteDriver,\n} from '@tanstack/db-sqlite-persistence-core'\nimport type { DurableObjectStorageLike } from './do-driver'\n\nexport type { DurableObjectStorageLike } from './do-driver'\n\ntype CloudflareDOCoreSchemaMismatchPolicy =\n `sync-present-reset` | `sync-absent-error` | `reset`\n\nexport type CloudflareDOSchemaMismatchPolicy =\n CloudflareDOCoreSchemaMismatchPolicy | `throw`\n\ntype CloudflareDOSQLitePersistenceBaseOptions = Omit<\n SQLiteCoreAdapterOptions,\n `driver` | `schemaVersion` | `schemaMismatchPolicy`\n> & {\n storage: DurableObjectStorageLike\n coordinator?: PersistedCollectionCoordinator\n schemaMismatchPolicy?: CloudflareDOSchemaMismatchPolicy\n}\n\nexport type CloudflareDOSQLitePersistenceOptions =\n CloudflareDOSQLitePersistenceBaseOptions\n\nfunction normalizeSchemaMismatchPolicy(\n policy: CloudflareDOSchemaMismatchPolicy,\n): CloudflareDOCoreSchemaMismatchPolicy {\n if (policy === `throw`) {\n return `sync-absent-error`\n }\n return policy\n}\n\nfunction resolveSchemaMismatchPolicy(\n explicitPolicy: CloudflareDOSchemaMismatchPolicy | undefined,\n mode: PersistedCollectionMode,\n): CloudflareDOCoreSchemaMismatchPolicy {\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: CloudflareDOCoreSchemaMismatchPolicy,\n schemaVersion: number | undefined,\n): string {\n const schemaVersionKey =\n schemaVersion === undefined ? `schema:default` : `schema:${schemaVersion}`\n return `${schemaMismatchPolicy}|${schemaVersionKey}`\n}\n\nfunction resolveSQLiteDriver(\n options: CloudflareDOSQLitePersistenceOptions,\n): SQLiteDriver {\n return new CloudflareDOSQLiteDriver({\n storage: options.storage,\n })\n}\n\nfunction resolveAdapterBaseOptions(\n options: CloudflareDOSQLitePersistenceOptions,\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 Durable Object SQLite persistence instance that can be reused\n * by many collections in a single Durable Object storage.\n */\nexport function createCloudflareDOSQLitePersistence(\n options: CloudflareDOSQLitePersistenceOptions,\n): PersistedCollectionPersistence {\n const { coordinator, schemaMismatchPolicy } = options\n const driver = resolveSQLiteDriver(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":["CloudflareDOSQLiteDriver","DEFAULT_APPLIED_TX_PRUNE_MAX_ROWS","DEFAULT_APPLIED_TX_PRUNE_MAX_AGE_SECONDS","SingleProcessCoordinator","createSQLiteCorePersistenceAdapter"],"mappings":";;;;AAoCA,SAAS,8BACP,QACsC;AACtC,MAAI,WAAW,SAAS;AACtB,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEA,SAAS,4BACP,gBACA,MACsC;AACtC,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,oBACP,SACc;AACd,SAAO,IAAIA,SAAAA,yBAAyB;AAAA,IAClC,SAAS,QAAQ;AAAA,EAAA,CAClB;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;AAMO,SAAS,oCACd,SACgC;AAChC,QAAM,EAAE,aAAa,qBAAA,IAAyB;AAC9C,QAAM,SAAS,oBAAoB,OAAO;AAC1C,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,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/dist/esm/do-driver.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"do-driver.js","sources":["../../src/do-driver.ts"],"sourcesContent":["import { InvalidPersistedCollectionConfigError } from '@tanstack/db-sqlite-persistence-core'\nimport type { SQLiteDriver } from '@tanstack/db-sqlite-persistence-core'\n\ntype DurableObjectSqlRow = Record<string, unknown>\n\ntype DurableObjectSqlCursorLike = Iterable<DurableObjectSqlRow> & {\n toArray?: () => Array<DurableObjectSqlRow>\n}\n\nexport type DurableObjectSqlStorageLike = {\n exec: (\n sql: string,\n ...params: ReadonlyArray<unknown>\n ) => DurableObjectSqlCursorLike | ReadonlyArray<DurableObjectSqlRow> | null\n}\n\nexport type DurableObjectTransactionExecutor = <T>(\n fn: () => Promise<T>,\n) => Promise<T>\n\nexport type DurableObjectStorageLike = {\n sql: DurableObjectSqlStorageLike\n transaction?: DurableObjectTransactionExecutor\n}\n\ntype CloudflareDOProvidedSqlOptions = {\n sql: DurableObjectSqlStorageLike\n transaction?: DurableObjectTransactionExecutor\n}\n\ntype CloudflareDOProvidedStorageOptions = {\n storage: DurableObjectStorageLike\n}\n\nexport type CloudflareDOSQLiteDriverOptions =\n | CloudflareDOProvidedSqlOptions\n | CloudflareDOProvidedStorageOptions\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 isIterableRecord(\n value: unknown,\n): value is Iterable<DurableObjectSqlRow> {\n if (!value || typeof value !== `object`) {\n return false\n }\n\n const iterator = (value as { [Symbol.iterator]?: unknown })[Symbol.iterator]\n return typeof iterator === `function`\n}\n\nfunction toRowArray<T>(\n result: ReturnType<DurableObjectSqlStorageLike[`exec`]>,\n sql: string,\n): ReadonlyArray<T> {\n if (result == null) {\n return []\n }\n\n if (Array.isArray(result)) {\n return result as ReadonlyArray<T>\n }\n\n const cursorResult = result as DurableObjectSqlCursorLike\n if (typeof cursorResult.toArray === `function`) {\n return cursorResult.toArray() as ReadonlyArray<T>\n }\n\n if (isIterableRecord(cursorResult)) {\n return Array.from(cursorResult as Iterable<T>)\n }\n\n throw new InvalidPersistedCollectionConfigError(\n `Unsupported Durable Object SQL result shape for query \"${sql}\"`,\n )\n}\n\nexport class CloudflareDOSQLiteDriver implements SQLiteDriver {\n // https://developers.cloudflare.com/durable-objects/platform/limits/\n // Durable Object SQL storage permits at most 100 bound parameters per query.\n readonly maxBoundParameters = 100\n private readonly sqlStorage: DurableObjectSqlStorageLike\n private readonly storage: DurableObjectStorageLike\n private readonly transactionExecutor: DurableObjectTransactionExecutor | null\n private queue: Promise<void> = Promise.resolve()\n private nextSavepointId = 1\n\n constructor(options: CloudflareDOSQLiteDriverOptions) {\n const resolvedStorage: DurableObjectStorageLike =\n `storage` in options\n ? options.storage\n : {\n sql: options.sql,\n ...(typeof options.transaction === `function`\n ? { transaction: options.transaction }\n : {}),\n }\n const resolvedSqlStorage = resolvedStorage.sql\n if (typeof resolvedSqlStorage.exec !== `function`) {\n throw new InvalidPersistedCollectionConfigError(\n `Cloudflare DO SQL driver requires a sql.exec function`,\n )\n }\n this.storage = resolvedStorage\n this.sqlStorage = resolvedSqlStorage\n if (typeof resolvedStorage.transaction === `function`) {\n const transactionMethod = resolvedStorage.transaction\n this.transactionExecutor = <T>(fn: () => Promise<T>) =>\n Promise.resolve(\n transactionMethod.call(resolvedStorage, fn) as Promise<T> | T,\n )\n } else {\n this.transactionExecutor = null\n }\n }\n\n async exec(sql: string): Promise<void> {\n await this.enqueue(() => {\n this.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.executeQuery<T>(sql, params))\n }\n\n async run(sql: string, params: ReadonlyArray<unknown> = []): Promise<void> {\n await this.enqueue(() => {\n this.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 const transactionDriver = this.createTransactionDriver()\n if (this.transactionExecutor) {\n return this.transactionExecutor(() => fn(transactionDriver))\n }\n\n this.execute(`BEGIN IMMEDIATE`)\n try {\n const result = await fn(transactionDriver)\n this.execute(`COMMIT`)\n return result\n } catch (error) {\n try {\n this.execute(`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 getStorage(): DurableObjectStorageLike {\n return this.storage\n }\n\n private execute(sql: string, params: ReadonlyArray<unknown> = []): unknown {\n return this.sqlStorage.exec(sql, ...params)\n }\n\n private executeQuery<T>(\n sql: string,\n params: ReadonlyArray<unknown>,\n ): ReadonlyArray<T> {\n const result = this.execute(sql, params)\n return toRowArray<T>(\n result as ReturnType<DurableObjectSqlStorageLike[`exec`]>,\n sql,\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 private createTransactionDriver(): SQLiteDriver {\n const transactionDriver: SQLiteDriver = {\n exec: (sql) => {\n this.execute(sql)\n return Promise.resolve()\n },\n query: <T>(\n sql: string,\n params: ReadonlyArray<unknown> = [],\n ): Promise<ReadonlyArray<T>> =>\n Promise.resolve(this.executeQuery<T>(sql, params)),\n run: (sql, params = []) => {\n this.execute(sql, params)\n return Promise.resolve()\n },\n transaction: <T>(\n fn: (nestedDriver: SQLiteDriver) => Promise<T>,\n ): Promise<T> => {\n assertTransactionCallbackHasDriverArg(fn)\n return this.runNestedTransaction(transactionDriver, fn)\n },\n transactionWithDriver: <T>(\n fn: (nestedDriver: SQLiteDriver) => Promise<T>,\n ): Promise<T> => this.runNestedTransaction(transactionDriver, fn),\n }\n\n return transactionDriver\n }\n\n private async runNestedTransaction<T>(\n transactionDriver: SQLiteDriver,\n fn: (nestedDriver: SQLiteDriver) => Promise<T>,\n ): Promise<T> {\n if (this.transactionExecutor) {\n throw new InvalidPersistedCollectionConfigError(\n `Nested SQL savepoints are not supported when using Durable Object transaction API`,\n )\n }\n\n const savepointName = `tsdb_sp_${this.nextSavepointId}`\n this.nextSavepointId++\n this.execute(`SAVEPOINT ${savepointName}`)\n\n try {\n const result = await fn(transactionDriver)\n this.execute(`RELEASE SAVEPOINT ${savepointName}`)\n return result\n } catch (error) {\n this.execute(`ROLLBACK TO SAVEPOINT ${savepointName}`)\n this.execute(`RELEASE SAVEPOINT ${savepointName}`)\n throw error\n }\n }\n}\n\nexport function createCloudflareDOSQLiteDriver(\n options: CloudflareDOSQLiteDriverOptions,\n): CloudflareDOSQLiteDriver {\n return new CloudflareDOSQLiteDriver(options)\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"do-driver.js","sources":["../../src/do-driver.ts"],"sourcesContent":["import { InvalidPersistedCollectionConfigError } from '@tanstack/db-sqlite-persistence-core'\nimport type { SQLiteDriver } from '@tanstack/db-sqlite-persistence-core'\n\ntype DurableObjectSqlRow = Record<string, unknown>\n\ntype DurableObjectSqlCursorLike = Iterable<DurableObjectSqlRow> & {\n toArray?: () => Array<DurableObjectSqlRow>\n}\n\nexport type DurableObjectSqlStorageLike = {\n exec: (\n sql: string,\n ...params: ReadonlyArray<unknown>\n ) => DurableObjectSqlCursorLike | ReadonlyArray<DurableObjectSqlRow> | null\n}\n\nexport type DurableObjectTransactionExecutor = <T>(\n fn: () => Promise<T>,\n) => Promise<T>\n\nexport type DurableObjectStorageLike = {\n sql: DurableObjectSqlStorageLike\n transaction?: DurableObjectTransactionExecutor\n}\n\ntype CloudflareDOProvidedSqlOptions = {\n sql: DurableObjectSqlStorageLike\n transaction?: DurableObjectTransactionExecutor\n}\n\ntype CloudflareDOProvidedStorageOptions = {\n storage: DurableObjectStorageLike\n}\n\nexport type CloudflareDOSQLiteDriverOptions =\n CloudflareDOProvidedSqlOptions | CloudflareDOProvidedStorageOptions\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 isIterableRecord(\n value: unknown,\n): value is Iterable<DurableObjectSqlRow> {\n if (!value || typeof value !== `object`) {\n return false\n }\n\n const iterator = (value as { [Symbol.iterator]?: unknown })[Symbol.iterator]\n return typeof iterator === `function`\n}\n\nfunction toRowArray<T>(\n result: ReturnType<DurableObjectSqlStorageLike[`exec`]>,\n sql: string,\n): ReadonlyArray<T> {\n if (result == null) {\n return []\n }\n\n if (Array.isArray(result)) {\n return result as ReadonlyArray<T>\n }\n\n const cursorResult = result as DurableObjectSqlCursorLike\n if (typeof cursorResult.toArray === `function`) {\n return cursorResult.toArray() as ReadonlyArray<T>\n }\n\n if (isIterableRecord(cursorResult)) {\n return Array.from(cursorResult as Iterable<T>)\n }\n\n throw new InvalidPersistedCollectionConfigError(\n `Unsupported Durable Object SQL result shape for query \"${sql}\"`,\n )\n}\n\nexport class CloudflareDOSQLiteDriver implements SQLiteDriver {\n // https://developers.cloudflare.com/durable-objects/platform/limits/\n // Durable Object SQL storage permits at most 100 bound parameters per query.\n readonly maxBoundParameters = 100\n private readonly sqlStorage: DurableObjectSqlStorageLike\n private readonly storage: DurableObjectStorageLike\n private readonly transactionExecutor: DurableObjectTransactionExecutor | null\n private queue: Promise<void> = Promise.resolve()\n private nextSavepointId = 1\n\n constructor(options: CloudflareDOSQLiteDriverOptions) {\n const resolvedStorage: DurableObjectStorageLike =\n `storage` in options\n ? options.storage\n : {\n sql: options.sql,\n ...(typeof options.transaction === `function`\n ? { transaction: options.transaction }\n : {}),\n }\n const resolvedSqlStorage = resolvedStorage.sql\n if (typeof resolvedSqlStorage.exec !== `function`) {\n throw new InvalidPersistedCollectionConfigError(\n `Cloudflare DO SQL driver requires a sql.exec function`,\n )\n }\n this.storage = resolvedStorage\n this.sqlStorage = resolvedSqlStorage\n if (typeof resolvedStorage.transaction === `function`) {\n const transactionMethod = resolvedStorage.transaction\n this.transactionExecutor = <T>(fn: () => Promise<T>) =>\n Promise.resolve(\n transactionMethod.call(resolvedStorage, fn) as Promise<T> | T,\n )\n } else {\n this.transactionExecutor = null\n }\n }\n\n async exec(sql: string): Promise<void> {\n await this.enqueue(() => {\n this.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.executeQuery<T>(sql, params))\n }\n\n async run(sql: string, params: ReadonlyArray<unknown> = []): Promise<void> {\n await this.enqueue(() => {\n this.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 const transactionDriver = this.createTransactionDriver()\n if (this.transactionExecutor) {\n return this.transactionExecutor(() => fn(transactionDriver))\n }\n\n this.execute(`BEGIN IMMEDIATE`)\n try {\n const result = await fn(transactionDriver)\n this.execute(`COMMIT`)\n return result\n } catch (error) {\n try {\n this.execute(`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 getStorage(): DurableObjectStorageLike {\n return this.storage\n }\n\n private execute(sql: string, params: ReadonlyArray<unknown> = []): unknown {\n return this.sqlStorage.exec(sql, ...params)\n }\n\n private executeQuery<T>(\n sql: string,\n params: ReadonlyArray<unknown>,\n ): ReadonlyArray<T> {\n const result = this.execute(sql, params)\n return toRowArray<T>(\n result as ReturnType<DurableObjectSqlStorageLike[`exec`]>,\n sql,\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 private createTransactionDriver(): SQLiteDriver {\n const transactionDriver: SQLiteDriver = {\n maxBoundParameters: this.maxBoundParameters,\n exec: (sql) => {\n this.execute(sql)\n return Promise.resolve()\n },\n query: <T>(\n sql: string,\n params: ReadonlyArray<unknown> = [],\n ): Promise<ReadonlyArray<T>> =>\n Promise.resolve(this.executeQuery<T>(sql, params)),\n run: (sql, params = []) => {\n this.execute(sql, params)\n return Promise.resolve()\n },\n transaction: <T>(\n fn: (nestedDriver: SQLiteDriver) => Promise<T>,\n ): Promise<T> => {\n assertTransactionCallbackHasDriverArg(fn)\n return this.runNestedTransaction(transactionDriver, fn)\n },\n transactionWithDriver: <T>(\n fn: (nestedDriver: SQLiteDriver) => Promise<T>,\n ): Promise<T> => this.runNestedTransaction(transactionDriver, fn),\n }\n\n return transactionDriver\n }\n\n private async runNestedTransaction<T>(\n transactionDriver: SQLiteDriver,\n fn: (nestedDriver: SQLiteDriver) => Promise<T>,\n ): Promise<T> {\n if (this.transactionExecutor) {\n throw new InvalidPersistedCollectionConfigError(\n `Nested SQL savepoints are not supported when using Durable Object transaction API`,\n )\n }\n\n const savepointName = `tsdb_sp_${this.nextSavepointId}`\n this.nextSavepointId++\n this.execute(`SAVEPOINT ${savepointName}`)\n\n try {\n const result = await fn(transactionDriver)\n this.execute(`RELEASE SAVEPOINT ${savepointName}`)\n return result\n } catch (error) {\n this.execute(`ROLLBACK TO SAVEPOINT ${savepointName}`)\n this.execute(`RELEASE SAVEPOINT ${savepointName}`)\n throw error\n }\n }\n}\n\nexport function createCloudflareDOSQLiteDriver(\n options: CloudflareDOSQLiteDriverOptions,\n): CloudflareDOSQLiteDriver {\n return new CloudflareDOSQLiteDriver(options)\n}\n"],"names":[],"mappings":";AAqCA,SAAS,sCACP,IACM;AACN,MAAI,GAAG,SAAS,GAAG;AACjB;AAAA,EACF;AAEA,QAAM,IAAI;AAAA,IACR;AAAA,EAAA;AAEJ;AAEA,SAAS,iBACP,OACwC;AACxC,MAAI,CAAC,SAAS,OAAO,UAAU,UAAU;AACvC,WAAO;AAAA,EACT;AAEA,QAAM,WAAY,MAA0C,OAAO,QAAQ;AAC3E,SAAO,OAAO,aAAa;AAC7B;AAEA,SAAS,WACP,QACA,KACkB;AAClB,MAAI,UAAU,MAAM;AAClB,WAAO,CAAA;AAAA,EACT;AAEA,MAAI,MAAM,QAAQ,MAAM,GAAG;AACzB,WAAO;AAAA,EACT;AAEA,QAAM,eAAe;AACrB,MAAI,OAAO,aAAa,YAAY,YAAY;AAC9C,WAAO,aAAa,QAAA;AAAA,EACtB;AAEA,MAAI,iBAAiB,YAAY,GAAG;AAClC,WAAO,MAAM,KAAK,YAA2B;AAAA,EAC/C;AAEA,QAAM,IAAI;AAAA,IACR,0DAA0D,GAAG;AAAA,EAAA;AAEjE;AAEO,MAAM,yBAAiD;AAAA,EAU5D,YAAY,SAA0C;AAPtD,SAAS,qBAAqB;AAI9B,SAAQ,QAAuB,QAAQ,QAAA;AACvC,SAAQ,kBAAkB;AAGxB,UAAM,kBACJ,aAAa,UACT,QAAQ,UACR;AAAA,MACE,KAAK,QAAQ;AAAA,MACb,GAAI,OAAO,QAAQ,gBAAgB,aAC/B,EAAE,aAAa,QAAQ,gBACvB,CAAA;AAAA,IAAC;AAEb,UAAM,qBAAqB,gBAAgB;AAC3C,QAAI,OAAO,mBAAmB,SAAS,YAAY;AACjD,YAAM,IAAI;AAAA,QACR;AAAA,MAAA;AAAA,IAEJ;AACA,SAAK,UAAU;AACf,SAAK,aAAa;AAClB,QAAI,OAAO,gBAAgB,gBAAgB,YAAY;AACrD,YAAM,oBAAoB,gBAAgB;AAC1C,WAAK,sBAAsB,CAAI,OAC7B,QAAQ;AAAA,QACN,kBAAkB,KAAK,iBAAiB,EAAE;AAAA,MAAA;AAAA,IAEhD,OAAO;AACL,WAAK,sBAAsB;AAAA,IAC7B;AAAA,EACF;AAAA,EAEA,MAAM,KAAK,KAA4B;AACrC,UAAM,KAAK,QAAQ,MAAM;AACvB,WAAK,QAAQ,GAAG;AAAA,IAClB,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,MACJ,KACA,SAAiC,IACN;AAC3B,WAAO,KAAK,QAAQ,MAAM,KAAK,aAAgB,KAAK,MAAM,CAAC;AAAA,EAC7D;AAAA,EAEA,MAAM,IAAI,KAAa,SAAiC,IAAmB;AACzE,UAAM,KAAK,QAAQ,MAAM;AACvB,WAAK,QAAQ,KAAK,MAAM;AAAA,IAC1B,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,YACJ,IACY;AACZ,0CAAsC,EAAE;AAExC,WAAO,KAAK,QAAQ,YAAY;AAC9B,YAAM,oBAAoB,KAAK,wBAAA;AAC/B,UAAI,KAAK,qBAAqB;AAC5B,eAAO,KAAK,oBAAoB,MAAM,GAAG,iBAAiB,CAAC;AAAA,MAC7D;AAEA,WAAK,QAAQ,iBAAiB;AAC9B,UAAI;AACF,cAAM,SAAS,MAAM,GAAG,iBAAiB;AACzC,aAAK,QAAQ,QAAQ;AACrB,eAAO;AAAA,MACT,SAAS,OAAO;AACd,YAAI;AACF,eAAK,QAAQ,UAAU;AAAA,QACzB,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,aAAuC;AACrC,WAAO,KAAK;AAAA,EACd;AAAA,EAEQ,QAAQ,KAAa,SAAiC,IAAa;AACzE,WAAO,KAAK,WAAW,KAAK,KAAK,GAAG,MAAM;AAAA,EAC5C;AAAA,EAEQ,aACN,KACA,QACkB;AAClB,UAAM,SAAS,KAAK,QAAQ,KAAK,MAAM;AACvC,WAAO;AAAA,MACL;AAAA,MACA;AAAA,IAAA;AAAA,EAEJ;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;AAAA,EAEQ,0BAAwC;AAC9C,UAAM,oBAAkC;AAAA,MACtC,oBAAoB,KAAK;AAAA,MACzB,MAAM,CAAC,QAAQ;AACb,aAAK,QAAQ,GAAG;AAChB,eAAO,QAAQ,QAAA;AAAA,MACjB;AAAA,MACA,OAAO,CACL,KACA,SAAiC,OAEjC,QAAQ,QAAQ,KAAK,aAAgB,KAAK,MAAM,CAAC;AAAA,MACnD,KAAK,CAAC,KAAK,SAAS,OAAO;AACzB,aAAK,QAAQ,KAAK,MAAM;AACxB,eAAO,QAAQ,QAAA;AAAA,MACjB;AAAA,MACA,aAAa,CACX,OACe;AACf,8CAAsC,EAAE;AACxC,eAAO,KAAK,qBAAqB,mBAAmB,EAAE;AAAA,MACxD;AAAA,MACA,uBAAuB,CACrB,OACe,KAAK,qBAAqB,mBAAmB,EAAE;AAAA,IAAA;AAGlE,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,qBACZ,mBACA,IACY;AACZ,QAAI,KAAK,qBAAqB;AAC5B,YAAM,IAAI;AAAA,QACR;AAAA,MAAA;AAAA,IAEJ;AAEA,UAAM,gBAAgB,WAAW,KAAK,eAAe;AACrD,SAAK;AACL,SAAK,QAAQ,aAAa,aAAa,EAAE;AAEzC,QAAI;AACF,YAAM,SAAS,MAAM,GAAG,iBAAiB;AACzC,WAAK,QAAQ,qBAAqB,aAAa,EAAE;AACjD,aAAO;AAAA,IACT,SAAS,OAAO;AACd,WAAK,QAAQ,yBAAyB,aAAa,EAAE;AACrD,WAAK,QAAQ,qBAAqB,aAAa,EAAE;AACjD,YAAM;AAAA,IACR;AAAA,EACF;AACF;"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { SingleProcessCoordinator,
|
|
1
|
+
import { SingleProcessCoordinator, DEFAULT_APPLIED_TX_PRUNE_MAX_AGE_SECONDS, DEFAULT_APPLIED_TX_PRUNE_MAX_ROWS, createSQLiteCorePersistenceAdapter } from "@tanstack/db-sqlite-persistence-core";
|
|
2
2
|
import { CloudflareDOSQLiteDriver } from "./do-driver.js";
|
|
3
3
|
function normalizeSchemaMismatchPolicy(policy) {
|
|
4
4
|
if (policy === `throw`) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"do-persistence.js","sources":["../../src/do-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 { CloudflareDOSQLiteDriver } from './do-driver'\nimport type {\n PersistedCollectionCoordinator,\n PersistedCollectionMode,\n PersistedCollectionPersistence,\n SQLiteCoreAdapterOptions,\n SQLiteDriver,\n} from '@tanstack/db-sqlite-persistence-core'\nimport type { DurableObjectStorageLike } from './do-driver'\n\nexport type { DurableObjectStorageLike } from './do-driver'\n\ntype CloudflareDOCoreSchemaMismatchPolicy =\n
|
|
1
|
+
{"version":3,"file":"do-persistence.js","sources":["../../src/do-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 { CloudflareDOSQLiteDriver } from './do-driver'\nimport type {\n PersistedCollectionCoordinator,\n PersistedCollectionMode,\n PersistedCollectionPersistence,\n SQLiteCoreAdapterOptions,\n SQLiteDriver,\n} from '@tanstack/db-sqlite-persistence-core'\nimport type { DurableObjectStorageLike } from './do-driver'\n\nexport type { DurableObjectStorageLike } from './do-driver'\n\ntype CloudflareDOCoreSchemaMismatchPolicy =\n `sync-present-reset` | `sync-absent-error` | `reset`\n\nexport type CloudflareDOSchemaMismatchPolicy =\n CloudflareDOCoreSchemaMismatchPolicy | `throw`\n\ntype CloudflareDOSQLitePersistenceBaseOptions = Omit<\n SQLiteCoreAdapterOptions,\n `driver` | `schemaVersion` | `schemaMismatchPolicy`\n> & {\n storage: DurableObjectStorageLike\n coordinator?: PersistedCollectionCoordinator\n schemaMismatchPolicy?: CloudflareDOSchemaMismatchPolicy\n}\n\nexport type CloudflareDOSQLitePersistenceOptions =\n CloudflareDOSQLitePersistenceBaseOptions\n\nfunction normalizeSchemaMismatchPolicy(\n policy: CloudflareDOSchemaMismatchPolicy,\n): CloudflareDOCoreSchemaMismatchPolicy {\n if (policy === `throw`) {\n return `sync-absent-error`\n }\n return policy\n}\n\nfunction resolveSchemaMismatchPolicy(\n explicitPolicy: CloudflareDOSchemaMismatchPolicy | undefined,\n mode: PersistedCollectionMode,\n): CloudflareDOCoreSchemaMismatchPolicy {\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: CloudflareDOCoreSchemaMismatchPolicy,\n schemaVersion: number | undefined,\n): string {\n const schemaVersionKey =\n schemaVersion === undefined ? `schema:default` : `schema:${schemaVersion}`\n return `${schemaMismatchPolicy}|${schemaVersionKey}`\n}\n\nfunction resolveSQLiteDriver(\n options: CloudflareDOSQLitePersistenceOptions,\n): SQLiteDriver {\n return new CloudflareDOSQLiteDriver({\n storage: options.storage,\n })\n}\n\nfunction resolveAdapterBaseOptions(\n options: CloudflareDOSQLitePersistenceOptions,\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 Durable Object SQLite persistence instance that can be reused\n * by many collections in a single Durable Object storage.\n */\nexport function createCloudflareDOSQLitePersistence(\n options: CloudflareDOSQLitePersistenceOptions,\n): PersistedCollectionPersistence {\n const { coordinator, schemaMismatchPolicy } = options\n const driver = resolveSQLiteDriver(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":[],"mappings":";;AAoCA,SAAS,8BACP,QACsC;AACtC,MAAI,WAAW,SAAS;AACtB,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEA,SAAS,4BACP,gBACA,MACsC;AACtC,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,oBACP,SACc;AACd,SAAO,IAAI,yBAAyB;AAAA,IAClC,SAAS,QAAQ;AAAA,EAAA,CAClB;AACH;AAEA,SAAS,0BACP,SAIA;AACA,SAAO;AAAA,IACL,uBACE,QAAQ,yBAAyB;AAAA,IACnC,6BACE,QAAQ,+BACR;AAAA,IACF,0BAA0B,QAAQ;AAAA,EAAA;AAEtC;AAMO,SAAS,oCACd,SACgC;AAChC,QAAM,EAAE,aAAa,qBAAA,IAAyB;AAC9C,QAAM,SAAS,oBAAoB,OAAO;AAC1C,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/cloudflare-durable-objects-db-sqlite-persistence",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.29",
|
|
4
4
|
"description": "Cloudflare Durable Object SQLite persisted collection adapter for TanStack DB",
|
|
5
5
|
"author": "TanStack Team",
|
|
6
6
|
"license": "MIT",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"src"
|
|
41
41
|
],
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@tanstack/db-sqlite-persistence-core": "0.4.
|
|
43
|
+
"@tanstack/db-sqlite-persistence-core": "0.4.4"
|
|
44
44
|
},
|
|
45
45
|
"peerDependencies": {
|
|
46
46
|
"typescript": ">=4.7"
|
package/src/do-driver.ts
CHANGED
|
@@ -33,8 +33,7 @@ type CloudflareDOProvidedStorageOptions = {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
export type CloudflareDOSQLiteDriverOptions =
|
|
36
|
-
|
|
|
37
|
-
| CloudflareDOProvidedStorageOptions
|
|
36
|
+
CloudflareDOProvidedSqlOptions | CloudflareDOProvidedStorageOptions
|
|
38
37
|
|
|
39
38
|
function assertTransactionCallbackHasDriverArg(
|
|
40
39
|
fn: (transactionDriver: SQLiteDriver) => Promise<unknown>,
|
|
@@ -206,6 +205,7 @@ export class CloudflareDOSQLiteDriver implements SQLiteDriver {
|
|
|
206
205
|
|
|
207
206
|
private createTransactionDriver(): SQLiteDriver {
|
|
208
207
|
const transactionDriver: SQLiteDriver = {
|
|
208
|
+
maxBoundParameters: this.maxBoundParameters,
|
|
209
209
|
exec: (sql) => {
|
|
210
210
|
this.execute(sql)
|
|
211
211
|
return Promise.resolve()
|
package/src/do-persistence.ts
CHANGED
|
@@ -17,13 +17,10 @@ import type { DurableObjectStorageLike } from './do-driver'
|
|
|
17
17
|
export type { DurableObjectStorageLike } from './do-driver'
|
|
18
18
|
|
|
19
19
|
type CloudflareDOCoreSchemaMismatchPolicy =
|
|
20
|
-
| `sync-
|
|
21
|
-
| `sync-absent-error`
|
|
22
|
-
| `reset`
|
|
20
|
+
`sync-present-reset` | `sync-absent-error` | `reset`
|
|
23
21
|
|
|
24
22
|
export type CloudflareDOSchemaMismatchPolicy =
|
|
25
|
-
|
|
|
26
|
-
| `throw`
|
|
23
|
+
CloudflareDOCoreSchemaMismatchPolicy | `throw`
|
|
27
24
|
|
|
28
25
|
type CloudflareDOSQLitePersistenceBaseOptions = Omit<
|
|
29
26
|
SQLiteCoreAdapterOptions,
|