Add neutral diagnostic framework for future reporting modules: - DiagnosticReporterInterface, Registry, Manager, PayloadSanitizer - Laravel exception hook in bootstrap/app.php - Module permission declarations (requires_permissions in module.json) - Core diagnostic report points (module boot/install/update failures) - Module documentation update (moduldoku.md) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
72 lines
2.4 KiB
JavaScript
72 lines
2.4 KiB
JavaScript
import { openDB } from 'idb';
|
|
|
|
const DB_NAME = 'schneespur_sync';
|
|
const DB_VERSION = 1;
|
|
const STORE_NAME = 'pending_requests';
|
|
|
|
export class SyncQueue {
|
|
constructor() {
|
|
this.db = null;
|
|
}
|
|
|
|
async init() {
|
|
this.db = await openDB(DB_NAME, DB_VERSION, {
|
|
upgrade(db) {
|
|
if (!db.objectStoreNames.contains(STORE_NAME)) {
|
|
const store = db.createObjectStore(STORE_NAME, {
|
|
keyPath: 'id',
|
|
autoIncrement: true,
|
|
});
|
|
store.createIndex('by_synced', 'synced');
|
|
store.createIndex('by_timestamp', 'timestamp');
|
|
}
|
|
},
|
|
});
|
|
return this;
|
|
}
|
|
|
|
async addRequest({ url, method, data, headers }) {
|
|
if (!this.db) throw new Error('SyncQueue not initialized — call init() first');
|
|
return this.db.add(STORE_NAME, {
|
|
url,
|
|
method,
|
|
data,
|
|
headers: headers || {},
|
|
timestamp: Date.now(),
|
|
synced: false,
|
|
});
|
|
}
|
|
|
|
async getPending() {
|
|
if (!this.db) throw new Error('SyncQueue not initialized — call init() first');
|
|
const all = await this.db.getAllFromIndex(STORE_NAME, 'by_synced', false);
|
|
return all.sort((a, b) => a.timestamp - b.timestamp);
|
|
}
|
|
|
|
async markSynced(id) {
|
|
if (!this.db) throw new Error('SyncQueue not initialized — call init() first');
|
|
const entry = await this.db.get(STORE_NAME, id);
|
|
if (!entry) return;
|
|
entry.synced = true;
|
|
entry.syncedAt = Date.now();
|
|
await this.db.put(STORE_NAME, entry);
|
|
}
|
|
|
|
async removeSynced() {
|
|
if (!this.db) throw new Error('SyncQueue not initialized — call init() first');
|
|
const oneHourAgo = Date.now() - 60 * 60 * 1000;
|
|
const synced = await this.db.getAllFromIndex(STORE_NAME, 'by_synced', true);
|
|
const tx = this.db.transaction(STORE_NAME, 'readwrite');
|
|
for (const entry of synced) {
|
|
if (entry.syncedAt && entry.syncedAt < oneHourAgo) {
|
|
await tx.store.delete(entry.id);
|
|
}
|
|
}
|
|
await tx.done;
|
|
}
|
|
|
|
async getCount() {
|
|
if (!this.db) throw new Error('SyncQueue not initialized — call init() first');
|
|
return this.db.countFromIndex(STORE_NAME, 'by_synced', false);
|
|
}
|
|
}
|