UNPKG

zeno-db

Version:

A lightweight, offline-first client-side database with automatic sync capabilities

225 lines (224 loc) 9.03 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.IndexedDBAdapter = void 0; class IndexedDBAdapter { constructor(config) { this.db = null; this.subscribers = []; this.changes = []; this.dbName = config.name || 'zenodb'; this.storeName = config.storeName || 'store'; this.version = config.version || 1; } init() { return __awaiter(this, void 0, void 0, function* () { 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; if (!db.objectStoreNames.contains(this.storeName)) { db.createObjectStore(this.storeName); } }; }); }); } get(key) { return __awaiter(this, void 0, void 0, function* () { return new Promise((resolve, reject) => { if (!this.db) { reject(new Error('Database not initialized')); return; } const transaction = this.db.transaction(this.storeName, 'readonly'); const store = transaction.objectStore(this.storeName); const request = store.get(key); request.onerror = () => reject(request.error); request.onsuccess = () => resolve(request.result); }); }); } set(key, value) { return __awaiter(this, void 0, void 0, function* () { return new Promise((resolve, reject) => { if (!this.db) { reject(new Error('Database not initialized')); return; } const transaction = this.db.transaction(this.storeName, 'readwrite'); const store = transaction.objectStore(this.storeName); const request = store.put(value, key); request.onerror = () => reject(request.error); request.onsuccess = () => { this.notifySubscribers(key, value); this.queueChange({ key, value, timestamp: Date.now(), clientId: 'local', operation: 'set' }); resolve(); }; }); }); } delete(key) { return __awaiter(this, void 0, void 0, function* () { return new Promise((resolve, reject) => { if (!this.db) { reject(new Error('Database not initialized')); return; } const transaction = this.db.transaction(this.storeName, 'readwrite'); const store = transaction.objectStore(this.storeName); const request = store.delete(key); request.onerror = () => reject(request.error); request.onsuccess = () => { this.notifySubscribers(key, undefined); this.queueChange({ key, value: undefined, timestamp: Date.now(), clientId: 'local', operation: 'delete' }); resolve(); }; }); }); } keys() { return __awaiter(this, void 0, void 0, function* () { return new Promise((resolve, reject) => { if (!this.db) { reject(new Error('Database not initialized')); return; } const transaction = this.db.transaction(this.storeName, 'readonly'); const store = transaction.objectStore(this.storeName); const request = store.getAllKeys(); request.onerror = () => reject(request.error); request.onsuccess = () => resolve(request.result); }); }); } getAll() { return __awaiter(this, void 0, void 0, function* () { if (!this.db) { throw new Error('Database not initialized'); } const db = this.db; // Create a local reference to avoid null checks return new Promise((resolve, reject) => { const request = db.transaction(this.storeName, 'readonly') .objectStore(this.storeName) .getAll(); request.onsuccess = () => { const result = {}; request.result.forEach((item) => { result[item.key] = item.value; }); resolve(result); }; request.onerror = () => { reject(request.error); }; }); }); } getMany(keys) { return __awaiter(this, void 0, void 0, function* () { if (!this.db) { throw new Error('Database not initialized'); } return new Promise((resolve, reject) => { const transaction = this.db.transaction(this.storeName, 'readonly'); const store = transaction.objectStore(this.storeName); const results = []; let completed = 0; keys.forEach((key, idx) => { const request = store.get(key); request.onsuccess = () => { results[idx] = request.result; completed++; if (completed === keys.length) { resolve(results); } }; request.onerror = () => { results[idx] = undefined; completed++; if (completed === keys.length) { resolve(results); } }; }); }); }); } setMany(items) { return __awaiter(this, void 0, void 0, function* () { if (!this.db) { throw new Error('Database not initialized'); } return new Promise((resolve, reject) => { const transaction = this.db.transaction(this.storeName, 'readwrite'); const store = transaction.objectStore(this.storeName); let completed = 0; items.forEach((item) => { const request = store.put(item, item.id); request.onsuccess = () => { this.notifySubscribers(item.id, item); this.queueChange({ key: item.id, value: item, timestamp: Date.now(), clientId: 'local', operation: 'set', }); completed++; if (completed === items.length) { resolve(); } }; request.onerror = () => { completed++; if (completed === items.length) { resolve(); // Ignore errors for now, could be improved } }; }); }); }); } subscribe(callback) { this.subscribers.push(callback); } notifySubscribers(key, value) { this.subscribers.forEach(callback => callback(key, value)); } getChanges() { return this.changes; } clearChanges() { this.changes = []; } queueChange(change) { this.changes.push(change); } } exports.IndexedDBAdapter = IndexedDBAdapter;