@topgunbuild/client 0.2.0-alpha → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +26 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.js +116 -14
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +116 -14
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/SyncEngine.ts","../src/utils/logger.ts","../src/SyncState.ts","../src/SyncStateMachine.ts","../src/errors/BackpressureError.ts","../src/BackpressureConfig.ts","../src/TopGunClient.ts","../src/QueryHandle.ts","../src/DistributedLock.ts","../src/TopicHandle.ts","../src/adapters/IDBAdapter.ts","../src/TopGun.ts","../src/crypto/EncryptionManager.ts","../src/adapters/EncryptedStorageAdapter.ts"],"sourcesContent":["import { SyncEngine } from './SyncEngine';\nimport { TopGunClient } from './TopGunClient';\nimport { TopGun } from './TopGun';\nexport * from './adapters/IDBAdapter';\nexport * from './adapters/EncryptedStorageAdapter';\nimport { QueryHandle } from './QueryHandle';\nimport { LWWMap, Predicates } from '@topgunbuild/core';\nimport { TopicHandle } from './TopicHandle';\nimport { SyncState, VALID_TRANSITIONS, isValidTransition } from './SyncState';\nimport { SyncStateMachine } from './SyncStateMachine';\nimport { BackpressureError } from './errors/BackpressureError';\nimport { DEFAULT_BACKPRESSURE_CONFIG } from './BackpressureConfig';\n\n// Type imports\nimport type { IStorageAdapter, OpLogEntry } from './IStorageAdapter';\nimport type { LWWRecord, PredicateNode } from '@topgunbuild/core';\nimport type { QueryFilter, QueryResultItem, QueryResultSource } from './QueryHandle';\nimport type { TopicCallback } from './TopicHandle';\nimport type { BackoffConfig, HeartbeatConfig, SyncEngineConfig } from './SyncEngine';\nimport type { StateChangeEvent, StateChangeListener, SyncStateMachineConfig } from './SyncStateMachine';\nimport type {\n BackpressureConfig,\n BackpressureStrategy,\n BackpressureStatus,\n BackpressureThresholdEvent,\n OperationDroppedEvent,\n} from './BackpressureConfig';\n\n// Value exports\nexport { SyncEngine, TopGunClient, TopGun, QueryHandle, LWWMap, Predicates, TopicHandle };\nexport { SyncState, VALID_TRANSITIONS, isValidTransition, SyncStateMachine };\nexport { BackpressureError, DEFAULT_BACKPRESSURE_CONFIG };\nexport { logger } from './utils/logger';\n\n// Type exports\nexport type {\n IStorageAdapter,\n OpLogEntry,\n LWWRecord,\n PredicateNode,\n QueryFilter,\n QueryResultItem,\n QueryResultSource,\n TopicCallback,\n BackoffConfig,\n HeartbeatConfig,\n SyncEngineConfig,\n StateChangeEvent,\n StateChangeListener,\n SyncStateMachineConfig,\n BackpressureConfig,\n BackpressureStrategy,\n BackpressureStatus,\n BackpressureThresholdEvent,\n OperationDroppedEvent,\n};\n","import { HLC, LWWMap, ORMap, serialize, deserialize, evaluatePredicate } from '@topgunbuild/core';\nimport type { LWWRecord, ORMapRecord, Timestamp } from '@topgunbuild/core';\nimport type { IStorageAdapter } from './IStorageAdapter';\nimport { QueryHandle } from './QueryHandle';\nimport type { QueryFilter } from './QueryHandle';\nimport { TopicHandle } from './TopicHandle';\nimport { logger } from './utils/logger';\nimport { SyncStateMachine, StateChangeEvent } from './SyncStateMachine';\nimport { SyncState } from './SyncState';\nimport { BackpressureError } from './errors/BackpressureError';\nimport type {\n BackpressureConfig,\n BackpressureStatus,\n BackpressureStrategy,\n BackpressureThresholdEvent,\n OperationDroppedEvent,\n} from './BackpressureConfig';\nimport { DEFAULT_BACKPRESSURE_CONFIG } from './BackpressureConfig';\n\nexport interface OpLogEntry {\n id: string; // Unique ID for the operation\n mapName: string;\n opType: 'PUT' | 'REMOVE' | 'OR_ADD' | 'OR_REMOVE';\n key: string;\n record?: LWWRecord<any>; // LWW Put/Remove (Remove has null value)\n orRecord?: ORMapRecord<any>; // ORMap Add\n orTag?: string; // ORMap Remove (Tombstone tag)\n timestamp: Timestamp; // HLC timestamp of the operation\n synced: boolean; // True if this operation has been successfully pushed to the server\n}\n\nexport interface HeartbeatConfig {\n intervalMs: number; // Default: 5000 (5 seconds)\n timeoutMs: number; // Default: 15000 (15 seconds)\n enabled: boolean; // Default: true\n}\n\nexport interface BackoffConfig {\n /** Initial delay in milliseconds (default: 1000) */\n initialDelayMs: number;\n /** Maximum delay in milliseconds (default: 30000) */\n maxDelayMs: number;\n /** Multiplier for exponential backoff (default: 2) */\n multiplier: number;\n /** Whether to add random jitter to delay (default: true) */\n jitter: boolean;\n /** Maximum number of retry attempts before entering ERROR state (default: 10) */\n maxRetries: number;\n}\n\nexport interface SyncEngineConfig {\n nodeId: string;\n serverUrl: string;\n storageAdapter: IStorageAdapter;\n reconnectInterval?: number;\n heartbeat?: Partial<HeartbeatConfig>;\n backoff?: Partial<BackoffConfig>;\n backpressure?: Partial<BackpressureConfig>;\n}\n\nconst DEFAULT_BACKOFF_CONFIG: BackoffConfig = {\n initialDelayMs: 1000,\n maxDelayMs: 30000,\n multiplier: 2,\n jitter: true,\n maxRetries: 10,\n};\n\nexport class SyncEngine {\n private readonly nodeId: string;\n private readonly serverUrl: string;\n private readonly storageAdapter: IStorageAdapter;\n private readonly hlc: HLC;\n private readonly stateMachine: SyncStateMachine;\n private readonly backoffConfig: BackoffConfig;\n\n private websocket: WebSocket | null = null;\n private opLog: OpLogEntry[] = [];\n private maps: Map<string, LWWMap<any, any> | ORMap<any, any>> = new Map();\n private queries: Map<string, QueryHandle<any>> = new Map();\n private topics: Map<string, TopicHandle> = new Map();\n private pendingLockRequests: Map<string, { resolve: (res: any) => void, reject: (err: any) => void, timer: any }> = new Map();\n private lastSyncTimestamp: number = 0;\n private reconnectTimer: any = null; // NodeJS.Timeout\n private authToken: string | null = null;\n private tokenProvider: (() => Promise<string | null>) | null = null;\n private backoffAttempt: number = 0;\n\n // Heartbeat state\n private readonly heartbeatConfig: HeartbeatConfig;\n private heartbeatInterval: ReturnType<typeof setInterval> | null = null;\n private lastPongReceived: number = Date.now();\n private lastRoundTripTime: number | null = null;\n\n // Backpressure state\n private readonly backpressureConfig: BackpressureConfig;\n private backpressurePaused: boolean = false;\n private waitingForCapacity: Array<() => void> = [];\n private highWaterMarkEmitted: boolean = false;\n private backpressureListeners: Map<string, Set<(...args: any[]) => void>> = new Map();\n\n constructor(config: SyncEngineConfig) {\n this.nodeId = config.nodeId;\n this.serverUrl = config.serverUrl;\n this.storageAdapter = config.storageAdapter;\n this.hlc = new HLC(this.nodeId);\n\n // Initialize state machine\n this.stateMachine = new SyncStateMachine();\n\n // Initialize heartbeat config with defaults\n this.heartbeatConfig = {\n intervalMs: config.heartbeat?.intervalMs ?? 5000,\n timeoutMs: config.heartbeat?.timeoutMs ?? 15000,\n enabled: config.heartbeat?.enabled ?? true,\n };\n\n // Merge backoff config with defaults\n this.backoffConfig = {\n ...DEFAULT_BACKOFF_CONFIG,\n ...config.backoff,\n };\n\n // Merge backpressure config with defaults\n this.backpressureConfig = {\n ...DEFAULT_BACKPRESSURE_CONFIG,\n ...config.backpressure,\n };\n\n this.initConnection();\n this.loadOpLog();\n }\n\n // ============================================\n // State Machine Public API\n // ============================================\n\n /**\n * Get the current connection state\n */\n getConnectionState(): SyncState {\n return this.stateMachine.getState();\n }\n\n /**\n * Subscribe to connection state changes\n * @returns Unsubscribe function\n */\n onConnectionStateChange(listener: (event: StateChangeEvent) => void): () => void {\n return this.stateMachine.onStateChange(listener);\n }\n\n /**\n * Get state machine history for debugging\n */\n getStateHistory(limit?: number): StateChangeEvent[] {\n return this.stateMachine.getHistory(limit);\n }\n\n // ============================================\n // Internal State Helpers (replace boolean flags)\n // ============================================\n\n /**\n * Check if WebSocket is connected (but may not be authenticated yet)\n */\n private isOnline(): boolean {\n const state = this.stateMachine.getState();\n return (\n state === SyncState.CONNECTING ||\n state === SyncState.AUTHENTICATING ||\n state === SyncState.SYNCING ||\n state === SyncState.CONNECTED\n );\n }\n\n /**\n * Check if fully authenticated and ready for operations\n */\n private isAuthenticated(): boolean {\n const state = this.stateMachine.getState();\n return state === SyncState.SYNCING || state === SyncState.CONNECTED;\n }\n\n /**\n * Check if fully connected and synced\n */\n private isConnected(): boolean {\n return this.stateMachine.getState() === SyncState.CONNECTED;\n }\n\n // ============================================\n // Connection Management\n // ============================================\n\n private initConnection(): void {\n // Transition to CONNECTING state\n this.stateMachine.transition(SyncState.CONNECTING);\n\n this.websocket = new WebSocket(this.serverUrl);\n this.websocket.binaryType = 'arraybuffer';\n\n this.websocket.onopen = () => {\n // WebSocket is open, now we need to authenticate\n // [CHANGE] Don't send auth immediately if we don't have a token\n // This prevents the \"AUTH_REQUIRED -> Close -> Retry loop\" for anonymous initial connects\n if (this.authToken || this.tokenProvider) {\n logger.info('WebSocket connected. Sending auth...');\n this.stateMachine.transition(SyncState.AUTHENTICATING);\n this.sendAuth();\n } else {\n logger.info('WebSocket connected. Waiting for auth token...');\n // Stay in CONNECTING state until we have a token\n // We're online but not authenticated\n this.stateMachine.transition(SyncState.AUTHENTICATING);\n }\n };\n\n this.websocket.onmessage = (event) => {\n let message: any;\n if (event.data instanceof ArrayBuffer) {\n message = deserialize(new Uint8Array(event.data));\n } else {\n try {\n message = JSON.parse(event.data);\n } catch (e) {\n logger.error({ err: e }, 'Failed to parse message');\n return;\n }\n }\n this.handleServerMessage(message);\n };\n\n this.websocket.onclose = () => {\n logger.info('WebSocket disconnected.');\n this.stopHeartbeat();\n this.stateMachine.transition(SyncState.DISCONNECTED);\n this.scheduleReconnect();\n };\n\n this.websocket.onerror = (error) => {\n logger.error({ err: error }, 'WebSocket error');\n // Error will typically be followed by close, so we don't transition here\n };\n }\n\n private scheduleReconnect(): void {\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n\n // Check if we've exceeded max retries\n if (this.backoffAttempt >= this.backoffConfig.maxRetries) {\n logger.error(\n { attempts: this.backoffAttempt },\n 'Max reconnection attempts reached. Entering ERROR state.'\n );\n this.stateMachine.transition(SyncState.ERROR);\n return;\n }\n\n // Transition to BACKOFF state\n this.stateMachine.transition(SyncState.BACKOFF);\n\n const delay = this.calculateBackoffDelay();\n logger.info({ delay, attempt: this.backoffAttempt }, `Backing off for ${delay}ms`);\n\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null;\n this.backoffAttempt++;\n this.initConnection();\n }, delay);\n }\n\n private calculateBackoffDelay(): number {\n const { initialDelayMs, maxDelayMs, multiplier, jitter } = this.backoffConfig;\n let delay = initialDelayMs * Math.pow(multiplier, this.backoffAttempt);\n delay = Math.min(delay, maxDelayMs);\n\n if (jitter) {\n // Add jitter: 0.5x to 1.5x of calculated delay\n delay = delay * (0.5 + Math.random());\n }\n\n return Math.floor(delay);\n }\n\n /**\n * Reset backoff counter (called on successful connection)\n */\n private resetBackoff(): void {\n this.backoffAttempt = 0;\n }\n\n private async loadOpLog(): Promise<void> {\n const storedTimestamp = await this.storageAdapter.getMeta('lastSyncTimestamp');\n if (storedTimestamp) {\n this.lastSyncTimestamp = storedTimestamp;\n }\n\n const pendingOps = await this.storageAdapter.getPendingOps();\n this.opLog = pendingOps.map(op => ({\n ...op,\n id: String(op.id),\n synced: false\n })) as unknown as OpLogEntry[];\n\n if (this.opLog.length > 0) {\n logger.info({ count: this.opLog.length }, 'Loaded pending operations from local storage');\n }\n }\n\n private async saveOpLog(): Promise<void> {\n await this.storageAdapter.setMeta('lastSyncTimestamp', this.lastSyncTimestamp);\n }\n\n public registerMap(mapName: string, map: LWWMap<any, any> | ORMap<any, any>): void {\n this.maps.set(mapName, map);\n }\n\n public async recordOperation(\n mapName: string,\n opType: 'PUT' | 'REMOVE' | 'OR_ADD' | 'OR_REMOVE',\n key: string,\n data: { record?: LWWRecord<any>; orRecord?: ORMapRecord<any>; orTag?: string; timestamp: Timestamp }\n ): Promise<string> {\n // Check backpressure before adding new operation\n await this.checkBackpressure();\n\n const opLogEntry: Omit<OpLogEntry, 'id'> & { id?: string } = {\n mapName,\n opType,\n key,\n record: data.record,\n orRecord: data.orRecord,\n orTag: data.orTag,\n timestamp: data.timestamp,\n synced: false,\n };\n\n const id = await this.storageAdapter.appendOpLog(opLogEntry as any);\n opLogEntry.id = String(id);\n\n this.opLog.push(opLogEntry as OpLogEntry);\n\n // Check high water mark after adding operation\n this.checkHighWaterMark();\n\n if (this.isAuthenticated()) {\n this.syncPendingOperations();\n }\n\n return opLogEntry.id;\n }\n\n private syncPendingOperations(): void {\n const pending = this.opLog.filter(op => !op.synced);\n if (pending.length === 0) return;\n\n logger.info({ count: pending.length }, 'Syncing pending operations');\n\n if (this.websocket?.readyState === WebSocket.OPEN) {\n this.websocket.send(serialize({\n type: 'OP_BATCH',\n payload: {\n ops: pending\n }\n }));\n }\n }\n\n private startMerkleSync(): void {\n for (const [mapName, map] of this.maps) {\n if (map instanceof LWWMap) {\n logger.info({ mapName }, 'Starting Merkle sync for LWWMap');\n this.websocket?.send(serialize({\n type: 'SYNC_INIT',\n mapName,\n lastSyncTimestamp: this.lastSyncTimestamp\n }));\n } else if (map instanceof ORMap) {\n logger.info({ mapName }, 'Starting Merkle sync for ORMap');\n const tree = map.getMerkleTree();\n const rootHash = tree.getRootHash();\n\n // Build bucket hashes for all non-empty buckets at depth 0\n const bucketHashes: Record<string, number> = tree.getBuckets('');\n\n this.websocket?.send(serialize({\n type: 'ORMAP_SYNC_INIT',\n mapName,\n rootHash,\n bucketHashes,\n lastSyncTimestamp: this.lastSyncTimestamp\n }));\n }\n }\n }\n\n public setAuthToken(token: string): void {\n this.authToken = token;\n this.tokenProvider = null;\n\n const state = this.stateMachine.getState();\n if (state === SyncState.AUTHENTICATING || state === SyncState.CONNECTING) {\n // If we are already connected (e.g. waiting for token), send it now\n this.sendAuth();\n } else if (state === SyncState.BACKOFF || state === SyncState.DISCONNECTED) {\n // [CHANGE] Force immediate reconnect if we were waiting for retry timer\n logger.info('Auth token set during backoff/disconnect. Reconnecting immediately.');\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n // Reset backoff since user provided new credentials\n this.resetBackoff();\n this.initConnection();\n }\n }\n\n public setTokenProvider(provider: () => Promise<string | null>): void {\n this.tokenProvider = provider;\n const state = this.stateMachine.getState();\n if (state === SyncState.AUTHENTICATING) {\n this.sendAuth();\n }\n }\n\n private async sendAuth(): Promise<void> {\n if (this.tokenProvider) {\n try {\n const token = await this.tokenProvider();\n if (token) {\n this.authToken = token;\n }\n } catch (err) {\n logger.error({ err }, 'Failed to get token from provider');\n return;\n }\n }\n\n const token = this.authToken;\n if (!token) return; // Don't send anonymous auth anymore\n\n this.websocket?.send(serialize({\n type: 'AUTH',\n token\n }));\n }\n\n public subscribeToQuery(query: QueryHandle<any>) {\n this.queries.set(query.id, query);\n if (this.isAuthenticated()) {\n this.sendQuerySubscription(query);\n }\n }\n\n public subscribeToTopic(topic: string, handle: TopicHandle) {\n this.topics.set(topic, handle);\n if (this.isAuthenticated()) {\n this.sendTopicSubscription(topic);\n }\n }\n\n public unsubscribeFromTopic(topic: string) {\n this.topics.delete(topic);\n if (this.isAuthenticated()) {\n this.websocket?.send(serialize({\n type: 'TOPIC_UNSUB',\n payload: { topic }\n }));\n }\n }\n\n public publishTopic(topic: string, data: any) {\n if (this.isAuthenticated()) {\n this.websocket?.send(serialize({\n type: 'TOPIC_PUB',\n payload: { topic, data }\n }));\n } else {\n // TODO: Queue topic messages or drop?\n // Spec says Fire-and-Forget, so dropping is acceptable if offline,\n // but queueing is better UX.\n // For now, log warning.\n logger.warn({ topic }, 'Dropped topic publish (offline)');\n }\n }\n\n private sendTopicSubscription(topic: string) {\n this.websocket?.send(serialize({\n type: 'TOPIC_SUB',\n payload: { topic }\n }));\n }\n\n /**\n * Executes a query against local storage immediately\n */\n public async runLocalQuery(mapName: string, filter: QueryFilter): Promise<{ key: string, value: any }[]> {\n // Retrieve all keys for the map\n const keys = await this.storageAdapter.getAllKeys();\n const mapKeys = keys.filter(k => k.startsWith(mapName + ':'));\n\n const results = [];\n for (const fullKey of mapKeys) {\n const record = await this.storageAdapter.get(fullKey);\n if (record && record.value) {\n // Extract actual key from \"mapName:key\"\n const actualKey = fullKey.slice(mapName.length + 1);\n\n let matches = true;\n\n // Apply 'where' (equality)\n if (filter.where) {\n for (const [k, v] of Object.entries(filter.where)) {\n if (record.value[k] !== v) {\n matches = false;\n break;\n }\n }\n }\n\n // Apply 'predicate'\n if (matches && filter.predicate) {\n if (!evaluatePredicate(filter.predicate, record.value)) {\n matches = false;\n }\n }\n\n if (matches) {\n results.push({ key: actualKey, value: record.value });\n }\n }\n }\n return results;\n }\n\n public unsubscribeFromQuery(queryId: string) {\n this.queries.delete(queryId);\n if (this.isAuthenticated()) {\n this.websocket?.send(serialize({\n type: 'QUERY_UNSUB',\n payload: { queryId }\n }));\n }\n }\n\n private sendQuerySubscription(query: QueryHandle<any>) {\n this.websocket?.send(serialize({\n type: 'QUERY_SUB',\n payload: {\n queryId: query.id,\n mapName: query.getMapName(),\n query: query.getFilter()\n }\n }));\n }\n\n public requestLock(name: string, requestId: string, ttl: number): Promise<{ fencingToken: number }> {\n if (!this.isAuthenticated()) {\n return Promise.reject(new Error('Not connected or authenticated'));\n }\n\n return new Promise((resolve, reject) => {\n // Timeout if no response (server might be down or message lost)\n // We set a client-side timeout slightly larger than TTL if TTL is short,\n // but usually we want a separate \"Wait Timeout\".\n // For now, use a fixed 30s timeout for the *response*.\n const timer = setTimeout(() => {\n if (this.pendingLockRequests.has(requestId)) {\n this.pendingLockRequests.delete(requestId);\n reject(new Error('Lock request timed out waiting for server response'));\n }\n }, 30000);\n\n this.pendingLockRequests.set(requestId, { resolve, reject, timer });\n\n try {\n this.websocket?.send(serialize({\n type: 'LOCK_REQUEST',\n payload: { requestId, name, ttl }\n }));\n } catch (e) {\n clearTimeout(timer);\n this.pendingLockRequests.delete(requestId);\n reject(e);\n }\n });\n }\n\n public releaseLock(name: string, requestId: string, fencingToken: number): Promise<boolean> {\n if (!this.isOnline()) return Promise.resolve(false);\n\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n if (this.pendingLockRequests.has(requestId)) {\n this.pendingLockRequests.delete(requestId);\n // Resolve false on timeout? Or reject?\n // Release is usually fire-and-forget but we wanted ACK.\n resolve(false);\n }\n }, 5000);\n\n this.pendingLockRequests.set(requestId, { resolve, reject, timer });\n\n try {\n this.websocket?.send(serialize({\n type: 'LOCK_RELEASE',\n payload: { requestId, name, fencingToken }\n }));\n } catch (e) {\n clearTimeout(timer);\n this.pendingLockRequests.delete(requestId);\n resolve(false);\n }\n });\n }\n\n private async handleServerMessage(message: any): Promise<void> {\n switch (message.type) {\n case 'AUTH_REQUIRED':\n this.sendAuth();\n break;\n\n case 'AUTH_ACK': {\n logger.info('Authenticated successfully');\n const wasAuthenticated = this.isAuthenticated();\n\n // Transition to SYNCING state\n this.stateMachine.transition(SyncState.SYNCING);\n\n // Reset backoff on successful auth\n this.resetBackoff();\n\n this.syncPendingOperations();\n\n // Only re-subscribe on first authentication to prevent UI flickering\n if (!wasAuthenticated) {\n this.startHeartbeat();\n this.startMerkleSync();\n for (const query of this.queries.values()) {\n this.sendQuerySubscription(query);\n }\n for (const topic of this.topics.keys()) {\n this.sendTopicSubscription(topic);\n }\n }\n\n // After initial sync setup, transition to CONNECTED\n // In a real implementation, you might wait for SYNC_COMPLETE message\n this.stateMachine.transition(SyncState.CONNECTED);\n break;\n }\n\n case 'PONG': {\n this.handlePong(message);\n break;\n }\n\n case 'AUTH_FAIL':\n logger.error({ error: message.error }, 'Authentication failed');\n this.authToken = null; // Clear invalid token\n // Stay in AUTHENTICATING or go to ERROR depending on severity\n // For now, let the connection close naturally or retry with new token\n break;\n\n case 'OP_ACK': {\n const { lastId } = message.payload;\n logger.info({ lastId }, 'Received ACK for ops');\n let maxSyncedId = -1;\n let ackedCount = 0;\n this.opLog.forEach(op => {\n if (op.id && op.id <= lastId) {\n if (!op.synced) {\n ackedCount++;\n }\n op.synced = true;\n const idNum = parseInt(op.id, 10);\n if (!isNaN(idNum) && idNum > maxSyncedId) {\n maxSyncedId = idNum;\n }\n }\n });\n if (maxSyncedId !== -1) {\n this.storageAdapter.markOpsSynced(maxSyncedId).catch(err => logger.error({ err }, 'Failed to mark ops synced'));\n }\n // Check low water mark after ACKs reduce pending count\n if (ackedCount > 0) {\n this.checkLowWaterMark();\n }\n break;\n }\n\n case 'LOCK_GRANTED': {\n const { requestId, fencingToken } = message.payload;\n const req = this.pendingLockRequests.get(requestId);\n if (req) {\n clearTimeout(req.timer);\n this.pendingLockRequests.delete(requestId);\n req.resolve({ fencingToken });\n }\n break;\n }\n\n case 'LOCK_RELEASED': {\n const { requestId, success } = message.payload;\n const req = this.pendingLockRequests.get(requestId);\n if (req) {\n clearTimeout(req.timer);\n this.pendingLockRequests.delete(requestId);\n req.resolve(success);\n }\n break;\n }\n\n case 'QUERY_RESP': {\n const { queryId, results } = message.payload;\n const query = this.queries.get(queryId);\n if (query) {\n query.onResult(results, 'server');\n }\n break;\n }\n\n case 'QUERY_UPDATE': {\n const { queryId, key, value, type } = message.payload;\n const query = this.queries.get(queryId);\n if (query) {\n query.onUpdate(key, type === 'REMOVE' ? null : value);\n }\n break;\n }\n\n case 'SERVER_EVENT': {\n // Modified to support ORMap\n const { mapName, eventType, key, record, orRecord, orTag } = message.payload;\n const localMap = this.maps.get(mapName);\n if (localMap) {\n if (localMap instanceof LWWMap && record) {\n localMap.merge(key, record);\n await this.storageAdapter.put(`${mapName}:${key}`, record);\n } else if (localMap instanceof ORMap) {\n if (eventType === 'OR_ADD' && orRecord) {\n localMap.apply(key, orRecord);\n // We need to store ORMap records differently in storageAdapter or use a convention\n // For now, skipping persistent storage update for ORMap in this example\n } else if (eventType === 'OR_REMOVE' && orTag) {\n localMap.applyTombstone(orTag);\n }\n }\n }\n break;\n }\n\n case 'TOPIC_MESSAGE': {\n const { topic, data, publisherId, timestamp } = message.payload;\n const handle = this.topics.get(topic);\n if (handle) {\n handle.onMessage(data, { publisherId, timestamp });\n }\n break;\n }\n\n case 'GC_PRUNE': {\n const { olderThan } = message.payload;\n logger.info({ olderThan: olderThan.millis }, 'Received GC_PRUNE request');\n\n for (const [name, map] of this.maps) {\n if (map instanceof LWWMap) {\n const removedKeys = map.prune(olderThan);\n for (const key of removedKeys) {\n await this.storageAdapter.remove(`${name}:${key}`);\n }\n if (removedKeys.length > 0) {\n logger.info({ mapName: name, count: removedKeys.length }, 'Pruned tombstones from LWWMap');\n }\n } else if (map instanceof ORMap) {\n const removedTags = map.prune(olderThan);\n if (removedTags.length > 0) {\n logger.info({ mapName: name, count: removedTags.length }, 'Pruned tombstones from ORMap');\n }\n }\n }\n break;\n }\n\n case 'SYNC_RESET_REQUIRED': {\n const { mapName } = message.payload;\n logger.warn({ mapName }, 'Sync Reset Required due to GC Age');\n await this.resetMap(mapName);\n // Trigger re-sync as fresh\n this.websocket?.send(serialize({\n type: 'SYNC_INIT',\n mapName,\n lastSyncTimestamp: 0\n }));\n break;\n }\n\n case 'SYNC_RESP_ROOT': {\n const { mapName, rootHash, timestamp } = message.payload;\n const map = this.maps.get(mapName);\n if (map instanceof LWWMap) {\n const localRootHash = map.getMerkleTree().getRootHash();\n if (localRootHash !== rootHash) {\n logger.info({ mapName, localRootHash, remoteRootHash: rootHash }, 'Root hash mismatch, requesting buckets');\n this.websocket?.send(serialize({\n type: 'MERKLE_REQ_BUCKET',\n payload: { mapName, path: '' }\n }));\n } else {\n logger.info({ mapName }, 'Map is in sync');\n }\n }\n // Update HLC with server timestamp\n if (timestamp) {\n this.hlc.update(timestamp);\n this.lastSyncTimestamp = timestamp.millis;\n await this.saveOpLog();\n }\n break;\n }\n\n case 'SYNC_RESP_BUCKETS': {\n const { mapName, path, buckets } = message.payload;\n const map = this.maps.get(mapName);\n if (map instanceof LWWMap) {\n const tree = map.getMerkleTree();\n const localBuckets = tree.getBuckets(path);\n\n for (const [bucketKey, remoteHash] of Object.entries(buckets)) {\n const localHash = localBuckets[bucketKey] || 0;\n if (localHash !== remoteHash) {\n const newPath = path + bucketKey;\n this.websocket?.send(serialize({\n type: 'MERKLE_REQ_BUCKET',\n payload: { mapName, path: newPath }\n }));\n }\n }\n }\n break;\n }\n\n case 'SYNC_RESP_LEAF': {\n const { mapName, records } = message.payload;\n const map = this.maps.get(mapName);\n if (map instanceof LWWMap) {\n let updateCount = 0;\n for (const { key, record } of records) {\n // Merge into local map\n const updated = map.merge(key, record);\n if (updated) {\n updateCount++;\n // Persist to storage\n await this.storageAdapter.put(`${mapName}:${key}`, record);\n }\n }\n if (updateCount > 0) {\n logger.info({ mapName, count: updateCount }, 'Synced records from server');\n }\n }\n break;\n }\n\n // ============ ORMap Sync Message Handlers ============\n\n case 'ORMAP_SYNC_RESP_ROOT': {\n const { mapName, rootHash, timestamp } = message.payload;\n const map = this.maps.get(mapName);\n if (map instanceof ORMap) {\n const localTree = map.getMerkleTree();\n const localRootHash = localTree.getRootHash();\n\n if (localRootHash !== rootHash) {\n logger.info({ mapName, localRootHash, remoteRootHash: rootHash }, 'ORMap root hash mismatch, requesting buckets');\n this.websocket?.send(serialize({\n type: 'ORMAP_MERKLE_REQ_BUCKET',\n payload: { mapName, path: '' }\n }));\n } else {\n logger.info({ mapName }, 'ORMap is in sync');\n }\n }\n // Update HLC with server timestamp\n if (timestamp) {\n this.hlc.update(timestamp);\n this.lastSyncTimestamp = timestamp.millis;\n await this.saveOpLog();\n }\n break;\n }\n\n case 'ORMAP_SYNC_RESP_BUCKETS': {\n const { mapName, path, buckets } = message.payload;\n const map = this.maps.get(mapName);\n if (map instanceof ORMap) {\n const tree = map.getMerkleTree();\n const localBuckets = tree.getBuckets(path);\n\n for (const [bucketKey, remoteHash] of Object.entries(buckets)) {\n const localHash = localBuckets[bucketKey] || 0;\n if (localHash !== remoteHash) {\n const newPath = path + bucketKey;\n this.websocket?.send(serialize({\n type: 'ORMAP_MERKLE_REQ_BUCKET',\n payload: { mapName, path: newPath }\n }));\n }\n }\n\n // Also check for buckets that exist locally but not on remote\n for (const [bucketKey, localHash] of Object.entries(localBuckets)) {\n if (!(bucketKey in buckets) && localHash !== 0) {\n // Local has data that remote doesn't - need to push\n const newPath = path + bucketKey;\n const keys = tree.getKeysInBucket(newPath);\n if (keys.length > 0) {\n this.pushORMapDiff(mapName, keys, map);\n }\n }\n }\n }\n break;\n }\n\n case 'ORMAP_SYNC_RESP_LEAF': {\n const { mapName, entries } = message.payload;\n const map = this.maps.get(mapName);\n if (map instanceof ORMap) {\n let totalAdded = 0;\n let totalUpdated = 0;\n\n for (const entry of entries) {\n const { key, records, tombstones } = entry;\n const result = map.mergeKey(key, records, tombstones);\n totalAdded += result.added;\n totalUpdated += result.updated;\n }\n\n if (totalAdded > 0 || totalUpdated > 0) {\n logger.info({ mapName, added: totalAdded, updated: totalUpdated }, 'Synced ORMap records from server');\n }\n\n // Now push any local records that server might not have\n const keysToCheck = entries.map((e: { key: string }) => e.key);\n await this.pushORMapDiff(mapName, keysToCheck, map);\n }\n break;\n }\n\n case 'ORMAP_DIFF_RESPONSE': {\n const { mapName, entries } = message.payload;\n const map = this.maps.get(mapName);\n if (map instanceof ORMap) {\n let totalAdded = 0;\n let totalUpdated = 0;\n\n for (const entry of entries) {\n const { key, records, tombstones } = entry;\n const result = map.mergeKey(key, records, tombstones);\n totalAdded += result.added;\n totalUpdated += result.updated;\n }\n\n if (totalAdded > 0 || totalUpdated > 0) {\n logger.info({ mapName, added: totalAdded, updated: totalUpdated }, 'Merged ORMap diff from server');\n }\n }\n break;\n }\n }\n\n if (message.timestamp) {\n this.hlc.update(message.timestamp);\n this.lastSyncTimestamp = message.timestamp.millis;\n await this.saveOpLog();\n }\n }\n\n public getHLC(): HLC {\n return this.hlc;\n }\n\n /**\n * Closes the WebSocket connection and cleans up resources.\n */\n public close(): void {\n this.stopHeartbeat();\n\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n\n if (this.websocket) {\n this.websocket.onclose = null; // Prevent reconnect on intentional close\n this.websocket.close();\n this.websocket = null;\n }\n\n this.stateMachine.transition(SyncState.DISCONNECTED);\n logger.info('SyncEngine closed');\n }\n\n /**\n * Reset the state machine and connection.\n * Use after fatal errors to start fresh.\n */\n public resetConnection(): void {\n this.close();\n this.stateMachine.reset();\n this.resetBackoff();\n this.initConnection();\n }\n\n private async resetMap(mapName: string): Promise<void> {\n const map = this.maps.get(mapName);\n if (map) {\n // Clear memory\n if (map instanceof LWWMap) {\n map.clear();\n } else if (map instanceof ORMap) {\n map.clear();\n }\n }\n\n // Clear storage\n const allKeys = await this.storageAdapter.getAllKeys();\n const mapKeys = allKeys.filter(k => k.startsWith(mapName + ':'));\n for (const key of mapKeys) {\n await this.storageAdapter.remove(key);\n }\n logger.info({ mapName, removedStorageCount: mapKeys.length }, 'Reset map: Cleared memory and storage');\n }\n\n // ============ Heartbeat Methods ============\n\n /**\n * Starts the heartbeat mechanism after successful connection.\n */\n private startHeartbeat(): void {\n if (!this.heartbeatConfig.enabled) {\n return;\n }\n\n this.stopHeartbeat(); // Clear any existing interval\n this.lastPongReceived = Date.now();\n\n this.heartbeatInterval = setInterval(() => {\n this.sendPing();\n this.checkHeartbeatTimeout();\n }, this.heartbeatConfig.intervalMs);\n\n logger.info({ intervalMs: this.heartbeatConfig.intervalMs }, 'Heartbeat started');\n }\n\n /**\n * Stops the heartbeat mechanism.\n */\n private stopHeartbeat(): void {\n if (this.heartbeatInterval) {\n clearInterval(this.heartbeatInterval);\n this.heartbeatInterval = null;\n logger.info('Heartbeat stopped');\n }\n }\n\n /**\n * Sends a PING message to the server.\n */\n private sendPing(): void {\n if (this.websocket?.readyState === WebSocket.OPEN) {\n const pingMessage = {\n type: 'PING',\n timestamp: Date.now(),\n };\n this.websocket.send(serialize(pingMessage));\n }\n }\n\n /**\n * Handles incoming PONG message from server.\n */\n private handlePong(msg: { timestamp: number; serverTime: number }): void {\n const now = Date.now();\n this.lastPongReceived = now;\n this.lastRoundTripTime = now - msg.timestamp;\n\n logger.debug({\n rtt: this.lastRoundTripTime,\n serverTime: msg.serverTime,\n clockSkew: msg.serverTime - (msg.timestamp + this.lastRoundTripTime / 2),\n }, 'Received PONG');\n }\n\n /**\n * Checks if heartbeat has timed out and triggers reconnection if needed.\n */\n private checkHeartbeatTimeout(): void {\n const now = Date.now();\n const timeSinceLastPong = now - this.lastPongReceived;\n\n if (timeSinceLastPong > this.heartbeatConfig.timeoutMs) {\n logger.warn({\n timeSinceLastPong,\n timeoutMs: this.heartbeatConfig.timeoutMs,\n }, 'Heartbeat timeout - triggering reconnection');\n\n this.stopHeartbeat();\n\n // Force close and reconnect\n if (this.websocket) {\n this.websocket.close();\n }\n }\n }\n\n /**\n * Returns the last measured round-trip time in milliseconds.\n * Returns null if no PONG has been received yet.\n */\n public getLastRoundTripTime(): number | null {\n return this.lastRoundTripTime;\n }\n\n /**\n * Returns true if the connection is considered healthy based on heartbeat.\n * A connection is healthy if it's online, authenticated, and has received\n * a PONG within the timeout window.\n */\n public isConnectionHealthy(): boolean {\n if (!this.isOnline() || !this.isAuthenticated()) {\n return false;\n }\n\n if (!this.heartbeatConfig.enabled) {\n return true; // If heartbeat disabled, consider healthy if online\n }\n\n const timeSinceLastPong = Date.now() - this.lastPongReceived;\n return timeSinceLastPong < this.heartbeatConfig.timeoutMs;\n }\n\n // ============ ORMap Sync Methods ============\n\n /**\n * Push local ORMap diff to server for the given keys.\n * Sends local records and tombstones that the server might not have.\n */\n private async pushORMapDiff(\n mapName: string,\n keys: string[],\n map: ORMap<any, any>\n ): Promise<void> {\n const entries: Array<{\n key: string;\n records: ORMapRecord<any>[];\n tombstones: string[];\n }> = [];\n\n const snapshot = map.getSnapshot();\n\n for (const key of keys) {\n const recordsMap = map.getRecordsMap(key);\n if (recordsMap && recordsMap.size > 0) {\n // Get records as array\n const records = Array.from(recordsMap.values());\n\n // Get tombstones relevant to this key's records\n // (tombstones that match tags that were in this key)\n const tombstones: string[] = [];\n for (const tag of snapshot.tombstones) {\n // Include all tombstones - server will filter\n tombstones.push(tag);\n }\n\n entries.push({\n key,\n records,\n tombstones\n });\n }\n }\n\n if (entries.length > 0) {\n this.websocket?.send(serialize({\n type: 'ORMAP_PUSH_DIFF',\n payload: {\n mapName,\n entries\n }\n }));\n logger.debug({ mapName, keyCount: entries.length }, 'Pushed ORMap diff to server');\n }\n }\n\n // ============ Backpressure Methods ============\n\n /**\n * Get the current number of pending (unsynced) operations.\n */\n public getPendingOpsCount(): number {\n return this.opLog.filter(op => !op.synced).length;\n }\n\n /**\n * Get the current backpressure status.\n */\n public getBackpressureStatus(): BackpressureStatus {\n const pending = this.getPendingOpsCount();\n const max = this.backpressureConfig.maxPendingOps;\n return {\n pending,\n max,\n percentage: max > 0 ? pending / max : 0,\n isPaused: this.backpressurePaused,\n strategy: this.backpressureConfig.strategy,\n };\n }\n\n /**\n * Returns true if writes are currently paused due to backpressure.\n */\n public isBackpressurePaused(): boolean {\n return this.backpressurePaused;\n }\n\n /**\n * Subscribe to backpressure events.\n * @param event Event name: 'backpressure:high', 'backpressure:low', 'backpressure:paused', 'backpressure:resumed', 'operation:dropped'\n * @param listener Callback function\n * @returns Unsubscribe function\n */\n public onBackpressure(\n event: 'backpressure:high' | 'backpressure:low' | 'backpressure:paused' | 'backpressure:resumed' | 'operation:dropped',\n listener: (data?: BackpressureThresholdEvent | OperationDroppedEvent) => void\n ): () => void {\n if (!this.backpressureListeners.has(event)) {\n this.backpressureListeners.set(event, new Set());\n }\n this.backpressureListeners.get(event)!.add(listener);\n\n return () => {\n this.backpressureListeners.get(event)?.delete(listener);\n };\n }\n\n /**\n * Emit a backpressure event to all listeners.\n */\n private emitBackpressureEvent(\n event: 'backpressure:high' | 'backpressure:low' | 'backpressure:paused' | 'backpressure:resumed' | 'operation:dropped',\n data?: BackpressureThresholdEvent | OperationDroppedEvent\n ): void {\n const listeners = this.backpressureListeners.get(event);\n if (listeners) {\n for (const listener of listeners) {\n try {\n listener(data);\n } catch (err) {\n logger.error({ err, event }, 'Error in backpressure event listener');\n }\n }\n }\n }\n\n /**\n * Check backpressure before adding a new operation.\n * May pause, throw, or drop depending on strategy.\n */\n private async checkBackpressure(): Promise<void> {\n const pendingCount = this.getPendingOpsCount();\n\n if (pendingCount < this.backpressureConfig.maxPendingOps) {\n return; // Capacity available\n }\n\n switch (this.backpressureConfig.strategy) {\n case 'pause':\n await this.waitForCapacity();\n break;\n case 'throw':\n throw new BackpressureError(\n pendingCount,\n this.backpressureConfig.maxPendingOps\n );\n case 'drop-oldest':\n this.dropOldestOp();\n break;\n }\n }\n\n /**\n * Check high water mark and emit event if threshold reached.\n */\n private checkHighWaterMark(): void {\n const pendingCount = this.getPendingOpsCount();\n const threshold = Math.floor(\n this.backpressureConfig.maxPendingOps * this.backpressureConfig.highWaterMark\n );\n\n if (pendingCount >= threshold && !this.highWaterMarkEmitted) {\n this.highWaterMarkEmitted = true;\n logger.warn(\n { pending: pendingCount, max: this.backpressureConfig.maxPendingOps },\n 'Backpressure high water mark reached'\n );\n this.emitBackpressureEvent('backpressure:high', {\n pending: pendingCount,\n max: this.backpressureConfig.maxPendingOps,\n });\n }\n }\n\n /**\n * Check low water mark and resume paused writes if threshold reached.\n */\n private checkLowWaterMark(): void {\n const pendingCount = this.getPendingOpsCount();\n const lowThreshold = Math.floor(\n this.backpressureConfig.maxPendingOps * this.backpressureConfig.lowWaterMark\n );\n const highThreshold = Math.floor(\n this.backpressureConfig.maxPendingOps * this.backpressureConfig.highWaterMark\n );\n\n // Reset high water mark flag when below high threshold\n if (pendingCount < highThreshold && this.highWaterMarkEmitted) {\n this.highWaterMarkEmitted = false;\n }\n\n // Emit low water mark event when crossing below threshold\n if (pendingCount <= lowThreshold) {\n if (this.backpressurePaused) {\n this.backpressurePaused = false;\n logger.info(\n { pending: pendingCount, max: this.backpressureConfig.maxPendingOps },\n 'Backpressure low water mark reached, resuming writes'\n );\n this.emitBackpressureEvent('backpressure:low', {\n pending: pendingCount,\n max: this.backpressureConfig.maxPendingOps,\n });\n this.emitBackpressureEvent('backpressure:resumed');\n\n // Resume all waiting writes\n const waiting = this.waitingForCapacity;\n this.waitingForCapacity = [];\n for (const resolve of waiting) {\n resolve();\n }\n }\n }\n }\n\n /**\n * Wait for capacity to become available (used by 'pause' strategy).\n */\n private async waitForCapacity(): Promise<void> {\n if (!this.backpressurePaused) {\n this.backpressurePaused = true;\n logger.warn('Backpressure paused - waiting for capacity');\n this.emitBackpressureEvent('backpressure:paused');\n }\n\n return new Promise<void>((resolve) => {\n this.waitingForCapacity.push(resolve);\n });\n }\n\n /**\n * Drop the oldest pending operation (used by 'drop-oldest' strategy).\n */\n private dropOldestOp(): void {\n // Find oldest unsynced operation by array order (oldest first)\n const oldestIndex = this.opLog.findIndex(op => !op.synced);\n\n if (oldestIndex !== -1) {\n const dropped = this.opLog[oldestIndex];\n this.opLog.splice(oldestIndex, 1);\n\n logger.warn(\n { opId: dropped.id, mapName: dropped.mapName, key: dropped.key },\n 'Dropped oldest pending operation due to backpressure'\n );\n\n this.emitBackpressureEvent('operation:dropped', {\n opId: dropped.id,\n mapName: dropped.mapName,\n opType: dropped.opType,\n key: dropped.key,\n });\n }\n }\n}\n","import pino from 'pino';\n\n// Simple check for browser environment\nconst isBrowser = typeof window !== 'undefined';\n\n// In browser, we might not have process.env, so we default to 'info'\n// Users can configure this via window.LOG_LEVEL or similar if needed,\n// but for now we stick to a safe default.\nconst logLevel = (typeof process !== 'undefined' && process.env && process.env.LOG_LEVEL) || 'info';\n\nexport const logger = pino({\n level: logLevel,\n transport: !isBrowser && (typeof process !== 'undefined' && process.env.NODE_ENV !== 'production') ? {\n target: 'pino-pretty',\n options: {\n colorize: true,\n translateTime: 'SYS:standard',\n ignore: 'pid,hostname'\n }\n } : undefined,\n browser: {\n asObject: true\n }\n});\n\nexport type Logger = typeof logger;\n\n","/**\n * Defines the possible states for the SyncEngine connection state machine.\n */\nexport enum SyncState {\n /** Initial state before any connection attempt */\n INITIAL = 'INITIAL',\n /** WebSocket connection is being established */\n CONNECTING = 'CONNECTING',\n /** Connected, waiting for authentication response */\n AUTHENTICATING = 'AUTHENTICATING',\n /** Authenticated, performing initial data sync */\n SYNCING = 'SYNCING',\n /** Fully connected and synchronized */\n CONNECTED = 'CONNECTED',\n /** Intentionally or unexpectedly disconnected */\n DISCONNECTED = 'DISCONNECTED',\n /** Waiting before retry (exponential backoff) */\n BACKOFF = 'BACKOFF',\n /** Fatal error requiring manual intervention or reset */\n ERROR = 'ERROR',\n}\n\n/**\n * Defines valid state transitions for the SyncEngine FSM.\n * Each key is a current state, and the value is an array of valid target states.\n */\nexport const VALID_TRANSITIONS: Record<SyncState, SyncState[]> = {\n [SyncState.INITIAL]: [SyncState.CONNECTING],\n [SyncState.CONNECTING]: [SyncState.AUTHENTICATING, SyncState.BACKOFF, SyncState.ERROR, SyncState.DISCONNECTED],\n [SyncState.AUTHENTICATING]: [SyncState.SYNCING, SyncState.BACKOFF, SyncState.ERROR, SyncState.DISCONNECTED],\n [SyncState.SYNCING]: [SyncState.CONNECTED, SyncState.BACKOFF, SyncState.ERROR, SyncState.DISCONNECTED],\n [SyncState.CONNECTED]: [SyncState.SYNCING, SyncState.DISCONNECTED, SyncState.BACKOFF],\n [SyncState.DISCONNECTED]: [SyncState.CONNECTING, SyncState.BACKOFF, SyncState.INITIAL],\n [SyncState.BACKOFF]: [SyncState.CONNECTING, SyncState.DISCONNECTED, SyncState.INITIAL],\n [SyncState.ERROR]: [SyncState.INITIAL],\n};\n\n/**\n * Helper function to check if a transition is valid\n */\nexport function isValidTransition(from: SyncState, to: SyncState): boolean {\n return VALID_TRANSITIONS[from]?.includes(to) ?? false;\n}\n","import { SyncState, isValidTransition } from './SyncState';\nimport { logger } from './utils/logger';\n\n/**\n * Event emitted when the state machine transitions between states.\n */\nexport interface StateChangeEvent {\n /** The state before the transition */\n from: SyncState;\n /** The state after the transition */\n to: SyncState;\n /** Unix timestamp (ms) when the transition occurred */\n timestamp: number;\n}\n\n/**\n * Listener callback for state change events.\n */\nexport type StateChangeListener = (event: StateChangeEvent) => void;\n\n/**\n * Configuration options for the state machine.\n */\nexport interface SyncStateMachineConfig {\n /** Maximum number of state transitions to keep in history (default: 50) */\n maxHistorySize?: number;\n}\n\nconst DEFAULT_MAX_HISTORY_SIZE = 50;\n\n/**\n * A finite state machine for managing SyncEngine connection states.\n *\n * Features:\n * - Validates all state transitions against allowed paths\n * - Emits events on state changes for observability\n * - Maintains a history of transitions for debugging\n * - Logs invalid transition attempts (graceful degradation)\n */\nexport class SyncStateMachine {\n private state: SyncState = SyncState.INITIAL;\n private readonly listeners: Set<StateChangeListener> = new Set();\n private history: StateChangeEvent[] = [];\n private readonly maxHistorySize: number;\n\n constructor(config: SyncStateMachineConfig = {}) {\n this.maxHistorySize = config.maxHistorySize ?? DEFAULT_MAX_HISTORY_SIZE;\n }\n\n /**\n * Attempt to transition to a new state.\n * @param to The target state\n * @returns true if the transition was valid and executed, false otherwise\n */\n transition(to: SyncState): boolean {\n const from = this.state;\n\n if (from === to) {\n // No-op: already in target state\n return true;\n }\n\n if (!isValidTransition(from, to)) {\n logger.warn(\n { from, to, currentHistory: this.getHistory(5) },\n `Invalid state transition attempted: ${from} → ${to}`\n );\n return false;\n }\n\n // Execute the transition\n this.state = to;\n\n const event: StateChangeEvent = {\n from,\n to,\n timestamp: Date.now(),\n };\n\n // Add to history\n this.history.push(event);\n if (this.history.length > this.maxHistorySize) {\n this.history.shift();\n }\n\n // Notify listeners\n for (const listener of this.listeners) {\n try {\n listener(event);\n } catch (err) {\n logger.error({ err, event }, 'State change listener threw an error');\n }\n }\n\n logger.debug({ from, to }, `State transition: ${from} → ${to}`);\n\n return true;\n }\n\n /**\n * Get the current state.\n */\n getState(): SyncState {\n return this.state;\n }\n\n /**\n * Check if a transition from the current state to the target state is valid.\n * @param to The target state to check\n */\n canTransition(to: SyncState): boolean {\n return this.state === to || isValidTransition(this.state, to);\n }\n\n /**\n * Subscribe to state change events.\n * @param listener Callback function to be called on each state change\n * @returns An unsubscribe function\n */\n onStateChange(listener: StateChangeListener): () => void {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n /**\n * Get the state transition history.\n * @param limit Maximum number of entries to return (default: all)\n * @returns Array of state change events, oldest first\n */\n getHistory(limit?: number): StateChangeEvent[] {\n if (limit === undefined || limit >= this.history.length) {\n return [...this.history];\n }\n return this.history.slice(-limit);\n }\n\n /**\n * Reset the state machine to INITIAL state.\n * This is a forced reset that bypasses normal transition validation.\n * Use for testing or hard resets after fatal errors.\n * @param clearHistory If true, also clears the transition history (default: true)\n */\n reset(clearHistory = true): void {\n const from = this.state;\n this.state = SyncState.INITIAL;\n\n if (clearHistory) {\n this.history = [];\n } else {\n // Record the reset as a transition\n const event: StateChangeEvent = {\n from,\n to: SyncState.INITIAL,\n timestamp: Date.now(),\n };\n this.history.push(event);\n if (this.history.length > this.maxHistorySize) {\n this.history.shift();\n }\n\n // Notify listeners\n for (const listener of this.listeners) {\n try {\n listener(event);\n } catch (err) {\n logger.error({ err, event }, 'State change listener threw an error during reset');\n }\n }\n }\n\n logger.info({ from }, 'State machine reset to INITIAL');\n }\n\n /**\n * Check if the state machine is in a \"connected\" state\n * (either SYNCING or CONNECTED)\n */\n isConnected(): boolean {\n return this.state === SyncState.CONNECTED || this.state === SyncState.SYNCING;\n }\n\n /**\n * Check if the state machine is in a state where operations can be sent\n * (authenticated and connected)\n */\n isReady(): boolean {\n return this.state === SyncState.CONNECTED;\n }\n\n /**\n * Check if the state machine is currently attempting to connect\n */\n isConnecting(): boolean {\n return (\n this.state === SyncState.CONNECTING ||\n this.state === SyncState.AUTHENTICATING ||\n this.state === SyncState.SYNCING\n );\n }\n}\n","/**\n * Error thrown when backpressure limit is reached and strategy is 'throw'.\n */\nexport class BackpressureError extends Error {\n public readonly name = 'BackpressureError';\n\n constructor(\n public readonly pendingCount: number,\n public readonly maxPending: number\n ) {\n super(\n `Backpressure limit reached: ${pendingCount}/${maxPending} pending operations. ` +\n `Wait for acknowledgments or increase maxPendingOps.`\n );\n\n // Maintains proper stack trace for where error was thrown (only available on V8)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, BackpressureError);\n }\n }\n}\n","/**\n * Backpressure strategy when maxPendingOps is reached.\n */\nexport type BackpressureStrategy = 'pause' | 'throw' | 'drop-oldest';\n\n/**\n * Configuration for backpressure control on SyncEngine.\n */\nexport interface BackpressureConfig {\n /**\n * Maximum number of operations waiting for server acknowledgment.\n * When this limit is reached, the configured strategy will be applied.\n * @default 1000\n */\n maxPendingOps: number;\n\n /**\n * Strategy when maxPendingOps is reached:\n * - 'pause': Wait for capacity (returns Promise that resolves when space available)\n * - 'throw': Throw BackpressureError immediately\n * - 'drop-oldest': Remove oldest pending op to make room (data loss!)\n * @default 'pause'\n */\n strategy: BackpressureStrategy;\n\n /**\n * High water mark (percentage of maxPendingOps).\n * Emit 'backpressure:high' event when reached.\n * Value should be between 0 and 1.\n * @default 0.8 (80%)\n */\n highWaterMark: number;\n\n /**\n * Low water mark (percentage of maxPendingOps).\n * Resume paused writes and emit 'backpressure:low' when pending ops drop below this.\n * Value should be between 0 and 1.\n * @default 0.5 (50%)\n */\n lowWaterMark: number;\n}\n\n/**\n * Default backpressure configuration.\n */\nexport const DEFAULT_BACKPRESSURE_CONFIG: BackpressureConfig = {\n maxPendingOps: 1000,\n strategy: 'pause',\n highWaterMark: 0.8,\n lowWaterMark: 0.5,\n};\n\n/**\n * Status of backpressure mechanism.\n */\nexport interface BackpressureStatus {\n /** Current number of pending (unacknowledged) operations */\n pending: number;\n /** Maximum allowed pending operations */\n max: number;\n /** Percentage of capacity used (0-1) */\n percentage: number;\n /** Whether writes are currently paused due to backpressure */\n isPaused: boolean;\n /** Current backpressure strategy */\n strategy: BackpressureStrategy;\n}\n\n/**\n * Event data for backpressure:high and backpressure:low events.\n */\nexport interface BackpressureThresholdEvent {\n pending: number;\n max: number;\n}\n\n/**\n * Event data for operation:dropped event.\n */\nexport interface OperationDroppedEvent {\n opId: string;\n mapName: string;\n opType: string;\n key: string;\n}\n","import { LWWMap, ORMap } from '@topgunbuild/core';\nimport type { ORMapRecord, LWWRecord } from '@topgunbuild/core';\nimport type { IStorageAdapter } from './IStorageAdapter';\nimport { SyncEngine } from './SyncEngine';\nimport type { BackoffConfig } from './SyncEngine';\nimport { QueryHandle } from './QueryHandle';\nimport type { QueryFilter } from './QueryHandle';\nimport { DistributedLock } from './DistributedLock';\nimport { TopicHandle } from './TopicHandle';\nimport { logger } from './utils/logger';\nimport { SyncState } from './SyncState';\nimport type { StateChangeEvent } from './SyncStateMachine';\nimport type {\n BackpressureConfig,\n BackpressureStatus,\n BackpressureThresholdEvent,\n OperationDroppedEvent,\n} from './BackpressureConfig';\n\nexport class TopGunClient {\n private readonly nodeId: string;\n private readonly syncEngine: SyncEngine;\n private readonly maps: Map<string, LWWMap<any, any> | ORMap<any, any>> = new Map();\n private readonly storageAdapter: IStorageAdapter;\n private readonly topicHandles: Map<string, TopicHandle> = new Map();\n\n constructor(config: {\n nodeId?: string;\n serverUrl: string;\n storage: IStorageAdapter;\n backoff?: Partial<BackoffConfig>;\n backpressure?: Partial<BackpressureConfig>;\n }) {\n this.nodeId = config.nodeId || crypto.randomUUID();\n this.storageAdapter = config.storage;\n\n const syncEngineConfig = {\n nodeId: this.nodeId,\n serverUrl: config.serverUrl,\n storageAdapter: this.storageAdapter,\n backoff: config.backoff,\n backpressure: config.backpressure,\n };\n this.syncEngine = new SyncEngine(syncEngineConfig);\n }\n\n public async start(): Promise<void> {\n await this.storageAdapter.initialize('topgun_offline_db');\n // this.syncEngine.start();\n }\n\n public setAuthToken(token: string): void {\n this.syncEngine.setAuthToken(token);\n }\n\n public setAuthTokenProvider(provider: () => Promise<string | null>): void {\n this.syncEngine.setTokenProvider(provider);\n }\n\n /**\n * Creates a live query subscription for a map.\n */\n public query<T>(mapName: string, filter: QueryFilter): QueryHandle<T> {\n return new QueryHandle<T>(this.syncEngine, mapName, filter);\n }\n\n /**\n * Retrieves a distributed lock instance.\n * @param name The name of the lock.\n */\n public getLock(name: string): DistributedLock {\n return new DistributedLock(this.syncEngine, name);\n }\n\n /**\n * Retrieves a topic handle for Pub/Sub messaging.\n * @param name The name of the topic.\n */\n public topic(name: string): TopicHandle {\n if (!this.topicHandles.has(name)) {\n this.topicHandles.set(name, new TopicHandle(this.syncEngine, name));\n }\n return this.topicHandles.get(name)!;\n }\n\n /**\n * Retrieves an LWWMap instance. If the map doesn't exist locally, it's created.\n * @param name The name of the map.\n * @returns An LWWMap instance.\n */\n public getMap<K, V>(name: string): LWWMap<K, V> {\n if (this.maps.has(name)) {\n const map = this.maps.get(name);\n if (map instanceof LWWMap) {\n return map as LWWMap<K, V>;\n }\n throw new Error(`Map ${name} exists but is not an LWWMap`);\n }\n\n const lwwMap = new LWWMap<K, V>(this.syncEngine.getHLC());\n this.maps.set(name, lwwMap);\n this.syncEngine.registerMap(name, lwwMap);\n\n // Restore state from storage asynchronously\n this.storageAdapter.getAllKeys().then(async (keys) => {\n const mapPrefix = `${name}:`;\n for (const fullKey of keys) {\n if (fullKey.startsWith(mapPrefix)) {\n const record = await this.storageAdapter.get(fullKey);\n if (record && (record as LWWRecord<V>).timestamp && !(record as any).tag) {\n // Strip prefix to get actual key\n const key = fullKey.substring(mapPrefix.length) as unknown as K;\n // Merge into in-memory map without triggering new ops\n lwwMap.merge(key, record as LWWRecord<V>);\n }\n }\n }\n }).catch(err => logger.error({ err }, 'Failed to restore keys from storage'));\n\n // Wrap LWWMap with IMap interface logic\n const originalSet = lwwMap.set.bind(lwwMap);\n lwwMap.set = (key: K, value: V, ttlMs?: number) => {\n const record = originalSet(key, value, ttlMs);\n this.storageAdapter.put(`${name}:${key}`, record).catch(err => logger.error({ err }, 'Failed to put record to storage'));\n this.syncEngine.recordOperation(name, 'PUT', String(key), { record, timestamp: record.timestamp }).catch(err => logger.error({ err }, 'Failed to record PUT op'));\n return record;\n };\n\n const originalRemove = lwwMap.remove.bind(lwwMap);\n lwwMap.remove = (key: K) => {\n const tombstone = originalRemove(key);\n this.storageAdapter.put(`${name}:${key}`, tombstone).catch(err => logger.error({ err }, 'Failed to put tombstone to storage'));\n this.syncEngine.recordOperation(name, 'REMOVE', String(key), { record: tombstone, timestamp: tombstone.timestamp }).catch(err => logger.error({ err }, 'Failed to record REMOVE op'));\n return tombstone;\n };\n\n return lwwMap;\n }\n\n /**\n * Retrieves an ORMap instance. If the map doesn't exist locally, it's created.\n * @param name The name of the map.\n * @returns An ORMap instance.\n */\n public getORMap<K, V>(name: string): ORMap<K, V> {\n if (this.maps.has(name)) {\n const map = this.maps.get(name);\n if (map instanceof ORMap) {\n return map as ORMap<K, V>;\n }\n throw new Error(`Map ${name} exists but is not an ORMap`);\n }\n\n const orMap = new ORMap<K, V>(this.syncEngine.getHLC());\n this.maps.set(name, orMap);\n this.syncEngine.registerMap(name, orMap);\n\n // Restore state from storage\n this.restoreORMap(name, orMap);\n\n // Wrap ORMap methods to record operations\n const originalAdd = orMap.add.bind(orMap);\n orMap.add = (key: K, value: V, ttlMs?: number) => {\n const record = originalAdd(key, value, ttlMs);\n \n // Persist records\n this.persistORMapKey(name, orMap, key);\n\n this.syncEngine.recordOperation(name, 'OR_ADD', String(key), { orRecord: record, timestamp: record.timestamp }).catch(err => logger.error({ err }, 'Failed to record OR_ADD op'));\n return record;\n };\n\n const originalRemove = orMap.remove.bind(orMap);\n orMap.remove = (key: K, value: V) => {\n const tombstones = originalRemove(key, value);\n const timestamp = this.syncEngine.getHLC().now(); \n \n // Update storage for the key (items removed)\n this.persistORMapKey(name, orMap, key);\n // Update storage for tombstones\n this.persistORMapTombstones(name, orMap);\n\n for (const tag of tombstones) {\n this.syncEngine.recordOperation(name, 'OR_REMOVE', String(key), { orTag: tag, timestamp }).catch(err => logger.error({ err }, 'Failed to record OR_REMOVE op'));\n }\n return tombstones;\n };\n\n return orMap;\n }\n\n private async restoreORMap<K, V>(name: string, orMap: ORMap<K, V>) {\n try {\n // 1. Restore Tombstones\n const tombstoneKey = `__sys__:${name}:tombstones`;\n const tombstones = await this.storageAdapter.getMeta(tombstoneKey);\n if (Array.isArray(tombstones)) {\n for (const tag of tombstones) {\n orMap.applyTombstone(tag);\n }\n }\n\n // 2. Restore Items\n const keys = await this.storageAdapter.getAllKeys();\n const mapPrefix = `${name}:`;\n for (const fullKey of keys) {\n if (fullKey.startsWith(mapPrefix)) {\n const keyPart = fullKey.substring(mapPrefix.length);\n \n const data = await this.storageAdapter.get(fullKey);\n if (Array.isArray(data)) {\n // It's likely an ORMap value list (Array of ORMapRecord)\n const records = data as ORMapRecord<V>[];\n const key = keyPart as unknown as K;\n \n for (const record of records) {\n orMap.apply(key, record);\n }\n }\n }\n }\n } catch (e) {\n logger.error({ mapName: name, err: e }, 'Failed to restore ORMap');\n }\n }\n\n private async persistORMapKey<K, V>(mapName: string, orMap: ORMap<K, V>, key: K) {\n const records = orMap.getRecords(key);\n if (records.length > 0) {\n await this.storageAdapter.put(`${mapName}:${key}`, records);\n } else {\n await this.storageAdapter.remove(`${mapName}:${key}`);\n }\n }\n \n private async persistORMapTombstones<K, V>(mapName: string, orMap: ORMap<K, V>) {\n const tombstoneKey = `__sys__:${mapName}:tombstones`;\n const tombstones = orMap.getTombstones();\n await this.storageAdapter.setMeta(tombstoneKey, tombstones);\n }\n\n /**\n * Closes the client, disconnecting from the server and cleaning up resources.\n */\n public close(): void {\n this.syncEngine.close();\n }\n\n // ============================================\n // Connection State API\n // ============================================\n\n /**\n * Get the current connection state\n */\n public getConnectionState(): SyncState {\n return this.syncEngine.getConnectionState();\n }\n\n /**\n * Subscribe to connection state changes\n * @param listener Callback function called on each state change\n * @returns Unsubscribe function\n */\n public onConnectionStateChange(listener: (event: StateChangeEvent) => void): () => void {\n return this.syncEngine.onConnectionStateChange(listener);\n }\n\n /**\n * Get state machine history for debugging\n * @param limit Maximum number of entries to return\n */\n public getStateHistory(limit?: number): StateChangeEvent[] {\n return this.syncEngine.getStateHistory(limit);\n }\n\n /**\n * Reset the connection and state machine.\n * Use after fatal errors to start fresh.\n */\n public resetConnection(): void {\n this.syncEngine.resetConnection();\n }\n\n // ============================================\n // Backpressure API\n // ============================================\n\n /**\n * Get the current number of pending (unacknowledged) operations.\n */\n public getPendingOpsCount(): number {\n return this.syncEngine.getPendingOpsCount();\n }\n\n /**\n * Get the current backpressure status.\n */\n public getBackpressureStatus(): BackpressureStatus {\n return this.syncEngine.getBackpressureStatus();\n }\n\n /**\n * Returns true if writes are currently paused due to backpressure.\n */\n public isBackpressurePaused(): boolean {\n return this.syncEngine.isBackpressurePaused();\n }\n\n /**\n * Subscribe to backpressure events.\n *\n * Available events:\n * - 'backpressure:high': Emitted when pending ops reach high water mark\n * - 'backpressure:low': Emitted when pending ops drop below low water mark\n * - 'backpressure:paused': Emitted when writes are paused (pause strategy)\n * - 'backpressure:resumed': Emitted when writes resume after being paused\n * - 'operation:dropped': Emitted when an operation is dropped (drop-oldest strategy)\n *\n * @param event Event name\n * @param listener Callback function\n * @returns Unsubscribe function\n *\n * @example\n * ```typescript\n * client.onBackpressure('backpressure:high', ({ pending, max }) => {\n * console.warn(`Warning: ${pending}/${max} pending ops`);\n * });\n *\n * client.onBackpressure('backpressure:paused', () => {\n * showLoadingSpinner();\n * });\n *\n * client.onBackpressure('backpressure:resumed', () => {\n * hideLoadingSpinner();\n * });\n * ```\n */\n public onBackpressure(\n event: 'backpressure:high' | 'backpressure:low' | 'backpressure:paused' | 'backpressure:resumed' | 'operation:dropped',\n listener: (data?: BackpressureThresholdEvent | OperationDroppedEvent) => void\n ): () => void {\n return this.syncEngine.onBackpressure(event, listener);\n }\n}\n","import { SyncEngine } from './SyncEngine';\nimport type { PredicateNode } from '@topgunbuild/core';\n\nexport interface QueryFilter {\n where?: Record<string, any>;\n predicate?: PredicateNode;\n sort?: Record<string, 'asc' | 'desc'>;\n limit?: number;\n offset?: number;\n}\n\n/** Source of query results for proper handling of race conditions */\nexport type QueryResultSource = 'local' | 'server';\n\n/** Result item with _key field for client-side lookups */\nexport type QueryResultItem<T> = T & { _key: string };\n\nexport class QueryHandle<T> {\n public readonly id: string;\n private syncEngine: SyncEngine;\n private mapName: string;\n private filter: QueryFilter;\n private listeners: Set<(results: QueryResultItem<T>[]) => void> = new Set();\n private currentResults: Map<string, T> = new Map();\n\n constructor(syncEngine: SyncEngine, mapName: string, filter: QueryFilter = {}) {\n this.id = crypto.randomUUID();\n this.syncEngine = syncEngine;\n this.mapName = mapName;\n this.filter = filter;\n }\n\n public subscribe(callback: (results: QueryResultItem<T>[]) => void): () => void {\n this.listeners.add(callback);\n \n // If this is the first listener, activate subscription\n if (this.listeners.size === 1) {\n this.syncEngine.subscribeToQuery(this);\n } else {\n // Immediately invoke with cached results\n callback(this.getSortedResults());\n }\n \n // [FIX]: Attempt to load local results immediately if available\n // This ensures that if data is already in storage but sync hasn't happened,\n // we still show something.\n this.loadInitialLocalData().then(data => {\n // If we haven't received server results yet (currentResults empty),\n // and we have local data OR it's just the initial load, we should notify.\n // Even if data is empty, we might want to tell the subscriber \"nothing here yet\".\n if (this.currentResults.size === 0) {\n this.onResult(data, 'local');\n }\n });\n\n return () => {\n this.listeners.delete(callback);\n if (this.listeners.size === 0) {\n this.syncEngine.unsubscribeFromQuery(this.id);\n }\n };\n }\n\n private async loadInitialLocalData() {\n // This requires SyncEngine to expose a method to query local storage\n // For now, we can't easily reach storageAdapter directly from here without leaking abstraction.\n // A better approach is for SyncEngine.subscribeToQuery to trigger a local load.\n return this.syncEngine.runLocalQuery(this.mapName, this.filter);\n }\n\n // Track if we've received authoritative server response\n private hasReceivedServerData: boolean = false;\n\n /**\n * Called by SyncEngine when server sends initial results or by local storage load.\n * Uses merge strategy instead of clear to prevent UI flickering.\n *\n * @param items - Array of key-value pairs\n * @param source - 'local' for IndexedDB data, 'server' for QUERY_RESP from server\n *\n * Race condition protection:\n * - Empty server responses are ignored until we receive non-empty server data\n * - This prevents clearing local data when server hasn't loaded from storage yet\n * - Works with any async storage adapter (PostgreSQL, SQLite, Redis, etc.)\n */\n public onResult(items: { key: string, value: T }[], source: QueryResultSource = 'server') {\n console.log(`[QueryHandle:${this.mapName}] onResult called with ${items.length} items`, {\n source,\n currentResultsCount: this.currentResults.size,\n newItemKeys: items.map(i => i.key),\n hasReceivedServerData: this.hasReceivedServerData\n });\n\n // [FIX] Race condition protection for any async storage adapter:\n // If server sends empty QUERY_RESP before loading data from storage,\n // we ignore it to prevent clearing valid local data.\n // This is safe because:\n // 1. If server truly has no data, next non-empty response will clear local-only items\n // 2. If server is still loading, we preserve local data until real data arrives\n if (source === 'server' && items.length === 0 && !this.hasReceivedServerData) {\n console.log(`[QueryHandle:${this.mapName}] Ignoring empty server response - waiting for authoritative data`);\n return;\n }\n\n // Mark that we've received authoritative server data (non-empty from server)\n if (source === 'server' && items.length > 0) {\n this.hasReceivedServerData = true;\n }\n\n const newKeys = new Set(items.map(i => i.key));\n\n // Remove only keys that are not in the new results\n const removedKeys: string[] = [];\n for (const key of this.currentResults.keys()) {\n if (!newKeys.has(key)) {\n removedKeys.push(key);\n this.currentResults.delete(key);\n }\n }\n if (removedKeys.length > 0) {\n console.log(`[QueryHandle:${this.mapName}] Removed ${removedKeys.length} keys:`, removedKeys);\n }\n\n // Add/update new results\n for (const item of items) {\n this.currentResults.set(item.key, item.value);\n }\n console.log(`[QueryHandle:${this.mapName}] After merge: ${this.currentResults.size} results`);\n this.notify();\n }\n\n /**\n * Called by SyncEngine when server sends a live update\n */\n public onUpdate(key: string, value: T | null) {\n if (value === null) {\n this.currentResults.delete(key);\n } else {\n this.currentResults.set(key, value);\n }\n this.notify();\n }\n\n private notify() {\n const results = this.getSortedResults();\n for (const listener of this.listeners) {\n listener(results);\n }\n }\n\n private getSortedResults(): (T & { _key: string })[] {\n // Include _key in each result for client-side matching/lookup\n const results = Array.from(this.currentResults.entries()).map(\n ([key, value]) => ({ ...(value as object), _key: key } as T & { _key: string })\n );\n\n if (this.filter.sort) {\n results.sort((a: any, b: any) => {\n for (const [field, direction] of Object.entries(this.filter.sort!)) {\n const valA = a[field];\n const valB = b[field];\n\n if (valA < valB) return direction === 'asc' ? -1 : 1;\n if (valA > valB) return direction === 'asc' ? 1 : -1;\n }\n return 0;\n });\n }\n\n return results;\n }\n\n public getFilter(): QueryFilter {\n return this.filter;\n }\n\n public getMapName(): string {\n return this.mapName;\n }\n}\n","import { SyncEngine } from './SyncEngine';\n\nexport interface ILock {\n lock(ttl?: number): Promise<boolean>;\n unlock(): Promise<void>;\n isLocked(): boolean;\n}\n\nexport class DistributedLock implements ILock {\n private syncEngine: SyncEngine;\n private name: string;\n private fencingToken: number | null = null;\n private _isLocked: boolean = false;\n\n constructor(syncEngine: SyncEngine, name: string) {\n this.syncEngine = syncEngine;\n this.name = name;\n }\n\n public async lock(ttl: number = 10000): Promise<boolean> {\n const requestId = crypto.randomUUID();\n try {\n const result = await this.syncEngine.requestLock(this.name, requestId, ttl);\n this.fencingToken = result.fencingToken;\n this._isLocked = true;\n return true;\n } catch (e) {\n return false;\n }\n }\n\n public async unlock(): Promise<void> {\n if (!this._isLocked || this.fencingToken === null) return;\n \n const requestId = crypto.randomUUID();\n try {\n await this.syncEngine.releaseLock(this.name, requestId, this.fencingToken);\n } finally {\n this._isLocked = false;\n this.fencingToken = null;\n }\n }\n\n public isLocked(): boolean {\n return this._isLocked;\n }\n}\n\n","import { SyncEngine } from './SyncEngine';\n\nexport type TopicCallback = (data: any, context: { timestamp: number; publisherId?: string }) => void;\n\nexport class TopicHandle {\n private engine: SyncEngine;\n private topic: string;\n private listeners: Set<TopicCallback> = new Set();\n\n constructor(engine: SyncEngine, topic: string) {\n this.engine = engine;\n this.topic = topic;\n }\n\n public get id(): string {\n return this.topic;\n }\n\n /**\n * Publish a message to the topic\n */\n public publish(data: any) {\n this.engine.publishTopic(this.topic, data);\n }\n\n /**\n * Subscribe to the topic\n */\n public subscribe(callback: TopicCallback) {\n if (this.listeners.size === 0) {\n this.engine.subscribeToTopic(this.topic, this);\n }\n this.listeners.add(callback);\n return () => this.unsubscribe(callback);\n }\n\n private unsubscribe(callback: TopicCallback) {\n this.listeners.delete(callback);\n if (this.listeners.size === 0) {\n this.engine.unsubscribeFromTopic(this.topic);\n }\n }\n\n /**\n * Called by SyncEngine when a message is received\n */\n public onMessage(data: any, context: { timestamp: number; publisherId?: string }) {\n this.listeners.forEach(cb => {\n try {\n cb(data, context);\n } catch (e) {\n console.error('Error in topic listener', e);\n }\n });\n }\n}\n\n","import type { LWWRecord, ORMapRecord } from '@topgunbuild/core';\nimport type { IStorageAdapter, OpLogEntry } from '../IStorageAdapter';\nimport { openDB } from 'idb';\nimport type { IDBPDatabase } from 'idb';\n\n/**\n * Represents an operation queued before IndexedDB is ready.\n */\ninterface QueuedOperation {\n type: 'put' | 'remove' | 'setMeta' | 'appendOpLog' | 'markOpsSynced' | 'batchPut';\n args: any[];\n resolve: (value: any) => void;\n reject: (error: any) => void;\n}\n\n/**\n * Non-blocking IndexedDB adapter that allows immediate use before initialization completes.\n *\n * Operations are queued in memory and replayed once IndexedDB is ready.\n * This enables true \"memory-first\" behavior where the UI can render immediately\n * without waiting for IndexedDB to initialize (which can take 50-500ms).\n */\nexport class IDBAdapter implements IStorageAdapter {\n private dbPromise?: Promise<IDBPDatabase>;\n private db?: IDBPDatabase;\n private isReady = false;\n private operationQueue: QueuedOperation[] = [];\n private initPromise?: Promise<void>;\n\n /**\n * Initializes IndexedDB in the background.\n * Returns immediately - does NOT block on IndexedDB being ready.\n * Use waitForReady() if you need to ensure initialization is complete.\n */\n async initialize(dbName: string): Promise<void> {\n // Start initialization but don't await it\n this.initPromise = this.initializeInternal(dbName);\n // Return immediately - non-blocking!\n }\n\n /**\n * Internal initialization that actually opens IndexedDB.\n */\n private async initializeInternal(dbName: string): Promise<void> {\n try {\n this.dbPromise = openDB(dbName, 2, {\n upgrade(db) {\n if (!db.objectStoreNames.contains('kv_store')) {\n db.createObjectStore('kv_store', { keyPath: 'key' });\n }\n if (!db.objectStoreNames.contains('op_log')) {\n db.createObjectStore('op_log', { keyPath: 'id', autoIncrement: true });\n }\n if (!db.objectStoreNames.contains('meta_store')) {\n db.createObjectStore('meta_store', { keyPath: 'key' });\n }\n },\n });\n\n this.db = await this.dbPromise;\n this.isReady = true;\n\n // Replay queued operations\n await this.flushQueue();\n } catch (error) {\n // Re-throw to allow error handling\n throw error;\n }\n }\n\n /**\n * Waits for IndexedDB to be fully initialized.\n * Call this if you need guaranteed persistence before proceeding.\n */\n async waitForReady(): Promise<void> {\n if (this.isReady) return;\n if (this.initPromise) {\n await this.initPromise;\n }\n }\n\n /**\n * Flushes all queued operations once IndexedDB is ready.\n */\n private async flushQueue(): Promise<void> {\n const queue = this.operationQueue;\n this.operationQueue = [];\n\n for (const op of queue) {\n try {\n let result: any;\n switch (op.type) {\n case 'put':\n result = await this.putInternal(op.args[0], op.args[1]);\n break;\n case 'remove':\n result = await this.removeInternal(op.args[0]);\n break;\n case 'setMeta':\n result = await this.setMetaInternal(op.args[0], op.args[1]);\n break;\n case 'appendOpLog':\n result = await this.appendOpLogInternal(op.args[0]);\n break;\n case 'markOpsSynced':\n result = await this.markOpsSyncedInternal(op.args[0]);\n break;\n case 'batchPut':\n result = await this.batchPutInternal(op.args[0]);\n break;\n }\n op.resolve(result);\n } catch (error) {\n op.reject(error);\n }\n }\n }\n\n /**\n * Queues an operation if not ready, or executes immediately if ready.\n */\n private queueOrExecute<T>(\n type: QueuedOperation['type'],\n args: any[],\n executor: () => Promise<T>\n ): Promise<T> {\n if (this.isReady) {\n return executor();\n }\n\n return new Promise<T>((resolve, reject) => {\n this.operationQueue.push({ type, args, resolve, reject });\n });\n }\n\n async close(): Promise<void> {\n if (this.db) {\n this.db.close();\n }\n }\n\n // ============================================\n // Read Operations - Wait for ready\n // ============================================\n\n async get<V>(key: string): Promise<LWWRecord<V> | ORMapRecord<V>[] | any | undefined> {\n // Read operations must wait for DB to be ready\n await this.waitForReady();\n const result = await this.db?.get('kv_store', key);\n return result?.value;\n }\n\n async getMeta(key: string): Promise<any> {\n await this.waitForReady();\n const result = await this.db?.get('meta_store', key);\n return result?.value;\n }\n\n async getPendingOps(): Promise<OpLogEntry[]> {\n await this.waitForReady();\n const all = await this.db?.getAll('op_log');\n return all?.filter((op: any) => op.synced === 0) || [];\n }\n\n async getAllKeys(): Promise<string[]> {\n await this.waitForReady();\n return (await this.db?.getAllKeys('kv_store')) as string[] || [];\n }\n\n // ============================================\n // Write Operations - Queue if not ready\n // ============================================\n\n async put(key: string, value: any): Promise<void> {\n return this.queueOrExecute('put', [key, value], () => this.putInternal(key, value));\n }\n\n private async putInternal(key: string, value: any): Promise<void> {\n await this.db?.put('kv_store', { key, value });\n }\n\n async remove(key: string): Promise<void> {\n return this.queueOrExecute('remove', [key], () => this.removeInternal(key));\n }\n\n private async removeInternal(key: string): Promise<void> {\n await this.db?.delete('kv_store', key);\n }\n\n async setMeta(key: string, value: any): Promise<void> {\n return this.queueOrExecute('setMeta', [key, value], () => this.setMetaInternal(key, value));\n }\n\n private async setMetaInternal(key: string, value: any): Promise<void> {\n await this.db?.put('meta_store', { key, value });\n }\n\n async batchPut(entries: Map<string, any>): Promise<void> {\n return this.queueOrExecute('batchPut', [entries], () => this.batchPutInternal(entries));\n }\n\n private async batchPutInternal(entries: Map<string, any>): Promise<void> {\n const tx = this.db?.transaction('kv_store', 'readwrite');\n if (!tx) return;\n\n await Promise.all(\n Array.from(entries.entries()).map(([key, value]) =>\n tx.store.put({ key, value })\n )\n );\n await tx.done;\n }\n\n async appendOpLog(entry: any): Promise<number> {\n return this.queueOrExecute('appendOpLog', [entry], () => this.appendOpLogInternal(entry));\n }\n\n private async appendOpLogInternal(entry: any): Promise<number> {\n const entryToSave = { ...entry, synced: 0 };\n return await this.db?.add('op_log', entryToSave) as number;\n }\n\n async markOpsSynced(lastId: number): Promise<void> {\n return this.queueOrExecute('markOpsSynced', [lastId], () => this.markOpsSyncedInternal(lastId));\n }\n\n private async markOpsSyncedInternal(lastId: number): Promise<void> {\n const tx = this.db?.transaction('op_log', 'readwrite');\n if (!tx) return;\n\n let cursor = await tx.store.openCursor();\n while (cursor) {\n if (cursor.value.id <= lastId) {\n const update = { ...cursor.value, synced: 1 };\n await cursor.update(update);\n }\n cursor = await cursor.continue();\n }\n await tx.done;\n }\n}\n\n","import { TopGunClient } from './TopGunClient';\nimport { IDBAdapter } from './adapters/IDBAdapter';\nimport type { IStorageAdapter } from './IStorageAdapter';\nimport { LWWMap } from '@topgunbuild/core';\nimport type { LWWRecord } from '@topgunbuild/core';\n\nexport interface TopGunConfig {\n sync: string;\n persist: 'indexeddb' | IStorageAdapter;\n nodeId?: string;\n}\n\n// Generic schema type\nexport type TopGunSchema = Record<string, any>;\n\nconst handler: ProxyHandler<TopGun<any>> = {\n get(target, prop, receiver) {\n if (prop in target || typeof prop === 'symbol') {\n return Reflect.get(target, prop, receiver);\n }\n if (typeof prop === 'string') {\n return target.collection(prop);\n }\n return undefined;\n }\n};\n\nexport class TopGun<T extends TopGunSchema = any> {\n private client: TopGunClient;\n private initPromise: Promise<void>;\n \n // Allow property access for collections based on Schema T\n [key: string]: any;\n\n constructor(config: TopGunConfig) {\n let storage: IStorageAdapter;\n\n if (config.persist === 'indexeddb') {\n storage = new IDBAdapter();\n } else if (typeof config.persist === 'object') {\n storage = config.persist;\n } else {\n throw new Error(`Unsupported persist option: ${config.persist}`);\n }\n\n this.client = new TopGunClient({\n serverUrl: config.sync,\n storage,\n nodeId: config.nodeId\n });\n\n // Start client initialization (non-blocking)\n // The IDBAdapter now initializes in the background and queues operations\n this.initPromise = this.client.start().catch(err => {\n console.error('Failed to start TopGun client:', err);\n throw err;\n });\n\n return new Proxy(this, handler);\n }\n\n /**\n * Waits for the storage adapter to be fully initialized.\n * This is optional - you can start using the database immediately.\n * Operations are queued in memory and persisted once IndexedDB is ready.\n */\n public async waitForReady(): Promise<void> {\n await this.initPromise;\n }\n\n public collection<K extends keyof T & string>(name: K): CollectionWrapper<T[K]> {\n // Explicitly type the map\n const map = this.client.getMap<string, T[K]>(name);\n return new CollectionWrapper<T[K]>(map);\n }\n}\n\nexport class CollectionWrapper<ItemType = any> {\n private map: LWWMap<string, ItemType>;\n\n constructor(map: LWWMap<string, ItemType>) {\n this.map = map;\n }\n\n /**\n * Sets an item in the collection. \n * The item MUST have an 'id' or '_id' field.\n */\n async set(value: ItemType): Promise<ItemType> {\n const v = value as any;\n const key = v.id || v._id;\n if (!key) {\n throw new Error('Object must have an \"id\" or \"_id\" property to be saved in a collection.');\n }\n \n // LWWMap.set is synchronous in updating memory and queueing ops,\n // but we return a Promise to match typical async DB APIs.\n this.map.set(key, value);\n return Promise.resolve(value); \n }\n \n /**\n * Retrieves an item by ID.\n * Returns the value directly (unwrapped from CRDT record).\n */\n get(key: string): ItemType | undefined {\n return this.map.get(key);\n }\n\n /**\n * Get the raw LWWRecord (including metadata like timestamp).\n */\n getRecord(key: string): LWWRecord<ItemType> | undefined {\n return this.map.getRecord(key);\n }\n\n // Expose raw map if needed for advanced usage\n get raw() {\n return this.map;\n }\n}\n","import { serialize, deserialize } from '@topgunbuild/core';\n\nexport class EncryptionManager {\n private static ALGORITHM = 'AES-GCM';\n private static IV_LENGTH = 12;\n\n /**\n * Encrypts data using AES-GCM.\n * Serializes data to MessagePack before encryption.\n */\n static async encrypt(key: CryptoKey, data: any): Promise<{ iv: Uint8Array; data: Uint8Array }> {\n const encoded = serialize(data);\n\n // Generate IV\n const iv = window.crypto.getRandomValues(new Uint8Array(EncryptionManager.IV_LENGTH));\n\n // Encrypt\n const ciphertext = await window.crypto.subtle.encrypt(\n {\n name: EncryptionManager.ALGORITHM,\n iv: iv,\n },\n key,\n encoded as any\n );\n\n return {\n iv,\n data: new Uint8Array(ciphertext),\n };\n }\n\n /**\n * Decrypts AES-GCM encrypted data.\n * Deserializes from MessagePack after decryption.\n */\n static async decrypt(key: CryptoKey, record: { iv: Uint8Array; data: Uint8Array }): Promise<any> {\n try {\n const plaintextBuffer = await window.crypto.subtle.decrypt(\n {\n name: EncryptionManager.ALGORITHM,\n iv: record.iv as any,\n },\n key,\n record.data as any\n );\n\n return deserialize(new Uint8Array(plaintextBuffer));\n } catch (err) {\n console.error('Decryption failed', err);\n throw new Error('Failed to decrypt data: ' + err);\n }\n }\n}\n","import { IStorageAdapter, OpLogEntry } from '../IStorageAdapter';\nimport { EncryptionManager } from '../crypto/EncryptionManager';\n\n/**\n * Wraps an underlying storage adapter and encrypts data at rest using AES-GCM.\n */\nexport class EncryptedStorageAdapter implements IStorageAdapter {\n constructor(\n private wrapped: IStorageAdapter,\n private key: CryptoKey\n ) { }\n\n async initialize(dbName: string): Promise<void> {\n return this.wrapped.initialize(dbName);\n }\n\n async close(): Promise<void> {\n return this.wrapped.close();\n }\n\n // --- KV Operations ---\n\n async get<V>(key: string): Promise<V | any | undefined> {\n const raw = await this.wrapped.get<any>(key);\n\n if (!raw) {\n return undefined;\n }\n\n // Check if it looks like an encrypted record\n // We expect { iv: Uint8Array, data: Uint8Array }\n // Note: In a real app we might want a stricter check or a version tag.\n if (this.isEncryptedRecord(raw)) {\n try {\n return await EncryptionManager.decrypt(this.key, raw);\n } catch (e) {\n // Fallback for migration or corruption?\n // For now, fail loud as per spec.\n throw e;\n }\n }\n\n // Return raw if not encrypted (backwards compatibility during dev, or unencrypted data)\n return raw;\n }\n\n async put(key: string, value: any): Promise<void> {\n const encrypted = await EncryptionManager.encrypt(this.key, value);\n // Store as plain object to be compatible with structured clone algorithm of IndexedDB\n const storedValue = {\n iv: encrypted.iv,\n data: encrypted.data\n };\n return this.wrapped.put(key, storedValue);\n }\n\n async remove(key: string): Promise<void> {\n return this.wrapped.remove(key);\n }\n\n // --- Metadata ---\n\n async getMeta(key: string): Promise<any> {\n const raw = await this.wrapped.getMeta(key);\n if (!raw) return undefined;\n\n if (this.isEncryptedRecord(raw)) {\n return EncryptionManager.decrypt(this.key, raw);\n }\n return raw;\n }\n\n async setMeta(key: string, value: any): Promise<void> {\n const encrypted = await EncryptionManager.encrypt(this.key, value);\n return this.wrapped.setMeta(key, {\n iv: encrypted.iv,\n data: encrypted.data\n });\n }\n\n // --- Batch ---\n\n async batchPut(entries: Map<string, any>): Promise<void> {\n const encryptedEntries = new Map<string, any>();\n\n for (const [key, value] of entries.entries()) {\n const encrypted = await EncryptionManager.encrypt(this.key, value);\n encryptedEntries.set(key, {\n iv: encrypted.iv,\n data: encrypted.data\n });\n }\n\n return this.wrapped.batchPut(encryptedEntries);\n }\n\n // --- OpLog ---\n\n async appendOpLog(entry: Omit<OpLogEntry, 'id'>): Promise<number> {\n // Encrypt sensitive fields: value, record, orRecord\n const encryptedEntry = { ...entry };\n\n if (entry.value !== undefined) {\n const enc = await EncryptionManager.encrypt(this.key, entry.value);\n encryptedEntry.value = { iv: enc.iv, data: enc.data };\n }\n\n if (entry.record !== undefined) {\n const enc = await EncryptionManager.encrypt(this.key, entry.record);\n encryptedEntry.record = { iv: enc.iv, data: enc.data } as any;\n }\n\n if (entry.orRecord !== undefined) {\n const enc = await EncryptionManager.encrypt(this.key, entry.orRecord);\n encryptedEntry.orRecord = { iv: enc.iv, data: enc.data } as any;\n }\n\n // Note: 'key', 'op', 'mapName', 'orTag', 'hlc', 'synced' remain plaintext for indexing\n\n return this.wrapped.appendOpLog(encryptedEntry);\n }\n\n async getPendingOps(): Promise<OpLogEntry[]> {\n const ops = await this.wrapped.getPendingOps();\n\n // Decrypt in place\n // We map concurrently for performance\n return Promise.all(ops.map(async op => {\n const decryptedOp = { ...op };\n\n if (this.isEncryptedRecord(op.value)) {\n decryptedOp.value = await EncryptionManager.decrypt(this.key, op.value);\n }\n\n if (this.isEncryptedRecord(op.record)) {\n decryptedOp.record = await EncryptionManager.decrypt(this.key, op.record as any);\n }\n\n if (this.isEncryptedRecord(op.orRecord)) {\n decryptedOp.orRecord = await EncryptionManager.decrypt(this.key, op.orRecord as any);\n }\n\n return decryptedOp;\n }));\n }\n\n async markOpsSynced(lastId: number): Promise<void> {\n return this.wrapped.markOpsSynced(lastId);\n }\n\n // --- Iteration ---\n\n async getAllKeys(): Promise<string[]> {\n return this.wrapped.getAllKeys();\n }\n\n // --- Helpers ---\n\n private isEncryptedRecord(data: any): data is { iv: Uint8Array, data: Uint8Array } {\n return data &&\n typeof data === 'object' &&\n data.iv instanceof Uint8Array &&\n data.data instanceof Uint8Array;\n }\n}\n"],"mappings":"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","names":["pino","SyncState","token","import_core","import_core","import_core"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/SyncEngine.ts","../src/utils/logger.ts","../src/SyncState.ts","../src/SyncStateMachine.ts","../src/errors/BackpressureError.ts","../src/BackpressureConfig.ts","../src/TopGunClient.ts","../src/QueryHandle.ts","../src/DistributedLock.ts","../src/TopicHandle.ts","../src/adapters/IDBAdapter.ts","../src/TopGun.ts","../src/crypto/EncryptionManager.ts","../src/adapters/EncryptedStorageAdapter.ts"],"sourcesContent":["import { SyncEngine } from './SyncEngine';\nimport { TopGunClient } from './TopGunClient';\nimport { TopGun } from './TopGun';\nexport * from './adapters/IDBAdapter';\nexport * from './adapters/EncryptedStorageAdapter';\nimport { QueryHandle } from './QueryHandle';\nimport { LWWMap, Predicates } from '@topgunbuild/core';\nimport { TopicHandle } from './TopicHandle';\nimport { SyncState, VALID_TRANSITIONS, isValidTransition } from './SyncState';\nimport { SyncStateMachine } from './SyncStateMachine';\nimport { BackpressureError } from './errors/BackpressureError';\nimport { DEFAULT_BACKPRESSURE_CONFIG } from './BackpressureConfig';\n\n// Type imports\nimport type { IStorageAdapter, OpLogEntry } from './IStorageAdapter';\nimport type { LWWRecord, PredicateNode } from '@topgunbuild/core';\nimport type { QueryFilter, QueryResultItem, QueryResultSource } from './QueryHandle';\nimport type { TopicCallback } from './TopicHandle';\nimport type { BackoffConfig, HeartbeatConfig, SyncEngineConfig } from './SyncEngine';\nimport type { StateChangeEvent, StateChangeListener, SyncStateMachineConfig } from './SyncStateMachine';\nimport type {\n BackpressureConfig,\n BackpressureStrategy,\n BackpressureStatus,\n BackpressureThresholdEvent,\n OperationDroppedEvent,\n} from './BackpressureConfig';\n\n// Value exports\nexport { SyncEngine, TopGunClient, TopGun, QueryHandle, LWWMap, Predicates, TopicHandle };\nexport { SyncState, VALID_TRANSITIONS, isValidTransition, SyncStateMachine };\nexport { BackpressureError, DEFAULT_BACKPRESSURE_CONFIG };\nexport { logger } from './utils/logger';\n\n// Type exports\nexport type {\n IStorageAdapter,\n OpLogEntry,\n LWWRecord,\n PredicateNode,\n QueryFilter,\n QueryResultItem,\n QueryResultSource,\n TopicCallback,\n BackoffConfig,\n HeartbeatConfig,\n SyncEngineConfig,\n StateChangeEvent,\n StateChangeListener,\n SyncStateMachineConfig,\n BackpressureConfig,\n BackpressureStrategy,\n BackpressureStatus,\n BackpressureThresholdEvent,\n OperationDroppedEvent,\n};\n","import { HLC, LWWMap, ORMap, serialize, deserialize, evaluatePredicate } from '@topgunbuild/core';\nimport type { LWWRecord, ORMapRecord, Timestamp } from '@topgunbuild/core';\nimport type { IStorageAdapter } from './IStorageAdapter';\nimport { QueryHandle } from './QueryHandle';\nimport type { QueryFilter } from './QueryHandle';\nimport { TopicHandle } from './TopicHandle';\nimport { logger } from './utils/logger';\nimport { SyncStateMachine, StateChangeEvent } from './SyncStateMachine';\nimport { SyncState } from './SyncState';\nimport { BackpressureError } from './errors/BackpressureError';\nimport type {\n BackpressureConfig,\n BackpressureStatus,\n BackpressureStrategy,\n BackpressureThresholdEvent,\n OperationDroppedEvent,\n} from './BackpressureConfig';\nimport { DEFAULT_BACKPRESSURE_CONFIG } from './BackpressureConfig';\n\nexport interface OpLogEntry {\n id: string; // Unique ID for the operation\n mapName: string;\n opType: 'PUT' | 'REMOVE' | 'OR_ADD' | 'OR_REMOVE';\n key: string;\n record?: LWWRecord<any>; // LWW Put/Remove (Remove has null value)\n orRecord?: ORMapRecord<any>; // ORMap Add\n orTag?: string; // ORMap Remove (Tombstone tag)\n timestamp: Timestamp; // HLC timestamp of the operation\n synced: boolean; // True if this operation has been successfully pushed to the server\n}\n\nexport interface HeartbeatConfig {\n intervalMs: number; // Default: 5000 (5 seconds)\n timeoutMs: number; // Default: 15000 (15 seconds)\n enabled: boolean; // Default: true\n}\n\nexport interface BackoffConfig {\n /** Initial delay in milliseconds (default: 1000) */\n initialDelayMs: number;\n /** Maximum delay in milliseconds (default: 30000) */\n maxDelayMs: number;\n /** Multiplier for exponential backoff (default: 2) */\n multiplier: number;\n /** Whether to add random jitter to delay (default: true) */\n jitter: boolean;\n /** Maximum number of retry attempts before entering ERROR state (default: 10) */\n maxRetries: number;\n}\n\nexport interface SyncEngineConfig {\n nodeId: string;\n serverUrl: string;\n storageAdapter: IStorageAdapter;\n reconnectInterval?: number;\n heartbeat?: Partial<HeartbeatConfig>;\n backoff?: Partial<BackoffConfig>;\n backpressure?: Partial<BackpressureConfig>;\n}\n\nconst DEFAULT_BACKOFF_CONFIG: BackoffConfig = {\n initialDelayMs: 1000,\n maxDelayMs: 30000,\n multiplier: 2,\n jitter: true,\n maxRetries: 10,\n};\n\nexport class SyncEngine {\n private readonly nodeId: string;\n private readonly serverUrl: string;\n private readonly storageAdapter: IStorageAdapter;\n private readonly hlc: HLC;\n private readonly stateMachine: SyncStateMachine;\n private readonly backoffConfig: BackoffConfig;\n\n private websocket: WebSocket | null = null;\n private opLog: OpLogEntry[] = [];\n private maps: Map<string, LWWMap<any, any> | ORMap<any, any>> = new Map();\n private queries: Map<string, QueryHandle<any>> = new Map();\n private topics: Map<string, TopicHandle> = new Map();\n private pendingLockRequests: Map<string, { resolve: (res: any) => void, reject: (err: any) => void, timer: any }> = new Map();\n private lastSyncTimestamp: number = 0;\n private reconnectTimer: any = null; // NodeJS.Timeout\n private authToken: string | null = null;\n private tokenProvider: (() => Promise<string | null>) | null = null;\n private backoffAttempt: number = 0;\n\n // Heartbeat state\n private readonly heartbeatConfig: HeartbeatConfig;\n private heartbeatInterval: ReturnType<typeof setInterval> | null = null;\n private lastPongReceived: number = Date.now();\n private lastRoundTripTime: number | null = null;\n\n // Backpressure state\n private readonly backpressureConfig: BackpressureConfig;\n private backpressurePaused: boolean = false;\n private waitingForCapacity: Array<() => void> = [];\n private highWaterMarkEmitted: boolean = false;\n private backpressureListeners: Map<string, Set<(...args: any[]) => void>> = new Map();\n\n // Write Concern state (Phase 5.01)\n private pendingWriteConcernPromises: Map<string, {\n resolve: (result: any) => void;\n reject: (error: Error) => void;\n timeoutHandle?: ReturnType<typeof setTimeout>;\n }> = new Map();\n\n constructor(config: SyncEngineConfig) {\n this.nodeId = config.nodeId;\n this.serverUrl = config.serverUrl;\n this.storageAdapter = config.storageAdapter;\n this.hlc = new HLC(this.nodeId);\n\n // Initialize state machine\n this.stateMachine = new SyncStateMachine();\n\n // Initialize heartbeat config with defaults\n this.heartbeatConfig = {\n intervalMs: config.heartbeat?.intervalMs ?? 5000,\n timeoutMs: config.heartbeat?.timeoutMs ?? 15000,\n enabled: config.heartbeat?.enabled ?? true,\n };\n\n // Merge backoff config with defaults\n this.backoffConfig = {\n ...DEFAULT_BACKOFF_CONFIG,\n ...config.backoff,\n };\n\n // Merge backpressure config with defaults\n this.backpressureConfig = {\n ...DEFAULT_BACKPRESSURE_CONFIG,\n ...config.backpressure,\n };\n\n this.initConnection();\n this.loadOpLog();\n }\n\n // ============================================\n // State Machine Public API\n // ============================================\n\n /**\n * Get the current connection state\n */\n getConnectionState(): SyncState {\n return this.stateMachine.getState();\n }\n\n /**\n * Subscribe to connection state changes\n * @returns Unsubscribe function\n */\n onConnectionStateChange(listener: (event: StateChangeEvent) => void): () => void {\n return this.stateMachine.onStateChange(listener);\n }\n\n /**\n * Get state machine history for debugging\n */\n getStateHistory(limit?: number): StateChangeEvent[] {\n return this.stateMachine.getHistory(limit);\n }\n\n // ============================================\n // Internal State Helpers (replace boolean flags)\n // ============================================\n\n /**\n * Check if WebSocket is connected (but may not be authenticated yet)\n */\n private isOnline(): boolean {\n const state = this.stateMachine.getState();\n return (\n state === SyncState.CONNECTING ||\n state === SyncState.AUTHENTICATING ||\n state === SyncState.SYNCING ||\n state === SyncState.CONNECTED\n );\n }\n\n /**\n * Check if fully authenticated and ready for operations\n */\n private isAuthenticated(): boolean {\n const state = this.stateMachine.getState();\n return state === SyncState.SYNCING || state === SyncState.CONNECTED;\n }\n\n /**\n * Check if fully connected and synced\n */\n private isConnected(): boolean {\n return this.stateMachine.getState() === SyncState.CONNECTED;\n }\n\n // ============================================\n // Connection Management\n // ============================================\n\n private initConnection(): void {\n // Transition to CONNECTING state\n this.stateMachine.transition(SyncState.CONNECTING);\n\n this.websocket = new WebSocket(this.serverUrl);\n this.websocket.binaryType = 'arraybuffer';\n\n this.websocket.onopen = () => {\n // WebSocket is open, now we need to authenticate\n // [CHANGE] Don't send auth immediately if we don't have a token\n // This prevents the \"AUTH_REQUIRED -> Close -> Retry loop\" for anonymous initial connects\n if (this.authToken || this.tokenProvider) {\n logger.info('WebSocket connected. Sending auth...');\n this.stateMachine.transition(SyncState.AUTHENTICATING);\n this.sendAuth();\n } else {\n logger.info('WebSocket connected. Waiting for auth token...');\n // Stay in CONNECTING state until we have a token\n // We're online but not authenticated\n this.stateMachine.transition(SyncState.AUTHENTICATING);\n }\n };\n\n this.websocket.onmessage = (event) => {\n let message: any;\n if (event.data instanceof ArrayBuffer) {\n message = deserialize(new Uint8Array(event.data));\n } else {\n try {\n message = JSON.parse(event.data);\n } catch (e) {\n logger.error({ err: e }, 'Failed to parse message');\n return;\n }\n }\n this.handleServerMessage(message);\n };\n\n this.websocket.onclose = () => {\n logger.info('WebSocket disconnected.');\n this.stopHeartbeat();\n this.stateMachine.transition(SyncState.DISCONNECTED);\n this.scheduleReconnect();\n };\n\n this.websocket.onerror = (error) => {\n logger.error({ err: error }, 'WebSocket error');\n // Error will typically be followed by close, so we don't transition here\n };\n }\n\n private scheduleReconnect(): void {\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n\n // Check if we've exceeded max retries\n if (this.backoffAttempt >= this.backoffConfig.maxRetries) {\n logger.error(\n { attempts: this.backoffAttempt },\n 'Max reconnection attempts reached. Entering ERROR state.'\n );\n this.stateMachine.transition(SyncState.ERROR);\n return;\n }\n\n // Transition to BACKOFF state\n this.stateMachine.transition(SyncState.BACKOFF);\n\n const delay = this.calculateBackoffDelay();\n logger.info({ delay, attempt: this.backoffAttempt }, `Backing off for ${delay}ms`);\n\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null;\n this.backoffAttempt++;\n this.initConnection();\n }, delay);\n }\n\n private calculateBackoffDelay(): number {\n const { initialDelayMs, maxDelayMs, multiplier, jitter } = this.backoffConfig;\n let delay = initialDelayMs * Math.pow(multiplier, this.backoffAttempt);\n delay = Math.min(delay, maxDelayMs);\n\n if (jitter) {\n // Add jitter: 0.5x to 1.5x of calculated delay\n delay = delay * (0.5 + Math.random());\n }\n\n return Math.floor(delay);\n }\n\n /**\n * Reset backoff counter (called on successful connection)\n */\n private resetBackoff(): void {\n this.backoffAttempt = 0;\n }\n\n private async loadOpLog(): Promise<void> {\n const storedTimestamp = await this.storageAdapter.getMeta('lastSyncTimestamp');\n if (storedTimestamp) {\n this.lastSyncTimestamp = storedTimestamp;\n }\n\n const pendingOps = await this.storageAdapter.getPendingOps();\n this.opLog = pendingOps.map(op => ({\n ...op,\n id: String(op.id),\n synced: false\n })) as unknown as OpLogEntry[];\n\n if (this.opLog.length > 0) {\n logger.info({ count: this.opLog.length }, 'Loaded pending operations from local storage');\n }\n }\n\n private async saveOpLog(): Promise<void> {\n await this.storageAdapter.setMeta('lastSyncTimestamp', this.lastSyncTimestamp);\n }\n\n public registerMap(mapName: string, map: LWWMap<any, any> | ORMap<any, any>): void {\n this.maps.set(mapName, map);\n }\n\n public async recordOperation(\n mapName: string,\n opType: 'PUT' | 'REMOVE' | 'OR_ADD' | 'OR_REMOVE',\n key: string,\n data: { record?: LWWRecord<any>; orRecord?: ORMapRecord<any>; orTag?: string; timestamp: Timestamp }\n ): Promise<string> {\n // Check backpressure before adding new operation\n await this.checkBackpressure();\n\n const opLogEntry: Omit<OpLogEntry, 'id'> & { id?: string } = {\n mapName,\n opType,\n key,\n record: data.record,\n orRecord: data.orRecord,\n orTag: data.orTag,\n timestamp: data.timestamp,\n synced: false,\n };\n\n const id = await this.storageAdapter.appendOpLog(opLogEntry as any);\n opLogEntry.id = String(id);\n\n this.opLog.push(opLogEntry as OpLogEntry);\n\n // Check high water mark after adding operation\n this.checkHighWaterMark();\n\n if (this.isAuthenticated()) {\n this.syncPendingOperations();\n }\n\n return opLogEntry.id;\n }\n\n private syncPendingOperations(): void {\n const pending = this.opLog.filter(op => !op.synced);\n if (pending.length === 0) return;\n\n logger.info({ count: pending.length }, 'Syncing pending operations');\n\n if (this.websocket?.readyState === WebSocket.OPEN) {\n this.websocket.send(serialize({\n type: 'OP_BATCH',\n payload: {\n ops: pending\n }\n }));\n }\n }\n\n private startMerkleSync(): void {\n for (const [mapName, map] of this.maps) {\n if (map instanceof LWWMap) {\n logger.info({ mapName }, 'Starting Merkle sync for LWWMap');\n this.websocket?.send(serialize({\n type: 'SYNC_INIT',\n mapName,\n lastSyncTimestamp: this.lastSyncTimestamp\n }));\n } else if (map instanceof ORMap) {\n logger.info({ mapName }, 'Starting Merkle sync for ORMap');\n const tree = map.getMerkleTree();\n const rootHash = tree.getRootHash();\n\n // Build bucket hashes for all non-empty buckets at depth 0\n const bucketHashes: Record<string, number> = tree.getBuckets('');\n\n this.websocket?.send(serialize({\n type: 'ORMAP_SYNC_INIT',\n mapName,\n rootHash,\n bucketHashes,\n lastSyncTimestamp: this.lastSyncTimestamp\n }));\n }\n }\n }\n\n public setAuthToken(token: string): void {\n this.authToken = token;\n this.tokenProvider = null;\n\n const state = this.stateMachine.getState();\n if (state === SyncState.AUTHENTICATING || state === SyncState.CONNECTING) {\n // If we are already connected (e.g. waiting for token), send it now\n this.sendAuth();\n } else if (state === SyncState.BACKOFF || state === SyncState.DISCONNECTED) {\n // [CHANGE] Force immediate reconnect if we were waiting for retry timer\n logger.info('Auth token set during backoff/disconnect. Reconnecting immediately.');\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n // Reset backoff since user provided new credentials\n this.resetBackoff();\n this.initConnection();\n }\n }\n\n public setTokenProvider(provider: () => Promise<string | null>): void {\n this.tokenProvider = provider;\n const state = this.stateMachine.getState();\n if (state === SyncState.AUTHENTICATING) {\n this.sendAuth();\n }\n }\n\n private async sendAuth(): Promise<void> {\n if (this.tokenProvider) {\n try {\n const token = await this.tokenProvider();\n if (token) {\n this.authToken = token;\n }\n } catch (err) {\n logger.error({ err }, 'Failed to get token from provider');\n return;\n }\n }\n\n const token = this.authToken;\n if (!token) return; // Don't send anonymous auth anymore\n\n this.websocket?.send(serialize({\n type: 'AUTH',\n token\n }));\n }\n\n public subscribeToQuery(query: QueryHandle<any>) {\n this.queries.set(query.id, query);\n if (this.isAuthenticated()) {\n this.sendQuerySubscription(query);\n }\n }\n\n public subscribeToTopic(topic: string, handle: TopicHandle) {\n this.topics.set(topic, handle);\n if (this.isAuthenticated()) {\n this.sendTopicSubscription(topic);\n }\n }\n\n public unsubscribeFromTopic(topic: string) {\n this.topics.delete(topic);\n if (this.isAuthenticated()) {\n this.websocket?.send(serialize({\n type: 'TOPIC_UNSUB',\n payload: { topic }\n }));\n }\n }\n\n public publishTopic(topic: string, data: any) {\n if (this.isAuthenticated()) {\n this.websocket?.send(serialize({\n type: 'TOPIC_PUB',\n payload: { topic, data }\n }));\n } else {\n // TODO: Queue topic messages or drop?\n // Spec says Fire-and-Forget, so dropping is acceptable if offline,\n // but queueing is better UX.\n // For now, log warning.\n logger.warn({ topic }, 'Dropped topic publish (offline)');\n }\n }\n\n private sendTopicSubscription(topic: string) {\n this.websocket?.send(serialize({\n type: 'TOPIC_SUB',\n payload: { topic }\n }));\n }\n\n /**\n * Executes a query against local storage immediately\n */\n public async runLocalQuery(mapName: string, filter: QueryFilter): Promise<{ key: string, value: any }[]> {\n // Retrieve all keys for the map\n const keys = await this.storageAdapter.getAllKeys();\n const mapKeys = keys.filter(k => k.startsWith(mapName + ':'));\n\n const results = [];\n for (const fullKey of mapKeys) {\n const record = await this.storageAdapter.get(fullKey);\n if (record && record.value) {\n // Extract actual key from \"mapName:key\"\n const actualKey = fullKey.slice(mapName.length + 1);\n\n let matches = true;\n\n // Apply 'where' (equality)\n if (filter.where) {\n for (const [k, v] of Object.entries(filter.where)) {\n if (record.value[k] !== v) {\n matches = false;\n break;\n }\n }\n }\n\n // Apply 'predicate'\n if (matches && filter.predicate) {\n if (!evaluatePredicate(filter.predicate, record.value)) {\n matches = false;\n }\n }\n\n if (matches) {\n results.push({ key: actualKey, value: record.value });\n }\n }\n }\n return results;\n }\n\n public unsubscribeFromQuery(queryId: string) {\n this.queries.delete(queryId);\n if (this.isAuthenticated()) {\n this.websocket?.send(serialize({\n type: 'QUERY_UNSUB',\n payload: { queryId }\n }));\n }\n }\n\n private sendQuerySubscription(query: QueryHandle<any>) {\n this.websocket?.send(serialize({\n type: 'QUERY_SUB',\n payload: {\n queryId: query.id,\n mapName: query.getMapName(),\n query: query.getFilter()\n }\n }));\n }\n\n public requestLock(name: string, requestId: string, ttl: number): Promise<{ fencingToken: number }> {\n if (!this.isAuthenticated()) {\n return Promise.reject(new Error('Not connected or authenticated'));\n }\n\n return new Promise((resolve, reject) => {\n // Timeout if no response (server might be down or message lost)\n // We set a client-side timeout slightly larger than TTL if TTL is short,\n // but usually we want a separate \"Wait Timeout\".\n // For now, use a fixed 30s timeout for the *response*.\n const timer = setTimeout(() => {\n if (this.pendingLockRequests.has(requestId)) {\n this.pendingLockRequests.delete(requestId);\n reject(new Error('Lock request timed out waiting for server response'));\n }\n }, 30000);\n\n this.pendingLockRequests.set(requestId, { resolve, reject, timer });\n\n try {\n this.websocket?.send(serialize({\n type: 'LOCK_REQUEST',\n payload: { requestId, name, ttl }\n }));\n } catch (e) {\n clearTimeout(timer);\n this.pendingLockRequests.delete(requestId);\n reject(e);\n }\n });\n }\n\n public releaseLock(name: string, requestId: string, fencingToken: number): Promise<boolean> {\n if (!this.isOnline()) return Promise.resolve(false);\n\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n if (this.pendingLockRequests.has(requestId)) {\n this.pendingLockRequests.delete(requestId);\n // Resolve false on timeout? Or reject?\n // Release is usually fire-and-forget but we wanted ACK.\n resolve(false);\n }\n }, 5000);\n\n this.pendingLockRequests.set(requestId, { resolve, reject, timer });\n\n try {\n this.websocket?.send(serialize({\n type: 'LOCK_RELEASE',\n payload: { requestId, name, fencingToken }\n }));\n } catch (e) {\n clearTimeout(timer);\n this.pendingLockRequests.delete(requestId);\n resolve(false);\n }\n });\n }\n\n private async handleServerMessage(message: any): Promise<void> {\n switch (message.type) {\n case 'BATCH': {\n // Unbatch and process each message\n // Format: [4 bytes: count][4 bytes: len1][msg1][4 bytes: len2][msg2]...\n const batchData = message.data as Uint8Array;\n const view = new DataView(batchData.buffer, batchData.byteOffset, batchData.byteLength);\n let offset = 0;\n\n const count = view.getUint32(offset, true);\n offset += 4;\n\n for (let i = 0; i < count; i++) {\n const msgLen = view.getUint32(offset, true);\n offset += 4;\n\n const msgData = batchData.slice(offset, offset + msgLen);\n offset += msgLen;\n\n const innerMsg = deserialize(msgData);\n await this.handleServerMessage(innerMsg);\n }\n break;\n }\n\n case 'AUTH_REQUIRED':\n this.sendAuth();\n break;\n\n case 'AUTH_ACK': {\n logger.info('Authenticated successfully');\n const wasAuthenticated = this.isAuthenticated();\n\n // Transition to SYNCING state\n this.stateMachine.transition(SyncState.SYNCING);\n\n // Reset backoff on successful auth\n this.resetBackoff();\n\n this.syncPendingOperations();\n\n // Only re-subscribe on first authentication to prevent UI flickering\n if (!wasAuthenticated) {\n this.startHeartbeat();\n this.startMerkleSync();\n for (const query of this.queries.values()) {\n this.sendQuerySubscription(query);\n }\n for (const topic of this.topics.keys()) {\n this.sendTopicSubscription(topic);\n }\n }\n\n // After initial sync setup, transition to CONNECTED\n // In a real implementation, you might wait for SYNC_COMPLETE message\n this.stateMachine.transition(SyncState.CONNECTED);\n break;\n }\n\n case 'PONG': {\n this.handlePong(message);\n break;\n }\n\n case 'AUTH_FAIL':\n logger.error({ error: message.error }, 'Authentication failed');\n this.authToken = null; // Clear invalid token\n // Stay in AUTHENTICATING or go to ERROR depending on severity\n // For now, let the connection close naturally or retry with new token\n break;\n\n case 'OP_ACK': {\n const { lastId, achievedLevel, results } = message.payload;\n logger.info({ lastId, achievedLevel, hasResults: !!results }, 'Received ACK for ops');\n\n // Handle per-operation results if available (Write Concern Phase 5.01)\n if (results && Array.isArray(results)) {\n for (const result of results) {\n const op = this.opLog.find(o => o.id === result.opId);\n if (op && !op.synced) {\n op.synced = true;\n logger.debug({ opId: result.opId, achievedLevel: result.achievedLevel, success: result.success }, 'Op ACK with Write Concern');\n }\n // Resolve pending Write Concern promise if exists\n this.resolveWriteConcernPromise(result.opId, result);\n }\n }\n\n // Backwards compatible: mark all ops up to lastId as synced\n let maxSyncedId = -1;\n let ackedCount = 0;\n this.opLog.forEach(op => {\n if (op.id && op.id <= lastId) {\n if (!op.synced) {\n ackedCount++;\n }\n op.synced = true;\n const idNum = parseInt(op.id, 10);\n if (!isNaN(idNum) && idNum > maxSyncedId) {\n maxSyncedId = idNum;\n }\n }\n });\n if (maxSyncedId !== -1) {\n this.storageAdapter.markOpsSynced(maxSyncedId).catch(err => logger.error({ err }, 'Failed to mark ops synced'));\n }\n // Check low water mark after ACKs reduce pending count\n if (ackedCount > 0) {\n this.checkLowWaterMark();\n }\n break;\n }\n\n case 'LOCK_GRANTED': {\n const { requestId, fencingToken } = message.payload;\n const req = this.pendingLockRequests.get(requestId);\n if (req) {\n clearTimeout(req.timer);\n this.pendingLockRequests.delete(requestId);\n req.resolve({ fencingToken });\n }\n break;\n }\n\n case 'LOCK_RELEASED': {\n const { requestId, success } = message.payload;\n const req = this.pendingLockRequests.get(requestId);\n if (req) {\n clearTimeout(req.timer);\n this.pendingLockRequests.delete(requestId);\n req.resolve(success);\n }\n break;\n }\n\n case 'QUERY_RESP': {\n const { queryId, results } = message.payload;\n const query = this.queries.get(queryId);\n if (query) {\n query.onResult(results, 'server');\n }\n break;\n }\n\n case 'QUERY_UPDATE': {\n const { queryId, key, value, type } = message.payload;\n const query = this.queries.get(queryId);\n if (query) {\n query.onUpdate(key, type === 'REMOVE' ? null : value);\n }\n break;\n }\n\n case 'SERVER_EVENT': {\n // Modified to support ORMap\n const { mapName, eventType, key, record, orRecord, orTag } = message.payload;\n await this.applyServerEvent(mapName, eventType, key, record, orRecord, orTag);\n break;\n }\n\n case 'SERVER_BATCH_EVENT': {\n // === OPTIMIZATION: Batch event processing ===\n // Server sends multiple events in a single message for efficiency\n const { events } = message.payload;\n for (const event of events) {\n await this.applyServerEvent(\n event.mapName,\n event.eventType,\n event.key,\n event.record,\n event.orRecord,\n event.orTag\n );\n }\n break;\n }\n\n case 'TOPIC_MESSAGE': {\n const { topic, data, publisherId, timestamp } = message.payload;\n const handle = this.topics.get(topic);\n if (handle) {\n handle.onMessage(data, { publisherId, timestamp });\n }\n break;\n }\n\n case 'GC_PRUNE': {\n const { olderThan } = message.payload;\n logger.info({ olderThan: olderThan.millis }, 'Received GC_PRUNE request');\n\n for (const [name, map] of this.maps) {\n if (map instanceof LWWMap) {\n const removedKeys = map.prune(olderThan);\n for (const key of removedKeys) {\n await this.storageAdapter.remove(`${name}:${key}`);\n }\n if (removedKeys.length > 0) {\n logger.info({ mapName: name, count: removedKeys.length }, 'Pruned tombstones from LWWMap');\n }\n } else if (map instanceof ORMap) {\n const removedTags = map.prune(olderThan);\n if (removedTags.length > 0) {\n logger.info({ mapName: name, count: removedTags.length }, 'Pruned tombstones from ORMap');\n }\n }\n }\n break;\n }\n\n case 'SYNC_RESET_REQUIRED': {\n const { mapName } = message.payload;\n logger.warn({ mapName }, 'Sync Reset Required due to GC Age');\n await this.resetMap(mapName);\n // Trigger re-sync as fresh\n this.websocket?.send(serialize({\n type: 'SYNC_INIT',\n mapName,\n lastSyncTimestamp: 0\n }));\n break;\n }\n\n case 'SYNC_RESP_ROOT': {\n const { mapName, rootHash, timestamp } = message.payload;\n const map = this.maps.get(mapName);\n if (map instanceof LWWMap) {\n const localRootHash = map.getMerkleTree().getRootHash();\n if (localRootHash !== rootHash) {\n logger.info({ mapName, localRootHash, remoteRootHash: rootHash }, 'Root hash mismatch, requesting buckets');\n this.websocket?.send(serialize({\n type: 'MERKLE_REQ_BUCKET',\n payload: { mapName, path: '' }\n }));\n } else {\n logger.info({ mapName }, 'Map is in sync');\n }\n }\n // Update HLC with server timestamp\n if (timestamp) {\n this.hlc.update(timestamp);\n this.lastSyncTimestamp = timestamp.millis;\n await this.saveOpLog();\n }\n break;\n }\n\n case 'SYNC_RESP_BUCKETS': {\n const { mapName, path, buckets } = message.payload;\n const map = this.maps.get(mapName);\n if (map instanceof LWWMap) {\n const tree = map.getMerkleTree();\n const localBuckets = tree.getBuckets(path);\n\n for (const [bucketKey, remoteHash] of Object.entries(buckets)) {\n const localHash = localBuckets[bucketKey] || 0;\n if (localHash !== remoteHash) {\n const newPath = path + bucketKey;\n this.websocket?.send(serialize({\n type: 'MERKLE_REQ_BUCKET',\n payload: { mapName, path: newPath }\n }));\n }\n }\n }\n break;\n }\n\n case 'SYNC_RESP_LEAF': {\n const { mapName, records } = message.payload;\n const map = this.maps.get(mapName);\n if (map instanceof LWWMap) {\n let updateCount = 0;\n for (const { key, record } of records) {\n // Merge into local map\n const updated = map.merge(key, record);\n if (updated) {\n updateCount++;\n // Persist to storage\n await this.storageAdapter.put(`${mapName}:${key}`, record);\n }\n }\n if (updateCount > 0) {\n logger.info({ mapName, count: updateCount }, 'Synced records from server');\n }\n }\n break;\n }\n\n // ============ ORMap Sync Message Handlers ============\n\n case 'ORMAP_SYNC_RESP_ROOT': {\n const { mapName, rootHash, timestamp } = message.payload;\n const map = this.maps.get(mapName);\n if (map instanceof ORMap) {\n const localTree = map.getMerkleTree();\n const localRootHash = localTree.getRootHash();\n\n if (localRootHash !== rootHash) {\n logger.info({ mapName, localRootHash, remoteRootHash: rootHash }, 'ORMap root hash mismatch, requesting buckets');\n this.websocket?.send(serialize({\n type: 'ORMAP_MERKLE_REQ_BUCKET',\n payload: { mapName, path: '' }\n }));\n } else {\n logger.info({ mapName }, 'ORMap is in sync');\n }\n }\n // Update HLC with server timestamp\n if (timestamp) {\n this.hlc.update(timestamp);\n this.lastSyncTimestamp = timestamp.millis;\n await this.saveOpLog();\n }\n break;\n }\n\n case 'ORMAP_SYNC_RESP_BUCKETS': {\n const { mapName, path, buckets } = message.payload;\n const map = this.maps.get(mapName);\n if (map instanceof ORMap) {\n const tree = map.getMerkleTree();\n const localBuckets = tree.getBuckets(path);\n\n for (const [bucketKey, remoteHash] of Object.entries(buckets)) {\n const localHash = localBuckets[bucketKey] || 0;\n if (localHash !== remoteHash) {\n const newPath = path + bucketKey;\n this.websocket?.send(serialize({\n type: 'ORMAP_MERKLE_REQ_BUCKET',\n payload: { mapName, path: newPath }\n }));\n }\n }\n\n // Also check for buckets that exist locally but not on remote\n for (const [bucketKey, localHash] of Object.entries(localBuckets)) {\n if (!(bucketKey in buckets) && localHash !== 0) {\n // Local has data that remote doesn't - need to push\n const newPath = path + bucketKey;\n const keys = tree.getKeysInBucket(newPath);\n if (keys.length > 0) {\n this.pushORMapDiff(mapName, keys, map);\n }\n }\n }\n }\n break;\n }\n\n case 'ORMAP_SYNC_RESP_LEAF': {\n const { mapName, entries } = message.payload;\n const map = this.maps.get(mapName);\n if (map instanceof ORMap) {\n let totalAdded = 0;\n let totalUpdated = 0;\n\n for (const entry of entries) {\n const { key, records, tombstones } = entry;\n const result = map.mergeKey(key, records, tombstones);\n totalAdded += result.added;\n totalUpdated += result.updated;\n }\n\n if (totalAdded > 0 || totalUpdated > 0) {\n logger.info({ mapName, added: totalAdded, updated: totalUpdated }, 'Synced ORMap records from server');\n }\n\n // Now push any local records that server might not have\n const keysToCheck = entries.map((e: { key: string }) => e.key);\n await this.pushORMapDiff(mapName, keysToCheck, map);\n }\n break;\n }\n\n case 'ORMAP_DIFF_RESPONSE': {\n const { mapName, entries } = message.payload;\n const map = this.maps.get(mapName);\n if (map instanceof ORMap) {\n let totalAdded = 0;\n let totalUpdated = 0;\n\n for (const entry of entries) {\n const { key, records, tombstones } = entry;\n const result = map.mergeKey(key, records, tombstones);\n totalAdded += result.added;\n totalUpdated += result.updated;\n }\n\n if (totalAdded > 0 || totalUpdated > 0) {\n logger.info({ mapName, added: totalAdded, updated: totalUpdated }, 'Merged ORMap diff from server');\n }\n }\n break;\n }\n }\n\n if (message.timestamp) {\n this.hlc.update(message.timestamp);\n this.lastSyncTimestamp = message.timestamp.millis;\n await this.saveOpLog();\n }\n }\n\n public getHLC(): HLC {\n return this.hlc;\n }\n\n /**\n * Helper method to apply a single server event to the local map.\n * Used by both SERVER_EVENT and SERVER_BATCH_EVENT handlers.\n */\n private async applyServerEvent(\n mapName: string,\n eventType: string,\n key: string,\n record?: any,\n orRecord?: any,\n orTag?: string\n ): Promise<void> {\n const localMap = this.maps.get(mapName);\n if (localMap) {\n if (localMap instanceof LWWMap && record) {\n localMap.merge(key, record);\n await this.storageAdapter.put(`${mapName}:${key}`, record);\n } else if (localMap instanceof ORMap) {\n if (eventType === 'OR_ADD' && orRecord) {\n localMap.apply(key, orRecord);\n // We need to store ORMap records differently in storageAdapter or use a convention\n // For now, skipping persistent storage update for ORMap in this example\n } else if (eventType === 'OR_REMOVE' && orTag) {\n localMap.applyTombstone(orTag);\n }\n }\n }\n }\n\n /**\n * Closes the WebSocket connection and cleans up resources.\n */\n public close(): void {\n this.stopHeartbeat();\n\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n\n if (this.websocket) {\n this.websocket.onclose = null; // Prevent reconnect on intentional close\n this.websocket.close();\n this.websocket = null;\n }\n\n // Cancel pending Write Concern promises (Phase 5.01)\n this.cancelAllWriteConcernPromises(new Error('SyncEngine closed'));\n\n this.stateMachine.transition(SyncState.DISCONNECTED);\n logger.info('SyncEngine closed');\n }\n\n /**\n * Reset the state machine and connection.\n * Use after fatal errors to start fresh.\n */\n public resetConnection(): void {\n this.close();\n this.stateMachine.reset();\n this.resetBackoff();\n this.initConnection();\n }\n\n private async resetMap(mapName: string): Promise<void> {\n const map = this.maps.get(mapName);\n if (map) {\n // Clear memory\n if (map instanceof LWWMap) {\n map.clear();\n } else if (map instanceof ORMap) {\n map.clear();\n }\n }\n\n // Clear storage\n const allKeys = await this.storageAdapter.getAllKeys();\n const mapKeys = allKeys.filter(k => k.startsWith(mapName + ':'));\n for (const key of mapKeys) {\n await this.storageAdapter.remove(key);\n }\n logger.info({ mapName, removedStorageCount: mapKeys.length }, 'Reset map: Cleared memory and storage');\n }\n\n // ============ Heartbeat Methods ============\n\n /**\n * Starts the heartbeat mechanism after successful connection.\n */\n private startHeartbeat(): void {\n if (!this.heartbeatConfig.enabled) {\n return;\n }\n\n this.stopHeartbeat(); // Clear any existing interval\n this.lastPongReceived = Date.now();\n\n this.heartbeatInterval = setInterval(() => {\n this.sendPing();\n this.checkHeartbeatTimeout();\n }, this.heartbeatConfig.intervalMs);\n\n logger.info({ intervalMs: this.heartbeatConfig.intervalMs }, 'Heartbeat started');\n }\n\n /**\n * Stops the heartbeat mechanism.\n */\n private stopHeartbeat(): void {\n if (this.heartbeatInterval) {\n clearInterval(this.heartbeatInterval);\n this.heartbeatInterval = null;\n logger.info('Heartbeat stopped');\n }\n }\n\n /**\n * Sends a PING message to the server.\n */\n private sendPing(): void {\n if (this.websocket?.readyState === WebSocket.OPEN) {\n const pingMessage = {\n type: 'PING',\n timestamp: Date.now(),\n };\n this.websocket.send(serialize(pingMessage));\n }\n }\n\n /**\n * Handles incoming PONG message from server.\n */\n private handlePong(msg: { timestamp: number; serverTime: number }): void {\n const now = Date.now();\n this.lastPongReceived = now;\n this.lastRoundTripTime = now - msg.timestamp;\n\n logger.debug({\n rtt: this.lastRoundTripTime,\n serverTime: msg.serverTime,\n clockSkew: msg.serverTime - (msg.timestamp + this.lastRoundTripTime / 2),\n }, 'Received PONG');\n }\n\n /**\n * Checks if heartbeat has timed out and triggers reconnection if needed.\n */\n private checkHeartbeatTimeout(): void {\n const now = Date.now();\n const timeSinceLastPong = now - this.lastPongReceived;\n\n if (timeSinceLastPong > this.heartbeatConfig.timeoutMs) {\n logger.warn({\n timeSinceLastPong,\n timeoutMs: this.heartbeatConfig.timeoutMs,\n }, 'Heartbeat timeout - triggering reconnection');\n\n this.stopHeartbeat();\n\n // Force close and reconnect\n if (this.websocket) {\n this.websocket.close();\n }\n }\n }\n\n /**\n * Returns the last measured round-trip time in milliseconds.\n * Returns null if no PONG has been received yet.\n */\n public getLastRoundTripTime(): number | null {\n return this.lastRoundTripTime;\n }\n\n /**\n * Returns true if the connection is considered healthy based on heartbeat.\n * A connection is healthy if it's online, authenticated, and has received\n * a PONG within the timeout window.\n */\n public isConnectionHealthy(): boolean {\n if (!this.isOnline() || !this.isAuthenticated()) {\n return false;\n }\n\n if (!this.heartbeatConfig.enabled) {\n return true; // If heartbeat disabled, consider healthy if online\n }\n\n const timeSinceLastPong = Date.now() - this.lastPongReceived;\n return timeSinceLastPong < this.heartbeatConfig.timeoutMs;\n }\n\n // ============ ORMap Sync Methods ============\n\n /**\n * Push local ORMap diff to server for the given keys.\n * Sends local records and tombstones that the server might not have.\n */\n private async pushORMapDiff(\n mapName: string,\n keys: string[],\n map: ORMap<any, any>\n ): Promise<void> {\n const entries: Array<{\n key: string;\n records: ORMapRecord<any>[];\n tombstones: string[];\n }> = [];\n\n const snapshot = map.getSnapshot();\n\n for (const key of keys) {\n const recordsMap = map.getRecordsMap(key);\n if (recordsMap && recordsMap.size > 0) {\n // Get records as array\n const records = Array.from(recordsMap.values());\n\n // Get tombstones relevant to this key's records\n // (tombstones that match tags that were in this key)\n const tombstones: string[] = [];\n for (const tag of snapshot.tombstones) {\n // Include all tombstones - server will filter\n tombstones.push(tag);\n }\n\n entries.push({\n key,\n records,\n tombstones\n });\n }\n }\n\n if (entries.length > 0) {\n this.websocket?.send(serialize({\n type: 'ORMAP_PUSH_DIFF',\n payload: {\n mapName,\n entries\n }\n }));\n logger.debug({ mapName, keyCount: entries.length }, 'Pushed ORMap diff to server');\n }\n }\n\n // ============ Backpressure Methods ============\n\n /**\n * Get the current number of pending (unsynced) operations.\n */\n public getPendingOpsCount(): number {\n return this.opLog.filter(op => !op.synced).length;\n }\n\n /**\n * Get the current backpressure status.\n */\n public getBackpressureStatus(): BackpressureStatus {\n const pending = this.getPendingOpsCount();\n const max = this.backpressureConfig.maxPendingOps;\n return {\n pending,\n max,\n percentage: max > 0 ? pending / max : 0,\n isPaused: this.backpressurePaused,\n strategy: this.backpressureConfig.strategy,\n };\n }\n\n /**\n * Returns true if writes are currently paused due to backpressure.\n */\n public isBackpressurePaused(): boolean {\n return this.backpressurePaused;\n }\n\n /**\n * Subscribe to backpressure events.\n * @param event Event name: 'backpressure:high', 'backpressure:low', 'backpressure:paused', 'backpressure:resumed', 'operation:dropped'\n * @param listener Callback function\n * @returns Unsubscribe function\n */\n public onBackpressure(\n event: 'backpressure:high' | 'backpressure:low' | 'backpressure:paused' | 'backpressure:resumed' | 'operation:dropped',\n listener: (data?: BackpressureThresholdEvent | OperationDroppedEvent) => void\n ): () => void {\n if (!this.backpressureListeners.has(event)) {\n this.backpressureListeners.set(event, new Set());\n }\n this.backpressureListeners.get(event)!.add(listener);\n\n return () => {\n this.backpressureListeners.get(event)?.delete(listener);\n };\n }\n\n /**\n * Emit a backpressure event to all listeners.\n */\n private emitBackpressureEvent(\n event: 'backpressure:high' | 'backpressure:low' | 'backpressure:paused' | 'backpressure:resumed' | 'operation:dropped',\n data?: BackpressureThresholdEvent | OperationDroppedEvent\n ): void {\n const listeners = this.backpressureListeners.get(event);\n if (listeners) {\n for (const listener of listeners) {\n try {\n listener(data);\n } catch (err) {\n logger.error({ err, event }, 'Error in backpressure event listener');\n }\n }\n }\n }\n\n /**\n * Check backpressure before adding a new operation.\n * May pause, throw, or drop depending on strategy.\n */\n private async checkBackpressure(): Promise<void> {\n const pendingCount = this.getPendingOpsCount();\n\n if (pendingCount < this.backpressureConfig.maxPendingOps) {\n return; // Capacity available\n }\n\n switch (this.backpressureConfig.strategy) {\n case 'pause':\n await this.waitForCapacity();\n break;\n case 'throw':\n throw new BackpressureError(\n pendingCount,\n this.backpressureConfig.maxPendingOps\n );\n case 'drop-oldest':\n this.dropOldestOp();\n break;\n }\n }\n\n /**\n * Check high water mark and emit event if threshold reached.\n */\n private checkHighWaterMark(): void {\n const pendingCount = this.getPendingOpsCount();\n const threshold = Math.floor(\n this.backpressureConfig.maxPendingOps * this.backpressureConfig.highWaterMark\n );\n\n if (pendingCount >= threshold && !this.highWaterMarkEmitted) {\n this.highWaterMarkEmitted = true;\n logger.warn(\n { pending: pendingCount, max: this.backpressureConfig.maxPendingOps },\n 'Backpressure high water mark reached'\n );\n this.emitBackpressureEvent('backpressure:high', {\n pending: pendingCount,\n max: this.backpressureConfig.maxPendingOps,\n });\n }\n }\n\n /**\n * Check low water mark and resume paused writes if threshold reached.\n */\n private checkLowWaterMark(): void {\n const pendingCount = this.getPendingOpsCount();\n const lowThreshold = Math.floor(\n this.backpressureConfig.maxPendingOps * this.backpressureConfig.lowWaterMark\n );\n const highThreshold = Math.floor(\n this.backpressureConfig.maxPendingOps * this.backpressureConfig.highWaterMark\n );\n\n // Reset high water mark flag when below high threshold\n if (pendingCount < highThreshold && this.highWaterMarkEmitted) {\n this.highWaterMarkEmitted = false;\n }\n\n // Emit low water mark event when crossing below threshold\n if (pendingCount <= lowThreshold) {\n if (this.backpressurePaused) {\n this.backpressurePaused = false;\n logger.info(\n { pending: pendingCount, max: this.backpressureConfig.maxPendingOps },\n 'Backpressure low water mark reached, resuming writes'\n );\n this.emitBackpressureEvent('backpressure:low', {\n pending: pendingCount,\n max: this.backpressureConfig.maxPendingOps,\n });\n this.emitBackpressureEvent('backpressure:resumed');\n\n // Resume all waiting writes\n const waiting = this.waitingForCapacity;\n this.waitingForCapacity = [];\n for (const resolve of waiting) {\n resolve();\n }\n }\n }\n }\n\n /**\n * Wait for capacity to become available (used by 'pause' strategy).\n */\n private async waitForCapacity(): Promise<void> {\n if (!this.backpressurePaused) {\n this.backpressurePaused = true;\n logger.warn('Backpressure paused - waiting for capacity');\n this.emitBackpressureEvent('backpressure:paused');\n }\n\n return new Promise<void>((resolve) => {\n this.waitingForCapacity.push(resolve);\n });\n }\n\n /**\n * Drop the oldest pending operation (used by 'drop-oldest' strategy).\n */\n private dropOldestOp(): void {\n // Find oldest unsynced operation by array order (oldest first)\n const oldestIndex = this.opLog.findIndex(op => !op.synced);\n\n if (oldestIndex !== -1) {\n const dropped = this.opLog[oldestIndex];\n this.opLog.splice(oldestIndex, 1);\n\n logger.warn(\n { opId: dropped.id, mapName: dropped.mapName, key: dropped.key },\n 'Dropped oldest pending operation due to backpressure'\n );\n\n this.emitBackpressureEvent('operation:dropped', {\n opId: dropped.id,\n mapName: dropped.mapName,\n opType: dropped.opType,\n key: dropped.key,\n });\n }\n }\n\n // ============================================\n // Write Concern Methods (Phase 5.01)\n // ============================================\n\n /**\n * Register a pending Write Concern promise for an operation.\n * The promise will be resolved when the server sends an ACK with the operation result.\n *\n * @param opId - Operation ID\n * @param timeout - Timeout in ms (default: 5000)\n * @returns Promise that resolves with the Write Concern result\n */\n public registerWriteConcernPromise(opId: string, timeout: number = 5000): Promise<any> {\n return new Promise((resolve, reject) => {\n const timeoutHandle = setTimeout(() => {\n this.pendingWriteConcernPromises.delete(opId);\n reject(new Error(`Write Concern timeout for operation ${opId}`));\n }, timeout);\n\n this.pendingWriteConcernPromises.set(opId, {\n resolve,\n reject,\n timeoutHandle,\n });\n });\n }\n\n /**\n * Resolve a pending Write Concern promise with the server result.\n *\n * @param opId - Operation ID\n * @param result - Result from server ACK\n */\n private resolveWriteConcernPromise(opId: string, result: any): void {\n const pending = this.pendingWriteConcernPromises.get(opId);\n if (pending) {\n if (pending.timeoutHandle) {\n clearTimeout(pending.timeoutHandle);\n }\n pending.resolve(result);\n this.pendingWriteConcernPromises.delete(opId);\n }\n }\n\n /**\n * Cancel all pending Write Concern promises (e.g., on disconnect).\n */\n private cancelAllWriteConcernPromises(error: Error): void {\n for (const [opId, pending] of this.pendingWriteConcernPromises.entries()) {\n if (pending.timeoutHandle) {\n clearTimeout(pending.timeoutHandle);\n }\n pending.reject(error);\n }\n this.pendingWriteConcernPromises.clear();\n }\n}\n","import pino from 'pino';\n\n// Simple check for browser environment\nconst isBrowser = typeof window !== 'undefined';\n\n// In browser, we might not have process.env, so we default to 'info'\n// Users can configure this via window.LOG_LEVEL or similar if needed,\n// but for now we stick to a safe default.\nconst logLevel = (typeof process !== 'undefined' && process.env && process.env.LOG_LEVEL) || 'info';\n\nexport const logger = pino({\n level: logLevel,\n transport: !isBrowser && (typeof process !== 'undefined' && process.env.NODE_ENV !== 'production') ? {\n target: 'pino-pretty',\n options: {\n colorize: true,\n translateTime: 'SYS:standard',\n ignore: 'pid,hostname'\n }\n } : undefined,\n browser: {\n asObject: true\n }\n});\n\nexport type Logger = typeof logger;\n\n","/**\n * Defines the possible states for the SyncEngine connection state machine.\n */\nexport enum SyncState {\n /** Initial state before any connection attempt */\n INITIAL = 'INITIAL',\n /** WebSocket connection is being established */\n CONNECTING = 'CONNECTING',\n /** Connected, waiting for authentication response */\n AUTHENTICATING = 'AUTHENTICATING',\n /** Authenticated, performing initial data sync */\n SYNCING = 'SYNCING',\n /** Fully connected and synchronized */\n CONNECTED = 'CONNECTED',\n /** Intentionally or unexpectedly disconnected */\n DISCONNECTED = 'DISCONNECTED',\n /** Waiting before retry (exponential backoff) */\n BACKOFF = 'BACKOFF',\n /** Fatal error requiring manual intervention or reset */\n ERROR = 'ERROR',\n}\n\n/**\n * Defines valid state transitions for the SyncEngine FSM.\n * Each key is a current state, and the value is an array of valid target states.\n */\nexport const VALID_TRANSITIONS: Record<SyncState, SyncState[]> = {\n [SyncState.INITIAL]: [SyncState.CONNECTING],\n [SyncState.CONNECTING]: [SyncState.AUTHENTICATING, SyncState.BACKOFF, SyncState.ERROR, SyncState.DISCONNECTED],\n [SyncState.AUTHENTICATING]: [SyncState.SYNCING, SyncState.BACKOFF, SyncState.ERROR, SyncState.DISCONNECTED],\n [SyncState.SYNCING]: [SyncState.CONNECTED, SyncState.BACKOFF, SyncState.ERROR, SyncState.DISCONNECTED],\n [SyncState.CONNECTED]: [SyncState.SYNCING, SyncState.DISCONNECTED, SyncState.BACKOFF],\n [SyncState.DISCONNECTED]: [SyncState.CONNECTING, SyncState.BACKOFF, SyncState.INITIAL],\n [SyncState.BACKOFF]: [SyncState.CONNECTING, SyncState.DISCONNECTED, SyncState.INITIAL],\n [SyncState.ERROR]: [SyncState.INITIAL],\n};\n\n/**\n * Helper function to check if a transition is valid\n */\nexport function isValidTransition(from: SyncState, to: SyncState): boolean {\n return VALID_TRANSITIONS[from]?.includes(to) ?? false;\n}\n","import { SyncState, isValidTransition } from './SyncState';\nimport { logger } from './utils/logger';\n\n/**\n * Event emitted when the state machine transitions between states.\n */\nexport interface StateChangeEvent {\n /** The state before the transition */\n from: SyncState;\n /** The state after the transition */\n to: SyncState;\n /** Unix timestamp (ms) when the transition occurred */\n timestamp: number;\n}\n\n/**\n * Listener callback for state change events.\n */\nexport type StateChangeListener = (event: StateChangeEvent) => void;\n\n/**\n * Configuration options for the state machine.\n */\nexport interface SyncStateMachineConfig {\n /** Maximum number of state transitions to keep in history (default: 50) */\n maxHistorySize?: number;\n}\n\nconst DEFAULT_MAX_HISTORY_SIZE = 50;\n\n/**\n * A finite state machine for managing SyncEngine connection states.\n *\n * Features:\n * - Validates all state transitions against allowed paths\n * - Emits events on state changes for observability\n * - Maintains a history of transitions for debugging\n * - Logs invalid transition attempts (graceful degradation)\n */\nexport class SyncStateMachine {\n private state: SyncState = SyncState.INITIAL;\n private readonly listeners: Set<StateChangeListener> = new Set();\n private history: StateChangeEvent[] = [];\n private readonly maxHistorySize: number;\n\n constructor(config: SyncStateMachineConfig = {}) {\n this.maxHistorySize = config.maxHistorySize ?? DEFAULT_MAX_HISTORY_SIZE;\n }\n\n /**\n * Attempt to transition to a new state.\n * @param to The target state\n * @returns true if the transition was valid and executed, false otherwise\n */\n transition(to: SyncState): boolean {\n const from = this.state;\n\n if (from === to) {\n // No-op: already in target state\n return true;\n }\n\n if (!isValidTransition(from, to)) {\n logger.warn(\n { from, to, currentHistory: this.getHistory(5) },\n `Invalid state transition attempted: ${from} → ${to}`\n );\n return false;\n }\n\n // Execute the transition\n this.state = to;\n\n const event: StateChangeEvent = {\n from,\n to,\n timestamp: Date.now(),\n };\n\n // Add to history\n this.history.push(event);\n if (this.history.length > this.maxHistorySize) {\n this.history.shift();\n }\n\n // Notify listeners\n for (const listener of this.listeners) {\n try {\n listener(event);\n } catch (err) {\n logger.error({ err, event }, 'State change listener threw an error');\n }\n }\n\n logger.debug({ from, to }, `State transition: ${from} → ${to}`);\n\n return true;\n }\n\n /**\n * Get the current state.\n */\n getState(): SyncState {\n return this.state;\n }\n\n /**\n * Check if a transition from the current state to the target state is valid.\n * @param to The target state to check\n */\n canTransition(to: SyncState): boolean {\n return this.state === to || isValidTransition(this.state, to);\n }\n\n /**\n * Subscribe to state change events.\n * @param listener Callback function to be called on each state change\n * @returns An unsubscribe function\n */\n onStateChange(listener: StateChangeListener): () => void {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n /**\n * Get the state transition history.\n * @param limit Maximum number of entries to return (default: all)\n * @returns Array of state change events, oldest first\n */\n getHistory(limit?: number): StateChangeEvent[] {\n if (limit === undefined || limit >= this.history.length) {\n return [...this.history];\n }\n return this.history.slice(-limit);\n }\n\n /**\n * Reset the state machine to INITIAL state.\n * This is a forced reset that bypasses normal transition validation.\n * Use for testing or hard resets after fatal errors.\n * @param clearHistory If true, also clears the transition history (default: true)\n */\n reset(clearHistory = true): void {\n const from = this.state;\n this.state = SyncState.INITIAL;\n\n if (clearHistory) {\n this.history = [];\n } else {\n // Record the reset as a transition\n const event: StateChangeEvent = {\n from,\n to: SyncState.INITIAL,\n timestamp: Date.now(),\n };\n this.history.push(event);\n if (this.history.length > this.maxHistorySize) {\n this.history.shift();\n }\n\n // Notify listeners\n for (const listener of this.listeners) {\n try {\n listener(event);\n } catch (err) {\n logger.error({ err, event }, 'State change listener threw an error during reset');\n }\n }\n }\n\n logger.info({ from }, 'State machine reset to INITIAL');\n }\n\n /**\n * Check if the state machine is in a \"connected\" state\n * (either SYNCING or CONNECTED)\n */\n isConnected(): boolean {\n return this.state === SyncState.CONNECTED || this.state === SyncState.SYNCING;\n }\n\n /**\n * Check if the state machine is in a state where operations can be sent\n * (authenticated and connected)\n */\n isReady(): boolean {\n return this.state === SyncState.CONNECTED;\n }\n\n /**\n * Check if the state machine is currently attempting to connect\n */\n isConnecting(): boolean {\n return (\n this.state === SyncState.CONNECTING ||\n this.state === SyncState.AUTHENTICATING ||\n this.state === SyncState.SYNCING\n );\n }\n}\n","/**\n * Error thrown when backpressure limit is reached and strategy is 'throw'.\n */\nexport class BackpressureError extends Error {\n public readonly name = 'BackpressureError';\n\n constructor(\n public readonly pendingCount: number,\n public readonly maxPending: number\n ) {\n super(\n `Backpressure limit reached: ${pendingCount}/${maxPending} pending operations. ` +\n `Wait for acknowledgments or increase maxPendingOps.`\n );\n\n // Maintains proper stack trace for where error was thrown (only available on V8)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, BackpressureError);\n }\n }\n}\n","/**\n * Backpressure strategy when maxPendingOps is reached.\n */\nexport type BackpressureStrategy = 'pause' | 'throw' | 'drop-oldest';\n\n/**\n * Configuration for backpressure control on SyncEngine.\n */\nexport interface BackpressureConfig {\n /**\n * Maximum number of operations waiting for server acknowledgment.\n * When this limit is reached, the configured strategy will be applied.\n * @default 1000\n */\n maxPendingOps: number;\n\n /**\n * Strategy when maxPendingOps is reached:\n * - 'pause': Wait for capacity (returns Promise that resolves when space available)\n * - 'throw': Throw BackpressureError immediately\n * - 'drop-oldest': Remove oldest pending op to make room (data loss!)\n * @default 'pause'\n */\n strategy: BackpressureStrategy;\n\n /**\n * High water mark (percentage of maxPendingOps).\n * Emit 'backpressure:high' event when reached.\n * Value should be between 0 and 1.\n * @default 0.8 (80%)\n */\n highWaterMark: number;\n\n /**\n * Low water mark (percentage of maxPendingOps).\n * Resume paused writes and emit 'backpressure:low' when pending ops drop below this.\n * Value should be between 0 and 1.\n * @default 0.5 (50%)\n */\n lowWaterMark: number;\n}\n\n/**\n * Default backpressure configuration.\n */\nexport const DEFAULT_BACKPRESSURE_CONFIG: BackpressureConfig = {\n maxPendingOps: 1000,\n strategy: 'pause',\n highWaterMark: 0.8,\n lowWaterMark: 0.5,\n};\n\n/**\n * Status of backpressure mechanism.\n */\nexport interface BackpressureStatus {\n /** Current number of pending (unacknowledged) operations */\n pending: number;\n /** Maximum allowed pending operations */\n max: number;\n /** Percentage of capacity used (0-1) */\n percentage: number;\n /** Whether writes are currently paused due to backpressure */\n isPaused: boolean;\n /** Current backpressure strategy */\n strategy: BackpressureStrategy;\n}\n\n/**\n * Event data for backpressure:high and backpressure:low events.\n */\nexport interface BackpressureThresholdEvent {\n pending: number;\n max: number;\n}\n\n/**\n * Event data for operation:dropped event.\n */\nexport interface OperationDroppedEvent {\n opId: string;\n mapName: string;\n opType: string;\n key: string;\n}\n","import { LWWMap, ORMap } from '@topgunbuild/core';\nimport type { ORMapRecord, LWWRecord } from '@topgunbuild/core';\nimport type { IStorageAdapter } from './IStorageAdapter';\nimport { SyncEngine } from './SyncEngine';\nimport type { BackoffConfig } from './SyncEngine';\nimport { QueryHandle } from './QueryHandle';\nimport type { QueryFilter } from './QueryHandle';\nimport { DistributedLock } from './DistributedLock';\nimport { TopicHandle } from './TopicHandle';\nimport { logger } from './utils/logger';\nimport { SyncState } from './SyncState';\nimport type { StateChangeEvent } from './SyncStateMachine';\nimport type {\n BackpressureConfig,\n BackpressureStatus,\n BackpressureThresholdEvent,\n OperationDroppedEvent,\n} from './BackpressureConfig';\n\nexport class TopGunClient {\n private readonly nodeId: string;\n private readonly syncEngine: SyncEngine;\n private readonly maps: Map<string, LWWMap<any, any> | ORMap<any, any>> = new Map();\n private readonly storageAdapter: IStorageAdapter;\n private readonly topicHandles: Map<string, TopicHandle> = new Map();\n\n constructor(config: {\n nodeId?: string;\n serverUrl: string;\n storage: IStorageAdapter;\n backoff?: Partial<BackoffConfig>;\n backpressure?: Partial<BackpressureConfig>;\n }) {\n this.nodeId = config.nodeId || crypto.randomUUID();\n this.storageAdapter = config.storage;\n\n const syncEngineConfig = {\n nodeId: this.nodeId,\n serverUrl: config.serverUrl,\n storageAdapter: this.storageAdapter,\n backoff: config.backoff,\n backpressure: config.backpressure,\n };\n this.syncEngine = new SyncEngine(syncEngineConfig);\n }\n\n public async start(): Promise<void> {\n await this.storageAdapter.initialize('topgun_offline_db');\n // this.syncEngine.start();\n }\n\n public setAuthToken(token: string): void {\n this.syncEngine.setAuthToken(token);\n }\n\n public setAuthTokenProvider(provider: () => Promise<string | null>): void {\n this.syncEngine.setTokenProvider(provider);\n }\n\n /**\n * Creates a live query subscription for a map.\n */\n public query<T>(mapName: string, filter: QueryFilter): QueryHandle<T> {\n return new QueryHandle<T>(this.syncEngine, mapName, filter);\n }\n\n /**\n * Retrieves a distributed lock instance.\n * @param name The name of the lock.\n */\n public getLock(name: string): DistributedLock {\n return new DistributedLock(this.syncEngine, name);\n }\n\n /**\n * Retrieves a topic handle for Pub/Sub messaging.\n * @param name The name of the topic.\n */\n public topic(name: string): TopicHandle {\n if (!this.topicHandles.has(name)) {\n this.topicHandles.set(name, new TopicHandle(this.syncEngine, name));\n }\n return this.topicHandles.get(name)!;\n }\n\n /**\n * Retrieves an LWWMap instance. If the map doesn't exist locally, it's created.\n * @param name The name of the map.\n * @returns An LWWMap instance.\n */\n public getMap<K, V>(name: string): LWWMap<K, V> {\n if (this.maps.has(name)) {\n const map = this.maps.get(name);\n if (map instanceof LWWMap) {\n return map as LWWMap<K, V>;\n }\n throw new Error(`Map ${name} exists but is not an LWWMap`);\n }\n\n const lwwMap = new LWWMap<K, V>(this.syncEngine.getHLC());\n this.maps.set(name, lwwMap);\n this.syncEngine.registerMap(name, lwwMap);\n\n // Restore state from storage asynchronously\n this.storageAdapter.getAllKeys().then(async (keys) => {\n const mapPrefix = `${name}:`;\n for (const fullKey of keys) {\n if (fullKey.startsWith(mapPrefix)) {\n const record = await this.storageAdapter.get(fullKey);\n if (record && (record as LWWRecord<V>).timestamp && !(record as any).tag) {\n // Strip prefix to get actual key\n const key = fullKey.substring(mapPrefix.length) as unknown as K;\n // Merge into in-memory map without triggering new ops\n lwwMap.merge(key, record as LWWRecord<V>);\n }\n }\n }\n }).catch(err => logger.error({ err }, 'Failed to restore keys from storage'));\n\n // Wrap LWWMap with IMap interface logic\n const originalSet = lwwMap.set.bind(lwwMap);\n lwwMap.set = (key: K, value: V, ttlMs?: number) => {\n const record = originalSet(key, value, ttlMs);\n this.storageAdapter.put(`${name}:${key}`, record).catch(err => logger.error({ err }, 'Failed to put record to storage'));\n this.syncEngine.recordOperation(name, 'PUT', String(key), { record, timestamp: record.timestamp }).catch(err => logger.error({ err }, 'Failed to record PUT op'));\n return record;\n };\n\n const originalRemove = lwwMap.remove.bind(lwwMap);\n lwwMap.remove = (key: K) => {\n const tombstone = originalRemove(key);\n this.storageAdapter.put(`${name}:${key}`, tombstone).catch(err => logger.error({ err }, 'Failed to put tombstone to storage'));\n this.syncEngine.recordOperation(name, 'REMOVE', String(key), { record: tombstone, timestamp: tombstone.timestamp }).catch(err => logger.error({ err }, 'Failed to record REMOVE op'));\n return tombstone;\n };\n\n return lwwMap;\n }\n\n /**\n * Retrieves an ORMap instance. If the map doesn't exist locally, it's created.\n * @param name The name of the map.\n * @returns An ORMap instance.\n */\n public getORMap<K, V>(name: string): ORMap<K, V> {\n if (this.maps.has(name)) {\n const map = this.maps.get(name);\n if (map instanceof ORMap) {\n return map as ORMap<K, V>;\n }\n throw new Error(`Map ${name} exists but is not an ORMap`);\n }\n\n const orMap = new ORMap<K, V>(this.syncEngine.getHLC());\n this.maps.set(name, orMap);\n this.syncEngine.registerMap(name, orMap);\n\n // Restore state from storage\n this.restoreORMap(name, orMap);\n\n // Wrap ORMap methods to record operations\n const originalAdd = orMap.add.bind(orMap);\n orMap.add = (key: K, value: V, ttlMs?: number) => {\n const record = originalAdd(key, value, ttlMs);\n \n // Persist records\n this.persistORMapKey(name, orMap, key);\n\n this.syncEngine.recordOperation(name, 'OR_ADD', String(key), { orRecord: record, timestamp: record.timestamp }).catch(err => logger.error({ err }, 'Failed to record OR_ADD op'));\n return record;\n };\n\n const originalRemove = orMap.remove.bind(orMap);\n orMap.remove = (key: K, value: V) => {\n const tombstones = originalRemove(key, value);\n const timestamp = this.syncEngine.getHLC().now(); \n \n // Update storage for the key (items removed)\n this.persistORMapKey(name, orMap, key);\n // Update storage for tombstones\n this.persistORMapTombstones(name, orMap);\n\n for (const tag of tombstones) {\n this.syncEngine.recordOperation(name, 'OR_REMOVE', String(key), { orTag: tag, timestamp }).catch(err => logger.error({ err }, 'Failed to record OR_REMOVE op'));\n }\n return tombstones;\n };\n\n return orMap;\n }\n\n private async restoreORMap<K, V>(name: string, orMap: ORMap<K, V>) {\n try {\n // 1. Restore Tombstones\n const tombstoneKey = `__sys__:${name}:tombstones`;\n const tombstones = await this.storageAdapter.getMeta(tombstoneKey);\n if (Array.isArray(tombstones)) {\n for (const tag of tombstones) {\n orMap.applyTombstone(tag);\n }\n }\n\n // 2. Restore Items\n const keys = await this.storageAdapter.getAllKeys();\n const mapPrefix = `${name}:`;\n for (const fullKey of keys) {\n if (fullKey.startsWith(mapPrefix)) {\n const keyPart = fullKey.substring(mapPrefix.length);\n \n const data = await this.storageAdapter.get(fullKey);\n if (Array.isArray(data)) {\n // It's likely an ORMap value list (Array of ORMapRecord)\n const records = data as ORMapRecord<V>[];\n const key = keyPart as unknown as K;\n \n for (const record of records) {\n orMap.apply(key, record);\n }\n }\n }\n }\n } catch (e) {\n logger.error({ mapName: name, err: e }, 'Failed to restore ORMap');\n }\n }\n\n private async persistORMapKey<K, V>(mapName: string, orMap: ORMap<K, V>, key: K) {\n const records = orMap.getRecords(key);\n if (records.length > 0) {\n await this.storageAdapter.put(`${mapName}:${key}`, records);\n } else {\n await this.storageAdapter.remove(`${mapName}:${key}`);\n }\n }\n \n private async persistORMapTombstones<K, V>(mapName: string, orMap: ORMap<K, V>) {\n const tombstoneKey = `__sys__:${mapName}:tombstones`;\n const tombstones = orMap.getTombstones();\n await this.storageAdapter.setMeta(tombstoneKey, tombstones);\n }\n\n /**\n * Closes the client, disconnecting from the server and cleaning up resources.\n */\n public close(): void {\n this.syncEngine.close();\n }\n\n // ============================================\n // Connection State API\n // ============================================\n\n /**\n * Get the current connection state\n */\n public getConnectionState(): SyncState {\n return this.syncEngine.getConnectionState();\n }\n\n /**\n * Subscribe to connection state changes\n * @param listener Callback function called on each state change\n * @returns Unsubscribe function\n */\n public onConnectionStateChange(listener: (event: StateChangeEvent) => void): () => void {\n return this.syncEngine.onConnectionStateChange(listener);\n }\n\n /**\n * Get state machine history for debugging\n * @param limit Maximum number of entries to return\n */\n public getStateHistory(limit?: number): StateChangeEvent[] {\n return this.syncEngine.getStateHistory(limit);\n }\n\n /**\n * Reset the connection and state machine.\n * Use after fatal errors to start fresh.\n */\n public resetConnection(): void {\n this.syncEngine.resetConnection();\n }\n\n // ============================================\n // Backpressure API\n // ============================================\n\n /**\n * Get the current number of pending (unacknowledged) operations.\n */\n public getPendingOpsCount(): number {\n return this.syncEngine.getPendingOpsCount();\n }\n\n /**\n * Get the current backpressure status.\n */\n public getBackpressureStatus(): BackpressureStatus {\n return this.syncEngine.getBackpressureStatus();\n }\n\n /**\n * Returns true if writes are currently paused due to backpressure.\n */\n public isBackpressurePaused(): boolean {\n return this.syncEngine.isBackpressurePaused();\n }\n\n /**\n * Subscribe to backpressure events.\n *\n * Available events:\n * - 'backpressure:high': Emitted when pending ops reach high water mark\n * - 'backpressure:low': Emitted when pending ops drop below low water mark\n * - 'backpressure:paused': Emitted when writes are paused (pause strategy)\n * - 'backpressure:resumed': Emitted when writes resume after being paused\n * - 'operation:dropped': Emitted when an operation is dropped (drop-oldest strategy)\n *\n * @param event Event name\n * @param listener Callback function\n * @returns Unsubscribe function\n *\n * @example\n * ```typescript\n * client.onBackpressure('backpressure:high', ({ pending, max }) => {\n * console.warn(`Warning: ${pending}/${max} pending ops`);\n * });\n *\n * client.onBackpressure('backpressure:paused', () => {\n * showLoadingSpinner();\n * });\n *\n * client.onBackpressure('backpressure:resumed', () => {\n * hideLoadingSpinner();\n * });\n * ```\n */\n public onBackpressure(\n event: 'backpressure:high' | 'backpressure:low' | 'backpressure:paused' | 'backpressure:resumed' | 'operation:dropped',\n listener: (data?: BackpressureThresholdEvent | OperationDroppedEvent) => void\n ): () => void {\n return this.syncEngine.onBackpressure(event, listener);\n }\n}\n","import { SyncEngine } from './SyncEngine';\nimport type { PredicateNode } from '@topgunbuild/core';\n\nexport interface QueryFilter {\n where?: Record<string, any>;\n predicate?: PredicateNode;\n sort?: Record<string, 'asc' | 'desc'>;\n limit?: number;\n offset?: number;\n}\n\n/** Source of query results for proper handling of race conditions */\nexport type QueryResultSource = 'local' | 'server';\n\n/** Result item with _key field for client-side lookups */\nexport type QueryResultItem<T> = T & { _key: string };\n\nexport class QueryHandle<T> {\n public readonly id: string;\n private syncEngine: SyncEngine;\n private mapName: string;\n private filter: QueryFilter;\n private listeners: Set<(results: QueryResultItem<T>[]) => void> = new Set();\n private currentResults: Map<string, T> = new Map();\n\n constructor(syncEngine: SyncEngine, mapName: string, filter: QueryFilter = {}) {\n this.id = crypto.randomUUID();\n this.syncEngine = syncEngine;\n this.mapName = mapName;\n this.filter = filter;\n }\n\n public subscribe(callback: (results: QueryResultItem<T>[]) => void): () => void {\n this.listeners.add(callback);\n \n // If this is the first listener, activate subscription\n if (this.listeners.size === 1) {\n this.syncEngine.subscribeToQuery(this);\n } else {\n // Immediately invoke with cached results\n callback(this.getSortedResults());\n }\n \n // [FIX]: Attempt to load local results immediately if available\n // This ensures that if data is already in storage but sync hasn't happened,\n // we still show something.\n this.loadInitialLocalData().then(data => {\n // If we haven't received server results yet (currentResults empty),\n // and we have local data OR it's just the initial load, we should notify.\n // Even if data is empty, we might want to tell the subscriber \"nothing here yet\".\n if (this.currentResults.size === 0) {\n this.onResult(data, 'local');\n }\n });\n\n return () => {\n this.listeners.delete(callback);\n if (this.listeners.size === 0) {\n this.syncEngine.unsubscribeFromQuery(this.id);\n }\n };\n }\n\n private async loadInitialLocalData() {\n // This requires SyncEngine to expose a method to query local storage\n // For now, we can't easily reach storageAdapter directly from here without leaking abstraction.\n // A better approach is for SyncEngine.subscribeToQuery to trigger a local load.\n return this.syncEngine.runLocalQuery(this.mapName, this.filter);\n }\n\n // Track if we've received authoritative server response\n private hasReceivedServerData: boolean = false;\n\n /**\n * Called by SyncEngine when server sends initial results or by local storage load.\n * Uses merge strategy instead of clear to prevent UI flickering.\n *\n * @param items - Array of key-value pairs\n * @param source - 'local' for IndexedDB data, 'server' for QUERY_RESP from server\n *\n * Race condition protection:\n * - Empty server responses are ignored until we receive non-empty server data\n * - This prevents clearing local data when server hasn't loaded from storage yet\n * - Works with any async storage adapter (PostgreSQL, SQLite, Redis, etc.)\n */\n public onResult(items: { key: string, value: T }[], source: QueryResultSource = 'server') {\n console.log(`[QueryHandle:${this.mapName}] onResult called with ${items.length} items`, {\n source,\n currentResultsCount: this.currentResults.size,\n newItemKeys: items.map(i => i.key),\n hasReceivedServerData: this.hasReceivedServerData\n });\n\n // [FIX] Race condition protection for any async storage adapter:\n // If server sends empty QUERY_RESP before loading data from storage,\n // we ignore it to prevent clearing valid local data.\n // This is safe because:\n // 1. If server truly has no data, next non-empty response will clear local-only items\n // 2. If server is still loading, we preserve local data until real data arrives\n if (source === 'server' && items.length === 0 && !this.hasReceivedServerData) {\n console.log(`[QueryHandle:${this.mapName}] Ignoring empty server response - waiting for authoritative data`);\n return;\n }\n\n // Mark that we've received authoritative server data (non-empty from server)\n if (source === 'server' && items.length > 0) {\n this.hasReceivedServerData = true;\n }\n\n const newKeys = new Set(items.map(i => i.key));\n\n // Remove only keys that are not in the new results\n const removedKeys: string[] = [];\n for (const key of this.currentResults.keys()) {\n if (!newKeys.has(key)) {\n removedKeys.push(key);\n this.currentResults.delete(key);\n }\n }\n if (removedKeys.length > 0) {\n console.log(`[QueryHandle:${this.mapName}] Removed ${removedKeys.length} keys:`, removedKeys);\n }\n\n // Add/update new results\n for (const item of items) {\n this.currentResults.set(item.key, item.value);\n }\n console.log(`[QueryHandle:${this.mapName}] After merge: ${this.currentResults.size} results`);\n this.notify();\n }\n\n /**\n * Called by SyncEngine when server sends a live update\n */\n public onUpdate(key: string, value: T | null) {\n if (value === null) {\n this.currentResults.delete(key);\n } else {\n this.currentResults.set(key, value);\n }\n this.notify();\n }\n\n private notify() {\n const results = this.getSortedResults();\n for (const listener of this.listeners) {\n listener(results);\n }\n }\n\n private getSortedResults(): (T & { _key: string })[] {\n // Include _key in each result for client-side matching/lookup\n const results = Array.from(this.currentResults.entries()).map(\n ([key, value]) => ({ ...(value as object), _key: key } as T & { _key: string })\n );\n\n if (this.filter.sort) {\n results.sort((a: any, b: any) => {\n for (const [field, direction] of Object.entries(this.filter.sort!)) {\n const valA = a[field];\n const valB = b[field];\n\n if (valA < valB) return direction === 'asc' ? -1 : 1;\n if (valA > valB) return direction === 'asc' ? 1 : -1;\n }\n return 0;\n });\n }\n\n return results;\n }\n\n public getFilter(): QueryFilter {\n return this.filter;\n }\n\n public getMapName(): string {\n return this.mapName;\n }\n}\n","import { SyncEngine } from './SyncEngine';\n\nexport interface ILock {\n lock(ttl?: number): Promise<boolean>;\n unlock(): Promise<void>;\n isLocked(): boolean;\n}\n\nexport class DistributedLock implements ILock {\n private syncEngine: SyncEngine;\n private name: string;\n private fencingToken: number | null = null;\n private _isLocked: boolean = false;\n\n constructor(syncEngine: SyncEngine, name: string) {\n this.syncEngine = syncEngine;\n this.name = name;\n }\n\n public async lock(ttl: number = 10000): Promise<boolean> {\n const requestId = crypto.randomUUID();\n try {\n const result = await this.syncEngine.requestLock(this.name, requestId, ttl);\n this.fencingToken = result.fencingToken;\n this._isLocked = true;\n return true;\n } catch (e) {\n return false;\n }\n }\n\n public async unlock(): Promise<void> {\n if (!this._isLocked || this.fencingToken === null) return;\n \n const requestId = crypto.randomUUID();\n try {\n await this.syncEngine.releaseLock(this.name, requestId, this.fencingToken);\n } finally {\n this._isLocked = false;\n this.fencingToken = null;\n }\n }\n\n public isLocked(): boolean {\n return this._isLocked;\n }\n}\n\n","import { SyncEngine } from './SyncEngine';\n\nexport type TopicCallback = (data: any, context: { timestamp: number; publisherId?: string }) => void;\n\nexport class TopicHandle {\n private engine: SyncEngine;\n private topic: string;\n private listeners: Set<TopicCallback> = new Set();\n\n constructor(engine: SyncEngine, topic: string) {\n this.engine = engine;\n this.topic = topic;\n }\n\n public get id(): string {\n return this.topic;\n }\n\n /**\n * Publish a message to the topic\n */\n public publish(data: any) {\n this.engine.publishTopic(this.topic, data);\n }\n\n /**\n * Subscribe to the topic\n */\n public subscribe(callback: TopicCallback) {\n if (this.listeners.size === 0) {\n this.engine.subscribeToTopic(this.topic, this);\n }\n this.listeners.add(callback);\n return () => this.unsubscribe(callback);\n }\n\n private unsubscribe(callback: TopicCallback) {\n this.listeners.delete(callback);\n if (this.listeners.size === 0) {\n this.engine.unsubscribeFromTopic(this.topic);\n }\n }\n\n /**\n * Called by SyncEngine when a message is received\n */\n public onMessage(data: any, context: { timestamp: number; publisherId?: string }) {\n this.listeners.forEach(cb => {\n try {\n cb(data, context);\n } catch (e) {\n console.error('Error in topic listener', e);\n }\n });\n }\n}\n\n","import type { LWWRecord, ORMapRecord } from '@topgunbuild/core';\nimport type { IStorageAdapter, OpLogEntry } from '../IStorageAdapter';\nimport { openDB } from 'idb';\nimport type { IDBPDatabase } from 'idb';\n\n/**\n * Represents an operation queued before IndexedDB is ready.\n */\ninterface QueuedOperation {\n type: 'put' | 'remove' | 'setMeta' | 'appendOpLog' | 'markOpsSynced' | 'batchPut';\n args: any[];\n resolve: (value: any) => void;\n reject: (error: any) => void;\n}\n\n/**\n * Non-blocking IndexedDB adapter that allows immediate use before initialization completes.\n *\n * Operations are queued in memory and replayed once IndexedDB is ready.\n * This enables true \"memory-first\" behavior where the UI can render immediately\n * without waiting for IndexedDB to initialize (which can take 50-500ms).\n */\nexport class IDBAdapter implements IStorageAdapter {\n private dbPromise?: Promise<IDBPDatabase>;\n private db?: IDBPDatabase;\n private isReady = false;\n private operationQueue: QueuedOperation[] = [];\n private initPromise?: Promise<void>;\n\n /**\n * Initializes IndexedDB in the background.\n * Returns immediately - does NOT block on IndexedDB being ready.\n * Use waitForReady() if you need to ensure initialization is complete.\n */\n async initialize(dbName: string): Promise<void> {\n // Start initialization but don't await it\n this.initPromise = this.initializeInternal(dbName);\n // Return immediately - non-blocking!\n }\n\n /**\n * Internal initialization that actually opens IndexedDB.\n */\n private async initializeInternal(dbName: string): Promise<void> {\n try {\n this.dbPromise = openDB(dbName, 2, {\n upgrade(db) {\n if (!db.objectStoreNames.contains('kv_store')) {\n db.createObjectStore('kv_store', { keyPath: 'key' });\n }\n if (!db.objectStoreNames.contains('op_log')) {\n db.createObjectStore('op_log', { keyPath: 'id', autoIncrement: true });\n }\n if (!db.objectStoreNames.contains('meta_store')) {\n db.createObjectStore('meta_store', { keyPath: 'key' });\n }\n },\n });\n\n this.db = await this.dbPromise;\n this.isReady = true;\n\n // Replay queued operations\n await this.flushQueue();\n } catch (error) {\n // Re-throw to allow error handling\n throw error;\n }\n }\n\n /**\n * Waits for IndexedDB to be fully initialized.\n * Call this if you need guaranteed persistence before proceeding.\n */\n async waitForReady(): Promise<void> {\n if (this.isReady) return;\n if (this.initPromise) {\n await this.initPromise;\n }\n }\n\n /**\n * Flushes all queued operations once IndexedDB is ready.\n */\n private async flushQueue(): Promise<void> {\n const queue = this.operationQueue;\n this.operationQueue = [];\n\n for (const op of queue) {\n try {\n let result: any;\n switch (op.type) {\n case 'put':\n result = await this.putInternal(op.args[0], op.args[1]);\n break;\n case 'remove':\n result = await this.removeInternal(op.args[0]);\n break;\n case 'setMeta':\n result = await this.setMetaInternal(op.args[0], op.args[1]);\n break;\n case 'appendOpLog':\n result = await this.appendOpLogInternal(op.args[0]);\n break;\n case 'markOpsSynced':\n result = await this.markOpsSyncedInternal(op.args[0]);\n break;\n case 'batchPut':\n result = await this.batchPutInternal(op.args[0]);\n break;\n }\n op.resolve(result);\n } catch (error) {\n op.reject(error);\n }\n }\n }\n\n /**\n * Queues an operation if not ready, or executes immediately if ready.\n */\n private queueOrExecute<T>(\n type: QueuedOperation['type'],\n args: any[],\n executor: () => Promise<T>\n ): Promise<T> {\n if (this.isReady) {\n return executor();\n }\n\n return new Promise<T>((resolve, reject) => {\n this.operationQueue.push({ type, args, resolve, reject });\n });\n }\n\n async close(): Promise<void> {\n if (this.db) {\n this.db.close();\n }\n }\n\n // ============================================\n // Read Operations - Wait for ready\n // ============================================\n\n async get<V>(key: string): Promise<LWWRecord<V> | ORMapRecord<V>[] | any | undefined> {\n // Read operations must wait for DB to be ready\n await this.waitForReady();\n const result = await this.db?.get('kv_store', key);\n return result?.value;\n }\n\n async getMeta(key: string): Promise<any> {\n await this.waitForReady();\n const result = await this.db?.get('meta_store', key);\n return result?.value;\n }\n\n async getPendingOps(): Promise<OpLogEntry[]> {\n await this.waitForReady();\n const all = await this.db?.getAll('op_log');\n return all?.filter((op: any) => op.synced === 0) || [];\n }\n\n async getAllKeys(): Promise<string[]> {\n await this.waitForReady();\n return (await this.db?.getAllKeys('kv_store')) as string[] || [];\n }\n\n // ============================================\n // Write Operations - Queue if not ready\n // ============================================\n\n async put(key: string, value: any): Promise<void> {\n return this.queueOrExecute('put', [key, value], () => this.putInternal(key, value));\n }\n\n private async putInternal(key: string, value: any): Promise<void> {\n await this.db?.put('kv_store', { key, value });\n }\n\n async remove(key: string): Promise<void> {\n return this.queueOrExecute('remove', [key], () => this.removeInternal(key));\n }\n\n private async removeInternal(key: string): Promise<void> {\n await this.db?.delete('kv_store', key);\n }\n\n async setMeta(key: string, value: any): Promise<void> {\n return this.queueOrExecute('setMeta', [key, value], () => this.setMetaInternal(key, value));\n }\n\n private async setMetaInternal(key: string, value: any): Promise<void> {\n await this.db?.put('meta_store', { key, value });\n }\n\n async batchPut(entries: Map<string, any>): Promise<void> {\n return this.queueOrExecute('batchPut', [entries], () => this.batchPutInternal(entries));\n }\n\n private async batchPutInternal(entries: Map<string, any>): Promise<void> {\n const tx = this.db?.transaction('kv_store', 'readwrite');\n if (!tx) return;\n\n await Promise.all(\n Array.from(entries.entries()).map(([key, value]) =>\n tx.store.put({ key, value })\n )\n );\n await tx.done;\n }\n\n async appendOpLog(entry: any): Promise<number> {\n return this.queueOrExecute('appendOpLog', [entry], () => this.appendOpLogInternal(entry));\n }\n\n private async appendOpLogInternal(entry: any): Promise<number> {\n const entryToSave = { ...entry, synced: 0 };\n return await this.db?.add('op_log', entryToSave) as number;\n }\n\n async markOpsSynced(lastId: number): Promise<void> {\n return this.queueOrExecute('markOpsSynced', [lastId], () => this.markOpsSyncedInternal(lastId));\n }\n\n private async markOpsSyncedInternal(lastId: number): Promise<void> {\n const tx = this.db?.transaction('op_log', 'readwrite');\n if (!tx) return;\n\n let cursor = await tx.store.openCursor();\n while (cursor) {\n if (cursor.value.id <= lastId) {\n const update = { ...cursor.value, synced: 1 };\n await cursor.update(update);\n }\n cursor = await cursor.continue();\n }\n await tx.done;\n }\n}\n\n","import { TopGunClient } from './TopGunClient';\nimport { IDBAdapter } from './adapters/IDBAdapter';\nimport type { IStorageAdapter } from './IStorageAdapter';\nimport { LWWMap } from '@topgunbuild/core';\nimport type { LWWRecord } from '@topgunbuild/core';\n\nexport interface TopGunConfig {\n sync: string;\n persist: 'indexeddb' | IStorageAdapter;\n nodeId?: string;\n}\n\n// Generic schema type\nexport type TopGunSchema = Record<string, any>;\n\nconst handler: ProxyHandler<TopGun<any>> = {\n get(target, prop, receiver) {\n if (prop in target || typeof prop === 'symbol') {\n return Reflect.get(target, prop, receiver);\n }\n if (typeof prop === 'string') {\n return target.collection(prop);\n }\n return undefined;\n }\n};\n\nexport class TopGun<T extends TopGunSchema = any> {\n private client: TopGunClient;\n private initPromise: Promise<void>;\n \n // Allow property access for collections based on Schema T\n [key: string]: any;\n\n constructor(config: TopGunConfig) {\n let storage: IStorageAdapter;\n\n if (config.persist === 'indexeddb') {\n storage = new IDBAdapter();\n } else if (typeof config.persist === 'object') {\n storage = config.persist;\n } else {\n throw new Error(`Unsupported persist option: ${config.persist}`);\n }\n\n this.client = new TopGunClient({\n serverUrl: config.sync,\n storage,\n nodeId: config.nodeId\n });\n\n // Start client initialization (non-blocking)\n // The IDBAdapter now initializes in the background and queues operations\n this.initPromise = this.client.start().catch(err => {\n console.error('Failed to start TopGun client:', err);\n throw err;\n });\n\n return new Proxy(this, handler);\n }\n\n /**\n * Waits for the storage adapter to be fully initialized.\n * This is optional - you can start using the database immediately.\n * Operations are queued in memory and persisted once IndexedDB is ready.\n */\n public async waitForReady(): Promise<void> {\n await this.initPromise;\n }\n\n public collection<K extends keyof T & string>(name: K): CollectionWrapper<T[K]> {\n // Explicitly type the map\n const map = this.client.getMap<string, T[K]>(name);\n return new CollectionWrapper<T[K]>(map);\n }\n}\n\nexport class CollectionWrapper<ItemType = any> {\n private map: LWWMap<string, ItemType>;\n\n constructor(map: LWWMap<string, ItemType>) {\n this.map = map;\n }\n\n /**\n * Sets an item in the collection. \n * The item MUST have an 'id' or '_id' field.\n */\n async set(value: ItemType): Promise<ItemType> {\n const v = value as any;\n const key = v.id || v._id;\n if (!key) {\n throw new Error('Object must have an \"id\" or \"_id\" property to be saved in a collection.');\n }\n \n // LWWMap.set is synchronous in updating memory and queueing ops,\n // but we return a Promise to match typical async DB APIs.\n this.map.set(key, value);\n return Promise.resolve(value); \n }\n \n /**\n * Retrieves an item by ID.\n * Returns the value directly (unwrapped from CRDT record).\n */\n get(key: string): ItemType | undefined {\n return this.map.get(key);\n }\n\n /**\n * Get the raw LWWRecord (including metadata like timestamp).\n */\n getRecord(key: string): LWWRecord<ItemType> | undefined {\n return this.map.getRecord(key);\n }\n\n // Expose raw map if needed for advanced usage\n get raw() {\n return this.map;\n }\n}\n","import { serialize, deserialize } from '@topgunbuild/core';\n\nexport class EncryptionManager {\n private static ALGORITHM = 'AES-GCM';\n private static IV_LENGTH = 12;\n\n /**\n * Encrypts data using AES-GCM.\n * Serializes data to MessagePack before encryption.\n */\n static async encrypt(key: CryptoKey, data: any): Promise<{ iv: Uint8Array; data: Uint8Array }> {\n const encoded = serialize(data);\n\n // Generate IV\n const iv = window.crypto.getRandomValues(new Uint8Array(EncryptionManager.IV_LENGTH));\n\n // Encrypt\n const ciphertext = await window.crypto.subtle.encrypt(\n {\n name: EncryptionManager.ALGORITHM,\n iv: iv,\n },\n key,\n encoded as any\n );\n\n return {\n iv,\n data: new Uint8Array(ciphertext),\n };\n }\n\n /**\n * Decrypts AES-GCM encrypted data.\n * Deserializes from MessagePack after decryption.\n */\n static async decrypt(key: CryptoKey, record: { iv: Uint8Array; data: Uint8Array }): Promise<any> {\n try {\n const plaintextBuffer = await window.crypto.subtle.decrypt(\n {\n name: EncryptionManager.ALGORITHM,\n iv: record.iv as any,\n },\n key,\n record.data as any\n );\n\n return deserialize(new Uint8Array(plaintextBuffer));\n } catch (err) {\n console.error('Decryption failed', err);\n throw new Error('Failed to decrypt data: ' + err);\n }\n }\n}\n","import { IStorageAdapter, OpLogEntry } from '../IStorageAdapter';\nimport { EncryptionManager } from '../crypto/EncryptionManager';\n\n/**\n * Wraps an underlying storage adapter and encrypts data at rest using AES-GCM.\n */\nexport class EncryptedStorageAdapter implements IStorageAdapter {\n constructor(\n private wrapped: IStorageAdapter,\n private key: CryptoKey\n ) { }\n\n async initialize(dbName: string): Promise<void> {\n return this.wrapped.initialize(dbName);\n }\n\n async close(): Promise<void> {\n return this.wrapped.close();\n }\n\n // --- KV Operations ---\n\n async get<V>(key: string): Promise<V | any | undefined> {\n const raw = await this.wrapped.get<any>(key);\n\n if (!raw) {\n return undefined;\n }\n\n // Check if it looks like an encrypted record\n // We expect { iv: Uint8Array, data: Uint8Array }\n // Note: In a real app we might want a stricter check or a version tag.\n if (this.isEncryptedRecord(raw)) {\n try {\n return await EncryptionManager.decrypt(this.key, raw);\n } catch (e) {\n // Fallback for migration or corruption?\n // For now, fail loud as per spec.\n throw e;\n }\n }\n\n // Return raw if not encrypted (backwards compatibility during dev, or unencrypted data)\n return raw;\n }\n\n async put(key: string, value: any): Promise<void> {\n const encrypted = await EncryptionManager.encrypt(this.key, value);\n // Store as plain object to be compatible with structured clone algorithm of IndexedDB\n const storedValue = {\n iv: encrypted.iv,\n data: encrypted.data\n };\n return this.wrapped.put(key, storedValue);\n }\n\n async remove(key: string): Promise<void> {\n return this.wrapped.remove(key);\n }\n\n // --- Metadata ---\n\n async getMeta(key: string): Promise<any> {\n const raw = await this.wrapped.getMeta(key);\n if (!raw) return undefined;\n\n if (this.isEncryptedRecord(raw)) {\n return EncryptionManager.decrypt(this.key, raw);\n }\n return raw;\n }\n\n async setMeta(key: string, value: any): Promise<void> {\n const encrypted = await EncryptionManager.encrypt(this.key, value);\n return this.wrapped.setMeta(key, {\n iv: encrypted.iv,\n data: encrypted.data\n });\n }\n\n // --- Batch ---\n\n async batchPut(entries: Map<string, any>): Promise<void> {\n const encryptedEntries = new Map<string, any>();\n\n for (const [key, value] of entries.entries()) {\n const encrypted = await EncryptionManager.encrypt(this.key, value);\n encryptedEntries.set(key, {\n iv: encrypted.iv,\n data: encrypted.data\n });\n }\n\n return this.wrapped.batchPut(encryptedEntries);\n }\n\n // --- OpLog ---\n\n async appendOpLog(entry: Omit<OpLogEntry, 'id'>): Promise<number> {\n // Encrypt sensitive fields: value, record, orRecord\n const encryptedEntry = { ...entry };\n\n if (entry.value !== undefined) {\n const enc = await EncryptionManager.encrypt(this.key, entry.value);\n encryptedEntry.value = { iv: enc.iv, data: enc.data };\n }\n\n if (entry.record !== undefined) {\n const enc = await EncryptionManager.encrypt(this.key, entry.record);\n encryptedEntry.record = { iv: enc.iv, data: enc.data } as any;\n }\n\n if (entry.orRecord !== undefined) {\n const enc = await EncryptionManager.encrypt(this.key, entry.orRecord);\n encryptedEntry.orRecord = { iv: enc.iv, data: enc.data } as any;\n }\n\n // Note: 'key', 'op', 'mapName', 'orTag', 'hlc', 'synced' remain plaintext for indexing\n\n return this.wrapped.appendOpLog(encryptedEntry);\n }\n\n async getPendingOps(): Promise<OpLogEntry[]> {\n const ops = await this.wrapped.getPendingOps();\n\n // Decrypt in place\n // We map concurrently for performance\n return Promise.all(ops.map(async op => {\n const decryptedOp = { ...op };\n\n if (this.isEncryptedRecord(op.value)) {\n decryptedOp.value = await EncryptionManager.decrypt(this.key, op.value);\n }\n\n if (this.isEncryptedRecord(op.record)) {\n decryptedOp.record = await EncryptionManager.decrypt(this.key, op.record as any);\n }\n\n if (this.isEncryptedRecord(op.orRecord)) {\n decryptedOp.orRecord = await EncryptionManager.decrypt(this.key, op.orRecord as any);\n }\n\n return decryptedOp;\n }));\n }\n\n async markOpsSynced(lastId: number): Promise<void> {\n return this.wrapped.markOpsSynced(lastId);\n }\n\n // --- Iteration ---\n\n async getAllKeys(): Promise<string[]> {\n return this.wrapped.getAllKeys();\n }\n\n // --- Helpers ---\n\n private isEncryptedRecord(data: any): data is { iv: Uint8Array, data: Uint8Array } {\n return data &&\n typeof data === 'object' &&\n data.iv instanceof Uint8Array &&\n data.data instanceof Uint8Array;\n }\n}\n"],"mappings":"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","names":["pino","SyncState","token","import_core","import_core","import_core"]}
|