@tanstack/capacitor-db-sqlite-persistence 0.1.2

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/README.md ADDED
@@ -0,0 +1,109 @@
1
+ # @tanstack/capacitor-db-sqlite-persistence
2
+
3
+ Thin SQLite persistence for Capacitor apps using
4
+ `@capacitor-community/sqlite`.
5
+
6
+ ## Public API
7
+
8
+ - `createCapacitorSQLitePersistence(...)`
9
+ - `persistedCollectionOptions(...)` (re-exported from core)
10
+
11
+ ## Install
12
+
13
+ ```bash
14
+ pnpm add @tanstack/capacitor-db-sqlite-persistence @capacitor-community/sqlite
15
+ ```
16
+
17
+ ## Quick start
18
+
19
+ ```ts
20
+ import { CapacitorSQLite, SQLiteConnection } from '@capacitor-community/sqlite'
21
+ import { createCollection } from '@tanstack/db'
22
+ import { QueryClient } from '@tanstack/query-core'
23
+ import { queryCollectionOptions } from '@tanstack/query-db-collection'
24
+ import {
25
+ createCapacitorSQLitePersistence,
26
+ persistedCollectionOptions,
27
+ } from '@tanstack/capacitor-db-sqlite-persistence'
28
+
29
+ type Todo = {
30
+ id: string
31
+ title: string
32
+ completed: boolean
33
+ }
34
+
35
+ const sqlite = new SQLiteConnection(CapacitorSQLite)
36
+ const database = await sqlite.createConnection(
37
+ `tanstack-db`,
38
+ false,
39
+ `no-encryption`,
40
+ 1,
41
+ false,
42
+ )
43
+
44
+ await database.open()
45
+
46
+ // One shared persistence instance for the whole database.
47
+ const persistence = createCapacitorSQLitePersistence({
48
+ database,
49
+ })
50
+ const queryClient = new QueryClient()
51
+
52
+ export const todosCollection = createCollection(
53
+ persistedCollectionOptions<Todo, string>({
54
+ ...queryCollectionOptions({
55
+ queryKey: [`todos`],
56
+ queryFn: async () => {
57
+ const response = await fetch(`/api/todos`)
58
+ return response.json() as Promise<Array<Todo>>
59
+ },
60
+ queryClient,
61
+ getKey: (todo) => todo.id,
62
+ }),
63
+ id: `todos`,
64
+ persistence,
65
+ schemaVersion: 1, // Per-collection schema version
66
+ }),
67
+ )
68
+ ```
69
+
70
+ ## Platform notes
71
+
72
+ - `createCapacitorSQLitePersistence` is shared across collections.
73
+ - Mode defaults (`sync-present` vs `sync-absent`) are inferred from whether a
74
+ `sync` config is present in `persistedCollectionOptions`.
75
+ - This package assumes you provide an already-created and opened
76
+ `SQLiteDBConnection`.
77
+ - Calling `close()` on this driver's database adapter closes the underlying
78
+ `SQLiteDBConnection`, so treat driver ownership as connection ownership.
79
+ - This package targets native Capacitor runtimes. Use the dedicated browser and
80
+ Electron persistence packages instead of the plugin's web or Electron modes.
81
+ - The plugin's database version and upgrade APIs are separate from TanStack DB
82
+ `schemaVersion`.
83
+ - `@capacitor-community/sqlite` uses SQLCipher-backed native builds, so app
84
+ setup may require additional platform configuration outside this package.
85
+ - Capacitor 8 creates iOS projects with Swift Package Manager by default, but
86
+ `@capacitor-community/sqlite` currently links through CocoaPods on iOS. Add
87
+ iOS with `npx cap add ios --packagemanager CocoaPods`, or recreate an SPM
88
+ project in CocoaPods mode before expecting the native plugin to load.
89
+
90
+ ## Testing
91
+
92
+ - `pnpm --filter @tanstack/capacitor-db-sqlite-persistence test:e2e`
93
+ runs the package e2e suite against the default `better-sqlite3` harness.
94
+ - `pnpm --filter @tanstack/capacitor-db-sqlite-persistence test:e2e:ios`
95
+ builds the package-local Capacitor harness in `e2e/app`, launches the iOS
96
+ simulator, and runs the full persisted collection e2e suite inside the real
97
+ native Capacitor runtime.
98
+ - `pnpm --filter @tanstack/capacitor-db-sqlite-persistence test:e2e:android`
99
+ builds the same package-local Capacitor harness in `e2e/app`, launches an
100
+ Android emulator or uses a connected debug target, and runs the full
101
+ persisted collection e2e suite inside the real native Capacitor runtime.
102
+ - `test:e2e:ios` is a repo-local validation path for this package. It depends on
103
+ the checked-in `e2e/app` harness plus local Capacitor/Xcode tooling.
104
+ - `test:e2e:android` depends on a local Android SDK. The runner auto-detects the
105
+ default macOS SDK location, boots the first available AVD when needed, and
106
+ reads the app-owned SQLite result database out of the debug sandbox with
107
+ `adb run-as`.
108
+ - The native harness lives under `e2e/app` so the same app can be extended to
109
+ other native targets later, including Android.
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const dbSqlitePersistenceCore = require("@tanstack/db-sqlite-persistence-core");
4
+ const capacitorSqliteDriver = require("./capacitor-sqlite-driver.cjs");
5
+ function normalizeSchemaMismatchPolicy(policy) {
6
+ if (policy === `throw`) {
7
+ return `sync-absent-error`;
8
+ }
9
+ return policy;
10
+ }
11
+ function resolveSchemaMismatchPolicy(explicitPolicy, mode) {
12
+ if (explicitPolicy) {
13
+ return normalizeSchemaMismatchPolicy(explicitPolicy);
14
+ }
15
+ return mode === `sync-present` ? `sync-present-reset` : `sync-absent-error`;
16
+ }
17
+ function createAdapterCacheKey(schemaMismatchPolicy, schemaVersion) {
18
+ const schemaVersionKey = schemaVersion === void 0 ? `schema:default` : `schema:${schemaVersion}`;
19
+ return `${schemaMismatchPolicy}|${schemaVersionKey}`;
20
+ }
21
+ function createInternalSQLiteDriver(options) {
22
+ return new capacitorSqliteDriver.CapacitorSQLiteDriver({
23
+ database: options.database
24
+ });
25
+ }
26
+ function resolveAdapterBaseOptions(options) {
27
+ return {
28
+ appliedTxPruneMaxRows: options.appliedTxPruneMaxRows,
29
+ appliedTxPruneMaxAgeSeconds: options.appliedTxPruneMaxAgeSeconds,
30
+ pullSinceReloadThreshold: options.pullSinceReloadThreshold
31
+ };
32
+ }
33
+ function createCapacitorSQLitePersistence(options) {
34
+ const { coordinator, schemaMismatchPolicy } = options;
35
+ const driver = createInternalSQLiteDriver(options);
36
+ const adapterBaseOptions = resolveAdapterBaseOptions(options);
37
+ const resolvedCoordinator = coordinator ?? new dbSqlitePersistenceCore.SingleProcessCoordinator();
38
+ const adapterCache = /* @__PURE__ */ new Map();
39
+ const getAdapterForCollection = (mode, schemaVersion) => {
40
+ const resolvedSchemaMismatchPolicy = resolveSchemaMismatchPolicy(
41
+ schemaMismatchPolicy,
42
+ mode
43
+ );
44
+ const cacheKey = createAdapterCacheKey(
45
+ resolvedSchemaMismatchPolicy,
46
+ schemaVersion
47
+ );
48
+ const cachedAdapter = adapterCache.get(cacheKey);
49
+ if (cachedAdapter) {
50
+ return cachedAdapter;
51
+ }
52
+ const adapter = dbSqlitePersistenceCore.createSQLiteCorePersistenceAdapter({
53
+ ...adapterBaseOptions,
54
+ driver,
55
+ schemaMismatchPolicy: resolvedSchemaMismatchPolicy,
56
+ ...schemaVersion === void 0 ? {} : { schemaVersion }
57
+ });
58
+ adapterCache.set(cacheKey, adapter);
59
+ return adapter;
60
+ };
61
+ const createCollectionPersistence = (mode, schemaVersion) => ({
62
+ adapter: getAdapterForCollection(
63
+ mode,
64
+ schemaVersion
65
+ ),
66
+ coordinator: resolvedCoordinator
67
+ });
68
+ const defaultPersistence = createCollectionPersistence(
69
+ `sync-absent`,
70
+ void 0
71
+ );
72
+ return {
73
+ ...defaultPersistence,
74
+ resolvePersistenceForCollection: ({ mode, schemaVersion }) => createCollectionPersistence(mode, schemaVersion),
75
+ resolvePersistenceForMode: (mode) => createCollectionPersistence(mode, void 0)
76
+ };
77
+ }
78
+ exports.createCapacitorSQLitePersistence = createCapacitorSQLitePersistence;
79
+ //# sourceMappingURL=capacitor-persistence.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capacitor-persistence.cjs","sources":["../../src/capacitor-persistence.ts"],"sourcesContent":["import {\n SingleProcessCoordinator,\n createSQLiteCorePersistenceAdapter,\n} from '@tanstack/db-sqlite-persistence-core'\nimport { CapacitorSQLiteDriver } from './capacitor-sqlite-driver'\nimport type { SQLiteDBConnection } from '@capacitor-community/sqlite'\nimport type {\n PersistedCollectionCoordinator,\n PersistedCollectionMode,\n PersistedCollectionPersistence,\n SQLiteCoreAdapterOptions,\n SQLiteDriver,\n} from '@tanstack/db-sqlite-persistence-core'\n\nexport type { CapacitorSQLiteDatabaseLike } from './capacitor-sqlite-driver'\nexport type { SQLiteDBConnection } from '@capacitor-community/sqlite'\n\ntype CapacitorSQLiteCoreSchemaMismatchPolicy =\n | `sync-present-reset`\n | `sync-absent-error`\n | `reset`\n\nexport type CapacitorSQLiteSchemaMismatchPolicy =\n | CapacitorSQLiteCoreSchemaMismatchPolicy\n | `throw`\n\ntype CapacitorSQLitePersistenceBaseOptions = Omit<\n SQLiteCoreAdapterOptions,\n `driver` | `schemaVersion` | `schemaMismatchPolicy`\n> & {\n database: SQLiteDBConnection\n coordinator?: PersistedCollectionCoordinator\n schemaMismatchPolicy?: CapacitorSQLiteSchemaMismatchPolicy\n}\n\nexport type CapacitorSQLitePersistenceOptions =\n CapacitorSQLitePersistenceBaseOptions\n\nfunction normalizeSchemaMismatchPolicy(\n policy: CapacitorSQLiteSchemaMismatchPolicy,\n): CapacitorSQLiteCoreSchemaMismatchPolicy {\n if (policy === `throw`) {\n return `sync-absent-error`\n }\n\n return policy\n}\n\nfunction resolveSchemaMismatchPolicy(\n explicitPolicy: CapacitorSQLiteSchemaMismatchPolicy | undefined,\n mode: PersistedCollectionMode,\n): CapacitorSQLiteCoreSchemaMismatchPolicy {\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: CapacitorSQLiteCoreSchemaMismatchPolicy,\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: CapacitorSQLitePersistenceOptions,\n): SQLiteDriver {\n return new CapacitorSQLiteDriver({\n database: options.database,\n })\n}\n\nfunction resolveAdapterBaseOptions(\n options: CapacitorSQLitePersistenceOptions,\n): Omit<\n SQLiteCoreAdapterOptions,\n `driver` | `schemaVersion` | `schemaMismatchPolicy`\n> {\n return {\n appliedTxPruneMaxRows: options.appliedTxPruneMaxRows,\n appliedTxPruneMaxAgeSeconds: options.appliedTxPruneMaxAgeSeconds,\n pullSinceReloadThreshold: options.pullSinceReloadThreshold,\n }\n}\n\nexport function createCapacitorSQLitePersistence<\n T extends object,\n TKey extends string | number = string | number,\n>(\n options: CapacitorSQLitePersistenceOptions,\n): PersistedCollectionPersistence<T, TKey> {\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<\n typeof createSQLiteCorePersistenceAdapter<\n Record<string, unknown>,\n string | number\n >\n >\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 Record<string, unknown>,\n string | number\n >({\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<T, TKey> => ({\n adapter: getAdapterForCollection(\n mode,\n schemaVersion,\n ) as unknown as PersistedCollectionPersistence<T, TKey>[`adapter`],\n coordinator: resolvedCoordinator,\n })\n\n const defaultPersistence = createCollectionPersistence(\n `sync-absent`,\n undefined,\n )\n\n return {\n ...defaultPersistence,\n resolvePersistenceForCollection: ({ mode, schemaVersion }) =>\n createCollectionPersistence(mode, schemaVersion),\n resolvePersistenceForMode: (mode) =>\n createCollectionPersistence(mode, undefined),\n }\n}\n"],"names":["CapacitorSQLiteDriver","SingleProcessCoordinator","createSQLiteCorePersistenceAdapter"],"mappings":";;;;AAsCA,SAAS,8BACP,QACyC;AACzC,MAAI,WAAW,SAAS;AACtB,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEA,SAAS,4BACP,gBACA,MACyC;AACzC,MAAI,gBAAgB;AAClB,WAAO,8BAA8B,cAAc;AAAA,EACrD;AAEA,SAAO,SAAS,iBAAiB,uBAAuB;AAC1D;AAEA,SAAS,sBACP,sBACA,eACQ;AACR,QAAM,mBACJ,kBAAkB,SAAY,mBAAmB,UAAU,aAAa;AAC1E,SAAO,GAAG,oBAAoB,IAAI,gBAAgB;AACpD;AAEA,SAAS,2BACP,SACc;AACd,SAAO,IAAIA,sBAAAA,sBAAsB;AAAA,IAC/B,UAAU,QAAQ;AAAA,EAAA,CACnB;AACH;AAEA,SAAS,0BACP,SAIA;AACA,SAAO;AAAA,IACL,uBAAuB,QAAQ;AAAA,IAC/B,6BAA6B,QAAQ;AAAA,IACrC,0BAA0B,QAAQ;AAAA,EAAA;AAEtC;AAEO,SAAS,iCAId,SACyC;AACzC,QAAM,EAAE,aAAa,qBAAA,IAAyB;AAC9C,QAAM,SAAS,2BAA2B,OAAO;AACjD,QAAM,qBAAqB,0BAA0B,OAAO;AAC5D,QAAM,sBAAsB,eAAe,IAAIC,iDAAA;AAC/C,QAAM,mCAAmB,IAAA;AAUzB,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,mCAGd;AAAA,MACA,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,mBAC6C;AAAA,IAC7C,SAAS;AAAA,MACP;AAAA,MACA;AAAA,IAAA;AAAA,IAEF,aAAa;AAAA,EAAA;AAGf,QAAM,qBAAqB;AAAA,IACzB;AAAA,IACA;AAAA,EAAA;AAGF,SAAO;AAAA,IACL,GAAG;AAAA,IACH,iCAAiC,CAAC,EAAE,MAAM,oBACxC,4BAA4B,MAAM,aAAa;AAAA,IACjD,2BAA2B,CAAC,SAC1B,4BAA4B,MAAM,MAAS;AAAA,EAAA;AAEjD;;"}
@@ -0,0 +1,13 @@
1
+ import { SQLiteDBConnection } from '@capacitor-community/sqlite';
2
+ import { PersistedCollectionCoordinator, PersistedCollectionPersistence, SQLiteCoreAdapterOptions } from '@tanstack/db-sqlite-persistence-core';
3
+ export type { CapacitorSQLiteDatabaseLike } from './capacitor-sqlite-driver.cjs';
4
+ export type { SQLiteDBConnection } from '@capacitor-community/sqlite';
5
+ type CapacitorSQLiteCoreSchemaMismatchPolicy = `sync-present-reset` | `sync-absent-error` | `reset`;
6
+ export type CapacitorSQLiteSchemaMismatchPolicy = CapacitorSQLiteCoreSchemaMismatchPolicy | `throw`;
7
+ type CapacitorSQLitePersistenceBaseOptions = Omit<SQLiteCoreAdapterOptions, `driver` | `schemaVersion` | `schemaMismatchPolicy`> & {
8
+ database: SQLiteDBConnection;
9
+ coordinator?: PersistedCollectionCoordinator;
10
+ schemaMismatchPolicy?: CapacitorSQLiteSchemaMismatchPolicy;
11
+ };
12
+ export type CapacitorSQLitePersistenceOptions = CapacitorSQLitePersistenceBaseOptions;
13
+ export declare function createCapacitorSQLitePersistence<T extends object, TKey extends string | number = string | number>(options: CapacitorSQLitePersistenceOptions): PersistedCollectionPersistence<T, TKey>;
@@ -0,0 +1,220 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const dbSqlitePersistenceCore = require("@tanstack/db-sqlite-persistence-core");
4
+ let asyncLocalStorageCtorPromise = null;
5
+ function canAttemptNodeAsyncLocalStorageLoad() {
6
+ if (typeof process === `undefined`) {
7
+ return false;
8
+ }
9
+ return typeof process.versions?.node === `string`;
10
+ }
11
+ function getNodeAsyncHooksSpecifier() {
12
+ const moduleName = `async_hooks`;
13
+ return `node:${moduleName}`;
14
+ }
15
+ async function resolveAsyncLocalStorageCtor() {
16
+ if (asyncLocalStorageCtorPromise) {
17
+ return asyncLocalStorageCtorPromise;
18
+ }
19
+ asyncLocalStorageCtorPromise = (async () => {
20
+ if (!canAttemptNodeAsyncLocalStorageLoad()) {
21
+ return null;
22
+ }
23
+ try {
24
+ const asyncHooksModule = await import(getNodeAsyncHooksSpecifier());
25
+ return typeof asyncHooksModule.AsyncLocalStorage === `function` ? asyncHooksModule.AsyncLocalStorage : null;
26
+ } catch {
27
+ return null;
28
+ }
29
+ })();
30
+ return asyncLocalStorageCtorPromise;
31
+ }
32
+ function assertTransactionCallbackHasDriverArg(fn) {
33
+ if (fn.length > 0) {
34
+ return;
35
+ }
36
+ throw new dbSqlitePersistenceCore.InvalidPersistedCollectionConfigError(
37
+ `SQLiteDriver.transaction callback must accept the transaction driver argument`
38
+ );
39
+ }
40
+ function isCapacitorSQLiteDatabaseLike(value) {
41
+ const candidate = value;
42
+ return typeof value === `object` && value !== null && typeof candidate.execute === `function` && typeof candidate.query === `function` && typeof candidate.run === `function`;
43
+ }
44
+ function extractQueryRows(result, sql) {
45
+ if (Array.isArray(result.values)) {
46
+ return result.values;
47
+ }
48
+ throw new dbSqlitePersistenceCore.InvalidPersistedCollectionConfigError(
49
+ `Unsupported Capacitor SQLite query result shape for SQL "${sql}"`
50
+ );
51
+ }
52
+ class CapacitorSQLiteDriver {
53
+ constructor(options) {
54
+ this.queue = Promise.resolve();
55
+ this.nextSavepointId = 1;
56
+ this.transactionContextStoragePromise = null;
57
+ if (!isCapacitorSQLiteDatabaseLike(options.database)) {
58
+ throw new dbSqlitePersistenceCore.InvalidPersistedCollectionConfigError(
59
+ `Capacitor SQLite database object must provide execute/query/run methods`
60
+ );
61
+ }
62
+ this.database = options.database;
63
+ }
64
+ async exec(sql) {
65
+ const activeTransactionDriver = await this.getActiveTransactionDriver();
66
+ if (activeTransactionDriver) {
67
+ await activeTransactionDriver.exec(sql);
68
+ return;
69
+ }
70
+ await this.enqueue(async () => {
71
+ await this.database.execute(sql, false);
72
+ });
73
+ }
74
+ async query(sql, params = []) {
75
+ const activeTransactionDriver = await this.getActiveTransactionDriver();
76
+ if (activeTransactionDriver) {
77
+ return activeTransactionDriver.query(sql, params);
78
+ }
79
+ return this.enqueue(async () => {
80
+ const result = await this.database.query(sql, [...params]);
81
+ return extractQueryRows(result, sql);
82
+ });
83
+ }
84
+ async run(sql, params = []) {
85
+ const activeTransactionDriver = await this.getActiveTransactionDriver();
86
+ if (activeTransactionDriver) {
87
+ await activeTransactionDriver.run(sql, params);
88
+ return;
89
+ }
90
+ await this.enqueue(async () => {
91
+ await this.database.run(sql, [...params], false);
92
+ });
93
+ }
94
+ async transaction(fn) {
95
+ assertTransactionCallbackHasDriverArg(fn);
96
+ const activeTransactionDriver = await this.getActiveTransactionDriver();
97
+ if (activeTransactionDriver) {
98
+ return activeTransactionDriver.transaction(fn);
99
+ }
100
+ return this.transactionWithDriver(
101
+ (transactionDriver) => fn(transactionDriver)
102
+ );
103
+ }
104
+ async transactionWithDriver(fn) {
105
+ const activeTransactionDriver = await this.getActiveTransactionDriver();
106
+ if (activeTransactionDriver && typeof activeTransactionDriver.transactionWithDriver === `function`) {
107
+ return activeTransactionDriver.transactionWithDriver(fn);
108
+ }
109
+ return this.enqueue(async () => {
110
+ await this.beginTopLevelTransaction();
111
+ const transactionDriver = this.createTransactionDriver();
112
+ try {
113
+ const result = await this.runWithTransactionContext(
114
+ transactionDriver,
115
+ async () => fn(transactionDriver)
116
+ );
117
+ await this.commitTopLevelTransaction();
118
+ return result;
119
+ } catch (error) {
120
+ try {
121
+ await this.rollbackTopLevelTransaction();
122
+ } catch {
123
+ }
124
+ throw error;
125
+ }
126
+ });
127
+ }
128
+ async close() {
129
+ await this.database.close();
130
+ }
131
+ getDatabase() {
132
+ return this.database;
133
+ }
134
+ enqueue(operation) {
135
+ const queuedOperation = this.queue.then(operation, operation);
136
+ this.queue = queuedOperation.then(
137
+ () => void 0,
138
+ () => void 0
139
+ );
140
+ return queuedOperation;
141
+ }
142
+ async getTransactionContextStorage() {
143
+ if (this.transactionContextStoragePromise) {
144
+ return this.transactionContextStoragePromise;
145
+ }
146
+ this.transactionContextStoragePromise = (async () => {
147
+ const asyncLocalStorageCtor = await resolveAsyncLocalStorageCtor();
148
+ if (!asyncLocalStorageCtor) {
149
+ return null;
150
+ }
151
+ return new asyncLocalStorageCtor();
152
+ })();
153
+ return this.transactionContextStoragePromise;
154
+ }
155
+ async getActiveTransactionDriver() {
156
+ const transactionContextStorage = await this.getTransactionContextStorage();
157
+ const store = transactionContextStorage?.getStore();
158
+ return store?.transactionDriver ?? null;
159
+ }
160
+ async runWithTransactionContext(transactionDriver, callback) {
161
+ const transactionContextStorage = await this.getTransactionContextStorage();
162
+ if (!transactionContextStorage) {
163
+ return callback();
164
+ }
165
+ return transactionContextStorage.run({ transactionDriver }, callback);
166
+ }
167
+ async beginTopLevelTransaction() {
168
+ await this.database.execute(`BEGIN IMMEDIATE`, false);
169
+ }
170
+ async commitTopLevelTransaction() {
171
+ await this.database.execute(`COMMIT`, false);
172
+ }
173
+ async rollbackTopLevelTransaction() {
174
+ await this.database.execute(`ROLLBACK`, false);
175
+ }
176
+ createTransactionDriver() {
177
+ const transactionDriver = {
178
+ exec: async (sql) => {
179
+ await this.database.execute(sql, false);
180
+ },
181
+ query: async (sql, params = []) => {
182
+ const result = await this.database.query(sql, [...params]);
183
+ return extractQueryRows(result, sql);
184
+ },
185
+ run: async (sql, params = []) => {
186
+ await this.database.run(sql, [...params], false);
187
+ },
188
+ transaction: async (fn) => {
189
+ assertTransactionCallbackHasDriverArg(fn);
190
+ return this.runNestedTransaction(transactionDriver, async (driver) => {
191
+ return fn(driver);
192
+ });
193
+ },
194
+ transactionWithDriver: async (fn) => this.runNestedTransaction(transactionDriver, fn)
195
+ };
196
+ return transactionDriver;
197
+ }
198
+ async runNestedTransaction(transactionDriver, fn) {
199
+ const savepointName = `tsdb_sp_${this.nextSavepointId}`;
200
+ this.nextSavepointId++;
201
+ await this.database.execute(`SAVEPOINT ${savepointName}`, false);
202
+ try {
203
+ const result = await this.runWithTransactionContext(
204
+ transactionDriver,
205
+ async () => fn(transactionDriver)
206
+ );
207
+ await this.database.execute(`RELEASE SAVEPOINT ${savepointName}`, false);
208
+ return result;
209
+ } catch (error) {
210
+ await this.database.execute(
211
+ `ROLLBACK TO SAVEPOINT ${savepointName}`,
212
+ false
213
+ );
214
+ await this.database.execute(`RELEASE SAVEPOINT ${savepointName}`, false);
215
+ throw error;
216
+ }
217
+ }
218
+ }
219
+ exports.CapacitorSQLiteDriver = CapacitorSQLiteDriver;
220
+ //# sourceMappingURL=capacitor-sqlite-driver.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capacitor-sqlite-driver.cjs","sources":["../../src/capacitor-sqlite-driver.ts"],"sourcesContent":["import { InvalidPersistedCollectionConfigError } from '@tanstack/db-sqlite-persistence-core'\nimport type { SQLiteDriver } from '@tanstack/db-sqlite-persistence-core'\nimport type {\n capSQLiteValues as CapacitorSQLiteValues,\n SQLiteDBConnection,\n} from '@capacitor-community/sqlite'\n\nexport type CapacitorSQLiteDatabaseLike = SQLiteDBConnection\n\ntype TransactionContextStore = {\n transactionDriver: SQLiteDriver\n}\n\ntype AsyncLocalStorageLike<TStore> = {\n getStore: () => TStore | undefined\n run: <TResult>(store: TStore, callback: () => TResult) => TResult\n}\n\ntype AsyncLocalStorageCtor = new <TStore>() => AsyncLocalStorageLike<TStore>\n\nlet asyncLocalStorageCtorPromise: Promise<AsyncLocalStorageCtor | null> | null =\n null\n\nfunction canAttemptNodeAsyncLocalStorageLoad(): boolean {\n if (typeof process === `undefined`) {\n return false\n }\n\n // In Capacitor webviews, process may be polyfilled without versions.\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n return typeof process.versions?.node === `string`\n}\n\nfunction getNodeAsyncHooksSpecifier(): string {\n const moduleName = `async_hooks`\n return `node:${moduleName}`\n}\n\nasync function resolveAsyncLocalStorageCtor(): Promise<AsyncLocalStorageCtor | null> {\n if (asyncLocalStorageCtorPromise) {\n return asyncLocalStorageCtorPromise\n }\n\n asyncLocalStorageCtorPromise = (async () => {\n if (!canAttemptNodeAsyncLocalStorageLoad()) {\n return null\n }\n\n try {\n const asyncHooksModule = (await import(getNodeAsyncHooksSpecifier())) as {\n AsyncLocalStorage?: AsyncLocalStorageCtor\n }\n\n return typeof asyncHooksModule.AsyncLocalStorage === `function`\n ? asyncHooksModule.AsyncLocalStorage\n : null\n } catch {\n return null\n }\n })()\n\n return asyncLocalStorageCtorPromise\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 isCapacitorSQLiteDatabaseLike(\n value: unknown,\n): value is CapacitorSQLiteDatabaseLike {\n const candidate = value as Partial<CapacitorSQLiteDatabaseLike>\n return (\n typeof value === `object` &&\n value !== null &&\n typeof candidate.execute === `function` &&\n typeof candidate.query === `function` &&\n typeof candidate.run === `function`\n )\n}\n\nfunction extractQueryRows<T>(\n result: CapacitorSQLiteValues,\n sql: string,\n): ReadonlyArray<T> {\n if (Array.isArray(result.values)) {\n return result.values as ReadonlyArray<T>\n }\n\n throw new InvalidPersistedCollectionConfigError(\n `Unsupported Capacitor SQLite query result shape for SQL \"${sql}\"`,\n )\n}\n\nexport type CapacitorSQLiteDriverOptions = {\n database: CapacitorSQLiteDatabaseLike\n}\n\nexport class CapacitorSQLiteDriver implements SQLiteDriver {\n private readonly database: CapacitorSQLiteDatabaseLike\n private queue: Promise<void> = Promise.resolve()\n private nextSavepointId = 1\n private transactionContextStoragePromise: Promise<AsyncLocalStorageLike<TransactionContextStore> | null> | null =\n null\n\n constructor(options: CapacitorSQLiteDriverOptions) {\n if (!isCapacitorSQLiteDatabaseLike(options.database)) {\n throw new InvalidPersistedCollectionConfigError(\n `Capacitor SQLite database object must provide execute/query/run methods`,\n )\n }\n\n this.database = options.database\n }\n\n async exec(sql: string): Promise<void> {\n const activeTransactionDriver = await this.getActiveTransactionDriver()\n if (activeTransactionDriver) {\n await activeTransactionDriver.exec(sql)\n return\n }\n\n await this.enqueue(async () => {\n await this.database.execute(sql, false)\n })\n }\n\n async query<T>(\n sql: string,\n params: ReadonlyArray<unknown> = [],\n ): Promise<ReadonlyArray<T>> {\n const activeTransactionDriver = await this.getActiveTransactionDriver()\n if (activeTransactionDriver) {\n return activeTransactionDriver.query<T>(sql, params)\n }\n\n return this.enqueue(async () => {\n const result = await this.database.query(sql, [...params])\n return extractQueryRows<T>(result, sql)\n })\n }\n\n async run(sql: string, params: ReadonlyArray<unknown> = []): Promise<void> {\n const activeTransactionDriver = await this.getActiveTransactionDriver()\n if (activeTransactionDriver) {\n await activeTransactionDriver.run(sql, params)\n return\n }\n\n await this.enqueue(async () => {\n await this.database.run(sql, [...params], false)\n })\n }\n\n async transaction<T>(\n fn: (transactionDriver: SQLiteDriver) => Promise<T>,\n ): Promise<T> {\n assertTransactionCallbackHasDriverArg(fn)\n\n const activeTransactionDriver = await this.getActiveTransactionDriver()\n if (activeTransactionDriver) {\n return activeTransactionDriver.transaction(fn)\n }\n\n return this.transactionWithDriver((transactionDriver) =>\n fn(transactionDriver),\n )\n }\n\n async transactionWithDriver<T>(\n fn: (transactionDriver: SQLiteDriver) => Promise<T>,\n ): Promise<T> {\n const activeTransactionDriver = await this.getActiveTransactionDriver()\n if (\n activeTransactionDriver &&\n typeof activeTransactionDriver.transactionWithDriver === `function`\n ) {\n return activeTransactionDriver.transactionWithDriver(fn)\n }\n\n return this.enqueue(async () => {\n await this.beginTopLevelTransaction()\n const transactionDriver = this.createTransactionDriver()\n try {\n const result = await this.runWithTransactionContext(\n transactionDriver,\n async () => fn(transactionDriver),\n )\n await this.commitTopLevelTransaction()\n return result\n } catch (error) {\n try {\n await this.rollbackTopLevelTransaction()\n } catch {\n // Preserve the original transaction failure as the primary error.\n }\n throw error\n }\n })\n }\n\n async close(): Promise<void> {\n await this.database.close()\n }\n\n getDatabase(): CapacitorSQLiteDatabaseLike {\n return this.database\n }\n\n private enqueue<T>(operation: () => Promise<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 async getTransactionContextStorage(): Promise<AsyncLocalStorageLike<TransactionContextStore> | null> {\n if (this.transactionContextStoragePromise) {\n return this.transactionContextStoragePromise\n }\n\n this.transactionContextStoragePromise = (async () => {\n const asyncLocalStorageCtor = await resolveAsyncLocalStorageCtor()\n if (!asyncLocalStorageCtor) {\n return null\n }\n\n return new asyncLocalStorageCtor<TransactionContextStore>()\n })()\n\n return this.transactionContextStoragePromise\n }\n\n private async getActiveTransactionDriver(): Promise<SQLiteDriver | null> {\n const transactionContextStorage = await this.getTransactionContextStorage()\n const store = transactionContextStorage?.getStore()\n return store?.transactionDriver ?? null\n }\n\n private async runWithTransactionContext<TResult>(\n transactionDriver: SQLiteDriver,\n callback: () => Promise<TResult>,\n ): Promise<TResult> {\n const transactionContextStorage = await this.getTransactionContextStorage()\n if (!transactionContextStorage) {\n return callback()\n }\n\n return transactionContextStorage.run({ transactionDriver }, callback)\n }\n\n private async beginTopLevelTransaction(): Promise<void> {\n await this.database.execute(`BEGIN IMMEDIATE`, false)\n }\n\n private async commitTopLevelTransaction(): Promise<void> {\n await this.database.execute(`COMMIT`, false)\n }\n\n private async rollbackTopLevelTransaction(): Promise<void> {\n await this.database.execute(`ROLLBACK`, false)\n }\n\n private createTransactionDriver(): SQLiteDriver {\n const transactionDriver: SQLiteDriver = {\n exec: async (sql) => {\n await this.database.execute(sql, false)\n },\n query: async <T>(\n sql: string,\n params: ReadonlyArray<unknown> = [],\n ): Promise<ReadonlyArray<T>> => {\n const result = await this.database.query(sql, [...params])\n return extractQueryRows<T>(result, sql)\n },\n run: async (sql, params = []) => {\n await this.database.run(sql, [...params], false)\n },\n transaction: async <T>(\n fn: (transactionDriver: SQLiteDriver) => Promise<T>,\n ): Promise<T> => {\n assertTransactionCallbackHasDriverArg(fn)\n return this.runNestedTransaction(transactionDriver, async (driver) => {\n return fn(driver)\n })\n },\n transactionWithDriver: async <T>(\n fn: (transactionDriver: 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: (transactionDriver: SQLiteDriver) => Promise<T>,\n ): Promise<T> {\n const savepointName = `tsdb_sp_${this.nextSavepointId}`\n this.nextSavepointId++\n await this.database.execute(`SAVEPOINT ${savepointName}`, false)\n\n try {\n const result = await this.runWithTransactionContext(\n transactionDriver,\n async () => fn(transactionDriver),\n )\n await this.database.execute(`RELEASE SAVEPOINT ${savepointName}`, false)\n return result\n } catch (error) {\n await this.database.execute(\n `ROLLBACK TO SAVEPOINT ${savepointName}`,\n false,\n )\n await this.database.execute(`RELEASE SAVEPOINT ${savepointName}`, false)\n throw error\n }\n }\n}\n\nexport function createCapacitorSQLiteDriver(\n options: CapacitorSQLiteDriverOptions,\n): CapacitorSQLiteDriver {\n return new CapacitorSQLiteDriver(options)\n}\n"],"names":["InvalidPersistedCollectionConfigError"],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import { SQLiteDriver } from '@tanstack/db-sqlite-persistence-core';
2
+ import { SQLiteDBConnection } from '@capacitor-community/sqlite';
3
+ export type CapacitorSQLiteDatabaseLike = SQLiteDBConnection;
4
+ export type CapacitorSQLiteDriverOptions = {
5
+ database: CapacitorSQLiteDatabaseLike;
6
+ };
7
+ export declare class CapacitorSQLiteDriver implements SQLiteDriver {
8
+ private readonly database;
9
+ private queue;
10
+ private nextSavepointId;
11
+ private transactionContextStoragePromise;
12
+ constructor(options: CapacitorSQLiteDriverOptions);
13
+ exec(sql: string): Promise<void>;
14
+ query<T>(sql: string, params?: ReadonlyArray<unknown>): Promise<ReadonlyArray<T>>;
15
+ run(sql: string, params?: ReadonlyArray<unknown>): Promise<void>;
16
+ transaction<T>(fn: (transactionDriver: SQLiteDriver) => Promise<T>): Promise<T>;
17
+ transactionWithDriver<T>(fn: (transactionDriver: SQLiteDriver) => Promise<T>): Promise<T>;
18
+ close(): Promise<void>;
19
+ getDatabase(): CapacitorSQLiteDatabaseLike;
20
+ private enqueue;
21
+ private getTransactionContextStorage;
22
+ private getActiveTransactionDriver;
23
+ private runWithTransactionContext;
24
+ private beginTopLevelTransaction;
25
+ private commitTopLevelTransaction;
26
+ private rollbackTopLevelTransaction;
27
+ private createTransactionDriver;
28
+ private runNestedTransaction;
29
+ }
30
+ export declare function createCapacitorSQLiteDriver(options: CapacitorSQLiteDriverOptions): CapacitorSQLiteDriver;
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const capacitorPersistence = require("./capacitor-persistence.cjs");
4
+ function createCapacitorSQLitePersistence(options) {
5
+ return capacitorPersistence.createCapacitorSQLitePersistence(options);
6
+ }
7
+ exports.createCapacitorSQLitePersistence = createCapacitorSQLitePersistence;
8
+ //# sourceMappingURL=capacitor.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capacitor.cjs","sources":["../../src/capacitor.ts"],"sourcesContent":["import { createCapacitorSQLitePersistence as createPersistence } from './capacitor-persistence'\nimport type {\n CapacitorSQLitePersistenceOptions as CapacitorSQLitePersistenceOptionsBase,\n CapacitorSQLiteSchemaMismatchPolicy as CapacitorSQLiteSchemaMismatchPolicyBase,\n} from './capacitor-persistence'\nimport type { PersistedCollectionPersistence } from '@tanstack/db-sqlite-persistence-core'\n\nexport type CapacitorSQLitePersistenceOptions =\n CapacitorSQLitePersistenceOptionsBase\nexport type CapacitorSQLiteSchemaMismatchPolicy =\n CapacitorSQLiteSchemaMismatchPolicyBase\nexport type { CapacitorSQLiteDatabaseLike } from './capacitor-persistence'\nexport type { SQLiteDBConnection } from './capacitor-persistence'\n\nexport function createCapacitorSQLitePersistence<\n T extends object,\n TKey extends string | number = string | number,\n>(\n options: CapacitorSQLitePersistenceOptions,\n): PersistedCollectionPersistence<T, TKey> {\n return createPersistence<T, TKey>(options)\n}\n"],"names":["createPersistence"],"mappings":";;;AAcO,SAAS,iCAId,SACyC;AACzC,SAAOA,qBAAAA,iCAA2B,OAAO;AAC3C;;"}
@@ -0,0 +1,7 @@
1
+ import { CapacitorSQLitePersistenceOptions as CapacitorSQLitePersistenceOptionsBase, CapacitorSQLiteSchemaMismatchPolicy as CapacitorSQLiteSchemaMismatchPolicyBase } from './capacitor-persistence.cjs';
2
+ import { PersistedCollectionPersistence } from '@tanstack/db-sqlite-persistence-core';
3
+ export type CapacitorSQLitePersistenceOptions = CapacitorSQLitePersistenceOptionsBase;
4
+ export type CapacitorSQLiteSchemaMismatchPolicy = CapacitorSQLiteSchemaMismatchPolicyBase;
5
+ export type { CapacitorSQLiteDatabaseLike } from './capacitor-persistence.cjs';
6
+ export type { SQLiteDBConnection } from './capacitor-persistence.cjs';
7
+ export declare function createCapacitorSQLitePersistence<T extends object, TKey extends string | number = string | number>(options: CapacitorSQLitePersistenceOptions): PersistedCollectionPersistence<T, TKey>;
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const capacitor = require("./capacitor.cjs");
4
+ const dbSqlitePersistenceCore = require("@tanstack/db-sqlite-persistence-core");
5
+ exports.createCapacitorSQLitePersistence = capacitor.createCapacitorSQLitePersistence;
6
+ Object.defineProperty(exports, "persistedCollectionOptions", {
7
+ enumerable: true,
8
+ get: () => dbSqlitePersistenceCore.persistedCollectionOptions
9
+ });
10
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;"}
@@ -0,0 +1,4 @@
1
+ export { createCapacitorSQLitePersistence } from './capacitor.cjs';
2
+ export type { CapacitorSQLiteDatabaseLike, CapacitorSQLitePersistenceOptions, CapacitorSQLiteSchemaMismatchPolicy, SQLiteDBConnection, } from './capacitor.cjs';
3
+ export { persistedCollectionOptions } from '@tanstack/db-sqlite-persistence-core';
4
+ export type { PersistedCollectionCoordinator, PersistedCollectionPersistence, } from '@tanstack/db-sqlite-persistence-core';
@@ -0,0 +1,13 @@
1
+ import { SQLiteDBConnection } from '@capacitor-community/sqlite';
2
+ import { PersistedCollectionCoordinator, PersistedCollectionPersistence, SQLiteCoreAdapterOptions } from '@tanstack/db-sqlite-persistence-core';
3
+ export type { CapacitorSQLiteDatabaseLike } from './capacitor-sqlite-driver.js';
4
+ export type { SQLiteDBConnection } from '@capacitor-community/sqlite';
5
+ type CapacitorSQLiteCoreSchemaMismatchPolicy = `sync-present-reset` | `sync-absent-error` | `reset`;
6
+ export type CapacitorSQLiteSchemaMismatchPolicy = CapacitorSQLiteCoreSchemaMismatchPolicy | `throw`;
7
+ type CapacitorSQLitePersistenceBaseOptions = Omit<SQLiteCoreAdapterOptions, `driver` | `schemaVersion` | `schemaMismatchPolicy`> & {
8
+ database: SQLiteDBConnection;
9
+ coordinator?: PersistedCollectionCoordinator;
10
+ schemaMismatchPolicy?: CapacitorSQLiteSchemaMismatchPolicy;
11
+ };
12
+ export type CapacitorSQLitePersistenceOptions = CapacitorSQLitePersistenceBaseOptions;
13
+ export declare function createCapacitorSQLitePersistence<T extends object, TKey extends string | number = string | number>(options: CapacitorSQLitePersistenceOptions): PersistedCollectionPersistence<T, TKey>;
@@ -0,0 +1,79 @@
1
+ import { SingleProcessCoordinator, createSQLiteCorePersistenceAdapter } from "@tanstack/db-sqlite-persistence-core";
2
+ import { CapacitorSQLiteDriver } from "./capacitor-sqlite-driver.js";
3
+ function normalizeSchemaMismatchPolicy(policy) {
4
+ if (policy === `throw`) {
5
+ return `sync-absent-error`;
6
+ }
7
+ return policy;
8
+ }
9
+ function resolveSchemaMismatchPolicy(explicitPolicy, mode) {
10
+ if (explicitPolicy) {
11
+ return normalizeSchemaMismatchPolicy(explicitPolicy);
12
+ }
13
+ return mode === `sync-present` ? `sync-present-reset` : `sync-absent-error`;
14
+ }
15
+ function createAdapterCacheKey(schemaMismatchPolicy, schemaVersion) {
16
+ const schemaVersionKey = schemaVersion === void 0 ? `schema:default` : `schema:${schemaVersion}`;
17
+ return `${schemaMismatchPolicy}|${schemaVersionKey}`;
18
+ }
19
+ function createInternalSQLiteDriver(options) {
20
+ return new CapacitorSQLiteDriver({
21
+ database: options.database
22
+ });
23
+ }
24
+ function resolveAdapterBaseOptions(options) {
25
+ return {
26
+ appliedTxPruneMaxRows: options.appliedTxPruneMaxRows,
27
+ appliedTxPruneMaxAgeSeconds: options.appliedTxPruneMaxAgeSeconds,
28
+ pullSinceReloadThreshold: options.pullSinceReloadThreshold
29
+ };
30
+ }
31
+ function createCapacitorSQLitePersistence(options) {
32
+ const { coordinator, schemaMismatchPolicy } = options;
33
+ const driver = createInternalSQLiteDriver(options);
34
+ const adapterBaseOptions = resolveAdapterBaseOptions(options);
35
+ const resolvedCoordinator = coordinator ?? new SingleProcessCoordinator();
36
+ const adapterCache = /* @__PURE__ */ new Map();
37
+ const getAdapterForCollection = (mode, schemaVersion) => {
38
+ const resolvedSchemaMismatchPolicy = resolveSchemaMismatchPolicy(
39
+ schemaMismatchPolicy,
40
+ mode
41
+ );
42
+ const cacheKey = createAdapterCacheKey(
43
+ resolvedSchemaMismatchPolicy,
44
+ schemaVersion
45
+ );
46
+ const cachedAdapter = adapterCache.get(cacheKey);
47
+ if (cachedAdapter) {
48
+ return cachedAdapter;
49
+ }
50
+ const adapter = createSQLiteCorePersistenceAdapter({
51
+ ...adapterBaseOptions,
52
+ driver,
53
+ schemaMismatchPolicy: resolvedSchemaMismatchPolicy,
54
+ ...schemaVersion === void 0 ? {} : { schemaVersion }
55
+ });
56
+ adapterCache.set(cacheKey, adapter);
57
+ return adapter;
58
+ };
59
+ const createCollectionPersistence = (mode, schemaVersion) => ({
60
+ adapter: getAdapterForCollection(
61
+ mode,
62
+ schemaVersion
63
+ ),
64
+ coordinator: resolvedCoordinator
65
+ });
66
+ const defaultPersistence = createCollectionPersistence(
67
+ `sync-absent`,
68
+ void 0
69
+ );
70
+ return {
71
+ ...defaultPersistence,
72
+ resolvePersistenceForCollection: ({ mode, schemaVersion }) => createCollectionPersistence(mode, schemaVersion),
73
+ resolvePersistenceForMode: (mode) => createCollectionPersistence(mode, void 0)
74
+ };
75
+ }
76
+ export {
77
+ createCapacitorSQLitePersistence
78
+ };
79
+ //# sourceMappingURL=capacitor-persistence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capacitor-persistence.js","sources":["../../src/capacitor-persistence.ts"],"sourcesContent":["import {\n SingleProcessCoordinator,\n createSQLiteCorePersistenceAdapter,\n} from '@tanstack/db-sqlite-persistence-core'\nimport { CapacitorSQLiteDriver } from './capacitor-sqlite-driver'\nimport type { SQLiteDBConnection } from '@capacitor-community/sqlite'\nimport type {\n PersistedCollectionCoordinator,\n PersistedCollectionMode,\n PersistedCollectionPersistence,\n SQLiteCoreAdapterOptions,\n SQLiteDriver,\n} from '@tanstack/db-sqlite-persistence-core'\n\nexport type { CapacitorSQLiteDatabaseLike } from './capacitor-sqlite-driver'\nexport type { SQLiteDBConnection } from '@capacitor-community/sqlite'\n\ntype CapacitorSQLiteCoreSchemaMismatchPolicy =\n | `sync-present-reset`\n | `sync-absent-error`\n | `reset`\n\nexport type CapacitorSQLiteSchemaMismatchPolicy =\n | CapacitorSQLiteCoreSchemaMismatchPolicy\n | `throw`\n\ntype CapacitorSQLitePersistenceBaseOptions = Omit<\n SQLiteCoreAdapterOptions,\n `driver` | `schemaVersion` | `schemaMismatchPolicy`\n> & {\n database: SQLiteDBConnection\n coordinator?: PersistedCollectionCoordinator\n schemaMismatchPolicy?: CapacitorSQLiteSchemaMismatchPolicy\n}\n\nexport type CapacitorSQLitePersistenceOptions =\n CapacitorSQLitePersistenceBaseOptions\n\nfunction normalizeSchemaMismatchPolicy(\n policy: CapacitorSQLiteSchemaMismatchPolicy,\n): CapacitorSQLiteCoreSchemaMismatchPolicy {\n if (policy === `throw`) {\n return `sync-absent-error`\n }\n\n return policy\n}\n\nfunction resolveSchemaMismatchPolicy(\n explicitPolicy: CapacitorSQLiteSchemaMismatchPolicy | undefined,\n mode: PersistedCollectionMode,\n): CapacitorSQLiteCoreSchemaMismatchPolicy {\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: CapacitorSQLiteCoreSchemaMismatchPolicy,\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: CapacitorSQLitePersistenceOptions,\n): SQLiteDriver {\n return new CapacitorSQLiteDriver({\n database: options.database,\n })\n}\n\nfunction resolveAdapterBaseOptions(\n options: CapacitorSQLitePersistenceOptions,\n): Omit<\n SQLiteCoreAdapterOptions,\n `driver` | `schemaVersion` | `schemaMismatchPolicy`\n> {\n return {\n appliedTxPruneMaxRows: options.appliedTxPruneMaxRows,\n appliedTxPruneMaxAgeSeconds: options.appliedTxPruneMaxAgeSeconds,\n pullSinceReloadThreshold: options.pullSinceReloadThreshold,\n }\n}\n\nexport function createCapacitorSQLitePersistence<\n T extends object,\n TKey extends string | number = string | number,\n>(\n options: CapacitorSQLitePersistenceOptions,\n): PersistedCollectionPersistence<T, TKey> {\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<\n typeof createSQLiteCorePersistenceAdapter<\n Record<string, unknown>,\n string | number\n >\n >\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 Record<string, unknown>,\n string | number\n >({\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<T, TKey> => ({\n adapter: getAdapterForCollection(\n mode,\n schemaVersion,\n ) as unknown as PersistedCollectionPersistence<T, TKey>[`adapter`],\n coordinator: resolvedCoordinator,\n })\n\n const defaultPersistence = createCollectionPersistence(\n `sync-absent`,\n undefined,\n )\n\n return {\n ...defaultPersistence,\n resolvePersistenceForCollection: ({ mode, schemaVersion }) =>\n createCollectionPersistence(mode, schemaVersion),\n resolvePersistenceForMode: (mode) =>\n createCollectionPersistence(mode, undefined),\n }\n}\n"],"names":[],"mappings":";;AAsCA,SAAS,8BACP,QACyC;AACzC,MAAI,WAAW,SAAS;AACtB,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEA,SAAS,4BACP,gBACA,MACyC;AACzC,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,sBAAsB;AAAA,IAC/B,UAAU,QAAQ;AAAA,EAAA,CACnB;AACH;AAEA,SAAS,0BACP,SAIA;AACA,SAAO;AAAA,IACL,uBAAuB,QAAQ;AAAA,IAC/B,6BAA6B,QAAQ;AAAA,IACrC,0BAA0B,QAAQ;AAAA,EAAA;AAEtC;AAEO,SAAS,iCAId,SACyC;AACzC,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;AAUzB,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,mCAGd;AAAA,MACA,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,mBAC6C;AAAA,IAC7C,SAAS;AAAA,MACP;AAAA,MACA;AAAA,IAAA;AAAA,IAEF,aAAa;AAAA,EAAA;AAGf,QAAM,qBAAqB;AAAA,IACzB;AAAA,IACA;AAAA,EAAA;AAGF,SAAO;AAAA,IACL,GAAG;AAAA,IACH,iCAAiC,CAAC,EAAE,MAAM,oBACxC,4BAA4B,MAAM,aAAa;AAAA,IACjD,2BAA2B,CAAC,SAC1B,4BAA4B,MAAM,MAAS;AAAA,EAAA;AAEjD;"}