UNPKG

sveltekit-sync

Version:
141 lines (140 loc) 5.08 kB
export class IndexedDBAdapter { db = null; dbName; version; constructor(dbName = 'sync-db', version = 1) { this.dbName = dbName; this.version = version; } ensureInitialized() { if (!this.db) { throw new Error('Database not initialized. Call adapter.init() first.'); } } async init(schema) { if (this.db) return; // Already initialized return new Promise((resolve, reject) => { const request = indexedDB.open(this.dbName, this.version); request.onerror = () => reject(request.error); request.onsuccess = () => { this.db = request.result; resolve(); }; request.onupgradeneeded = (event) => { const db = event.target.result; // Create default stores if (!db.objectStoreNames.contains('sync_queue')) { db.createObjectStore('sync_queue', { keyPath: 'id' }); } if (!db.objectStoreNames.contains('sync_meta')) { db.createObjectStore('sync_meta', { keyPath: 'key' }); } // Create user-defined stores if (schema) { Object.keys(schema).forEach(table => { if (!db.objectStoreNames.contains(table)) { db.createObjectStore(table, { keyPath: 'id' }); } }); } }; }); } getStore(table, mode = 'readonly') { this.ensureInitialized(); return this.db.transaction(table, mode).objectStore(table); } async insert(table, data) { const store = this.getStore(table, 'readwrite'); return new Promise((resolve, reject) => { const request = store.add(data); request.onsuccess = () => resolve(data); request.onerror = () => reject(request.error); }); } async update(table, id, data) { const store = this.getStore(table, 'readwrite'); return new Promise((resolve, reject) => { const request = store.put({ ...data, id }); request.onsuccess = () => resolve(data); request.onerror = () => reject(request.error); }); } async delete(table, id) { const store = this.getStore(table, 'readwrite'); return new Promise((resolve, reject) => { const request = store.delete(id); request.onsuccess = () => resolve(); request.onerror = () => reject(request.error); }); } async find(table, query) { const store = this.getStore(table); return new Promise((resolve, reject) => { const request = store.getAll(); request.onsuccess = () => resolve(request.result); request.onerror = () => reject(request.error); }); } async findOne(table, id) { const store = this.getStore(table); return new Promise((resolve, reject) => { const request = store.get(id); request.onsuccess = () => resolve(request.result || null); request.onerror = () => reject(request.error); }); } async addToQueue(op) { await this.insert('sync_queue', op); } async getQueue() { return this.find('sync_queue'); } async removeFromQueue(ids) { for (const id of ids) { await this.delete('sync_queue', id); } } async updateQueueStatus(id, status, error) { const op = await this.findOne('sync_queue', id); if (op) { await this.update('sync_queue', id, { ...op, status, error }); } } async getLastSync() { const meta = await this.findOne('sync_meta', 'lastSync'); return meta?.value || 0; } async setLastSync(timestamp) { const existing = await this.findOne('sync_meta', 'lastSync'); if (existing) { await this.update('sync_meta', 'lastSync', { key: 'lastSync', value: timestamp }); } else { await this.insert('sync_meta', { key: 'lastSync', value: timestamp }); } } async getClientId() { let meta = await this.findOne('sync_meta', 'clientId'); if (!meta) { const clientId = crypto.randomUUID(); await this.insert('sync_meta', { key: 'clientId', value: clientId }); return clientId; } return meta.value; } async isInitialized() { const meta = await this.findOne('sync_meta', 'isInitialized'); return meta?.value || false; } async setInitialized(value) { const existing = await this.findOne('sync_meta', 'isInitialized'); if (existing) { await this.update('sync_meta', 'isInitialized', { key: 'isInitialized', value }); } else { await this.insert('sync_meta', { key: 'isInitialized', value }); } } }