UNPKG

resig.js

Version:

Universal reactive signal library with complete platform features: signals, animations, CRDTs, scheduling, DOM integration. Works identically across React, SolidJS, Svelte, Vue, and Qwik.

292 lines 26.9 kB
/** * Event Sourcing with CRDTs * Complete state reconstruction with event replay, snapshots, and compaction */ import { gCounter, orSet } from '../crdt'; import { createStreamingSignal } from './coalgebra'; // In-memory event store implementation export class MemoryEventStore { constructor() { this.events = []; this.snapshots = []; } async append(events) { this.events.push(...events); this.events.sort((a, b) => a.version - b.version); } async getEvents(fromVersion = 0, toVersion = Infinity) { return this.events.filter((e) => e.version >= fromVersion && e.version <= toVersion); } async getSnapshot(beforeVersion = Infinity) { const validSnapshots = this.snapshots.filter((s) => s.version < beforeVersion); return validSnapshots.length > 0 ? validSnapshots[validSnapshots.length - 1] : null; } async saveSnapshot(snapshot) { this.snapshots.push(snapshot); this.snapshots.sort((a, b) => a.version - b.version); } async compact(beforeVersion) { this.events = this.events.filter((e) => e.version >= beforeVersion); this.snapshots = this.snapshots.filter((s) => s.version >= beforeVersion); } } // IndexedDB event store for browser persistence export class IndexedDBEventStore { constructor(dbName) { this.db = null; this.dbName = dbName; } async getDB() { if (this.db) return this.db; return new Promise((resolve, reject) => { const request = indexedDB.open(this.dbName, 1); request.onerror = () => reject(request.error); request.onsuccess = () => { this.db = request.result; resolve(this.db); }; request.onupgradeneeded = () => { const db = request.result; if (!db.objectStoreNames.contains('events')) { const eventStore = db.createObjectStore('events', { keyPath: 'id' }); eventStore.createIndex('version', 'version', { unique: false }); eventStore.createIndex('timestamp', 'timestamp', { unique: false }); } if (!db.objectStoreNames.contains('snapshots')) { const snapshotStore = db.createObjectStore('snapshots', { keyPath: 'version', }); snapshotStore.createIndex('timestamp', 'timestamp', { unique: false, }); } }; }); } async append(events) { const db = await this.getDB(); const transaction = db.transaction(['events'], 'readwrite'); const store = transaction.objectStore('events'); for (const event of events) { store.add(event); } return new Promise((resolve, reject) => { transaction.oncomplete = () => resolve(); transaction.onerror = () => reject(transaction.error); }); } async getEvents(fromVersion = 0, toVersion = Infinity) { const db = await this.getDB(); const transaction = db.transaction(['events'], 'readonly'); const store = transaction.objectStore('events'); const index = store.index('version'); const range = IDBKeyRange.bound(fromVersion, toVersion); const request = index.getAll(range); return new Promise((resolve, reject) => { request.onsuccess = () => resolve(request.result); request.onerror = () => reject(request.error); }); } async getSnapshot(beforeVersion = Infinity) { const db = await this.getDB(); const transaction = db.transaction(['snapshots'], 'readonly'); const store = transaction.objectStore('snapshots'); const range = IDBKeyRange.upperBound(beforeVersion, true); const request = store.openCursor(range, 'prev'); return new Promise((resolve, reject) => { request.onsuccess = () => { const cursor = request.result; resolve(cursor ? cursor.value : null); }; request.onerror = () => reject(request.error); }); } async saveSnapshot(snapshot) { const db = await this.getDB(); const transaction = db.transaction(['snapshots'], 'readwrite'); const store = transaction.objectStore('snapshots'); store.put(snapshot); return new Promise((resolve, reject) => { transaction.oncomplete = () => resolve(); transaction.onerror = () => reject(transaction.error); }); } async compact(beforeVersion) { const db = await this.getDB(); const transaction = db.transaction(['events', 'snapshots'], 'readwrite'); // Remove old events const eventStore = transaction.objectStore('events'); const eventIndex = eventStore.index('version'); const eventRange = IDBKeyRange.upperBound(beforeVersion, true); const eventRequest = eventIndex.openCursor(eventRange); eventRequest.onsuccess = () => { const cursor = eventRequest.result; if (cursor) { cursor.delete(); cursor.continue(); } }; // Remove old snapshots const snapshotStore = transaction.objectStore('snapshots'); const snapshotRange = IDBKeyRange.upperBound(beforeVersion, true); const snapshotRequest = snapshotStore.openCursor(snapshotRange); snapshotRequest.onsuccess = () => { const cursor = snapshotRequest.result; if (cursor) { cursor.delete(); cursor.continue(); } }; return new Promise((resolve, reject) => { transaction.oncomplete = () => resolve(); transaction.onerror = () => reject(transaction.error); }); } } // Create event sourced CRDT wrapper export const createEventSourcedCRDT = (baseCRDT, config, nodeId = Math.random().toString(36)) => { let version = 0; let eventCount = 0; const eventStream = createStreamingSignal(null); // Track pending events for batching const pendingEvents = []; let flushTimeout = null; const flushEvents = async () => { if (pendingEvents.length === 0) return; const eventsToFlush = [...pendingEvents]; pendingEvents.length = 0; await config.eventStore.append(eventsToFlush); // Check if we need to create a snapshot if (eventCount % config.snapshotInterval === 0) { await createSnapshot(); } // Check if we need to compact await checkCompaction(); }; const createSnapshot = async () => { const snapshot = { timestamp: Date.now(), version, state: baseCRDT.value(), eventCount, checksum: generateChecksum(baseCRDT.value()), }; await config.eventStore.saveSnapshot(snapshot); return snapshot; }; const checkCompaction = async () => { const { compactionStrategy, maxEvents, maxAge } = config; switch (compactionStrategy) { case 'event-count': if (maxEvents && eventCount > maxEvents) { const compactBefore = version - Math.floor(maxEvents / 2); await config.eventStore.compact(compactBefore); } break; case 'time-based': if (maxAge) { const cutoffTime = Date.now() - maxAge; const events = await config.eventStore.getEvents(); const cutoffVersion = events.find((e) => e.timestamp > cutoffTime)?.version || version; await config.eventStore.compact(cutoffVersion); } break; case 'sliding-window': if (maxEvents && eventCount > maxEvents) { await config.eventStore.compact(version - maxEvents); } break; } }; const generateChecksum = (state) => { return btoa(JSON.stringify(state)).slice(0, 16); }; const addEvent = (event) => { const fullEvent = { ...event, id: `${nodeId}-${Date.now()}-${Math.random().toString(36)}`, version: ++version, nodeId, timestamp: Date.now(), }; pendingEvents.push(fullEvent); eventCount++; // Emit event immediately eventStream._set(fullEvent); // Batch flush events if (flushTimeout) clearTimeout(flushTimeout); flushTimeout = (typeof window !== 'undefined' ? window.setTimeout : setTimeout)(flushEvents, 10); }; const eventSourcedCRDT = { value: baseCRDT.value, merge: (other) => { const merged = baseCRDT.merge(other); addEvent({ type: 'merge', data: other.value() }); return merged; }, events: () => eventStream, replayFrom: async (timestamp) => { // Get the latest snapshot before the timestamp const snapshot = await config.eventStore.getSnapshot(); const state = snapshot ? snapshot.state : baseCRDT.value(); // Get events from snapshot version or beginning const fromVersion = snapshot ? snapshot.version : 0; const events = await config.eventStore.getEvents(fromVersion); // Filter events by timestamp and replay events.filter((e) => e.timestamp >= timestamp); // This is a simplified replay - in practice, you'd need to apply events to recreate state // For now, we return the current state return state; }, snapshot: createSnapshot, compact: async () => { await createSnapshot(); await config.eventStore.compact(version - config.snapshotInterval); }, getEventCount: () => eventCount, getVersion: () => version, clone: () => { return createEventSourcedCRDT(baseCRDT, config, nodeId); }, toJSON: () => { return { value: baseCRDT.value(), version, eventCount, nodeId, }; }, fromJSON: (data) => { return createEventSourcedCRDT(baseCRDT, config, data.nodeId || nodeId); }, }; // Wrap original CRDT methods to emit events const originalMethods = Object.getOwnPropertyNames(Object.getPrototypeOf(baseCRDT)); originalMethods.forEach((methodName) => { if (typeof baseCRDT[methodName] === 'function' && methodName !== 'value' && methodName !== 'merge') { const originalMethod = baseCRDT[methodName]; eventSourcedCRDT[methodName] = (...args) => { const result = originalMethod.apply(baseCRDT, args); addEvent({ type: methodName, data: args }); return result; }; } }); return eventSourcedCRDT; }; // Convenience functions for common CRDT types export const eventSourcedORSet = (nodeId, config) => { return createEventSourcedCRDT(orSet(nodeId), config, nodeId); }; export const eventSourcedGCounter = (nodeId, config) => { return createEventSourcedCRDT(gCounter(nodeId), config, nodeId); }; export const indexedDBEventStore = (dbName) => new IndexedDBEventStore(dbName); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXZlbnQtc291cmNpbmcuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvc3RyZWFtaW5nL2V2ZW50LXNvdXJjaW5nLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7R0FHRztBQUVILE9BQU8sRUFBUSxRQUFRLEVBQUUsS0FBSyxFQUFFLE1BQU0sU0FBUyxDQUFDO0FBRWhELE9BQU8sRUFBRSxxQkFBcUIsRUFBbUIsTUFBTSxhQUFhLENBQUM7QUEyRHJFLHVDQUF1QztBQUN2QyxNQUFNLE9BQU8sZ0JBQWdCO0lBQTdCO1FBQ1UsV0FBTSxHQUFZLEVBQUUsQ0FBQztRQUNyQixjQUFTLEdBQXdCLEVBQUUsQ0FBQztJQWlDOUMsQ0FBQztJQS9CQyxLQUFLLENBQUMsTUFBTSxDQUFDLE1BQWU7UUFDMUIsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxNQUFNLENBQUMsQ0FBQztRQUM1QixJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxPQUFPLEdBQUcsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQ3BELENBQUM7SUFFRCxLQUFLLENBQUMsU0FBUyxDQUFDLFdBQVcsR0FBRyxDQUFDLEVBQUUsU0FBUyxHQUFHLFFBQVE7UUFDbkQsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FDdkIsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxPQUFPLElBQUksV0FBVyxJQUFJLENBQUMsQ0FBQyxPQUFPLElBQUksU0FBUyxDQUMxRCxDQUFDO0lBQ0osQ0FBQztJQUVELEtBQUssQ0FBQyxXQUFXLENBQ2YsYUFBYSxHQUFHLFFBQVE7UUFFeEIsTUFBTSxjQUFjLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQzFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsT0FBTyxHQUFH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