@framers/sql-storage-adapter 0.1.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 +363 -0
- package/dist/adapters/baseStorageAdapter.d.ts +204 -0
- package/dist/adapters/baseStorageAdapter.d.ts.map +1 -0
- package/dist/adapters/baseStorageAdapter.js +364 -0
- package/dist/adapters/baseStorageAdapter.js.map +1 -0
- package/dist/adapters/betterSqliteAdapter.d.ts +64 -0
- package/dist/adapters/betterSqliteAdapter.d.ts.map +1 -0
- package/dist/adapters/betterSqliteAdapter.js +206 -0
- package/dist/adapters/betterSqliteAdapter.js.map +1 -0
- package/dist/adapters/capacitorSqliteAdapter.d.ts +33 -0
- package/dist/adapters/capacitorSqliteAdapter.d.ts.map +1 -0
- package/dist/adapters/capacitorSqliteAdapter.js +95 -0
- package/dist/adapters/capacitorSqliteAdapter.js.map +1 -0
- package/dist/adapters/postgresAdapter.d.ts +180 -0
- package/dist/adapters/postgresAdapter.d.ts.map +1 -0
- package/dist/adapters/postgresAdapter.js +271 -0
- package/dist/adapters/postgresAdapter.js.map +1 -0
- package/dist/adapters/sqlJsAdapter.d.ts +28 -0
- package/dist/adapters/sqlJsAdapter.d.ts.map +1 -0
- package/dist/adapters/sqlJsAdapter.js +136 -0
- package/dist/adapters/sqlJsAdapter.js.map +1 -0
- package/dist/adapters/supabase.d.ts +58 -0
- package/dist/adapters/supabase.d.ts.map +1 -0
- package/dist/adapters/supabase.js +385 -0
- package/dist/adapters/supabase.js.map +1 -0
- package/dist/database.d.ts +124 -0
- package/dist/database.d.ts.map +1 -0
- package/dist/database.js +136 -0
- package/dist/database.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/dist/resolver.d.ts +24 -0
- package/dist/resolver.d.ts.map +1 -0
- package/dist/resolver.js +91 -0
- package/dist/resolver.js.map +1 -0
- package/dist/types/context.d.ts +221 -0
- package/dist/types/context.d.ts.map +1 -0
- package/dist/types/context.js +9 -0
- package/dist/types/context.js.map +1 -0
- package/dist/types/events.d.ts +225 -0
- package/dist/types/events.d.ts.map +1 -0
- package/dist/types/events.js +8 -0
- package/dist/types/events.js.map +1 -0
- package/dist/types/extensions.d.ts +73 -0
- package/dist/types/extensions.d.ts.map +1 -0
- package/dist/types/extensions.js +7 -0
- package/dist/types/extensions.js.map +1 -0
- package/dist/types/limitations.d.ts +46 -0
- package/dist/types/limitations.d.ts.map +1 -0
- package/dist/types/limitations.js +154 -0
- package/dist/types/limitations.js.map +1 -0
- package/dist/types.d.ts +235 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +18 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/cloudBackup.d.ts +219 -0
- package/dist/utils/cloudBackup.d.ts.map +1 -0
- package/dist/utils/cloudBackup.js +289 -0
- package/dist/utils/cloudBackup.js.map +1 -0
- package/dist/utils/dataExport.d.ts +77 -0
- package/dist/utils/dataExport.d.ts.map +1 -0
- package/dist/utils/dataExport.js +212 -0
- package/dist/utils/dataExport.js.map +1 -0
- package/dist/utils/dataImport.d.ts +54 -0
- package/dist/utils/dataImport.d.ts.map +1 -0
- package/dist/utils/dataImport.js +324 -0
- package/dist/utils/dataImport.js.map +1 -0
- package/dist/utils/migration.d.ts +89 -0
- package/dist/utils/migration.d.ts.map +1 -0
- package/dist/utils/migration.js +184 -0
- package/dist/utils/migration.js.map +1 -0
- package/dist/utils/parameterUtils.d.ts +9 -0
- package/dist/utils/parameterUtils.d.ts.map +1 -0
- package/dist/utils/parameterUtils.js +17 -0
- package/dist/utils/parameterUtils.js.map +1 -0
- package/dist/utils/syncManager.d.ts +342 -0
- package/dist/utils/syncManager.d.ts.map +1 -0
- package/dist/utils/syncManager.js +533 -0
- package/dist/utils/syncManager.js.map +1 -0
- package/package.json +108 -0
|
@@ -0,0 +1,533 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sync Manager for hybrid local/cloud database synchronization.
|
|
3
|
+
*
|
|
4
|
+
* Supports both online-first and offline-first patterns with automatic
|
|
5
|
+
* conflict resolution and intelligent sync strategies.
|
|
6
|
+
*
|
|
7
|
+
* @example Online-first with fallback
|
|
8
|
+
* ```typescript
|
|
9
|
+
* const manager = await createSyncManager({
|
|
10
|
+
* primary: { url: process.env.DATABASE_URL, fallback: './local.db' },
|
|
11
|
+
* sync: { mode: 'auto', interval: 30000 }
|
|
12
|
+
* });
|
|
13
|
+
* ```
|
|
14
|
+
*
|
|
15
|
+
* @example Offline-first with cloud sync
|
|
16
|
+
* ```typescript
|
|
17
|
+
* const manager = await createSyncManager({
|
|
18
|
+
* primary: { file: './local.db' },
|
|
19
|
+
* remote: { url: process.env.DATABASE_URL },
|
|
20
|
+
* sync: { mode: 'periodic', interval: 60000 }
|
|
21
|
+
* });
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* @example Manual sync control
|
|
25
|
+
* ```typescript
|
|
26
|
+
* const manager = await createSyncManager({
|
|
27
|
+
* primary: './local.db',
|
|
28
|
+
* remote: process.env.DATABASE_URL,
|
|
29
|
+
* sync: { mode: 'manual' }
|
|
30
|
+
* });
|
|
31
|
+
*
|
|
32
|
+
* // Trigger sync when you want
|
|
33
|
+
* await manager.sync();
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
import { createDatabase, openDatabase, connectDatabase } from '../database';
|
|
37
|
+
import { exportData } from './dataExport';
|
|
38
|
+
import { importData } from './dataImport';
|
|
39
|
+
/**
|
|
40
|
+
* Sync manager for hybrid local/cloud databases.
|
|
41
|
+
* Handles automatic synchronization, conflict resolution, and offline support.
|
|
42
|
+
*/
|
|
43
|
+
export class SyncManager {
|
|
44
|
+
constructor(primary, remote, callbacks, syncConfig) {
|
|
45
|
+
this.callbacks = callbacks;
|
|
46
|
+
this.remoteDb = null;
|
|
47
|
+
this.syncTimer = null;
|
|
48
|
+
this.debounceTimer = null;
|
|
49
|
+
this.syncQueue = [];
|
|
50
|
+
this.isSyncing = false;
|
|
51
|
+
this.isOnline = true;
|
|
52
|
+
this.lastSyncTime = null;
|
|
53
|
+
this.pendingWrites = new Set();
|
|
54
|
+
this.primaryDb = primary;
|
|
55
|
+
this.remoteDb = remote;
|
|
56
|
+
// Set defaults
|
|
57
|
+
this.config = {
|
|
58
|
+
mode: syncConfig.mode ?? 'manual',
|
|
59
|
+
direction: syncConfig.direction ?? 'bidirectional',
|
|
60
|
+
conflictStrategy: syncConfig.conflictStrategy ?? 'last-write-wins',
|
|
61
|
+
interval: syncConfig.interval ?? 30000,
|
|
62
|
+
debounce: syncConfig.debounce ?? 500,
|
|
63
|
+
batchSize: syncConfig.batchSize ?? 100,
|
|
64
|
+
retryOnError: syncConfig.retryOnError ?? true,
|
|
65
|
+
maxRetries: syncConfig.maxRetries ?? 3,
|
|
66
|
+
retryDelay: syncConfig.retryDelay ?? 1000,
|
|
67
|
+
tables: syncConfig.tables ?? {},
|
|
68
|
+
mobileStorageLimit: syncConfig.mobileStorageLimit ?? 50,
|
|
69
|
+
storageLimitAction: syncConfig.storageLimitAction ?? 'warn',
|
|
70
|
+
includeTables: syncConfig.includeTables,
|
|
71
|
+
excludeTables: syncConfig.excludeTables,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Get the primary database adapter.
|
|
76
|
+
* Use this for all database operations.
|
|
77
|
+
*/
|
|
78
|
+
get db() {
|
|
79
|
+
return this.primaryDb;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Check if manager is currently syncing.
|
|
83
|
+
*/
|
|
84
|
+
get syncing() {
|
|
85
|
+
return this.isSyncing;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Check if currently online.
|
|
89
|
+
*/
|
|
90
|
+
get online() {
|
|
91
|
+
return this.isOnline;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Get last successful sync time.
|
|
95
|
+
*/
|
|
96
|
+
get lastSync() {
|
|
97
|
+
return this.lastSyncTime;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Trigger manual sync.
|
|
101
|
+
* Safe to call multiple times - queues if already syncing.
|
|
102
|
+
*/
|
|
103
|
+
async sync() {
|
|
104
|
+
if (!this.remoteDb) {
|
|
105
|
+
throw new Error('No remote database configured for sync');
|
|
106
|
+
}
|
|
107
|
+
if (this.isSyncing) {
|
|
108
|
+
// Queue this sync request
|
|
109
|
+
return new Promise((resolve, reject) => {
|
|
110
|
+
this.syncQueue.push(async () => {
|
|
111
|
+
try {
|
|
112
|
+
const result = await this.performSync();
|
|
113
|
+
resolve(result);
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
reject(error);
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
return this.performSync();
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Perform the actual sync operation.
|
|
125
|
+
*/
|
|
126
|
+
async performSync() {
|
|
127
|
+
if (!this.remoteDb) {
|
|
128
|
+
throw new Error('No remote database configured');
|
|
129
|
+
}
|
|
130
|
+
this.isSyncing = true;
|
|
131
|
+
const startTime = Date.now();
|
|
132
|
+
let recordsSynced = 0;
|
|
133
|
+
let conflicts = 0;
|
|
134
|
+
const tablesSynced = [];
|
|
135
|
+
const errors = [];
|
|
136
|
+
const details = {};
|
|
137
|
+
try {
|
|
138
|
+
// Check network connectivity
|
|
139
|
+
await this.checkConnection();
|
|
140
|
+
// Get list of tables to sync
|
|
141
|
+
const tables = await this.getTablesToSync();
|
|
142
|
+
const totalTables = tables.length;
|
|
143
|
+
// Sort by priority
|
|
144
|
+
const sortedTables = this.sortTablesByPriority(tables);
|
|
145
|
+
for (let i = 0; i < sortedTables.length; i++) {
|
|
146
|
+
const table = sortedTables[i];
|
|
147
|
+
this.callbacks.onProgress?.({
|
|
148
|
+
phase: 'pulling',
|
|
149
|
+
percent: Math.round((i / totalTables) * 50), // 0-50% for pull
|
|
150
|
+
currentTable: table,
|
|
151
|
+
recordsProcessed: recordsSynced,
|
|
152
|
+
totalRecords: 0 // Unknown until we query
|
|
153
|
+
});
|
|
154
|
+
try {
|
|
155
|
+
const tableResult = await this.syncTable(table);
|
|
156
|
+
details[table] = tableResult;
|
|
157
|
+
recordsSynced += tableResult.pushed + tableResult.pulled;
|
|
158
|
+
conflicts += tableResult.conflicts;
|
|
159
|
+
tablesSynced.push(table);
|
|
160
|
+
}
|
|
161
|
+
catch (error) {
|
|
162
|
+
errors.push(error);
|
|
163
|
+
this.callbacks.onError?.(error);
|
|
164
|
+
if (!this.config.retryOnError) {
|
|
165
|
+
throw error;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
this.lastSyncTime = new Date();
|
|
170
|
+
const duration = Date.now() - startTime;
|
|
171
|
+
const result = {
|
|
172
|
+
success: errors.length === 0,
|
|
173
|
+
direction: this.config.direction,
|
|
174
|
+
recordsSynced,
|
|
175
|
+
conflicts,
|
|
176
|
+
duration,
|
|
177
|
+
timestamp: this.lastSyncTime.toISOString(),
|
|
178
|
+
tables: tablesSynced,
|
|
179
|
+
errors: errors.length > 0 ? errors : undefined,
|
|
180
|
+
details
|
|
181
|
+
};
|
|
182
|
+
this.callbacks.onSync?.(result);
|
|
183
|
+
return result;
|
|
184
|
+
}
|
|
185
|
+
finally {
|
|
186
|
+
this.isSyncing = false;
|
|
187
|
+
this.pendingWrites.clear();
|
|
188
|
+
// Process queued syncs
|
|
189
|
+
if (this.syncQueue.length > 0) {
|
|
190
|
+
const nextSync = this.syncQueue.shift();
|
|
191
|
+
nextSync?.();
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Sync a single table.
|
|
197
|
+
*/
|
|
198
|
+
async syncTable(table) {
|
|
199
|
+
// const tableConfig = this.config.tables[table] ?? {}; // Reserved for future table-specific config
|
|
200
|
+
const direction = this.config.direction;
|
|
201
|
+
let pushed = 0;
|
|
202
|
+
let pulled = 0;
|
|
203
|
+
let conflicts = 0;
|
|
204
|
+
// Pull from remote (if bidirectional or pull-only)
|
|
205
|
+
if (direction === 'bidirectional' || direction === 'pull-only') {
|
|
206
|
+
const pullResult = await this.pullTable(table);
|
|
207
|
+
pulled = pullResult.records;
|
|
208
|
+
conflicts += pullResult.conflicts;
|
|
209
|
+
}
|
|
210
|
+
// Push to remote (if bidirectional or push-only)
|
|
211
|
+
if (direction === 'bidirectional' || direction === 'push-only') {
|
|
212
|
+
const pushResult = await this.pushTable(table);
|
|
213
|
+
pushed = pushResult.records;
|
|
214
|
+
conflicts += pushResult.conflicts;
|
|
215
|
+
}
|
|
216
|
+
return { pushed, pulled, conflicts };
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Pull table data from remote to local.
|
|
220
|
+
*/
|
|
221
|
+
async pullTable(table) {
|
|
222
|
+
if (!this.remoteDb)
|
|
223
|
+
return { records: 0, conflicts: 0 };
|
|
224
|
+
// Export from remote
|
|
225
|
+
const remoteData = await exportData(this.remoteDb, {
|
|
226
|
+
tables: [table],
|
|
227
|
+
includeSchema: false
|
|
228
|
+
});
|
|
229
|
+
if (!remoteData.data[table]?.length) {
|
|
230
|
+
return { records: 0, conflicts: 0 };
|
|
231
|
+
}
|
|
232
|
+
// Get local data for conflict detection
|
|
233
|
+
const localData = await exportData(this.primaryDb, {
|
|
234
|
+
tables: [table],
|
|
235
|
+
includeSchema: false
|
|
236
|
+
});
|
|
237
|
+
const conflicts = await this.resolveConflicts(table, localData.data[table] ?? [], remoteData.data[table]);
|
|
238
|
+
// Import to local
|
|
239
|
+
await importData(this.primaryDb, remoteData, {
|
|
240
|
+
onConflict: 'replace', // We already resolved conflicts
|
|
241
|
+
skipSchema: true,
|
|
242
|
+
tables: [table]
|
|
243
|
+
});
|
|
244
|
+
return {
|
|
245
|
+
records: remoteData.data[table].length,
|
|
246
|
+
conflicts
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Push table data from local to remote.
|
|
251
|
+
*/
|
|
252
|
+
async pushTable(table) {
|
|
253
|
+
if (!this.remoteDb)
|
|
254
|
+
return { records: 0, conflicts: 0 };
|
|
255
|
+
// Export from local
|
|
256
|
+
const localData = await exportData(this.primaryDb, {
|
|
257
|
+
tables: [table],
|
|
258
|
+
includeSchema: false
|
|
259
|
+
});
|
|
260
|
+
if (!localData.data[table]?.length) {
|
|
261
|
+
return { records: 0, conflicts: 0 };
|
|
262
|
+
}
|
|
263
|
+
// Import to remote
|
|
264
|
+
await importData(this.remoteDb, localData, {
|
|
265
|
+
onConflict: 'replace',
|
|
266
|
+
skipSchema: true,
|
|
267
|
+
tables: [table]
|
|
268
|
+
});
|
|
269
|
+
return {
|
|
270
|
+
records: localData.data[table].length,
|
|
271
|
+
conflicts: 0
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Resolve conflicts between local and remote data.
|
|
276
|
+
*/
|
|
277
|
+
async resolveConflicts(table, local, remote) {
|
|
278
|
+
const tableConfig = this.config.tables[table];
|
|
279
|
+
const strategy = tableConfig?.conflictStrategy ?? this.config.conflictStrategy;
|
|
280
|
+
let conflictCount = 0;
|
|
281
|
+
// Build map of local records by ID
|
|
282
|
+
const localMap = new Map(local.map(r => [r.id, r]));
|
|
283
|
+
for (const remoteRecord of remote) {
|
|
284
|
+
const localRecord = localMap.get(remoteRecord.id);
|
|
285
|
+
if (!localRecord)
|
|
286
|
+
continue; // No conflict
|
|
287
|
+
// Check if both were modified
|
|
288
|
+
const localTime = new Date(localRecord.updated_at || localRecord.created_at);
|
|
289
|
+
const remoteTime = new Date(remoteRecord.updated_at || remoteRecord.created_at);
|
|
290
|
+
if (localRecord.updated_at || remoteRecord.updated_at) {
|
|
291
|
+
conflictCount++;
|
|
292
|
+
const conflict = {
|
|
293
|
+
table,
|
|
294
|
+
id: remoteRecord.id,
|
|
295
|
+
local: localRecord,
|
|
296
|
+
remote: remoteRecord,
|
|
297
|
+
localTimestamp: localTime.toISOString(),
|
|
298
|
+
remoteTimestamp: remoteTime.toISOString()
|
|
299
|
+
};
|
|
300
|
+
this.callbacks.onConflict?.(conflict);
|
|
301
|
+
// Apply conflict resolution strategy
|
|
302
|
+
switch (strategy) {
|
|
303
|
+
case 'last-write-wins':
|
|
304
|
+
// Keep newer record (already handled by timestamp comparison)
|
|
305
|
+
break;
|
|
306
|
+
case 'local-wins':
|
|
307
|
+
// Remote record will be overwritten
|
|
308
|
+
break;
|
|
309
|
+
case 'remote-wins':
|
|
310
|
+
// Local record will be overwritten
|
|
311
|
+
break;
|
|
312
|
+
case 'merge':
|
|
313
|
+
// Use custom merge function if provided
|
|
314
|
+
if (tableConfig?.mergeFn) {
|
|
315
|
+
// const merged = tableConfig.mergeFn(localRecord, remoteRecord);
|
|
316
|
+
// Update both local and remote with merged version (TODO: implement)
|
|
317
|
+
}
|
|
318
|
+
break;
|
|
319
|
+
case 'keep-both':
|
|
320
|
+
// Create duplicate records
|
|
321
|
+
break;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
return conflictCount;
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Get list of tables to sync.
|
|
329
|
+
*/
|
|
330
|
+
async getTablesToSync() {
|
|
331
|
+
// Get all tables from primary database
|
|
332
|
+
const schema = await exportData(this.primaryDb, {
|
|
333
|
+
includeSchema: true
|
|
334
|
+
});
|
|
335
|
+
const allTables = schema.schema?.map(s => s.name) ?? [];
|
|
336
|
+
// Filter based on include/exclude
|
|
337
|
+
let tables = allTables;
|
|
338
|
+
if (this.config.includeTables) {
|
|
339
|
+
tables = tables.filter(t => this.config.includeTables.includes(t));
|
|
340
|
+
}
|
|
341
|
+
if (this.config.excludeTables) {
|
|
342
|
+
tables = tables.filter(t => !this.config.excludeTables.includes(t));
|
|
343
|
+
}
|
|
344
|
+
// Filter out skipped tables
|
|
345
|
+
tables = tables.filter(t => !this.config.tables[t]?.skip);
|
|
346
|
+
return tables;
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Sort tables by priority.
|
|
350
|
+
*/
|
|
351
|
+
sortTablesByPriority(tables) {
|
|
352
|
+
const priorityOrder = { critical: 0, high: 1, medium: 2, low: 3 };
|
|
353
|
+
return tables.sort((a, b) => {
|
|
354
|
+
const aPriority = this.config.tables[a]?.priority ?? 'medium';
|
|
355
|
+
const bPriority = this.config.tables[b]?.priority ?? 'medium';
|
|
356
|
+
return priorityOrder[aPriority] - priorityOrder[bPriority];
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Check network connection.
|
|
361
|
+
*/
|
|
362
|
+
async checkConnection() {
|
|
363
|
+
if (!this.remoteDb)
|
|
364
|
+
return;
|
|
365
|
+
try {
|
|
366
|
+
await this.remoteDb.get('SELECT 1 as ok');
|
|
367
|
+
if (!this.isOnline) {
|
|
368
|
+
this.isOnline = true;
|
|
369
|
+
this.callbacks.onOnline?.();
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
catch {
|
|
373
|
+
if (this.isOnline) {
|
|
374
|
+
this.isOnline = false;
|
|
375
|
+
this.callbacks.onOffline?.();
|
|
376
|
+
}
|
|
377
|
+
throw new Error('Remote database not accessible');
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Start automatic sync based on mode.
|
|
382
|
+
*/
|
|
383
|
+
startAutoSync() {
|
|
384
|
+
if (this.config.mode === 'periodic') {
|
|
385
|
+
this.syncTimer = setInterval(() => {
|
|
386
|
+
this.sync().catch(error => {
|
|
387
|
+
this.callbacks.onError?.(error);
|
|
388
|
+
});
|
|
389
|
+
}, this.config.interval);
|
|
390
|
+
}
|
|
391
|
+
else if (this.config.mode === 'on-reconnect') {
|
|
392
|
+
// Set up network listener (browser only)
|
|
393
|
+
if (typeof window !== 'undefined') {
|
|
394
|
+
window.addEventListener('online', () => {
|
|
395
|
+
this.sync().catch(error => {
|
|
396
|
+
this.callbacks.onError?.(error);
|
|
397
|
+
});
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* Stop automatic sync.
|
|
404
|
+
*/
|
|
405
|
+
stop() {
|
|
406
|
+
if (this.syncTimer) {
|
|
407
|
+
clearInterval(this.syncTimer);
|
|
408
|
+
this.syncTimer = null;
|
|
409
|
+
}
|
|
410
|
+
if (this.debounceTimer) {
|
|
411
|
+
clearTimeout(this.debounceTimer);
|
|
412
|
+
this.debounceTimer = null;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
/**
|
|
416
|
+
* Close all database connections.
|
|
417
|
+
*/
|
|
418
|
+
async close() {
|
|
419
|
+
this.stop();
|
|
420
|
+
await this.primaryDb.close();
|
|
421
|
+
if (this.remoteDb) {
|
|
422
|
+
await this.remoteDb.close();
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* Create a sync manager instance.
|
|
427
|
+
*/
|
|
428
|
+
static async create(config) {
|
|
429
|
+
// Parse primary database config
|
|
430
|
+
let primaryDb;
|
|
431
|
+
const primaryConfig = typeof config.primary === 'string'
|
|
432
|
+
? { file: config.primary }
|
|
433
|
+
: config.primary;
|
|
434
|
+
try {
|
|
435
|
+
if (primaryConfig.url) {
|
|
436
|
+
// Try cloud first
|
|
437
|
+
primaryDb = await createDatabase({ url: primaryConfig.url });
|
|
438
|
+
}
|
|
439
|
+
else if (primaryConfig.file) {
|
|
440
|
+
// Use local file
|
|
441
|
+
primaryDb = await openDatabase(primaryConfig.file);
|
|
442
|
+
}
|
|
443
|
+
else {
|
|
444
|
+
// Auto-detect
|
|
445
|
+
primaryDb = await createDatabase();
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
catch (error) {
|
|
449
|
+
// Fallback to local if cloud fails
|
|
450
|
+
if (primaryConfig.fallback) {
|
|
451
|
+
console.warn('[SyncManager] Primary database failed, using fallback:', error);
|
|
452
|
+
primaryDb = await openDatabase(primaryConfig.fallback);
|
|
453
|
+
}
|
|
454
|
+
else {
|
|
455
|
+
throw error;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
// Open primary database
|
|
459
|
+
await primaryDb.open();
|
|
460
|
+
// Parse remote database config (optional)
|
|
461
|
+
let remoteDb = null;
|
|
462
|
+
if (config.remote) {
|
|
463
|
+
const remoteConfig = typeof config.remote === 'string'
|
|
464
|
+
? { url: config.remote }
|
|
465
|
+
: config.remote;
|
|
466
|
+
try {
|
|
467
|
+
if (remoteConfig.url) {
|
|
468
|
+
remoteDb = await connectDatabase(remoteConfig.url);
|
|
469
|
+
await remoteDb.open();
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
catch (error) {
|
|
473
|
+
console.warn('[SyncManager] Remote database not available:', error);
|
|
474
|
+
// Continue without remote (offline mode)
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
const manager = new SyncManager(primaryDb, remoteDb, {
|
|
478
|
+
onSync: config.onSync,
|
|
479
|
+
onConflict: config.onConflict,
|
|
480
|
+
onOffline: config.onOffline,
|
|
481
|
+
onOnline: config.onOnline,
|
|
482
|
+
onError: config.onError,
|
|
483
|
+
onProgress: config.onProgress
|
|
484
|
+
}, config.sync ?? {});
|
|
485
|
+
// Start auto-sync if configured
|
|
486
|
+
if (config.sync?.mode && config.sync.mode !== 'manual') {
|
|
487
|
+
manager.startAutoSync();
|
|
488
|
+
}
|
|
489
|
+
return manager;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
/**
|
|
493
|
+
* Create a sync manager for hybrid local/cloud databases.
|
|
494
|
+
*
|
|
495
|
+
* @example Online-first with automatic fallback
|
|
496
|
+
* ```typescript
|
|
497
|
+
* const manager = await createSyncManager({
|
|
498
|
+
* primary: {
|
|
499
|
+
* url: process.env.DATABASE_URL,
|
|
500
|
+
* fallback: './offline.db'
|
|
501
|
+
* },
|
|
502
|
+
* sync: {
|
|
503
|
+
* mode: 'periodic',
|
|
504
|
+
* interval: 30000
|
|
505
|
+
* }
|
|
506
|
+
* });
|
|
507
|
+
*
|
|
508
|
+
* // Use like normal database
|
|
509
|
+
* await manager.db.run('INSERT INTO users (name) VALUES (?)', ['Alice']);
|
|
510
|
+
* // Syncs automatically every 30s
|
|
511
|
+
* ```
|
|
512
|
+
*
|
|
513
|
+
* @example Offline-first with cloud sync
|
|
514
|
+
* ```typescript
|
|
515
|
+
* const manager = await createSyncManager({
|
|
516
|
+
* primary: './local.db',
|
|
517
|
+
* remote: process.env.DATABASE_URL,
|
|
518
|
+
* sync: {
|
|
519
|
+
* mode: 'manual' // Sync only when you call manager.sync()
|
|
520
|
+
* }
|
|
521
|
+
* });
|
|
522
|
+
*
|
|
523
|
+
* // Work offline
|
|
524
|
+
* await manager.db.run('INSERT INTO ...');
|
|
525
|
+
*
|
|
526
|
+
* // Sync when ready
|
|
527
|
+
* await manager.sync();
|
|
528
|
+
* ```
|
|
529
|
+
*/
|
|
530
|
+
export async function createSyncManager(config) {
|
|
531
|
+
return SyncManager.create(config);
|
|
532
|
+
}
|
|
533
|
+
//# sourceMappingURL=syncManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"syncManager.js","sourceRoot":"","sources":["../../src/utils/syncManager.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@framers/sql-storage-adapter",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Robust cross-platform SQL storage abstraction with automatic fallbacks and runtime detection",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"module": "dist/index.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"./package.json": "./package.json"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"clean": "rimraf dist tsconfig.build.tsbuildinfo",
|
|
22
|
+
"build": "npm run clean && tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json",
|
|
23
|
+
"prepublishOnly": "npm run build && npm run test",
|
|
24
|
+
"lint": "eslint \"src/**/*.{ts,tsx}\"",
|
|
25
|
+
"lint:fix": "eslint \"src/**/*.{ts,tsx}\" --fix",
|
|
26
|
+
"format": "prettier --write \"src/**/*.{ts,tsx,json,md}\"",
|
|
27
|
+
"format:check": "prettier --check \"src/**/*.{ts,tsx,json,md}\"",
|
|
28
|
+
"typecheck": "tsc --noEmit",
|
|
29
|
+
"test": "vitest run",
|
|
30
|
+
"test:watch": "vitest",
|
|
31
|
+
"test:coverage": "vitest run --coverage",
|
|
32
|
+
"coverage": "npm run test:coverage",
|
|
33
|
+
"coverage:view": "open coverage/index.html || start coverage/index.html || xdg-open coverage/index.html",
|
|
34
|
+
"docs": "typedoc --out docs src/index.ts",
|
|
35
|
+
"docs:clean": "rimraf docs",
|
|
36
|
+
"docs:serve": "npx http-server docs -p 8080 -o"
|
|
37
|
+
},
|
|
38
|
+
"keywords": [
|
|
39
|
+
"sql",
|
|
40
|
+
"sqlite",
|
|
41
|
+
"postgres",
|
|
42
|
+
"postgresql",
|
|
43
|
+
"database",
|
|
44
|
+
"storage",
|
|
45
|
+
"adapter",
|
|
46
|
+
"abstraction",
|
|
47
|
+
"capacitor",
|
|
48
|
+
"sql.js",
|
|
49
|
+
"better-sqlite3",
|
|
50
|
+
"typescript",
|
|
51
|
+
"cross-platform",
|
|
52
|
+
"fallback",
|
|
53
|
+
"webassembly"
|
|
54
|
+
],
|
|
55
|
+
"author": "Framers (https://frame.dev)",
|
|
56
|
+
"license": "MIT",
|
|
57
|
+
"repository": {
|
|
58
|
+
"type": "git",
|
|
59
|
+
"url": "https://github.com/wearetheframers/sql-storage-adapter.git"
|
|
60
|
+
},
|
|
61
|
+
"bugs": {
|
|
62
|
+
"url": "https://github.com/wearetheframers/sql-storage-adapter/issues",
|
|
63
|
+
"email": "team@frame.dev"
|
|
64
|
+
},
|
|
65
|
+
"homepage": "https://github.com/wearetheframers/sql-storage-adapter#readme",
|
|
66
|
+
"devDependencies": {
|
|
67
|
+
"@aws-sdk/client-s3": "^3.709.0",
|
|
68
|
+
"@eslint/js": "^9.39.0",
|
|
69
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
70
|
+
"@types/node": "^20.17.6",
|
|
71
|
+
"@types/pg": "^8.10.7",
|
|
72
|
+
"@vitest/coverage-v8": "^1.6.1",
|
|
73
|
+
"eslint": "^9.13.0",
|
|
74
|
+
"eslint-config-prettier": "^9.1.0",
|
|
75
|
+
"rimraf": "^5.0.7",
|
|
76
|
+
"ts-node": "^10.9.2",
|
|
77
|
+
"tsc-alias": "^1.8.10",
|
|
78
|
+
"tsconfig-paths": "^4.2.0",
|
|
79
|
+
"typedoc": "^0.26.11",
|
|
80
|
+
"typescript": "^5.6.3",
|
|
81
|
+
"typescript-eslint": "^8.46.2",
|
|
82
|
+
"vitest": "^1.6.0"
|
|
83
|
+
},
|
|
84
|
+
"dependencies": {
|
|
85
|
+
"pg": "^8.13.1",
|
|
86
|
+
"sql.js": "^1.11.0"
|
|
87
|
+
},
|
|
88
|
+
"peerDependencies": {
|
|
89
|
+
"@aws-sdk/client-s3": "^3.0.0",
|
|
90
|
+
"@capacitor-community/sqlite": "^6.0.0",
|
|
91
|
+
"better-sqlite3": "^12.0.0",
|
|
92
|
+
"pg": "^8.13.1"
|
|
93
|
+
},
|
|
94
|
+
"peerDependenciesMeta": {
|
|
95
|
+
"@aws-sdk/client-s3": {
|
|
96
|
+
"optional": true
|
|
97
|
+
},
|
|
98
|
+
"@capacitor-community/sqlite": {
|
|
99
|
+
"optional": true
|
|
100
|
+
},
|
|
101
|
+
"better-sqlite3": {
|
|
102
|
+
"optional": true
|
|
103
|
+
},
|
|
104
|
+
"pg": {
|
|
105
|
+
"optional": true
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|