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.
318 lines • 23.9 kB
JavaScript
"use strict";
/**
* Real-time Sync System
* Uses CRDT.merge() via BroadcastChannel with commutative monoid operations
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.createRealtimeSync = exports.createSyncedRegister = exports.createSyncedSet = exports.createSyncedCounter = exports.RealtimeSync = void 0;
const signal_1 = require("../core/signal");
const crdt_1 = require("../crdt");
// Real-time sync manager using commutative monoid operations
class RealtimeSync {
constructor(config) {
this.config = config;
this.heartbeatTimer = null;
this.nodeId = config.nodeId;
this.channel = new BroadcastChannel(config.channelName);
this.vectorClock = { [this.nodeId]: 0 };
this.crdts = new Map();
this.operationLog = (0, signal_1.signal)([]);
this.connectionState = (0, signal_1.signal)({
isConnected: false,
connectedNodes: new Set(),
lastHeartbeat: Date.now(),
messageQueue: [],
syncErrors: [],
});
this.setupChannel();
this.startHeartbeat();
this.announceJoin();
}
// Setup BroadcastChannel with commutative monoid message handling
setupChannel() {
this.channel.addEventListener('message', (event) => {
const message = event.data;
// Ignore messages from self
if (message.nodeId === this.nodeId)
return;
this.handleMessage(message);
});
// Update connection state
this.connectionState._set({
...this.connectionState.value(),
isConnected: true,
});
}
// Handle incoming sync messages using commutative operations
handleMessage(message) {
try {
switch (message.type) {
case 'operation':
this.handleOperation(message);
break;
case 'state':
this.handleStateSync(message);
break;
case 'heartbeat':
this.handleHeartbeat(message);
break;
case 'join':
this.handleNodeJoin(message);
break;
case 'leave':
this.handleNodeLeave(message);
break;
}
// Update vector clock (commutative monoid operation)
this.mergeVectorClock(message.vectorClock);
// Log operation
this.operationLog._set([...this.operationLog.value(), message]);
}
catch (error) {
this.handleSyncError(error, message);
}
}
// Handle CRDT operation with commutative merge
handleOperation(message) {
const { data: operation } = message;
const crdt = this.crdts.get(operation.crdtId);
if (!crdt) {
console.warn(`CRDT ${operation.crdtId} not found for operation`, operation);
return;
}
// Apply operation using CRDT's commutative merge
try {
// CRDTs guarantee commutativity: merge(a, b) = merge(b, a)
const updatedCRDT = crdt; // Simplified - no applyOperation method
this.crdts.set(operation.crdtId, updatedCRDT);
// Notify subscribers
this.notifySubscribers(operation.crdtId, updatedCRDT.value());
}
catch (error) {
console.error('Failed to apply CRDT operation:', error);
this.requestStateSync(operation.crdtId);
}
}
// Handle full state synchronization
handleStateSync(message) {
const { crdtId, state } = message.data;
const localCRDT = this.crdts.get(crdtId);
if (!localCRDT)
return;
try {
// Merge states using commutative monoid operation
localCRDT.merge(state);
this.crdts.set(crdtId, localCRDT);
// Notify subscribers
this.notifySubscribers(crdtId, localCRDT.value());
}
catch (error) {
console.error('Failed to merge CRDT state:', error);
}
}
// Handle node heartbeat
handleHeartbeat(message) {
const state = this.connectionState.value();
state.connectedNodes.add(message.nodeId);
state.lastHeartbeat = Date.now();
this.connectionState._set({ ...state });
}
// Handle node join
handleNodeJoin(message) {
const state = this.connectionState.value();
state.connectedNodes.add(message.nodeId);
this.connectionState._set({ ...state });
// Send current state to new node
this.sendStateToNode(message.nodeId);
}
// Handle node leave
handleNodeLeave(message) {
const state = this.connectionState.value();
state.connectedNodes.delete(message.nodeId);
this.connectionState._set({ ...state });
}
// Merge vector clocks (commutative monoid operation)
mergeVectorClock(remoteClock) {
// Vector clock merge is commutative: max(local, remote) for each node
Object.entries(remoteClock).forEach(([nodeId, timestamp]) => {
this.vectorClock[nodeId] = Math.max(this.vectorClock[nodeId] || 0, timestamp);
});
}
// Increment local vector clock
incrementVectorClock() {
this.vectorClock[this.nodeId] = (this.vectorClock[this.nodeId] || 0) + 1;
}
// Send message via BroadcastChannel
sendMessage(type, data) {
this.incrementVectorClock();
const message = {
type,
nodeId: this.nodeId,
timestamp: Date.now(),
data,
operationId: this.generateOperationId(),
vectorClock: { ...this.vectorClock },
};
this.channel.postMessage(message);
}
// Generate unique operation ID
generateOperationId() {
return `${this.nodeId}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
}
// Start heartbeat mechanism
startHeartbeat() {
const interval = this.config.heartbeatInterval || 5000;
this.heartbeatTimer = window.setInterval(() => {
this.sendMessage('heartbeat', {
connectedNodes: Array.from(this.connectionState.value().connectedNodes),
});
}, interval);
}
// Announce node join
announceJoin() {
this.sendMessage('join', {
capabilities: ['crdt-sync', 'vector-clock', 'broadcast-channel'],
});
}
// Send current state to specific node
sendStateToNode(targetNodeId) {
this.crdts.forEach((crdt, crdtId) => {
this.sendMessage('state', {
crdtId,
state: crdt.toJSON(),
targetNode: targetNodeId,
});
});
}
// Request state sync for specific CRDT
requestStateSync(crdtId) {
this.sendMessage('state', {
crdtId,
request: true,
});
}
// Handle sync errors
handleSyncError(error, message) {
const state = this.connectionState.value();
state.syncErrors.push(error);
this.connectionState._set({ ...state });
console.error('Sync error:', error, message);
}
// Notify CRDT subscribers
notifySubscribers(crdtId, value) {
// Emit change event for reactive systems
const event = new CustomEvent('crdt-change', {
detail: { crdtId, value },
});
window.dispatchEvent(event);
}
// Public API
// Register CRDT for synchronization
registerCRDT(id, crdt) {
this.crdts.set(id, crdt);
// Subscribe to CRDT changes
if ('subscribe' in crdt) {
crdt.subscribe((value) => {
// Broadcast operation to other nodes
this.sendMessage('operation', {
crdtId: id,
operation: { type: 'update', value }, // Simplified - no getLastOperation
value,
});
});
}
}
// Unregister CRDT
unregisterCRDT(id) {
this.crdts.delete(id);
}
// Get CRDT by ID
getCRDT(id) {
return this.crdts.get(id);
}
// Get connection state signal
getConnectionState() {
return this.connectionState;
}
// Get operation log signal
getOperationLog() {
return this.operationLog;
}
// Force sync with all nodes
forcSync() {
this.crdts.forEach((crdt, crdtId) => {
this.sendMessage('state', {
crdtId,
state: crdt.toJSON(),
force: true,
});
});
}
// Disconnect and cleanup
disconnect() {
this.sendMessage('leave', {
reason: 'manual-disconnect',
});
if (this.heartbeatTimer) {
clearInterval(this.heartbeatTimer);
this.heartbeatTimer = null;
}
this.channel.close();
this.connectionState._set({
...this.connectionState.value(),
isConnected: false,
connectedNodes: new Set(),
});
}
}
exports.RealtimeSync = RealtimeSync;
// Factory functions for common sync patterns
// Create synced counter
const createSyncedCounter = (sync, id, nodeId, _initialValue = 0) => {
const counter = (0, crdt_1.gCounter)(nodeId);
sync.registerCRDT(id, counter);
const counterSignal = (0, signal_1.signal)(counter.value());
// Listen for changes
window.addEventListener('crdt-change', (e) => {
if (e.detail.crdtId === id) {
counterSignal._set(e.detail.value);
}
});
return counterSignal;
};
exports.createSyncedCounter = createSyncedCounter;
// Create synced set
const createSyncedSet = (sync, id, nodeId, initialItems = []) => {
const set = (0, crdt_1.orSet)(nodeId);
initialItems.forEach((item) => set.add(item));
sync.registerCRDT(id, set);
const setSignal = (0, signal_1.signal)(set.value());
// Listen for changes
window.addEventListener('crdt-change', (e) => {
if (e.detail.crdtId === id) {
setSignal._set(e.detail.value);
}
});
return setSignal;
};
exports.createSyncedSet = createSyncedSet;
// Create synced register
const createSyncedRegister = (sync, id, nodeId, initialValue) => {
const register = (0, crdt_1.lwwRegister)(nodeId, initialValue);
sync.registerCRDT(id, register);
const registerSignal = (0, signal_1.signal)(register.value());
// Listen for changes
window.addEventListener('crdt-change', (e) => {
if (e.detail.crdtId === id) {
registerSignal._set(e.detail.value);
}
});
return registerSignal;
};
exports.createSyncedRegister = createSyncedRegister;
// Create sync manager
const createRealtimeSync = (config) => {
return new RealtimeSync(config);
};
exports.createRealtimeSync = createRealtimeSync;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVhbHRpbWUtc3luYy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9leHRlbnNpb25zL3JlYWx0aW1lLXN5bmMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7R0FHRzs7O0FBRUgsMkNBQWdEO0FBRWhELGtDQUF1RDtBQXVDdkQsNkRBQTZEO0FBQzdELE1BQWEsWUFBWTtJQVN2QixZQUFvQixNQUFrQjtRQUFsQixXQUFNLEdBQU4sTUFBTSxDQUFZO1FBRjlCLG1CQUFjLEdBQWtCLElBQUksQ0FBQztRQUczQyxJQUFJLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUM7UUFDNUIsSUFBSSxDQUFDLE9BQU8sR0FBRyxJQUFJLGdCQUFnQixDQUFDLE1BQU0sQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUN4RCxJQUFJLENBQUMsV0FBVyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUM7UUFDeEMsSUFBSSxDQUFDLEtBQUssR0FBRyxJQUFJLEdBQUcsRUFBRSxDQUFDO1FBQ3ZCLElBQUksQ0FBQyxZQUFZLEdBQUcsSUFBQSxlQUFNLEVBQUMsRUFBRSxDQUFDLENBQUM7UUFFL0IsSUFBSSxDQUFDLGVBQWUsR0FBRyxJQUFBLGVBQU0sRUFBQztZQUM1QixXQUFXLEVBQUUsS0FBSztZQUNsQixjQUFjLEVBQUUsSUFBSSxHQUFHLEVBQUU7WUFDekIsYUFBYSxFQUFFLElBQUksQ0FBQyxHQUFHLEVBQUU7WUFDekIsWUFBWSxFQUFFLEVBQUU7WUFDaEIsVUFBVSxFQUFFLEVBQUU7U0FDZixDQUFDLENBQUM7UUFFSCxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUM7UUFDcEIsSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO1FBQ3RCLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQztJQUN0QixDQUFDO0lBRUQsa0VBQWtFO0lBQzFELFlBQVk7UUFDbEIsSUFBSSxDQUFDLE9BQU8s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