@anfenn/dync 1.0.0
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/LICENSE +21 -0
- package/README.md +212 -0
- package/dist/capacitor.cjs +228 -0
- package/dist/capacitor.cjs.map +1 -0
- package/dist/capacitor.d.cts +62 -0
- package/dist/capacitor.d.ts +62 -0
- package/dist/capacitor.js +9 -0
- package/dist/capacitor.js.map +1 -0
- package/dist/chunk-LGHOZECP.js +3884 -0
- package/dist/chunk-LGHOZECP.js.map +1 -0
- package/dist/chunk-SQB6E7V2.js +191 -0
- package/dist/chunk-SQB6E7V2.js.map +1 -0
- package/dist/dexie-Bv-fV10P.d.cts +444 -0
- package/dist/dexie-DJFApKsM.d.ts +444 -0
- package/dist/dexie.cjs +381 -0
- package/dist/dexie.cjs.map +1 -0
- package/dist/dexie.d.cts +3 -0
- package/dist/dexie.d.ts +3 -0
- package/dist/dexie.js +343 -0
- package/dist/dexie.js.map +1 -0
- package/dist/expoSqlite.cjs +98 -0
- package/dist/expoSqlite.cjs.map +1 -0
- package/dist/expoSqlite.d.cts +17 -0
- package/dist/expoSqlite.d.ts +17 -0
- package/dist/expoSqlite.js +61 -0
- package/dist/expoSqlite.js.map +1 -0
- package/dist/index.cjs +3916 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +8 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/index.shared-CPIge2ZM.d.ts +234 -0
- package/dist/index.shared-YSn6c01d.d.cts +234 -0
- package/dist/node.cjs +126 -0
- package/dist/node.cjs.map +1 -0
- package/dist/node.d.cts +80 -0
- package/dist/node.d.ts +80 -0
- package/dist/node.js +89 -0
- package/dist/node.js.map +1 -0
- package/dist/react/index.cjs +1754 -0
- package/dist/react/index.cjs.map +1 -0
- package/dist/react/index.d.cts +40 -0
- package/dist/react/index.d.ts +40 -0
- package/dist/react/index.js +78 -0
- package/dist/react/index.js.map +1 -0
- package/dist/types-CSbIAfu2.d.cts +46 -0
- package/dist/types-CSbIAfu2.d.ts +46 -0
- package/dist/wa-sqlite.cjs +318 -0
- package/dist/wa-sqlite.cjs.map +1 -0
- package/dist/wa-sqlite.d.cts +175 -0
- package/dist/wa-sqlite.d.ts +175 -0
- package/dist/wa-sqlite.js +281 -0
- package/dist/wa-sqlite.js.map +1 -0
- package/package.json +171 -0
- package/src/addVisibilityChangeListener.native.ts +33 -0
- package/src/addVisibilityChangeListener.ts +24 -0
- package/src/capacitor.ts +4 -0
- package/src/core/StateManager.ts +272 -0
- package/src/core/firstLoad.ts +332 -0
- package/src/core/pullOperations.ts +212 -0
- package/src/core/pushOperations.ts +290 -0
- package/src/core/tableEnhancers.ts +457 -0
- package/src/core/types.ts +3 -0
- package/src/createLocalId.native.ts +8 -0
- package/src/createLocalId.ts +6 -0
- package/src/dexie.ts +2 -0
- package/src/expoSqlite.ts +2 -0
- package/src/helpers.ts +87 -0
- package/src/index.native.ts +28 -0
- package/src/index.shared.ts +613 -0
- package/src/index.ts +28 -0
- package/src/logger.ts +26 -0
- package/src/node.ts +4 -0
- package/src/react/index.ts +2 -0
- package/src/react/useDync.ts +156 -0
- package/src/storage/dexie/DexieAdapter.ts +72 -0
- package/src/storage/dexie/DexieQueryContext.ts +14 -0
- package/src/storage/dexie/DexieStorageCollection.ts +124 -0
- package/src/storage/dexie/DexieStorageTable.ts +123 -0
- package/src/storage/dexie/DexieStorageWhereClause.ts +103 -0
- package/src/storage/dexie/helpers.ts +1 -0
- package/src/storage/dexie/index.ts +7 -0
- package/src/storage/memory/MemoryAdapter.ts +55 -0
- package/src/storage/memory/MemoryCollection.ts +215 -0
- package/src/storage/memory/MemoryQueryContext.ts +14 -0
- package/src/storage/memory/MemoryTable.ts +336 -0
- package/src/storage/memory/MemoryWhereClause.ts +134 -0
- package/src/storage/memory/index.ts +7 -0
- package/src/storage/memory/types.ts +24 -0
- package/src/storage/sqlite/SQLiteAdapter.ts +564 -0
- package/src/storage/sqlite/SQLiteCollection.ts +294 -0
- package/src/storage/sqlite/SQLiteTable.ts +604 -0
- package/src/storage/sqlite/SQLiteWhereClause.ts +341 -0
- package/src/storage/sqlite/SqliteQueryContext.ts +30 -0
- package/src/storage/sqlite/drivers/BetterSqlite3Driver.ts +156 -0
- package/src/storage/sqlite/drivers/CapacitorFastSqlDriver.ts +114 -0
- package/src/storage/sqlite/drivers/CapacitorSQLiteDriver.ts +137 -0
- package/src/storage/sqlite/drivers/ExpoSQLiteDriver.native.ts +67 -0
- package/src/storage/sqlite/drivers/WaSqliteDriver.ts +537 -0
- package/src/storage/sqlite/drivers/wa-sqlite-vfs.d.ts +46 -0
- package/src/storage/sqlite/helpers.ts +144 -0
- package/src/storage/sqlite/index.ts +11 -0
- package/src/storage/sqlite/schema.ts +44 -0
- package/src/storage/sqlite/types.ts +164 -0
- package/src/storage/types.ts +112 -0
- package/src/types.ts +186 -0
- package/src/wa-sqlite.ts +4 -0
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { A as AfterRemoteAddCallback, a as ApiFunctions, d as BatchFirstLoadResult, b as BatchPushPayload, c as BatchPushResult, B as BatchSync, C as ConflictResolutionStrategy, D as Dync, F as FirstLoadProgress, e as FirstLoadProgressCallback, f as MissingRemoteRecordDuringUpdateCallback, M as MissingRemoteRecordStrategy, g as MutationEvent, S as SyncAction, h as SyncOptions, i as SyncState, j as SyncedRecord, T as TableMap } from './index.shared-YSn6c01d.cjs';
|
|
2
|
+
export { M as MemoryAdapter, a as MemoryQueryContext, S as SQLiteAdapter, b as SqliteQueryContext, c as StorageAdapter } from './dexie-Bv-fV10P.cjs';
|
|
3
|
+
export { S as SQLiteDatabaseDriver, b as SQLiteQueryResult, a as SQLiteRunResult } from './types-CSbIAfu2.cjs';
|
|
4
|
+
import 'dexie';
|
|
5
|
+
|
|
6
|
+
declare function createLocalId(): string;
|
|
7
|
+
|
|
8
|
+
export { createLocalId };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { A as AfterRemoteAddCallback, a as ApiFunctions, d as BatchFirstLoadResult, b as BatchPushPayload, c as BatchPushResult, B as BatchSync, C as ConflictResolutionStrategy, D as Dync, F as FirstLoadProgress, e as FirstLoadProgressCallback, f as MissingRemoteRecordDuringUpdateCallback, M as MissingRemoteRecordStrategy, g as MutationEvent, S as SyncAction, h as SyncOptions, i as SyncState, j as SyncedRecord, T as TableMap } from './index.shared-CPIge2ZM.js';
|
|
2
|
+
export { M as MemoryAdapter, a as MemoryQueryContext, S as SQLiteAdapter, b as SqliteQueryContext, c as StorageAdapter } from './dexie-DJFApKsM.js';
|
|
3
|
+
export { S as SQLiteDatabaseDriver, b as SQLiteQueryResult, a as SQLiteRunResult } from './types-CSbIAfu2.js';
|
|
4
|
+
import 'dexie';
|
|
5
|
+
|
|
6
|
+
declare function createLocalId(): string;
|
|
7
|
+
|
|
8
|
+
export { createLocalId };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Dync,
|
|
3
|
+
MemoryAdapter,
|
|
4
|
+
MemoryQueryContext,
|
|
5
|
+
SQLiteAdapter,
|
|
6
|
+
SqliteQueryContext,
|
|
7
|
+
SyncAction,
|
|
8
|
+
createLocalId
|
|
9
|
+
} from "./chunk-LGHOZECP.js";
|
|
10
|
+
import "./chunk-SQB6E7V2.js";
|
|
11
|
+
export {
|
|
12
|
+
Dync,
|
|
13
|
+
MemoryAdapter,
|
|
14
|
+
MemoryQueryContext,
|
|
15
|
+
SQLiteAdapter,
|
|
16
|
+
SqliteQueryContext,
|
|
17
|
+
SyncAction,
|
|
18
|
+
createLocalId
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import { d as StorageTable, c as StorageAdapter, T as TableSchemaDefinition, D as DexieQueryContext, b as SqliteQueryContext, a as MemoryQueryContext } from './dexie-DJFApKsM.js';
|
|
2
|
+
import { c as SQLiteVersionConfigurator } from './types-CSbIAfu2.js';
|
|
3
|
+
|
|
4
|
+
type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'none';
|
|
5
|
+
interface Logger {
|
|
6
|
+
debug: (...args: any[]) => void;
|
|
7
|
+
info: (...args: any[]) => void;
|
|
8
|
+
warn: (...args: any[]) => void;
|
|
9
|
+
error: (...args: any[]) => void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
interface SyncedRecord {
|
|
13
|
+
_localId: string;
|
|
14
|
+
id?: any;
|
|
15
|
+
updated_at: string;
|
|
16
|
+
[k: string]: any;
|
|
17
|
+
}
|
|
18
|
+
interface ApiFunctions {
|
|
19
|
+
add: (item: any) => Promise<any | undefined>;
|
|
20
|
+
update: (id: any, changes: any, item: any) => Promise<boolean>;
|
|
21
|
+
remove: (id: any) => Promise<void>;
|
|
22
|
+
list: (lastUpdatedAt: Date) => Promise<any[]>;
|
|
23
|
+
firstLoad?: (lastId: any) => Promise<any[]>;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Payload for a single change in a batch push request.
|
|
27
|
+
*/
|
|
28
|
+
interface BatchPushPayload {
|
|
29
|
+
table: string;
|
|
30
|
+
action: 'add' | 'update' | 'remove';
|
|
31
|
+
localId: string;
|
|
32
|
+
id?: any;
|
|
33
|
+
data?: any;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Result for a single change in a batch push response.
|
|
37
|
+
*/
|
|
38
|
+
interface BatchPushResult {
|
|
39
|
+
localId: string;
|
|
40
|
+
success: boolean;
|
|
41
|
+
id?: any;
|
|
42
|
+
updated_at?: string;
|
|
43
|
+
error?: string;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Result for batch first load operation.
|
|
47
|
+
*/
|
|
48
|
+
interface BatchFirstLoadResult {
|
|
49
|
+
data: Record<string, any[]>;
|
|
50
|
+
cursors: Record<string, any>;
|
|
51
|
+
hasMore: boolean;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Batch sync configuration for
|
|
55
|
+
*/
|
|
56
|
+
interface BatchSync {
|
|
57
|
+
/**
|
|
58
|
+
* Array of table names to sync.
|
|
59
|
+
*/
|
|
60
|
+
syncTables: string[];
|
|
61
|
+
/**
|
|
62
|
+
* Push all pending changes to the server in a single request.
|
|
63
|
+
* @param changes Array of changes to push
|
|
64
|
+
* @returns Array of results, one per change, correlated by localId
|
|
65
|
+
*/
|
|
66
|
+
push: (changes: BatchPushPayload[]) => Promise<BatchPushResult[]>;
|
|
67
|
+
/**
|
|
68
|
+
* Pull changes from server since last sync.
|
|
69
|
+
* @param since Map of table name to last pulled timestamp
|
|
70
|
+
* @returns Map of table name to array of changed records
|
|
71
|
+
*/
|
|
72
|
+
pull: (since: Record<string, Date>) => Promise<Record<string, any[]>>;
|
|
73
|
+
/**
|
|
74
|
+
* Initial data load for all tables (optional).
|
|
75
|
+
* @param cursors Map of table name to pagination cursor
|
|
76
|
+
* @returns Batch first load result with data, cursors, and hasMore flag
|
|
77
|
+
*/
|
|
78
|
+
firstLoad?: (cursors: Record<string, any>) => Promise<BatchFirstLoadResult>;
|
|
79
|
+
}
|
|
80
|
+
type MissingRemoteRecordStrategy = 'ignore' | 'delete-local-record' | 'insert-remote-record';
|
|
81
|
+
type ConflictResolutionStrategy = 'local-wins' | 'remote-wins' | 'try-shallow-merge';
|
|
82
|
+
type AfterRemoteAddCallback = (stateKey: string, item: SyncedRecord) => void;
|
|
83
|
+
type MissingRemoteRecordDuringUpdateCallback = (strategy: MissingRemoteRecordStrategy, item: SyncedRecord) => void;
|
|
84
|
+
interface SyncOptions {
|
|
85
|
+
syncInterval?: number;
|
|
86
|
+
logger?: Logger;
|
|
87
|
+
minLogLevel?: LogLevel;
|
|
88
|
+
onAfterRemoteAdd?: AfterRemoteAddCallback;
|
|
89
|
+
missingRemoteRecordDuringUpdateStrategy?: MissingRemoteRecordStrategy;
|
|
90
|
+
onAfterMissingRemoteRecordDuringUpdate?: MissingRemoteRecordDuringUpdateCallback;
|
|
91
|
+
conflictResolutionStrategy?: ConflictResolutionStrategy;
|
|
92
|
+
}
|
|
93
|
+
interface FirstLoadProgress {
|
|
94
|
+
table: string;
|
|
95
|
+
inserted: number;
|
|
96
|
+
updated: number;
|
|
97
|
+
total: number;
|
|
98
|
+
}
|
|
99
|
+
type FirstLoadProgressCallback = (progress: FirstLoadProgress) => void;
|
|
100
|
+
type SyncApi = {
|
|
101
|
+
enable: (enabled: boolean) => Promise<void>;
|
|
102
|
+
startFirstLoad: (onProgress?: FirstLoadProgressCallback) => Promise<void>;
|
|
103
|
+
getState: () => SyncState;
|
|
104
|
+
resolveConflict: (localId: string, keepLocal: boolean) => Promise<void>;
|
|
105
|
+
onStateChange: (fn: (state: SyncState) => void) => () => void;
|
|
106
|
+
onMutation: (fn: (event: MutationEvent) => void) => () => void;
|
|
107
|
+
};
|
|
108
|
+
interface MutationEvent {
|
|
109
|
+
type: 'add' | 'update' | 'delete' | 'bulkAdd' | 'bulkPut' | 'bulkDelete' | 'clear' | 'put' | 'modify' | 'pull';
|
|
110
|
+
tableName: string;
|
|
111
|
+
keys?: unknown[];
|
|
112
|
+
}
|
|
113
|
+
interface PersistedSyncState {
|
|
114
|
+
firstLoadDone: boolean;
|
|
115
|
+
pendingChanges: PendingChange[];
|
|
116
|
+
lastPulled: Record<string, string>;
|
|
117
|
+
error?: Error;
|
|
118
|
+
conflicts?: Record<string, Conflict>;
|
|
119
|
+
}
|
|
120
|
+
type SyncStatus = 'disabled' | 'disabling' | 'idle' | 'syncing' | 'error';
|
|
121
|
+
interface SyncState extends PersistedSyncState {
|
|
122
|
+
status: SyncStatus;
|
|
123
|
+
hydrated: boolean;
|
|
124
|
+
}
|
|
125
|
+
declare enum SyncAction {
|
|
126
|
+
Create = "create",
|
|
127
|
+
Update = "update",
|
|
128
|
+
Remove = "remove"
|
|
129
|
+
}
|
|
130
|
+
interface PendingChange {
|
|
131
|
+
action: SyncAction;
|
|
132
|
+
stateKey: string;
|
|
133
|
+
localId: string;
|
|
134
|
+
id?: any;
|
|
135
|
+
version: number;
|
|
136
|
+
changes?: any;
|
|
137
|
+
before?: any;
|
|
138
|
+
after?: any;
|
|
139
|
+
}
|
|
140
|
+
interface Conflict {
|
|
141
|
+
stateKey: string;
|
|
142
|
+
fields: FieldConflict[];
|
|
143
|
+
}
|
|
144
|
+
interface FieldConflict {
|
|
145
|
+
key: string;
|
|
146
|
+
localValue: any;
|
|
147
|
+
remoteValue: any;
|
|
148
|
+
}
|
|
149
|
+
type TableMap<TStoreMap extends Record<string, unknown>> = {
|
|
150
|
+
[K in keyof TStoreMap]: StorageTable<TStoreMap[K]>;
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
declare class DyncBase<_TStoreMap = Record<string, any>> {
|
|
154
|
+
private readonly adapter;
|
|
155
|
+
private readonly tableCache;
|
|
156
|
+
private readonly mutationWrappedTables;
|
|
157
|
+
private readonly syncEnhancedTables;
|
|
158
|
+
private readonly mutationListeners;
|
|
159
|
+
private visibilitySubscription?;
|
|
160
|
+
private openPromise?;
|
|
161
|
+
private disableSyncPromise?;
|
|
162
|
+
private disableSyncPromiseResolver?;
|
|
163
|
+
private sleepAbortController?;
|
|
164
|
+
private closing;
|
|
165
|
+
private syncApis;
|
|
166
|
+
private batchSync?;
|
|
167
|
+
private syncedTables;
|
|
168
|
+
private syncOptions;
|
|
169
|
+
private logger;
|
|
170
|
+
private syncTimerStarted;
|
|
171
|
+
private mutationsDuringSync;
|
|
172
|
+
private state;
|
|
173
|
+
readonly name: string;
|
|
174
|
+
/**
|
|
175
|
+
* Create a new Dync instance.
|
|
176
|
+
*
|
|
177
|
+
* Mode 1 - Per-table endpoints:
|
|
178
|
+
* @param databaseName - Name of the database
|
|
179
|
+
* @param syncApis - Map of table names to API functions
|
|
180
|
+
* @param storageAdapter - Storage adapter implementation (required)
|
|
181
|
+
* @param options - Sync options
|
|
182
|
+
*
|
|
183
|
+
* Mode 2 - Batch endpoints:
|
|
184
|
+
* @param databaseName - Name of the database
|
|
185
|
+
* @param batchSync - Batch sync config (syncTables, push, pull, firstLoad)
|
|
186
|
+
* @param storageAdapter - Storage adapter implementation (required)
|
|
187
|
+
* @param options - Sync options
|
|
188
|
+
*/
|
|
189
|
+
constructor(databaseName: string, syncApis: Record<string, ApiFunctions>, storageAdapter: StorageAdapter, options?: SyncOptions);
|
|
190
|
+
constructor(databaseName: string, batchSync: BatchSync, storageAdapter: StorageAdapter, options?: SyncOptions);
|
|
191
|
+
version(versionNumber: number): {
|
|
192
|
+
stores(schema: Record<string, TableSchemaDefinition>): /*elided*/ any;
|
|
193
|
+
sqlite(configure: (builder: SQLiteVersionConfigurator) => void): /*elided*/ any;
|
|
194
|
+
};
|
|
195
|
+
open(): Promise<void>;
|
|
196
|
+
close(): Promise<void>;
|
|
197
|
+
delete(): Promise<void>;
|
|
198
|
+
query<R>(callback: (ctx: DexieQueryContext | SqliteQueryContext | MemoryQueryContext) => Promise<R>): Promise<R>;
|
|
199
|
+
table<K extends keyof _TStoreMap>(name: K): StorageTable<_TStoreMap[K]>;
|
|
200
|
+
table<T = any>(name: string): StorageTable<T>;
|
|
201
|
+
private withTransaction;
|
|
202
|
+
private setupEnhancedTables;
|
|
203
|
+
private injectSyncColumns;
|
|
204
|
+
private enhanceSyncTable;
|
|
205
|
+
private syncOnce;
|
|
206
|
+
private pullAll;
|
|
207
|
+
private pushAll;
|
|
208
|
+
private startSyncTimer;
|
|
209
|
+
private tryStart;
|
|
210
|
+
private setupVisibilityListener;
|
|
211
|
+
private handleVisibilityChange;
|
|
212
|
+
private startFirstLoad;
|
|
213
|
+
private getSyncState;
|
|
214
|
+
private resolveConflict;
|
|
215
|
+
private enableSync;
|
|
216
|
+
get syncStatus(): SyncStatus;
|
|
217
|
+
set syncStatus(status: SyncStatus);
|
|
218
|
+
private onSyncStateChange;
|
|
219
|
+
private onMutation;
|
|
220
|
+
private emitMutation;
|
|
221
|
+
sync: SyncApi;
|
|
222
|
+
}
|
|
223
|
+
type DyncInstance<TStoreMap extends Record<string, unknown> = Record<string, unknown>> = DyncBase<TStoreMap> & TableMap<TStoreMap> & {
|
|
224
|
+
table<K extends keyof TStoreMap & string>(name: K): StorageTable<TStoreMap[K]>;
|
|
225
|
+
table(name: string): StorageTable<any>;
|
|
226
|
+
};
|
|
227
|
+
declare const Dync: {
|
|
228
|
+
new <TStoreMap extends Record<string, unknown> = Record<string, unknown>>(databaseName: string, syncApis: Record<string, ApiFunctions>, storageAdapter: StorageAdapter, options?: SyncOptions): DyncInstance<TStoreMap>;
|
|
229
|
+
new <TStoreMap extends Record<string, unknown> = Record<string, unknown>>(databaseName: string, batchSync: BatchSync, storageAdapter: StorageAdapter, options?: SyncOptions): DyncInstance<TStoreMap>;
|
|
230
|
+
prototype: DyncInstance<Record<string, unknown>>;
|
|
231
|
+
} & typeof DyncBase;
|
|
232
|
+
type Dync<TStoreMap extends Record<string, unknown> = Record<string, unknown>> = DyncInstance<TStoreMap>;
|
|
233
|
+
|
|
234
|
+
export { type AfterRemoteAddCallback as A, type BatchSync as B, type ConflictResolutionStrategy as C, Dync as D, type FirstLoadProgress as F, type MissingRemoteRecordStrategy as M, SyncAction as S, type TableMap as T, type ApiFunctions as a, type BatchPushPayload as b, type BatchPushResult as c, type BatchFirstLoadResult as d, type FirstLoadProgressCallback as e, type MissingRemoteRecordDuringUpdateCallback as f, type MutationEvent as g, type SyncOptions as h, type SyncState as i, type SyncedRecord as j };
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import { d as StorageTable, c as StorageAdapter, T as TableSchemaDefinition, D as DexieQueryContext, b as SqliteQueryContext, a as MemoryQueryContext } from './dexie-Bv-fV10P.cjs';
|
|
2
|
+
import { c as SQLiteVersionConfigurator } from './types-CSbIAfu2.cjs';
|
|
3
|
+
|
|
4
|
+
type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'none';
|
|
5
|
+
interface Logger {
|
|
6
|
+
debug: (...args: any[]) => void;
|
|
7
|
+
info: (...args: any[]) => void;
|
|
8
|
+
warn: (...args: any[]) => void;
|
|
9
|
+
error: (...args: any[]) => void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
interface SyncedRecord {
|
|
13
|
+
_localId: string;
|
|
14
|
+
id?: any;
|
|
15
|
+
updated_at: string;
|
|
16
|
+
[k: string]: any;
|
|
17
|
+
}
|
|
18
|
+
interface ApiFunctions {
|
|
19
|
+
add: (item: any) => Promise<any | undefined>;
|
|
20
|
+
update: (id: any, changes: any, item: any) => Promise<boolean>;
|
|
21
|
+
remove: (id: any) => Promise<void>;
|
|
22
|
+
list: (lastUpdatedAt: Date) => Promise<any[]>;
|
|
23
|
+
firstLoad?: (lastId: any) => Promise<any[]>;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Payload for a single change in a batch push request.
|
|
27
|
+
*/
|
|
28
|
+
interface BatchPushPayload {
|
|
29
|
+
table: string;
|
|
30
|
+
action: 'add' | 'update' | 'remove';
|
|
31
|
+
localId: string;
|
|
32
|
+
id?: any;
|
|
33
|
+
data?: any;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Result for a single change in a batch push response.
|
|
37
|
+
*/
|
|
38
|
+
interface BatchPushResult {
|
|
39
|
+
localId: string;
|
|
40
|
+
success: boolean;
|
|
41
|
+
id?: any;
|
|
42
|
+
updated_at?: string;
|
|
43
|
+
error?: string;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Result for batch first load operation.
|
|
47
|
+
*/
|
|
48
|
+
interface BatchFirstLoadResult {
|
|
49
|
+
data: Record<string, any[]>;
|
|
50
|
+
cursors: Record<string, any>;
|
|
51
|
+
hasMore: boolean;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Batch sync configuration for
|
|
55
|
+
*/
|
|
56
|
+
interface BatchSync {
|
|
57
|
+
/**
|
|
58
|
+
* Array of table names to sync.
|
|
59
|
+
*/
|
|
60
|
+
syncTables: string[];
|
|
61
|
+
/**
|
|
62
|
+
* Push all pending changes to the server in a single request.
|
|
63
|
+
* @param changes Array of changes to push
|
|
64
|
+
* @returns Array of results, one per change, correlated by localId
|
|
65
|
+
*/
|
|
66
|
+
push: (changes: BatchPushPayload[]) => Promise<BatchPushResult[]>;
|
|
67
|
+
/**
|
|
68
|
+
* Pull changes from server since last sync.
|
|
69
|
+
* @param since Map of table name to last pulled timestamp
|
|
70
|
+
* @returns Map of table name to array of changed records
|
|
71
|
+
*/
|
|
72
|
+
pull: (since: Record<string, Date>) => Promise<Record<string, any[]>>;
|
|
73
|
+
/**
|
|
74
|
+
* Initial data load for all tables (optional).
|
|
75
|
+
* @param cursors Map of table name to pagination cursor
|
|
76
|
+
* @returns Batch first load result with data, cursors, and hasMore flag
|
|
77
|
+
*/
|
|
78
|
+
firstLoad?: (cursors: Record<string, any>) => Promise<BatchFirstLoadResult>;
|
|
79
|
+
}
|
|
80
|
+
type MissingRemoteRecordStrategy = 'ignore' | 'delete-local-record' | 'insert-remote-record';
|
|
81
|
+
type ConflictResolutionStrategy = 'local-wins' | 'remote-wins' | 'try-shallow-merge';
|
|
82
|
+
type AfterRemoteAddCallback = (stateKey: string, item: SyncedRecord) => void;
|
|
83
|
+
type MissingRemoteRecordDuringUpdateCallback = (strategy: MissingRemoteRecordStrategy, item: SyncedRecord) => void;
|
|
84
|
+
interface SyncOptions {
|
|
85
|
+
syncInterval?: number;
|
|
86
|
+
logger?: Logger;
|
|
87
|
+
minLogLevel?: LogLevel;
|
|
88
|
+
onAfterRemoteAdd?: AfterRemoteAddCallback;
|
|
89
|
+
missingRemoteRecordDuringUpdateStrategy?: MissingRemoteRecordStrategy;
|
|
90
|
+
onAfterMissingRemoteRecordDuringUpdate?: MissingRemoteRecordDuringUpdateCallback;
|
|
91
|
+
conflictResolutionStrategy?: ConflictResolutionStrategy;
|
|
92
|
+
}
|
|
93
|
+
interface FirstLoadProgress {
|
|
94
|
+
table: string;
|
|
95
|
+
inserted: number;
|
|
96
|
+
updated: number;
|
|
97
|
+
total: number;
|
|
98
|
+
}
|
|
99
|
+
type FirstLoadProgressCallback = (progress: FirstLoadProgress) => void;
|
|
100
|
+
type SyncApi = {
|
|
101
|
+
enable: (enabled: boolean) => Promise<void>;
|
|
102
|
+
startFirstLoad: (onProgress?: FirstLoadProgressCallback) => Promise<void>;
|
|
103
|
+
getState: () => SyncState;
|
|
104
|
+
resolveConflict: (localId: string, keepLocal: boolean) => Promise<void>;
|
|
105
|
+
onStateChange: (fn: (state: SyncState) => void) => () => void;
|
|
106
|
+
onMutation: (fn: (event: MutationEvent) => void) => () => void;
|
|
107
|
+
};
|
|
108
|
+
interface MutationEvent {
|
|
109
|
+
type: 'add' | 'update' | 'delete' | 'bulkAdd' | 'bulkPut' | 'bulkDelete' | 'clear' | 'put' | 'modify' | 'pull';
|
|
110
|
+
tableName: string;
|
|
111
|
+
keys?: unknown[];
|
|
112
|
+
}
|
|
113
|
+
interface PersistedSyncState {
|
|
114
|
+
firstLoadDone: boolean;
|
|
115
|
+
pendingChanges: PendingChange[];
|
|
116
|
+
lastPulled: Record<string, string>;
|
|
117
|
+
error?: Error;
|
|
118
|
+
conflicts?: Record<string, Conflict>;
|
|
119
|
+
}
|
|
120
|
+
type SyncStatus = 'disabled' | 'disabling' | 'idle' | 'syncing' | 'error';
|
|
121
|
+
interface SyncState extends PersistedSyncState {
|
|
122
|
+
status: SyncStatus;
|
|
123
|
+
hydrated: boolean;
|
|
124
|
+
}
|
|
125
|
+
declare enum SyncAction {
|
|
126
|
+
Create = "create",
|
|
127
|
+
Update = "update",
|
|
128
|
+
Remove = "remove"
|
|
129
|
+
}
|
|
130
|
+
interface PendingChange {
|
|
131
|
+
action: SyncAction;
|
|
132
|
+
stateKey: string;
|
|
133
|
+
localId: string;
|
|
134
|
+
id?: any;
|
|
135
|
+
version: number;
|
|
136
|
+
changes?: any;
|
|
137
|
+
before?: any;
|
|
138
|
+
after?: any;
|
|
139
|
+
}
|
|
140
|
+
interface Conflict {
|
|
141
|
+
stateKey: string;
|
|
142
|
+
fields: FieldConflict[];
|
|
143
|
+
}
|
|
144
|
+
interface FieldConflict {
|
|
145
|
+
key: string;
|
|
146
|
+
localValue: any;
|
|
147
|
+
remoteValue: any;
|
|
148
|
+
}
|
|
149
|
+
type TableMap<TStoreMap extends Record<string, unknown>> = {
|
|
150
|
+
[K in keyof TStoreMap]: StorageTable<TStoreMap[K]>;
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
declare class DyncBase<_TStoreMap = Record<string, any>> {
|
|
154
|
+
private readonly adapter;
|
|
155
|
+
private readonly tableCache;
|
|
156
|
+
private readonly mutationWrappedTables;
|
|
157
|
+
private readonly syncEnhancedTables;
|
|
158
|
+
private readonly mutationListeners;
|
|
159
|
+
private visibilitySubscription?;
|
|
160
|
+
private openPromise?;
|
|
161
|
+
private disableSyncPromise?;
|
|
162
|
+
private disableSyncPromiseResolver?;
|
|
163
|
+
private sleepAbortController?;
|
|
164
|
+
private closing;
|
|
165
|
+
private syncApis;
|
|
166
|
+
private batchSync?;
|
|
167
|
+
private syncedTables;
|
|
168
|
+
private syncOptions;
|
|
169
|
+
private logger;
|
|
170
|
+
private syncTimerStarted;
|
|
171
|
+
private mutationsDuringSync;
|
|
172
|
+
private state;
|
|
173
|
+
readonly name: string;
|
|
174
|
+
/**
|
|
175
|
+
* Create a new Dync instance.
|
|
176
|
+
*
|
|
177
|
+
* Mode 1 - Per-table endpoints:
|
|
178
|
+
* @param databaseName - Name of the database
|
|
179
|
+
* @param syncApis - Map of table names to API functions
|
|
180
|
+
* @param storageAdapter - Storage adapter implementation (required)
|
|
181
|
+
* @param options - Sync options
|
|
182
|
+
*
|
|
183
|
+
* Mode 2 - Batch endpoints:
|
|
184
|
+
* @param databaseName - Name of the database
|
|
185
|
+
* @param batchSync - Batch sync config (syncTables, push, pull, firstLoad)
|
|
186
|
+
* @param storageAdapter - Storage adapter implementation (required)
|
|
187
|
+
* @param options - Sync options
|
|
188
|
+
*/
|
|
189
|
+
constructor(databaseName: string, syncApis: Record<string, ApiFunctions>, storageAdapter: StorageAdapter, options?: SyncOptions);
|
|
190
|
+
constructor(databaseName: string, batchSync: BatchSync, storageAdapter: StorageAdapter, options?: SyncOptions);
|
|
191
|
+
version(versionNumber: number): {
|
|
192
|
+
stores(schema: Record<string, TableSchemaDefinition>): /*elided*/ any;
|
|
193
|
+
sqlite(configure: (builder: SQLiteVersionConfigurator) => void): /*elided*/ any;
|
|
194
|
+
};
|
|
195
|
+
open(): Promise<void>;
|
|
196
|
+
close(): Promise<void>;
|
|
197
|
+
delete(): Promise<void>;
|
|
198
|
+
query<R>(callback: (ctx: DexieQueryContext | SqliteQueryContext | MemoryQueryContext) => Promise<R>): Promise<R>;
|
|
199
|
+
table<K extends keyof _TStoreMap>(name: K): StorageTable<_TStoreMap[K]>;
|
|
200
|
+
table<T = any>(name: string): StorageTable<T>;
|
|
201
|
+
private withTransaction;
|
|
202
|
+
private setupEnhancedTables;
|
|
203
|
+
private injectSyncColumns;
|
|
204
|
+
private enhanceSyncTable;
|
|
205
|
+
private syncOnce;
|
|
206
|
+
private pullAll;
|
|
207
|
+
private pushAll;
|
|
208
|
+
private startSyncTimer;
|
|
209
|
+
private tryStart;
|
|
210
|
+
private setupVisibilityListener;
|
|
211
|
+
private handleVisibilityChange;
|
|
212
|
+
private startFirstLoad;
|
|
213
|
+
private getSyncState;
|
|
214
|
+
private resolveConflict;
|
|
215
|
+
private enableSync;
|
|
216
|
+
get syncStatus(): SyncStatus;
|
|
217
|
+
set syncStatus(status: SyncStatus);
|
|
218
|
+
private onSyncStateChange;
|
|
219
|
+
private onMutation;
|
|
220
|
+
private emitMutation;
|
|
221
|
+
sync: SyncApi;
|
|
222
|
+
}
|
|
223
|
+
type DyncInstance<TStoreMap extends Record<string, unknown> = Record<string, unknown>> = DyncBase<TStoreMap> & TableMap<TStoreMap> & {
|
|
224
|
+
table<K extends keyof TStoreMap & string>(name: K): StorageTable<TStoreMap[K]>;
|
|
225
|
+
table(name: string): StorageTable<any>;
|
|
226
|
+
};
|
|
227
|
+
declare const Dync: {
|
|
228
|
+
new <TStoreMap extends Record<string, unknown> = Record<string, unknown>>(databaseName: string, syncApis: Record<string, ApiFunctions>, storageAdapter: StorageAdapter, options?: SyncOptions): DyncInstance<TStoreMap>;
|
|
229
|
+
new <TStoreMap extends Record<string, unknown> = Record<string, unknown>>(databaseName: string, batchSync: BatchSync, storageAdapter: StorageAdapter, options?: SyncOptions): DyncInstance<TStoreMap>;
|
|
230
|
+
prototype: DyncInstance<Record<string, unknown>>;
|
|
231
|
+
} & typeof DyncBase;
|
|
232
|
+
type Dync<TStoreMap extends Record<string, unknown> = Record<string, unknown>> = DyncInstance<TStoreMap>;
|
|
233
|
+
|
|
234
|
+
export { type AfterRemoteAddCallback as A, type BatchSync as B, type ConflictResolutionStrategy as C, Dync as D, type FirstLoadProgress as F, type MissingRemoteRecordStrategy as M, SyncAction as S, type TableMap as T, type ApiFunctions as a, type BatchPushPayload as b, type BatchPushResult as c, type BatchFirstLoadResult as d, type FirstLoadProgressCallback as e, type MissingRemoteRecordDuringUpdateCallback as f, type MutationEvent as g, type SyncOptions as h, type SyncState as i, type SyncedRecord as j };
|
package/dist/node.cjs
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/node.ts
|
|
31
|
+
var node_exports = {};
|
|
32
|
+
__export(node_exports, {
|
|
33
|
+
BetterSqlite3Driver: () => BetterSqlite3Driver
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(node_exports);
|
|
36
|
+
|
|
37
|
+
// src/storage/sqlite/drivers/BetterSqlite3Driver.ts
|
|
38
|
+
var BetterSqlite3Driver = class {
|
|
39
|
+
type = "BetterSqlite3Driver";
|
|
40
|
+
db = null;
|
|
41
|
+
options;
|
|
42
|
+
opened = false;
|
|
43
|
+
name;
|
|
44
|
+
constructor(databasePath, options = {}) {
|
|
45
|
+
this.name = databasePath;
|
|
46
|
+
this.options = {
|
|
47
|
+
wal: true,
|
|
48
|
+
...options
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
async open() {
|
|
52
|
+
if (this.opened) return;
|
|
53
|
+
const Database = (await import("better-sqlite3")).default;
|
|
54
|
+
this.db = new Database(this.name, {
|
|
55
|
+
readonly: this.options.readonly ?? false,
|
|
56
|
+
fileMustExist: this.options.fileMustExist ?? false,
|
|
57
|
+
timeout: this.options.timeout ?? 5e3,
|
|
58
|
+
verbose: this.options.verbose
|
|
59
|
+
});
|
|
60
|
+
if (this.options.wal && !this.options.readonly) {
|
|
61
|
+
this.db.pragma("journal_mode = WAL");
|
|
62
|
+
}
|
|
63
|
+
this.opened = true;
|
|
64
|
+
}
|
|
65
|
+
async close() {
|
|
66
|
+
if (!this.db) return;
|
|
67
|
+
this.db.close();
|
|
68
|
+
this.db = null;
|
|
69
|
+
this.opened = false;
|
|
70
|
+
}
|
|
71
|
+
async execute(statement) {
|
|
72
|
+
await this.open();
|
|
73
|
+
this.db.exec(statement);
|
|
74
|
+
}
|
|
75
|
+
async run(statement, values = []) {
|
|
76
|
+
await this.open();
|
|
77
|
+
const stmt = this.db.prepare(statement);
|
|
78
|
+
const result = stmt.run(...values);
|
|
79
|
+
return {
|
|
80
|
+
changes: result.changes,
|
|
81
|
+
lastId: result.lastInsertRowid !== void 0 ? Number(result.lastInsertRowid) : void 0
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
async query(statement, values = []) {
|
|
85
|
+
await this.open();
|
|
86
|
+
const stmt = this.db.prepare(statement);
|
|
87
|
+
const rows = stmt.all(...values);
|
|
88
|
+
if (rows.length === 0) {
|
|
89
|
+
return { columns: [], values: [] };
|
|
90
|
+
}
|
|
91
|
+
const firstRow = rows[0];
|
|
92
|
+
const columns = Object.keys(firstRow);
|
|
93
|
+
const valuesMatrix = rows.map((row) => columns.map((col) => row[col]));
|
|
94
|
+
return { columns, values: valuesMatrix };
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Access the underlying better-sqlite3 Database instance for advanced operations.
|
|
98
|
+
* Returns null if the database is not open.
|
|
99
|
+
*/
|
|
100
|
+
getDatabase() {
|
|
101
|
+
return this.db;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Execute a function within a transaction.
|
|
105
|
+
* This provides better performance when doing many writes.
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* ```ts
|
|
109
|
+
* await driver.transaction(() => {
|
|
110
|
+
* driver.run('INSERT INTO users (name) VALUES (?)', ['Alice']);
|
|
111
|
+
* driver.run('INSERT INTO users (name) VALUES (?)', ['Bob']);
|
|
112
|
+
* });
|
|
113
|
+
* ```
|
|
114
|
+
*/
|
|
115
|
+
transaction(fn) {
|
|
116
|
+
if (!this.db) {
|
|
117
|
+
throw new Error("Database not open. Call open() first.");
|
|
118
|
+
}
|
|
119
|
+
return this.db.transaction(fn)();
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
123
|
+
0 && (module.exports = {
|
|
124
|
+
BetterSqlite3Driver
|
|
125
|
+
});
|
|
126
|
+
//# sourceMappingURL=node.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/node.ts","../src/storage/sqlite/drivers/BetterSqlite3Driver.ts"],"sourcesContent":["// Node.js SQLite Driver using better-sqlite3\n// Works in Node.js apps and Electron main process\nexport { BetterSqlite3Driver, type BetterSqlite3DriverOptions } from './storage/sqlite/drivers/BetterSqlite3Driver';\nexport type { SQLiteDatabaseDriver, SQLiteQueryResult, SQLiteRunResult } from './storage/sqlite/types';\n","import type { SQLiteDatabaseDriver, SQLiteQueryResult, SQLiteRunResult } from '../types';\n\n/**\n * Options for configuring the BetterSqlite3Driver.\n */\nexport interface BetterSqlite3DriverOptions {\n /**\n * Open the database in readonly mode.\n * @default false\n */\n readonly?: boolean;\n\n /**\n * Create the database file if it doesn't exist.\n * Set to false to throw an error if the file doesn't exist.\n * @default true\n */\n fileMustExist?: boolean;\n\n /**\n * Timeout in milliseconds when waiting for the database to become unlocked.\n * @default 5000\n */\n timeout?: number;\n\n /**\n * Enable verbose mode for debugging SQL statements.\n */\n verbose?: (message?: unknown, ...additionalArgs: unknown[]) => void;\n\n /**\n * Enable WAL (Write-Ahead Logging) mode for better concurrent access.\n * Recommended for most use cases.\n * @default true\n */\n wal?: boolean;\n}\n\n/**\n * SQLite driver for Node.js using better-sqlite3.\n * This driver is synchronous but wraps operations in Promises for API compatibility.\n *\n * @example\n * ```ts\n * import { BetterSqlite3Driver } from '@anfenn/dync/node';\n * import { SQLiteAdapter } from '@anfenn/dync';\n *\n * const driver = new BetterSqlite3Driver('myapp.db', { wal: true });\n * const adapter = new SQLiteAdapter('myapp', driver);\n * ```\n */\nexport class BetterSqlite3Driver implements SQLiteDatabaseDriver {\n readonly type = 'BetterSqlite3Driver';\n private db: import('better-sqlite3').Database | null = null;\n private readonly options: BetterSqlite3DriverOptions;\n private opened = false;\n readonly name: string;\n\n constructor(databasePath: string, options: BetterSqlite3DriverOptions = {}) {\n this.name = databasePath;\n this.options = {\n wal: true,\n ...options,\n };\n }\n\n async open(): Promise<void> {\n if (this.opened) return;\n\n // Dynamic import to avoid bundling issues in non-Electron environments\n const Database = (await import('better-sqlite3')).default;\n\n this.db = new Database(this.name, {\n readonly: this.options.readonly ?? false,\n fileMustExist: this.options.fileMustExist ?? false,\n timeout: this.options.timeout ?? 5000,\n verbose: this.options.verbose,\n });\n\n // Enable WAL mode for better concurrent access (recommended)\n if (this.options.wal && !this.options.readonly) {\n this.db.pragma('journal_mode = WAL');\n }\n\n this.opened = true;\n }\n\n async close(): Promise<void> {\n if (!this.db) return;\n\n this.db.close();\n this.db = null;\n this.opened = false;\n }\n\n async execute(statement: string): Promise<void> {\n await this.open();\n this.db!.exec(statement);\n }\n\n async run(statement: string, values: unknown[] = []): Promise<SQLiteRunResult> {\n await this.open();\n\n const stmt = this.db!.prepare(statement);\n const result = stmt.run(...values);\n\n return {\n changes: result.changes,\n lastId: result.lastInsertRowid !== undefined ? Number(result.lastInsertRowid) : undefined,\n };\n }\n\n async query(statement: string, values: unknown[] = []): Promise<SQLiteQueryResult> {\n await this.open();\n\n const stmt = this.db!.prepare(statement);\n const rows = stmt.all(...values) as Record<string, unknown>[];\n\n if (rows.length === 0) {\n return { columns: [], values: [] };\n }\n\n const firstRow = rows[0]!;\n const columns = Object.keys(firstRow);\n const valuesMatrix = rows.map((row) => columns.map((col) => row[col]));\n\n return { columns, values: valuesMatrix };\n }\n\n /**\n * Access the underlying better-sqlite3 Database instance for advanced operations.\n * Returns null if the database is not open.\n */\n getDatabase(): import('better-sqlite3').Database | null {\n return this.db;\n }\n\n /**\n * Execute a function within a transaction.\n * This provides better performance when doing many writes.\n *\n * @example\n * ```ts\n * await driver.transaction(() => {\n * driver.run('INSERT INTO users (name) VALUES (?)', ['Alice']);\n * driver.run('INSERT INTO users (name) VALUES (?)', ['Bob']);\n * });\n * ```\n */\n transaction<T>(fn: () => T): T {\n if (!this.db) {\n throw new Error('Database not open. Call open() first.');\n }\n return this.db.transaction(fn)();\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACmDO,IAAM,sBAAN,MAA0D;AAAA,EACpD,OAAO;AAAA,EACR,KAA+C;AAAA,EACtC;AAAA,EACT,SAAS;AAAA,EACR;AAAA,EAET,YAAY,cAAsB,UAAsC,CAAC,GAAG;AACxE,SAAK,OAAO;AACZ,SAAK,UAAU;AAAA,MACX,KAAK;AAAA,MACL,GAAG;AAAA,IACP;AAAA,EACJ;AAAA,EAEA,MAAM,OAAsB;AACxB,QAAI,KAAK,OAAQ;AAGjB,UAAM,YAAY,MAAM,OAAO,gBAAgB,GAAG;AAElD,SAAK,KAAK,IAAI,SAAS,KAAK,MAAM;AAAA,MAC9B,UAAU,KAAK,QAAQ,YAAY;AAAA,MACnC,eAAe,KAAK,QAAQ,iBAAiB;AAAA,MAC7C,SAAS,KAAK,QAAQ,WAAW;AAAA,MACjC,SAAS,KAAK,QAAQ;AAAA,IAC1B,CAAC;AAGD,QAAI,KAAK,QAAQ,OAAO,CAAC,KAAK,QAAQ,UAAU;AAC5C,WAAK,GAAG,OAAO,oBAAoB;AAAA,IACvC;AAEA,SAAK,SAAS;AAAA,EAClB;AAAA,EAEA,MAAM,QAAuB;AACzB,QAAI,CAAC,KAAK,GAAI;AAEd,SAAK,GAAG,MAAM;AACd,SAAK,KAAK;AACV,SAAK,SAAS;AAAA,EAClB;AAAA,EAEA,MAAM,QAAQ,WAAkC;AAC5C,UAAM,KAAK,KAAK;AAChB,SAAK,GAAI,KAAK,SAAS;AAAA,EAC3B;AAAA,EAEA,MAAM,IAAI,WAAmB,SAAoB,CAAC,GAA6B;AAC3E,UAAM,KAAK,KAAK;AAEhB,UAAM,OAAO,KAAK,GAAI,QAAQ,SAAS;AACvC,UAAM,SAAS,KAAK,IAAI,GAAG,MAAM;AAEjC,WAAO;AAAA,MACH,SAAS,OAAO;AAAA,MAChB,QAAQ,OAAO,oBAAoB,SAAY,OAAO,OAAO,eAAe,IAAI;AAAA,IACpF;AAAA,EACJ;AAAA,EAEA,MAAM,MAAM,WAAmB,SAAoB,CAAC,GAA+B;AAC/E,UAAM,KAAK,KAAK;AAEhB,UAAM,OAAO,KAAK,GAAI,QAAQ,SAAS;AACvC,UAAM,OAAO,KAAK,IAAI,GAAG,MAAM;AAE/B,QAAI,KAAK,WAAW,GAAG;AACnB,aAAO,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,EAAE;AAAA,IACrC;AAEA,UAAM,WAAW,KAAK,CAAC;AACvB,UAAM,UAAU,OAAO,KAAK,QAAQ;AACpC,UAAM,eAAe,KAAK,IAAI,CAAC,QAAQ,QAAQ,IAAI,CAAC,QAAQ,IAAI,GAAG,CAAC,CAAC;AAErE,WAAO,EAAE,SAAS,QAAQ,aAAa;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,cAAwD;AACpD,WAAO,KAAK;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA,YAAe,IAAgB;AAC3B,QAAI,CAAC,KAAK,IAAI;AACV,YAAM,IAAI,MAAM,uCAAuC;AAAA,IAC3D;AACA,WAAO,KAAK,GAAG,YAAY,EAAE,EAAE;AAAA,EACnC;AACJ;","names":[]}
|