@klastra/ksync
Version:
Real-time sync engine for modern applications with 300k+ ops/sec performance
117 lines • 4.49 kB
JavaScript
export class IndexedDBStorage {
dbName = 'ksync-db';
storeName = 'events';
version = 1;
db;
async getDB() {
if (this.db)
return this.db;
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(this.db);
};
request.onupgradeneeded = () => {
const db = request.result;
if (!db.objectStoreNames.contains(this.storeName)) {
const store = db.createObjectStore(this.storeName, { keyPath: 'id' });
store.createIndex('version', 'version', { unique: false });
store.createIndex('timestamp', 'timestamp', { unique: false });
}
};
});
}
async getEvents(fromVersion) {
const db = await this.getDB();
return new Promise((resolve, reject) => {
const transaction = db.transaction([this.storeName], 'readonly');
const store = transaction.objectStore(this.storeName);
const request = store.getAll();
request.onerror = () => reject(request.error);
request.onsuccess = () => {
let events = request.result;
if (fromVersion !== undefined) {
events = events.filter(event => event.version > fromVersion);
}
// Sort by version
events.sort((a, b) => a.version - b.version);
resolve(events);
};
});
}
async storeEvent(event) {
const db = await this.getDB();
return new Promise((resolve, reject) => {
const transaction = db.transaction([this.storeName], 'readwrite');
const store = transaction.objectStore(this.storeName);
const request = store.put(event);
request.onerror = () => reject(request.error);
request.onsuccess = () => resolve();
});
}
async storeEvents(events) {
const db = await this.getDB();
return new Promise((resolve, reject) => {
const transaction = db.transaction([this.storeName], 'readwrite');
const store = transaction.objectStore(this.storeName);
let completed = 0;
let hasError = false;
for (const event of events) {
const request = store.put(event);
request.onerror = () => {
if (!hasError) {
hasError = true;
reject(request.error);
}
};
request.onsuccess = () => {
completed++;
if (completed === events.length && !hasError) {
resolve();
}
};
}
if (events.length === 0) {
resolve();
}
});
}
async getLastVersion() {
const db = await this.getDB();
return new Promise((resolve, reject) => {
const transaction = db.transaction([this.storeName], 'readonly');
const store = transaction.objectStore(this.storeName);
const index = store.index('version');
const request = index.openCursor(null, 'prev'); // Get highest version
request.onerror = () => reject(request.error);
request.onsuccess = () => {
const cursor = request.result;
if (cursor) {
resolve(cursor.value.version);
}
else {
resolve(0); // No events
}
};
});
}
async saveEvents(events) {
return this.storeEvents(events);
}
async loadEvents() {
return this.getEvents();
}
async clear() {
const db = await this.getDB();
return new Promise((resolve, reject) => {
const transaction = db.transaction([this.storeName], 'readwrite');
const store = transaction.objectStore(this.storeName);
const request = store.clear();
request.onerror = () => reject(request.error);
request.onsuccess = () => resolve();
});
}
}
//# sourceMappingURL=indexeddb.js.map