@korajs/sync 0.3.2 → 0.4.0
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.cjs +1506 -70
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +515 -4
- package/dist/index.d.ts +515 -4
- package/dist/index.js +1471 -49
- package/dist/index.js.map +1 -1
- package/dist/internal.d.cts +1 -1
- package/dist/internal.d.ts +1 -1
- package/dist/transport-B-BIguq9.d.cts +385 -0
- package/dist/transport-B-BIguq9.d.ts +385 -0
- package/package.json +3 -3
- package/dist/transport-B5EFsr5F.d.cts +0 -215
- package/dist/transport-B5EFsr5F.d.ts +0 -215
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/types.ts","../src/protocol/messages.ts","../src/protocol/serializer.ts","../src/transport/websocket-transport.ts","../src/transport/http-long-polling-transport.ts","../src/transport/chaos-transport.ts","../src/engine/sync-engine.ts","../src/engine/memory-queue-storage.ts","../src/engine/outbound-queue.ts","../src/engine/connection-monitor.ts","../src/engine/reconnection-manager.ts"],"sourcesContent":["// @korajs/sync — public API\n// Every export here is a public API commitment. Be explicit.\n\n// === Types ===\nexport type {\n\tQueueStorage,\n\tSyncConfig,\n\tSyncScopeContext,\n\tSyncState,\n\tSyncStatus,\n\tSyncStatusInfo,\n} from './types'\n\nexport { SYNC_STATES, SYNC_STATUSES } from './types'\n\n// === SyncStore Interface ===\nexport type { ApplyResult, SyncStore } from './engine/sync-store'\n\n// === Protocol Messages ===\nexport type {\n\tAcknowledgmentMessage,\n\tErrorMessage,\n\tHandshakeMessage,\n\tHandshakeResponseMessage,\n\tOperationBatchMessage,\n\tSerializedOperation,\n\tSyncMessage,\n\tWireFormat,\n} from './protocol/messages'\n\nexport {\n\tisAcknowledgmentMessage,\n\tisErrorMessage,\n\tisHandshakeMessage,\n\tisHandshakeResponseMessage,\n\tisOperationBatchMessage,\n\tisSyncMessage,\n} from './protocol/messages'\n\n// === Serialization ===\nexport type { MessageSerializer } from './protocol/serializer'\n\nexport {\n\tJsonMessageSerializer,\n\tNegotiatedMessageSerializer,\n\tProtobufMessageSerializer,\n\tversionVectorToWire,\n\twireToVersionVector,\n} from './protocol/serializer'\n\n// === Transport ===\nexport type {\n\tSyncTransport,\n\tTransportCloseHandler,\n\tTransportErrorHandler,\n\tTransportMessageHandler,\n\tTransportOptions,\n} from './transport/transport'\n\nexport type {\n\tWebSocketConstructor,\n\tWebSocketLike,\n\tWebSocketTransportOptions,\n} from './transport/websocket-transport'\n\nexport type { HttpLongPollingTransportOptions } from './transport/http-long-polling-transport'\n\nexport { WebSocketTransport } from './transport/websocket-transport'\nexport { HttpLongPollingTransport } from './transport/http-long-polling-transport'\n\nexport type { ChaosConfig } from './transport/chaos-transport'\n\nexport { ChaosTransport } from './transport/chaos-transport'\n\n// === Engine ===\nexport type { SyncEngineOptions } from './engine/sync-engine'\n\nexport { SyncEngine } from './engine/sync-engine'\n\nexport type { OutboundBatch } from './engine/outbound-queue'\n\nexport { OutboundQueue } from './engine/outbound-queue'\n\nexport type { ConnectionMonitorConfig } from './engine/connection-monitor'\n\nexport { ConnectionMonitor } from './engine/connection-monitor'\n\nexport type { ReconnectionConfig } from './engine/reconnection-manager'\n\nexport { ReconnectionManager } from './engine/reconnection-manager'\n","import type { Operation } from '@korajs/core'\n\n/**\n * Internal sync engine states. Used for state machine transitions.\n */\nexport const SYNC_STATES = [\n\t'disconnected',\n\t'connecting',\n\t'handshaking',\n\t'syncing',\n\t'streaming',\n\t'error',\n] as const\nexport type SyncState = (typeof SYNC_STATES)[number]\n\n/**\n * Developer-facing sync status. Simplified view of the internal state.\n */\nexport const SYNC_STATUSES = ['connected', 'syncing', 'synced', 'offline', 'error'] as const\nexport type SyncStatus = (typeof SYNC_STATUSES)[number]\n\n/**\n * Sync status information exposed to developers.\n */\nexport interface SyncStatusInfo {\n\t/** Current developer-facing status */\n\tstatus: SyncStatus\n\t/** Number of operations waiting to be sent */\n\tpendingOperations: number\n\t/** Timestamp of last successful sync (null if never synced) */\n\tlastSyncedAt: number | null\n}\n\n/**\n * Sync configuration provided by the developer.\n */\nexport interface SyncConfig {\n\t/** WebSocket or HTTP URL for the sync server */\n\turl: string\n\t/** Transport type to use. Defaults to 'websocket'. */\n\ttransport?: 'websocket' | 'http'\n\t/** Auth provider function. Called before each connection attempt. */\n\tauth?: () => Promise<{ token: string }>\n\t/** Sync scopes per collection. Limits which records sync to this client. */\n\tscopes?: Record<string, (ctx: SyncScopeContext) => Record<string, unknown>>\n\t/** Number of operations per batch. Defaults to 100. */\n\tbatchSize?: number\n\t/** Initial reconnection delay in ms. Defaults to 1000. */\n\treconnectInterval?: number\n\t/** Maximum reconnection delay in ms. Defaults to 30000. */\n\tmaxReconnectInterval?: number\n\t/** Schema version of this client. */\n\tschemaVersion?: number\n}\n\n/**\n * Context passed to sync scope functions.\n */\nexport interface SyncScopeContext {\n\tuserId?: string\n\t[key: string]: unknown\n}\n\n/**\n * Interface for persisting the outbound operation queue.\n * Operations must survive page refreshes and be sent when connection is re-established.\n */\nexport interface QueueStorage {\n\t/** Load all queued operations from persistent storage */\n\tload(): Promise<Operation[]>\n\t/** Persist an operation to the queue */\n\tenqueue(op: Operation): Promise<void>\n\t/** Remove acknowledged operations by their IDs */\n\tdequeue(ids: string[]): Promise<void>\n\t/** Return number of operations in storage */\n\tcount(): Promise<number>\n}\n","import type { HLCTimestamp, OperationType } from '@korajs/core'\n\nexport type WireFormat = 'json' | 'protobuf'\n\n/**\n * Wire-format operation. Plain object (no Map) for JSON serialization.\n * Maps 1:1 with Operation, but uses Record instead of Map for version vectors.\n */\nexport interface SerializedOperation {\n\tid: string\n\tnodeId: string\n\ttype: OperationType\n\tcollection: string\n\trecordId: string\n\tdata: Record<string, unknown> | null\n\tpreviousData: Record<string, unknown> | null\n\ttimestamp: HLCTimestamp\n\tsequenceNumber: number\n\tcausalDeps: string[]\n\tschemaVersion: number\n}\n\n/**\n * Handshake message sent by client to initiate sync.\n */\nexport interface HandshakeMessage {\n\ttype: 'handshake'\n\tmessageId: string\n\tnodeId: string\n\t/** Version vector as plain object (nodeId -> sequence number) */\n\tversionVector: Record<string, number>\n\tschemaVersion: number\n\tauthToken?: string\n\tsupportedWireFormats?: WireFormat[]\n}\n\n/**\n * Server response to a handshake.\n */\nexport interface HandshakeResponseMessage {\n\ttype: 'handshake-response'\n\tmessageId: string\n\tnodeId: string\n\tversionVector: Record<string, number>\n\tschemaVersion: number\n\taccepted: boolean\n\trejectReason?: string\n\tselectedWireFormat?: WireFormat\n}\n\n/**\n * Batch of operations sent during delta exchange or streaming.\n */\nexport interface OperationBatchMessage {\n\ttype: 'operation-batch'\n\tmessageId: string\n\toperations: SerializedOperation[]\n\t/** True if this is the last batch in the delta exchange phase */\n\tisFinal: boolean\n\t/** Index of this batch (0-based) for ordering */\n\tbatchIndex: number\n}\n\n/**\n * Acknowledgment of a received message.\n */\nexport interface AcknowledgmentMessage {\n\ttype: 'acknowledgment'\n\tmessageId: string\n\tacknowledgedMessageId: string\n\tlastSequenceNumber: number\n}\n\n/**\n * Error message from the server or client.\n */\nexport interface ErrorMessage {\n\ttype: 'error'\n\tmessageId: string\n\tcode: string\n\tmessage: string\n\tretriable: boolean\n}\n\n/**\n * Union of all sync protocol messages.\n */\nexport type SyncMessage =\n\t| HandshakeMessage\n\t| HandshakeResponseMessage\n\t| OperationBatchMessage\n\t| AcknowledgmentMessage\n\t| ErrorMessage\n\n// --- Type Guards ---\n\n/**\n * Check if an unknown value is a valid SyncMessage.\n */\nexport function isSyncMessage(value: unknown): value is SyncMessage {\n\tif (typeof value !== 'object' || value === null) return false\n\tconst msg = value as Record<string, unknown>\n\tif (typeof msg.type !== 'string' || typeof msg.messageId !== 'string') return false\n\tswitch (msg.type) {\n\t\tcase 'handshake':\n\t\t\treturn isHandshakeMessage(value)\n\t\tcase 'handshake-response':\n\t\t\treturn isHandshakeResponseMessage(value)\n\t\tcase 'operation-batch':\n\t\t\treturn isOperationBatchMessage(value)\n\t\tcase 'acknowledgment':\n\t\t\treturn isAcknowledgmentMessage(value)\n\t\tcase 'error':\n\t\t\treturn isErrorMessage(value)\n\t\tdefault:\n\t\t\treturn false\n\t}\n}\n\n/**\n * Check if a value is a HandshakeMessage.\n */\nexport function isHandshakeMessage(value: unknown): value is HandshakeMessage {\n\tif (typeof value !== 'object' || value === null) return false\n\tconst msg = value as Record<string, unknown>\n\treturn (\n\t\tmsg.type === 'handshake' &&\n\t\ttypeof msg.messageId === 'string' &&\n\t\ttypeof msg.nodeId === 'string' &&\n\t\ttypeof msg.versionVector === 'object' &&\n\t\tmsg.versionVector !== null &&\n\t\t!Array.isArray(msg.versionVector) &&\n\t\ttypeof msg.schemaVersion === 'number'\n\t)\n}\n\n/**\n * Check if a value is a HandshakeResponseMessage.\n */\nexport function isHandshakeResponseMessage(value: unknown): value is HandshakeResponseMessage {\n\tif (typeof value !== 'object' || value === null) return false\n\tconst msg = value as Record<string, unknown>\n\treturn (\n\t\tmsg.type === 'handshake-response' &&\n\t\ttypeof msg.messageId === 'string' &&\n\t\ttypeof msg.nodeId === 'string' &&\n\t\ttypeof msg.versionVector === 'object' &&\n\t\tmsg.versionVector !== null &&\n\t\t!Array.isArray(msg.versionVector) &&\n\t\ttypeof msg.schemaVersion === 'number' &&\n\t\ttypeof msg.accepted === 'boolean'\n\t)\n}\n\n/**\n * Check if a value is an OperationBatchMessage.\n */\nexport function isOperationBatchMessage(value: unknown): value is OperationBatchMessage {\n\tif (typeof value !== 'object' || value === null) return false\n\tconst msg = value as Record<string, unknown>\n\treturn (\n\t\tmsg.type === 'operation-batch' &&\n\t\ttypeof msg.messageId === 'string' &&\n\t\tArray.isArray(msg.operations) &&\n\t\ttypeof msg.isFinal === 'boolean' &&\n\t\ttypeof msg.batchIndex === 'number'\n\t)\n}\n\n/**\n * Check if a value is an AcknowledgmentMessage.\n */\nexport function isAcknowledgmentMessage(value: unknown): value is AcknowledgmentMessage {\n\tif (typeof value !== 'object' || value === null) return false\n\tconst msg = value as Record<string, unknown>\n\treturn (\n\t\tmsg.type === 'acknowledgment' &&\n\t\ttypeof msg.messageId === 'string' &&\n\t\ttypeof msg.acknowledgedMessageId === 'string' &&\n\t\ttypeof msg.lastSequenceNumber === 'number'\n\t)\n}\n\n/**\n * Check if a value is an ErrorMessage.\n */\nexport function isErrorMessage(value: unknown): value is ErrorMessage {\n\tif (typeof value !== 'object' || value === null) return false\n\tconst msg = value as Record<string, unknown>\n\treturn (\n\t\tmsg.type === 'error' &&\n\t\ttypeof msg.messageId === 'string' &&\n\t\ttypeof msg.code === 'string' &&\n\t\ttypeof msg.message === 'string' &&\n\t\ttypeof msg.retriable === 'boolean'\n\t)\n}\n","import { SyncError } from '@korajs/core'\nimport type { Operation, VersionVector } from '@korajs/core'\n// protobufjs/minimal is CJS — named ESM imports fail in some runtimes (tsx, Node ESM).\n// Use a default import for the runtime values and type aliases for annotations.\nimport protobuf from 'protobufjs/minimal'\n\ntype Reader = protobuf.Reader\ntype Writer = protobuf.Writer\nconst { Reader, Writer } = protobuf\nimport type {\n\tAcknowledgmentMessage,\n\tErrorMessage,\n\tHandshakeMessage,\n\tHandshakeResponseMessage,\n\tOperationBatchMessage,\n\tSerializedOperation,\n\tSyncMessage,\n\tWireFormat,\n} from './messages'\nimport { isSyncMessage } from './messages'\n\nexport type EncodedMessage = string | Uint8Array\n\n/**\n * Interface for encoding/decoding sync protocol messages.\n */\nexport interface MessageSerializer {\n\tencode(message: SyncMessage): EncodedMessage\n\tdecode(data: string | Uint8Array | ArrayBuffer): SyncMessage\n\tencodeOperation(op: Operation): SerializedOperation\n\tdecodeOperation(serialized: SerializedOperation): Operation\n\tsetWireFormat?(format: WireFormat): void\n\tgetWireFormat?(): WireFormat\n}\n\n/**\n * Convert a VersionVector (Map) to a plain object for wire transmission.\n */\nexport function versionVectorToWire(vector: VersionVector): Record<string, number> {\n\tconst wire: Record<string, number> = {}\n\tfor (const [nodeId, seq] of vector) {\n\t\twire[nodeId] = seq\n\t}\n\treturn wire\n}\n\n/**\n * Convert a wire-format version vector (plain object) back to a VersionVector (Map).\n */\nexport function wireToVersionVector(wire: Record<string, number>): VersionVector {\n\treturn new Map(Object.entries(wire))\n}\n\n/**\n * JSON-based message serializer.\n */\nexport class JsonMessageSerializer implements MessageSerializer {\n\tencode(message: SyncMessage): string {\n\t\treturn JSON.stringify(message)\n\t}\n\n\tdecode(data: string | Uint8Array | ArrayBuffer): SyncMessage {\n\t\tconst text = decodeTextPayload(data)\n\n\t\tlet parsed: unknown\n\t\ttry {\n\t\t\tparsed = JSON.parse(text)\n\t\t} catch {\n\t\t\tthrow new SyncError('Failed to decode sync message: invalid JSON', {\n\t\t\t\tdataLength: text.length,\n\t\t\t})\n\t\t}\n\n\t\tif (!isSyncMessage(parsed)) {\n\t\t\tthrow new SyncError('Failed to decode sync message: invalid message structure', {\n\t\t\t\treceivedType:\n\t\t\t\t\ttypeof parsed === 'object' && parsed !== null\n\t\t\t\t\t\t? (parsed as Record<string, unknown>).type\n\t\t\t\t\t\t: typeof parsed,\n\t\t\t})\n\t\t}\n\n\t\treturn parsed\n\t}\n\n\tencodeOperation(op: Operation): SerializedOperation {\n\t\treturn {\n\t\t\tid: op.id,\n\t\t\tnodeId: op.nodeId,\n\t\t\ttype: op.type,\n\t\t\tcollection: op.collection,\n\t\t\trecordId: op.recordId,\n\t\t\tdata: op.data,\n\t\t\tpreviousData: op.previousData,\n\t\t\ttimestamp: {\n\t\t\t\twallTime: op.timestamp.wallTime,\n\t\t\t\tlogical: op.timestamp.logical,\n\t\t\t\tnodeId: op.timestamp.nodeId,\n\t\t\t},\n\t\t\tsequenceNumber: op.sequenceNumber,\n\t\t\tcausalDeps: [...op.causalDeps],\n\t\t\tschemaVersion: op.schemaVersion,\n\t\t}\n\t}\n\n\tdecodeOperation(serialized: SerializedOperation): Operation {\n\t\treturn {\n\t\t\tid: serialized.id,\n\t\t\tnodeId: serialized.nodeId,\n\t\t\ttype: serialized.type,\n\t\t\tcollection: serialized.collection,\n\t\t\trecordId: serialized.recordId,\n\t\t\tdata: serialized.data,\n\t\t\tpreviousData: serialized.previousData,\n\t\t\ttimestamp: {\n\t\t\t\twallTime: serialized.timestamp.wallTime,\n\t\t\t\tlogical: serialized.timestamp.logical,\n\t\t\t\tnodeId: serialized.timestamp.nodeId,\n\t\t\t},\n\t\t\tsequenceNumber: serialized.sequenceNumber,\n\t\t\tcausalDeps: [...serialized.causalDeps],\n\t\t\tschemaVersion: serialized.schemaVersion,\n\t\t}\n\t}\n}\n\n/**\n * Protobuf-based serializer for sync messages.\n */\nexport class ProtobufMessageSerializer implements MessageSerializer {\n\tencode(message: SyncMessage): Uint8Array {\n\t\tconst envelope = toProtoEnvelope(message)\n\t\treturn encodeEnvelope(envelope)\n\t}\n\n\tdecode(data: string | Uint8Array | ArrayBuffer): SyncMessage {\n\t\tconst bytes = toBytes(data)\n\t\tconst envelope = decodeEnvelope(bytes)\n\t\treturn fromProtoEnvelope(envelope)\n\t}\n\n\tencodeOperation(op: Operation): SerializedOperation {\n\t\treturn new JsonMessageSerializer().encodeOperation(op)\n\t}\n\n\tdecodeOperation(serialized: SerializedOperation): Operation {\n\t\treturn new JsonMessageSerializer().decodeOperation(serialized)\n\t}\n}\n\n/**\n * Negotiated serializer that supports runtime wire-format switching.\n */\nexport class NegotiatedMessageSerializer implements MessageSerializer {\n\tprivate readonly json = new JsonMessageSerializer()\n\tprivate readonly protobuf = new ProtobufMessageSerializer()\n\tprivate wireFormat: WireFormat\n\n\tconstructor(initialWireFormat: WireFormat = 'json') {\n\t\tthis.wireFormat = initialWireFormat\n\t}\n\n\tencode(message: SyncMessage): EncodedMessage {\n\t\tif (this.wireFormat === 'protobuf') {\n\t\t\treturn this.protobuf.encode(message)\n\t\t}\n\n\t\treturn this.json.encode(message)\n\t}\n\n\tdecode(data: string | Uint8Array | ArrayBuffer): SyncMessage {\n\t\tif (typeof data === 'string') {\n\t\t\treturn this.json.decode(data)\n\t\t}\n\n\t\ttry {\n\t\t\treturn this.protobuf.decode(data)\n\t\t} catch {\n\t\t\treturn this.json.decode(data)\n\t\t}\n\t}\n\n\tencodeOperation(op: Operation): SerializedOperation {\n\t\treturn this.json.encodeOperation(op)\n\t}\n\n\tdecodeOperation(serialized: SerializedOperation): Operation {\n\t\treturn this.json.decodeOperation(serialized)\n\t}\n\n\tsetWireFormat(format: WireFormat): void {\n\t\tthis.wireFormat = format\n\t}\n\n\tgetWireFormat(): WireFormat {\n\t\treturn this.wireFormat\n\t}\n}\n\ninterface ProtoVectorEntry {\n\tkey: string\n\tvalue: number\n}\n\ninterface ProtoTimestamp {\n\twallTime: number\n\tlogical: number\n\tnodeId: string\n}\n\ninterface ProtoOperation {\n\tid: string\n\tnodeId: string\n\ttype: string\n\tcollection: string\n\trecordId: string\n\tdataJson: string\n\tpreviousDataJson: string\n\ttimestamp: ProtoTimestamp\n\tsequenceNumber: number\n\tcausalDeps: string[]\n\tschemaVersion: number\n\thasData: boolean\n\thasPreviousData: boolean\n}\n\ninterface ProtoEnvelope {\n\ttype: SyncMessage['type']\n\tmessageId: string\n\tnodeId?: string\n\tversionVector?: ProtoVectorEntry[]\n\tschemaVersion?: number\n\tauthToken?: string\n\tsupportedWireFormats?: string[]\n\taccepted?: boolean\n\trejectReason?: string\n\tselectedWireFormat?: string\n\toperations?: ProtoOperation[]\n\tisFinal?: boolean\n\tbatchIndex?: number\n\tacknowledgedMessageId?: string\n\tlastSequenceNumber?: number\n\terrorCode?: string\n\terrorMessage?: string\n\tretriable?: boolean\n}\n\nfunction toProtoEnvelope(message: SyncMessage): ProtoEnvelope {\n\tswitch (message.type) {\n\t\tcase 'handshake':\n\t\t\treturn {\n\t\t\t\ttype: message.type,\n\t\t\t\tmessageId: message.messageId,\n\t\t\t\tnodeId: message.nodeId,\n\t\t\t\tversionVector: Object.entries(message.versionVector).map(([key, value]) => ({ key, value })),\n\t\t\t\tschemaVersion: message.schemaVersion,\n\t\t\t\tauthToken: message.authToken,\n\t\t\t\tsupportedWireFormats: message.supportedWireFormats,\n\t\t\t}\n\t\tcase 'handshake-response':\n\t\t\treturn {\n\t\t\t\ttype: message.type,\n\t\t\t\tmessageId: message.messageId,\n\t\t\t\tnodeId: message.nodeId,\n\t\t\t\tversionVector: Object.entries(message.versionVector).map(([key, value]) => ({ key, value })),\n\t\t\t\tschemaVersion: message.schemaVersion,\n\t\t\t\taccepted: message.accepted,\n\t\t\t\trejectReason: message.rejectReason,\n\t\t\t\tselectedWireFormat: message.selectedWireFormat,\n\t\t\t}\n\t\tcase 'operation-batch':\n\t\t\treturn {\n\t\t\t\ttype: message.type,\n\t\t\t\tmessageId: message.messageId,\n\t\t\t\toperations: message.operations.map(serializeProtoOperation),\n\t\t\t\tisFinal: message.isFinal,\n\t\t\t\tbatchIndex: message.batchIndex,\n\t\t\t}\n\t\tcase 'acknowledgment':\n\t\t\treturn {\n\t\t\t\ttype: message.type,\n\t\t\t\tmessageId: message.messageId,\n\t\t\t\tacknowledgedMessageId: message.acknowledgedMessageId,\n\t\t\t\tlastSequenceNumber: message.lastSequenceNumber,\n\t\t\t}\n\t\tcase 'error':\n\t\t\treturn {\n\t\t\t\ttype: message.type,\n\t\t\t\tmessageId: message.messageId,\n\t\t\t\terrorCode: message.code,\n\t\t\t\terrorMessage: message.message,\n\t\t\t\tretriable: message.retriable,\n\t\t\t}\n\t}\n}\n\nfunction fromProtoEnvelope(envelope: ProtoEnvelope): SyncMessage {\n\tswitch (envelope.type) {\n\t\tcase 'handshake':\n\t\t\treturn {\n\t\t\t\ttype: 'handshake',\n\t\t\t\tmessageId: envelope.messageId,\n\t\t\t\tnodeId: envelope.nodeId ?? '',\n\t\t\t\tversionVector: Object.fromEntries((envelope.versionVector ?? []).map((entry) => [entry.key, entry.value])),\n\t\t\t\tschemaVersion: envelope.schemaVersion ?? 0,\n\t\t\t\tauthToken: envelope.authToken,\n\t\t\t\tsupportedWireFormats:\n\t\t\t\t\tenvelope.supportedWireFormats?.filter(\n\t\t\t\t\t\t(format): format is WireFormat => format === 'json' || format === 'protobuf',\n\t\t\t\t\t),\n\t\t\t}\n\t\tcase 'handshake-response':\n\t\t\treturn {\n\t\t\t\ttype: 'handshake-response',\n\t\t\t\tmessageId: envelope.messageId,\n\t\t\t\tnodeId: envelope.nodeId ?? '',\n\t\t\t\tversionVector: Object.fromEntries((envelope.versionVector ?? []).map((entry) => [entry.key, entry.value])),\n\t\t\t\tschemaVersion: envelope.schemaVersion ?? 0,\n\t\t\t\taccepted: envelope.accepted ?? false,\n\t\t\t\trejectReason: envelope.rejectReason,\n\t\t\t\tselectedWireFormat:\n\t\t\t\t\tenvelope.selectedWireFormat === 'json' || envelope.selectedWireFormat === 'protobuf'\n\t\t\t\t\t\t? envelope.selectedWireFormat\n\t\t\t\t\t\t: undefined,\n\t\t\t}\n\t\tcase 'operation-batch':\n\t\t\treturn {\n\t\t\t\ttype: 'operation-batch',\n\t\t\t\tmessageId: envelope.messageId,\n\t\t\t\toperations: (envelope.operations ?? []).map(deserializeProtoOperation),\n\t\t\t\tisFinal: envelope.isFinal ?? false,\n\t\t\t\tbatchIndex: envelope.batchIndex ?? 0,\n\t\t\t}\n\t\tcase 'acknowledgment':\n\t\t\treturn {\n\t\t\t\ttype: 'acknowledgment',\n\t\t\t\tmessageId: envelope.messageId,\n\t\t\t\tacknowledgedMessageId: envelope.acknowledgedMessageId ?? '',\n\t\t\t\tlastSequenceNumber: envelope.lastSequenceNumber ?? 0,\n\t\t\t}\n\t\tcase 'error':\n\t\t\treturn {\n\t\t\t\ttype: 'error',\n\t\t\t\tmessageId: envelope.messageId,\n\t\t\t\tcode: envelope.errorCode ?? 'UNKNOWN',\n\t\t\t\tmessage: envelope.errorMessage ?? 'Unknown error',\n\t\t\t\tretriable: envelope.retriable ?? false,\n\t\t\t}\n\t\tdefault:\n\t\t\tthrow new SyncError('Failed to decode sync message: unknown protobuf type', {\n\t\t\t\ttype: envelope.type,\n\t\t\t})\n\t}\n}\n\nfunction serializeProtoOperation(operation: SerializedOperation): ProtoOperation {\n\treturn {\n\t\tid: operation.id,\n\t\tnodeId: operation.nodeId,\n\t\ttype: operation.type,\n\t\tcollection: operation.collection,\n\t\trecordId: operation.recordId,\n\t\tdataJson: operation.data === null ? '' : JSON.stringify(operation.data),\n\t\tpreviousDataJson:\n\t\t\toperation.previousData === null ? '' : JSON.stringify(operation.previousData),\n\t\ttimestamp: {\n\t\t\twallTime: operation.timestamp.wallTime,\n\t\t\tlogical: operation.timestamp.logical,\n\t\t\tnodeId: operation.timestamp.nodeId,\n\t\t},\n\t\tsequenceNumber: operation.sequenceNumber,\n\t\tcausalDeps: [...operation.causalDeps],\n\t\tschemaVersion: operation.schemaVersion,\n\t\thasData: operation.data !== null,\n\t\thasPreviousData: operation.previousData !== null,\n\t}\n}\n\nfunction deserializeProtoOperation(operation: ProtoOperation): SerializedOperation {\n\treturn {\n\t\tid: operation.id,\n\t\tnodeId: operation.nodeId,\n\t\ttype: operation.type as SerializedOperation['type'],\n\t\tcollection: operation.collection,\n\t\trecordId: operation.recordId,\n\t\tdata: operation.hasData ? (JSON.parse(operation.dataJson) as Record<string, unknown>) : null,\n\t\tpreviousData: operation.hasPreviousData\n\t\t\t? (JSON.parse(operation.previousDataJson) as Record<string, unknown>)\n\t\t\t: null,\n\t\ttimestamp: {\n\t\t\twallTime: operation.timestamp.wallTime,\n\t\t\tlogical: operation.timestamp.logical,\n\t\t\tnodeId: operation.timestamp.nodeId,\n\t\t},\n\t\tsequenceNumber: operation.sequenceNumber,\n\t\tcausalDeps: [...operation.causalDeps],\n\t\tschemaVersion: operation.schemaVersion,\n\t}\n}\n\nfunction decodeTextPayload(data: string | Uint8Array | ArrayBuffer): string {\n\tif (typeof data === 'string') return data\n\treturn new TextDecoder().decode(toBytes(data))\n}\n\nfunction toBytes(data: string | Uint8Array | ArrayBuffer): Uint8Array {\n\tif (typeof data === 'string') {\n\t\treturn new TextEncoder().encode(data)\n\t}\n\n\tif (data instanceof Uint8Array) {\n\t\treturn data\n\t}\n\n\tif (data instanceof ArrayBuffer) {\n\t\treturn new Uint8Array(data)\n\t}\n\n\tthrow new SyncError('Unsupported sync payload type', { receivedType: typeof data })\n}\n\nfunction encodeEnvelope(envelope: ProtoEnvelope): Uint8Array {\n\tconst writer = Writer.create()\n\tif (envelope.type.length > 0) writer.uint32(10).string(envelope.type)\n\tif (envelope.messageId.length > 0) writer.uint32(18).string(envelope.messageId)\n\tif (envelope.nodeId && envelope.nodeId.length > 0) writer.uint32(26).string(envelope.nodeId)\n\tfor (const entry of envelope.versionVector ?? []) {\n\t\twriter.uint32(34).fork()\n\t\twriter.uint32(10).string(entry.key)\n\t\twriter.uint32(16).int64(entry.value)\n\t\twriter.ldelim()\n\t}\n\tif (envelope.schemaVersion !== undefined) writer.uint32(40).int32(envelope.schemaVersion)\n\tif (envelope.authToken && envelope.authToken.length > 0) writer.uint32(50).string(envelope.authToken)\n\tfor (const format of envelope.supportedWireFormats ?? []) {\n\t\twriter.uint32(58).string(format)\n\t}\n\tif (envelope.accepted !== undefined) writer.uint32(64).bool(envelope.accepted)\n\tif (envelope.rejectReason && envelope.rejectReason.length > 0) writer.uint32(74).string(envelope.rejectReason)\n\tif (envelope.selectedWireFormat && envelope.selectedWireFormat.length > 0) {\n\t\twriter.uint32(82).string(envelope.selectedWireFormat)\n\t}\n\tfor (const operation of envelope.operations ?? []) {\n\t\twriter.uint32(90).fork()\n\t\tencodeProtoOperation(writer, operation)\n\t\twriter.ldelim()\n\t}\n\tif (envelope.isFinal !== undefined) writer.uint32(96).bool(envelope.isFinal)\n\tif (envelope.batchIndex !== undefined) writer.uint32(104).uint32(envelope.batchIndex)\n\tif (envelope.acknowledgedMessageId && envelope.acknowledgedMessageId.length > 0) {\n\t\twriter.uint32(114).string(envelope.acknowledgedMessageId)\n\t}\n\tif (envelope.lastSequenceNumber !== undefined) writer.uint32(120).int64(envelope.lastSequenceNumber)\n\tif (envelope.errorCode && envelope.errorCode.length > 0) writer.uint32(130).string(envelope.errorCode)\n\tif (envelope.errorMessage && envelope.errorMessage.length > 0) {\n\t\twriter.uint32(138).string(envelope.errorMessage)\n\t}\n\tif (envelope.retriable !== undefined) writer.uint32(144).bool(envelope.retriable)\n\treturn writer.finish()\n}\n\nfunction decodeEnvelope(bytes: Uint8Array): ProtoEnvelope {\n\tconst reader = Reader.create(bytes)\n\tconst envelope: ProtoEnvelope = { type: 'error', messageId: '' }\n\n\twhile (reader.pos < reader.len) {\n\t\tconst tag = reader.uint32()\n\t\tswitch (tag >>> 3) {\n\t\t\tcase 1:\n\t\t\t\tenvelope.type = reader.string() as SyncMessage['type']\n\t\t\t\tbreak\n\t\t\tcase 2:\n\t\t\t\tenvelope.messageId = reader.string()\n\t\t\t\tbreak\n\t\t\tcase 3:\n\t\t\t\tenvelope.nodeId = reader.string()\n\t\t\t\tbreak\n\t\t\tcase 4:\n\t\t\t\tenvelope.versionVector = [...(envelope.versionVector ?? []), decodeVectorEntry(reader, reader.uint32())]\n\t\t\t\tbreak\n\t\t\tcase 5:\n\t\t\t\tenvelope.schemaVersion = reader.int32()\n\t\t\t\tbreak\n\t\t\tcase 6:\n\t\t\t\tenvelope.authToken = reader.string()\n\t\t\t\tbreak\n\t\t\tcase 7:\n\t\t\t\tenvelope.supportedWireFormats = [...(envelope.supportedWireFormats ?? []), reader.string()]\n\t\t\t\tbreak\n\t\t\tcase 8:\n\t\t\t\tenvelope.accepted = reader.bool()\n\t\t\t\tbreak\n\t\t\tcase 9:\n\t\t\t\tenvelope.rejectReason = reader.string()\n\t\t\t\tbreak\n\t\t\tcase 10:\n\t\t\t\tenvelope.selectedWireFormat = reader.string()\n\t\t\t\tbreak\n\t\t\tcase 11:\n\t\t\t\tenvelope.operations = [...(envelope.operations ?? []), decodeProtoOperation(reader, reader.uint32())]\n\t\t\t\tbreak\n\t\t\tcase 12:\n\t\t\t\tenvelope.isFinal = reader.bool()\n\t\t\t\tbreak\n\t\t\tcase 13:\n\t\t\t\tenvelope.batchIndex = reader.uint32()\n\t\t\t\tbreak\n\t\t\tcase 14:\n\t\t\t\tenvelope.acknowledgedMessageId = reader.string()\n\t\t\t\tbreak\n\t\t\tcase 15:\n\t\t\t\tenvelope.lastSequenceNumber = longToNumber(reader.int64())\n\t\t\t\tbreak\n\t\t\tcase 16:\n\t\t\t\tenvelope.errorCode = reader.string()\n\t\t\t\tbreak\n\t\t\tcase 17:\n\t\t\t\tenvelope.errorMessage = reader.string()\n\t\t\t\tbreak\n\t\t\tcase 18:\n\t\t\t\tenvelope.retriable = reader.bool()\n\t\t\t\tbreak\n\t\t\tdefault:\n\t\t\t\treader.skipType(tag & 7)\n\t\t}\n\t}\n\n\treturn envelope\n}\n\nfunction encodeProtoOperation(writer: Writer, operation: ProtoOperation): void {\n\tif (operation.id.length > 0) writer.uint32(10).string(operation.id)\n\tif (operation.nodeId.length > 0) writer.uint32(18).string(operation.nodeId)\n\tif (operation.type.length > 0) writer.uint32(26).string(operation.type)\n\tif (operation.collection.length > 0) writer.uint32(34).string(operation.collection)\n\tif (operation.recordId.length > 0) writer.uint32(42).string(operation.recordId)\n\tif (operation.dataJson.length > 0) writer.uint32(50).string(operation.dataJson)\n\tif (operation.previousDataJson.length > 0) writer.uint32(58).string(operation.previousDataJson)\n\twriter.uint32(66).fork()\n\twriter.uint32(8).int64(operation.timestamp.wallTime)\n\twriter.uint32(16).uint32(operation.timestamp.logical)\n\twriter.uint32(26).string(operation.timestamp.nodeId)\n\twriter.ldelim()\n\twriter.uint32(72).int64(operation.sequenceNumber)\n\tfor (const dep of operation.causalDeps) {\n\t\twriter.uint32(82).string(dep)\n\t}\n\twriter.uint32(88).int32(operation.schemaVersion)\n\twriter.uint32(96).bool(operation.hasData)\n\twriter.uint32(104).bool(operation.hasPreviousData)\n}\n\nfunction decodeProtoOperation(reader: Reader, length: number): ProtoOperation {\n\tconst end = reader.pos + length\n\tconst operation: ProtoOperation = {\n\t\tid: '',\n\t\tnodeId: '',\n\t\ttype: 'insert',\n\t\tcollection: '',\n\t\trecordId: '',\n\t\tdataJson: '',\n\t\tpreviousDataJson: '',\n\t\ttimestamp: { wallTime: 0, logical: 0, nodeId: '' },\n\t\tsequenceNumber: 0,\n\t\tcausalDeps: [],\n\t\tschemaVersion: 0,\n\t\thasData: false,\n\t\thasPreviousData: false,\n\t}\n\n\twhile (reader.pos < end) {\n\t\tconst tag = reader.uint32()\n\t\tswitch (tag >>> 3) {\n\t\t\tcase 1:\n\t\t\t\toperation.id = reader.string()\n\t\t\t\tbreak\n\t\t\tcase 2:\n\t\t\t\toperation.nodeId = reader.string()\n\t\t\t\tbreak\n\t\t\tcase 3:\n\t\t\t\toperation.type = reader.string()\n\t\t\t\tbreak\n\t\t\tcase 4:\n\t\t\t\toperation.collection = reader.string()\n\t\t\t\tbreak\n\t\t\tcase 5:\n\t\t\t\toperation.recordId = reader.string()\n\t\t\t\tbreak\n\t\t\tcase 6:\n\t\t\t\toperation.dataJson = reader.string()\n\t\t\t\tbreak\n\t\t\tcase 7:\n\t\t\t\toperation.previousDataJson = reader.string()\n\t\t\t\tbreak\n\t\t\tcase 8: {\n\t\t\t\tconst timestampEnd = reader.pos + reader.uint32()\n\t\t\t\twhile (reader.pos < timestampEnd) {\n\t\t\t\t\tconst timestampTag = reader.uint32()\n\t\t\t\t\tswitch (timestampTag >>> 3) {\n\t\t\t\t\t\tcase 1:\n\t\t\t\t\t\t\toperation.timestamp.wallTime = longToNumber(reader.int64())\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\tcase 2:\n\t\t\t\t\t\t\toperation.timestamp.logical = reader.uint32()\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\tcase 3:\n\t\t\t\t\t\t\toperation.timestamp.nodeId = reader.string()\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\treader.skipType(timestampTag & 7)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 9:\n\t\t\t\toperation.sequenceNumber = longToNumber(reader.int64())\n\t\t\t\tbreak\n\t\t\tcase 10:\n\t\t\t\toperation.causalDeps.push(reader.string())\n\t\t\t\tbreak\n\t\t\tcase 11:\n\t\t\t\toperation.schemaVersion = reader.int32()\n\t\t\t\tbreak\n\t\t\tcase 12:\n\t\t\t\toperation.hasData = reader.bool()\n\t\t\t\tbreak\n\t\t\tcase 13:\n\t\t\t\toperation.hasPreviousData = reader.bool()\n\t\t\t\tbreak\n\t\t\tdefault:\n\t\t\t\treader.skipType(tag & 7)\n\t\t}\n\t}\n\n\treturn operation\n}\n\nfunction decodeVectorEntry(reader: Reader, length: number): ProtoVectorEntry {\n\tconst end = reader.pos + length\n\tconst entry: ProtoVectorEntry = { key: '', value: 0 }\n\twhile (reader.pos < end) {\n\t\tconst tag = reader.uint32()\n\t\tswitch (tag >>> 3) {\n\t\t\tcase 1:\n\t\t\t\tentry.key = reader.string()\n\t\t\t\tbreak\n\t\t\tcase 2:\n\t\t\t\tentry.value = longToNumber(reader.int64())\n\t\t\t\tbreak\n\t\t\tdefault:\n\t\t\t\treader.skipType(tag & 7)\n\t\t}\n\t}\n\treturn entry\n}\n\nfunction longToNumber(value: unknown): number {\n\tif (typeof value === 'number') return value\n\tif (typeof value === 'string') return Number.parseInt(value, 10)\n\tif (\n\t\ttypeof value === 'object' &&\n\t\tvalue !== null &&\n\t\t'toNumber' in value &&\n\t\ttypeof (value as { toNumber: unknown }).toNumber === 'function'\n\t) {\n\t\treturn (value as { toNumber(): number }).toNumber()\n\t}\n\n\tthrow new SyncError('Failed to decode int64 value', {\n\t\treceivedType: typeof value,\n\t})\n}\n","import { SyncError } from '@korajs/core'\nimport type { SyncMessage } from '../protocol/messages'\nimport { JsonMessageSerializer } from '../protocol/serializer'\nimport type { MessageSerializer } from '../protocol/serializer'\nimport type {\n\tSyncTransport,\n\tTransportCloseHandler,\n\tTransportErrorHandler,\n\tTransportMessageHandler,\n\tTransportOptions,\n} from './transport'\n\n/**\n * WebSocket event interface for dependency injection.\n * Matches the subset of the browser WebSocket API that we need.\n */\nexport interface WebSocketLike {\n\treadonly readyState: number\n\tsend(data: string | Uint8Array): void\n\tclose(code?: number, reason?: string): void\n\tonopen: ((event: unknown) => void) | null\n\tonmessage: ((event: { data: unknown }) => void) | null\n\tonclose: ((event: { reason: string; code: number }) => void) | null\n\tonerror: ((event: unknown) => void) | null\n}\n\n/**\n * Constructor for WebSocket-like objects. Allows injection of mock WebSocket for testing.\n */\nexport type WebSocketConstructor = new (url: string, protocols?: string | string[]) => WebSocketLike\n\n/**\n * Options for the WebSocket transport.\n */\nexport interface WebSocketTransportOptions {\n\t/** Custom serializer. Defaults to JSON. */\n\tserializer?: MessageSerializer\n\t/** Injectable WebSocket constructor for testing. Defaults to globalThis.WebSocket. */\n\tWebSocketImpl?: WebSocketConstructor\n\t/** Connection timeout in ms. Defaults to 10000 (10s). */\n\tconnectTimeout?: number\n}\n\n// WebSocket readyState constants\nconst WS_OPEN = 1\n\n/**\n * WebSocket-based sync transport implementation.\n */\nexport class WebSocketTransport implements SyncTransport {\n\tprivate ws: WebSocketLike | null = null\n\tprivate messageHandler: TransportMessageHandler | null = null\n\tprivate closeHandler: TransportCloseHandler | null = null\n\tprivate errorHandler: TransportErrorHandler | null = null\n\tprivate readonly serializer: MessageSerializer\n\tprivate readonly WebSocketImpl: WebSocketConstructor\n\tprivate readonly connectTimeout: number\n\n\tconstructor(options?: WebSocketTransportOptions) {\n\t\tthis.serializer = options?.serializer ?? new JsonMessageSerializer()\n\t\tthis.connectTimeout = options?.connectTimeout ?? 10000\n\n\t\tif (options?.WebSocketImpl) {\n\t\t\tthis.WebSocketImpl = options.WebSocketImpl\n\t\t} else if (typeof globalThis.WebSocket !== 'undefined') {\n\t\t\tthis.WebSocketImpl = globalThis.WebSocket as unknown as WebSocketConstructor\n\t\t} else {\n\t\t\t// Deferred — will throw on connect() if no implementation available\n\t\t\tthis.WebSocketImpl = null as unknown as WebSocketConstructor\n\t\t}\n\t}\n\n\tasync connect(url: string, options?: TransportOptions): Promise<void> {\n\t\tif (!this.WebSocketImpl) {\n\t\t\tthrow new SyncError('WebSocket is not available in this environment', {\n\t\t\t\thint: 'Provide a WebSocketImpl option or use a polyfill',\n\t\t\t})\n\t\t}\n\n\t\treturn new Promise<void>((resolve, reject) => {\n\t\t\tlet settled = false\n\n\t\t\tconst settle = (fn: () => void): void => {\n\t\t\t\tif (settled) return\n\t\t\t\tsettled = true\n\t\t\t\tclearTimeout(timer)\n\t\t\t\tfn()\n\t\t\t}\n\n\t\t\t// Connection timeout — prevents hanging for 30+ seconds on mobile when offline\n\t\t\tconst timer = setTimeout(() => {\n\t\t\t\tsettle(() => {\n\t\t\t\t\tconst err = new SyncError('WebSocket connection timed out', {\n\t\t\t\t\t\turl,\n\t\t\t\t\t\ttimeout: this.connectTimeout,\n\t\t\t\t\t})\n\t\t\t\t\t// Close the pending WebSocket\n\t\t\t\t\tif (this.ws) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tthis.ws.onclose = null\n\t\t\t\t\t\t\tthis.ws.onerror = null\n\t\t\t\t\t\t\tthis.ws.close()\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t// Ignore close errors\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthis.ws = null\n\t\t\t\t\t}\n\t\t\t\t\tthis.errorHandler?.(err)\n\t\t\t\t\treject(err)\n\t\t\t\t})\n\t\t\t}, this.connectTimeout)\n\n\t\t\ttry {\n\t\t\t\t// Append auth token as query param if provided\n\t\t\t\tconst connectUrl = options?.authToken\n\t\t\t\t\t? `${url}${url.includes('?') ? '&' : '?'}token=${encodeURIComponent(options.authToken)}`\n\t\t\t\t\t: url\n\n\t\t\t\tconst ws = new this.WebSocketImpl(connectUrl)\n\t\t\t\tthis.ws = ws\n\n\t\t\t\tws.onopen = () => {\n\t\t\t\t\tsettle(() => resolve())\n\t\t\t\t}\n\n\t\t\t\tws.onmessage = (event: { data: unknown }) => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\ttypeof event.data !== 'string' &&\n\t\t\t\t\t\t\t!(event.data instanceof Uint8Array) &&\n\t\t\t\t\t\t\t!(event.data instanceof ArrayBuffer)\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst message = this.serializer.decode(event.data)\n\t\t\t\t\t\tthis.messageHandler?.(message)\n\t\t\t\t\t} catch {\n\t\t\t\t\t\tthis.errorHandler?.(new SyncError('Failed to decode incoming message'))\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tws.onclose = (event: { reason: string; code: number }) => {\n\t\t\t\t\tthis.ws = null\n\t\t\t\t\tthis.closeHandler?.(event.reason || `WebSocket closed with code ${event.code}`)\n\t\t\t\t}\n\n\t\t\t\tws.onerror = (event: unknown) => {\n\t\t\t\t\tconst err = new SyncError('WebSocket error', {\n\t\t\t\t\t\turl,\n\t\t\t\t\t})\n\t\t\t\t\tthis.errorHandler?.(err)\n\t\t\t\t\t// If we haven't connected yet, reject the connect promise\n\t\t\t\t\tif (!this.isConnected()) {\n\t\t\t\t\t\tthis.ws = null\n\t\t\t\t\t\tsettle(() => reject(err))\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tsettle(() =>\n\t\t\t\t\treject(\n\t\t\t\t\t\terr instanceof SyncError\n\t\t\t\t\t\t\t? err\n\t\t\t\t\t\t\t: new SyncError('Failed to create WebSocket', {\n\t\t\t\t\t\t\t\t\turl,\n\t\t\t\t\t\t\t\t\terror: String(err),\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t}\n\t\t})\n\t}\n\n\tasync disconnect(): Promise<void> {\n\t\tif (this.ws) {\n\t\t\tthis.ws.onclose = null // Prevent close handler firing for intentional disconnect\n\t\t\tthis.ws.close(1000, 'Client disconnecting')\n\t\t\tthis.ws = null\n\t\t}\n\t}\n\n\tsend(message: SyncMessage): void {\n\t\tif (!this.ws || this.ws.readyState !== WS_OPEN) {\n\t\t\tthrow new SyncError('Cannot send message: WebSocket is not connected', {\n\t\t\t\tmessageType: message.type,\n\t\t\t})\n\t\t}\n\t\tconst encoded = this.serializer.encode(message)\n\t\tthis.ws.send(encoded)\n\t}\n\n\tonMessage(handler: TransportMessageHandler): void {\n\t\tthis.messageHandler = handler\n\t}\n\n\tonClose(handler: TransportCloseHandler): void {\n\t\tthis.closeHandler = handler\n\t}\n\n\tonError(handler: TransportErrorHandler): void {\n\t\tthis.errorHandler = handler\n\t}\n\n\tisConnected(): boolean {\n\t\treturn this.ws !== null && this.ws.readyState === WS_OPEN\n\t}\n}\n","import { SyncError } from '@korajs/core'\nimport { NegotiatedMessageSerializer } from '../protocol/serializer'\nimport type { MessageSerializer } from '../protocol/serializer'\nimport { WebSocketTransport } from './websocket-transport'\nimport type { SyncTransport, TransportCloseHandler, TransportErrorHandler, TransportMessageHandler, TransportOptions } from './transport'\n\nconst DEFAULT_RETRY_DELAY_MS = 250\n\nexport interface HttpLongPollingTransportOptions {\n\tserializer?: MessageSerializer\n\tfetchImpl?: typeof fetch\n\tretryDelayMs?: number\n\tpreferWebSocket?: boolean\n\twebSocketFactory?: () => SyncTransport\n}\n\n/**\n * HTTP long-polling transport with optional WebSocket upgrade.\n */\nexport class HttpLongPollingTransport implements SyncTransport {\n\tprivate readonly serializer: MessageSerializer\n\tprivate readonly fetchImpl: typeof fetch\n\tprivate readonly retryDelayMs: number\n\tprivate readonly preferWebSocket: boolean\n\tprivate readonly webSocketFactory: () => SyncTransport\n\n\tprivate messageHandler: TransportMessageHandler | null = null\n\tprivate closeHandler: TransportCloseHandler | null = null\n\tprivate errorHandler: TransportErrorHandler | null = null\n\n\tprivate connected = false\n\tprivate polling = false\n\tprivate url: string | null = null\n\tprivate authToken: string | undefined\n\tprivate pollAbort: AbortController | null = null\n\tprivate upgradedTransport: SyncTransport | null = null\n\n\tconstructor(options?: HttpLongPollingTransportOptions) {\n\t\tthis.serializer = options?.serializer ?? new NegotiatedMessageSerializer('json')\n\t\tthis.fetchImpl = options?.fetchImpl ?? fetch\n\t\tthis.retryDelayMs = options?.retryDelayMs ?? DEFAULT_RETRY_DELAY_MS\n\t\tthis.preferWebSocket = options?.preferWebSocket ?? true\n\t\tthis.webSocketFactory = options?.webSocketFactory ?? (() => new WebSocketTransport({ serializer: this.serializer }))\n\t}\n\n\tasync connect(url: string, options?: TransportOptions): Promise<void> {\n\t\tif (this.connected) {\n\t\t\tthrow new SyncError('HTTP long-poll transport already connected', { url })\n\t\t}\n\n\t\tthis.url = normalizeHttpUrl(url)\n\t\tthis.authToken = options?.authToken\n\n\t\tif (this.preferWebSocket) {\n\t\t\tconst upgraded = await this.tryUpgradeToWebSocket(url, options)\n\t\t\tif (upgraded) {\n\t\t\t\tthis.upgradedTransport = upgraded\n\t\t\t\tthis.connected = true\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\n\t\tthis.connected = true\n\t\tthis.polling = true\n\t\tthis.pollAbort = new AbortController()\n\t\tvoid this.runPollLoop()\n\t}\n\n\tasync disconnect(): Promise<void> {\n\t\tif (this.upgradedTransport) {\n\t\t\tawait this.upgradedTransport.disconnect()\n\t\t\tthis.upgradedTransport = null\n\t\t}\n\n\t\tthis.connected = false\n\t\tthis.polling = false\n\t\tthis.pollAbort?.abort()\n\t\tthis.pollAbort = null\n\t\tthis.url = null\n\t}\n\n\tsend(message: import('../protocol/messages').SyncMessage): void {\n\t\tif (!this.connected) {\n\t\t\tthrow new SyncError('Cannot send message: HTTP long-poll transport is not connected', {\n\t\t\t\tmessageType: message.type,\n\t\t\t})\n\t\t}\n\n\t\tif (this.upgradedTransport) {\n\t\t\tthis.upgradedTransport.send(message)\n\t\t\treturn\n\t\t}\n\n\t\tvoid this.postMessage(message)\n\t}\n\n\tonMessage(handler: TransportMessageHandler): void {\n\t\tthis.messageHandler = handler\n\t\tif (this.upgradedTransport) {\n\t\t\tthis.upgradedTransport.onMessage(handler)\n\t\t}\n\t}\n\n\tonClose(handler: TransportCloseHandler): void {\n\t\tthis.closeHandler = handler\n\t\tif (this.upgradedTransport) {\n\t\t\tthis.upgradedTransport.onClose(handler)\n\t\t}\n\t}\n\n\tonError(handler: TransportErrorHandler): void {\n\t\tthis.errorHandler = handler\n\t\tif (this.upgradedTransport) {\n\t\t\tthis.upgradedTransport.onError(handler)\n\t\t}\n\t}\n\n\tisConnected(): boolean {\n\t\tif (this.upgradedTransport) {\n\t\t\treturn this.upgradedTransport.isConnected()\n\t\t}\n\t\treturn this.connected\n\t}\n\n\tprivate async tryUpgradeToWebSocket(url: string, options?: TransportOptions): Promise<SyncTransport | null> {\n\t\tconst wsTransport = this.webSocketFactory()\n\n\t\tif (this.messageHandler) wsTransport.onMessage(this.messageHandler)\n\t\tif (this.closeHandler) wsTransport.onClose(this.closeHandler)\n\t\tif (this.errorHandler) wsTransport.onError(this.errorHandler)\n\n\t\ttry {\n\t\t\tawait wsTransport.connect(normalizeWebSocketUrl(url), options)\n\t\t\treturn wsTransport\n\t\t} catch {\n\t\t\treturn null\n\t\t}\n\t}\n\n\tprivate async postMessage(message: import('../protocol/messages').SyncMessage): Promise<void> {\n\t\tif (!this.url) return\n\n\t\tconst encoded = this.serializer.encode(message)\n\t\tconst headers = new Headers()\n\t\theaders.set('accept', 'application/json, application/x-protobuf')\n\t\tif (this.authToken) {\n\t\t\theaders.set('authorization', `Bearer ${this.authToken}`)\n\t\t}\n\n\t\tconst isBinary = encoded instanceof Uint8Array\n\t\theaders.set('content-type', isBinary ? 'application/x-protobuf' : 'application/json')\n\n\t\ttry {\n\t\t\tconst requestBody = isBinary ? toArrayBuffer(encoded) : encoded\n\n\t\t\tconst response = await this.fetchImpl(this.url, {\n\t\t\t\tmethod: 'POST',\n\t\t\t\theaders,\n\t\t\t\tbody: requestBody,\n\t\t\t})\n\n\t\t\tif (!response.ok) {\n\t\t\t\tthrow new SyncError('HTTP transport send failed', {\n\t\t\t\t\tstatus: response.status,\n\t\t\t\t\tmessageType: message.type,\n\t\t\t\t})\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tthis.errorHandler?.(error instanceof Error ? error : new Error(String(error)))\n\t\t}\n\t}\n\n\tprivate async runPollLoop(): Promise<void> {\n\t\twhile (this.polling && this.connected && this.url) {\n\t\t\ttry {\n\t\t\t\tconst response = await this.fetchImpl(this.url, {\n\t\t\t\t\tmethod: 'GET',\n\t\t\t\t\theaders: this.makePollHeaders(),\n\t\t\t\t\tsignal: this.pollAbort?.signal,\n\t\t\t\t})\n\n\t\t\t\tif (response.status === 204) {\n\t\t\t\t\tawait sleep(this.retryDelayMs)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\tthrow new SyncError('HTTP long-poll request failed', {\n\t\t\t\t\t\tstatus: response.status,\n\t\t\t\t\t})\n\t\t\t\t}\n\n\t\t\t\tconst payload = await readResponsePayload(response)\n\t\t\t\tif (payload === null) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tconst message = this.serializer.decode(payload)\n\t\t\t\tthis.messageHandler?.(message)\n\t\t\t} catch (error) {\n\t\t\t\tif (!this.connected || !this.polling) {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\tif (isAbortError(error)) {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\tthis.errorHandler?.(error instanceof Error ? error : new Error(String(error)))\n\t\t\t\tawait sleep(this.retryDelayMs)\n\t\t\t}\n\t\t}\n\n\t\tif (!this.connected) {\n\t\t\tthis.closeHandler?.('http long-polling disconnected')\n\t\t}\n\t}\n\n\tprivate makePollHeaders(): Headers {\n\t\tconst headers = new Headers()\n\t\theaders.set('accept', 'application/json, application/x-protobuf')\n\t\tif (this.authToken) {\n\t\t\theaders.set('authorization', `Bearer ${this.authToken}`)\n\t\t}\n\t\treturn headers\n\t}\n}\n\nfunction normalizeHttpUrl(url: string): string {\n\tif (url.startsWith('http://') || url.startsWith('https://')) {\n\t\treturn url\n\t}\n\n\tif (url.startsWith('ws://')) {\n\t\treturn `http://${url.slice('ws://'.length)}`\n\t}\n\n\tif (url.startsWith('wss://')) {\n\t\treturn `https://${url.slice('wss://'.length)}`\n\t}\n\n\treturn url\n}\n\nfunction normalizeWebSocketUrl(url: string): string {\n\tif (url.startsWith('ws://') || url.startsWith('wss://')) {\n\t\treturn url\n\t}\n\n\tif (url.startsWith('http://')) {\n\t\treturn `ws://${url.slice('http://'.length)}`\n\t}\n\n\tif (url.startsWith('https://')) {\n\t\treturn `wss://${url.slice('https://'.length)}`\n\t}\n\n\treturn url\n}\n\nasync function readResponsePayload(response: Response): Promise<string | Uint8Array | null> {\n\tconst contentType = response.headers.get('content-type') ?? ''\n\tif (contentType.includes('application/x-protobuf')) {\n\t\tconst buffer = await response.arrayBuffer()\n\t\tif (buffer.byteLength === 0) return null\n\t\treturn new Uint8Array(buffer)\n\t}\n\n\tconst text = await response.text()\n\tif (text.length === 0) return null\n\treturn text\n}\n\nfunction sleep(ms: number): Promise<void> {\n\treturn new Promise((resolve) => setTimeout(resolve, ms))\n}\n\nfunction isAbortError(error: unknown): boolean {\n\treturn (\n\t\ttypeof error === 'object' &&\n\t\terror !== null &&\n\t\t'name' in error &&\n\t\t(error as { name?: string }).name === 'AbortError'\n\t)\n}\n\nfunction toArrayBuffer(data: Uint8Array): ArrayBuffer {\n\tconst copied = new Uint8Array(data.byteLength)\n\tcopied.set(data)\n\treturn copied.buffer\n}\n","import type { SyncMessage } from '../protocol/messages'\nimport type {\n\tSyncTransport,\n\tTransportCloseHandler,\n\tTransportErrorHandler,\n\tTransportMessageHandler,\n\tTransportOptions,\n} from './transport'\n\n/**\n * Configuration for the chaos transport.\n */\nexport interface ChaosConfig {\n\t/** Probability of dropping a message (0-1). Defaults to 0. */\n\tdropRate?: number\n\t/** Probability of duplicating a message (0-1). Defaults to 0. */\n\tduplicateRate?: number\n\t/** Probability of reordering messages (0-1). Defaults to 0. */\n\treorderRate?: number\n\t/** Maximum latency in ms for delayed messages. Defaults to 0. */\n\tmaxLatency?: number\n\t/** Injectable random source for deterministic testing. Returns value in [0, 1). */\n\trandomSource?: () => number\n}\n\n/**\n * Chaos transport that wraps another transport and injects faults.\n * Used for testing sync convergence under unreliable network conditions.\n *\n * Supports message dropping, duplication, reordering, and latency injection.\n * All random behavior is injectable for deterministic, reproducible tests.\n */\nexport class ChaosTransport implements SyncTransport {\n\tprivate readonly inner: SyncTransport\n\tprivate readonly dropRate: number\n\tprivate readonly duplicateRate: number\n\tprivate readonly reorderRate: number\n\tprivate readonly maxLatency: number\n\tprivate readonly random: () => number\n\n\tprivate messageHandler: TransportMessageHandler | null = null\n\tprivate reorderBuffer: SyncMessage[] = []\n\tprivate timers: ReturnType<typeof setTimeout>[] = []\n\n\tconstructor(inner: SyncTransport, config?: ChaosConfig) {\n\t\tthis.inner = inner\n\t\tthis.dropRate = config?.dropRate ?? 0\n\t\tthis.duplicateRate = config?.duplicateRate ?? 0\n\t\tthis.reorderRate = config?.reorderRate ?? 0\n\t\tthis.maxLatency = config?.maxLatency ?? 0\n\t\tthis.random = config?.randomSource ?? Math.random\n\t}\n\n\tasync connect(url: string, options?: TransportOptions): Promise<void> {\n\t\t// Intercept incoming messages from the inner transport\n\t\tthis.inner.onMessage((msg) => this.handleIncoming(msg))\n\t\treturn this.inner.connect(url, options)\n\t}\n\n\tasync disconnect(): Promise<void> {\n\t\t// Flush reorder buffer\n\t\tthis.flushReorderBuffer()\n\t\t// Clear pending timers\n\t\tfor (const timer of this.timers) {\n\t\t\tclearTimeout(timer)\n\t\t}\n\t\tthis.timers = []\n\t\treturn this.inner.disconnect()\n\t}\n\n\tsend(message: SyncMessage): void {\n\t\t// Apply chaos to outgoing messages\n\t\tif (this.random() < this.dropRate) {\n\t\t\treturn // Dropped\n\t\t}\n\n\t\tif (this.random() < this.reorderRate) {\n\t\t\tthis.reorderBuffer.push(message)\n\t\t\t// Flush buffer on next non-reordered send\n\t\t\treturn\n\t\t}\n\n\t\t// Flush any buffered messages first\n\t\tthis.flushReorderBuffer()\n\n\t\tthis.inner.send(message)\n\n\t\t// Duplicate?\n\t\tif (this.random() < this.duplicateRate) {\n\t\t\tthis.inner.send(message)\n\t\t}\n\t}\n\n\tonMessage(handler: TransportMessageHandler): void {\n\t\tthis.messageHandler = handler\n\t}\n\n\tonClose(handler: TransportCloseHandler): void {\n\t\tthis.inner.onClose(handler)\n\t}\n\n\tonError(handler: TransportErrorHandler): void {\n\t\tthis.inner.onError(handler)\n\t}\n\n\tisConnected(): boolean {\n\t\treturn this.inner.isConnected()\n\t}\n\n\tprivate handleIncoming(message: SyncMessage): void {\n\t\tif (!this.messageHandler) return\n\n\t\t// Apply chaos to incoming messages\n\t\tif (this.random() < this.dropRate) {\n\t\t\treturn // Dropped\n\t\t}\n\n\t\tif (this.maxLatency > 0) {\n\t\t\tconst delay = Math.floor(this.random() * this.maxLatency)\n\t\t\tconst timer = setTimeout(() => {\n\t\t\t\tthis.deliverIncoming(message)\n\t\t\t}, delay)\n\t\t\tthis.timers.push(timer)\n\t\t\treturn\n\t\t}\n\n\t\tthis.deliverIncoming(message)\n\t}\n\n\tprivate deliverIncoming(message: SyncMessage): void {\n\t\tif (!this.messageHandler) return\n\n\t\tthis.messageHandler(message)\n\n\t\t// Duplicate incoming?\n\t\tif (this.random() < this.duplicateRate) {\n\t\t\tthis.messageHandler(message)\n\t\t}\n\t}\n\n\tprivate flushReorderBuffer(): void {\n\t\t// Send buffered messages in random order\n\t\tconst buffer = [...this.reorderBuffer]\n\t\tthis.reorderBuffer = []\n\n\t\t// Fisher-Yates shuffle with injectable random\n\t\tfor (let i = buffer.length - 1; i > 0; i--) {\n\t\t\tconst j = Math.floor(this.random() * (i + 1))\n\t\t\tconst temp = buffer[i] as SyncMessage\n\t\t\tbuffer[i] = buffer[j] as SyncMessage\n\t\t\tbuffer[j] = temp\n\t\t}\n\n\t\tfor (const msg of buffer) {\n\t\t\tthis.inner.send(msg)\n\t\t}\n\t}\n}\n","import type { KoraEventEmitter, Operation, VersionVector } from '@korajs/core'\nimport { SyncError } from '@korajs/core'\nimport { topologicalSort } from '@korajs/core/internal'\nimport type {\n\tAcknowledgmentMessage,\n\tHandshakeResponseMessage,\n\tOperationBatchMessage,\n\tSyncMessage,\n\tWireFormat,\n} from '../protocol/messages'\nimport {\n\tNegotiatedMessageSerializer,\n\tversionVectorToWire,\n\twireToVersionVector,\n} from '../protocol/serializer'\nimport type { MessageSerializer } from '../protocol/serializer'\nimport type { SyncTransport } from '../transport/transport'\nimport type { SyncConfig, SyncState, SyncStatusInfo } from '../types'\nimport type { QueueStorage } from '../types'\nimport { MemoryQueueStorage } from './memory-queue-storage'\nimport type { OutboundBatch } from './outbound-queue'\nimport { OutboundQueue } from './outbound-queue'\nimport type { SyncStore } from './sync-store'\n\nconst DEFAULT_BATCH_SIZE = 100\nconst DEFAULT_SCHEMA_VERSION = 1\n\n/**\n * Valid state transitions for the sync engine state machine.\n */\nconst VALID_TRANSITIONS: Record<SyncState, SyncState[]> = {\n\tdisconnected: ['connecting'],\n\tconnecting: ['handshaking', 'error', 'disconnected'],\n\thandshaking: ['syncing', 'error', 'disconnected'],\n\tsyncing: ['streaming', 'error', 'disconnected'],\n\tstreaming: ['disconnected', 'error'],\n\terror: ['disconnected'],\n}\n\n/**\n * Options for creating a SyncEngine.\n */\nexport interface SyncEngineOptions {\n\t/** Transport implementation (WebSocket, memory, etc.) */\n\ttransport: SyncTransport\n\t/** Local store implementing SyncStore */\n\tstore: SyncStore\n\t/** Sync configuration */\n\tconfig: SyncConfig\n\t/** Message serializer. Defaults to JSON. */\n\tserializer?: MessageSerializer\n\t/** Event emitter for DevTools integration */\n\temitter?: KoraEventEmitter\n\t/** Queue storage for persistent outbound queue. Defaults to in-memory. */\n\tqueueStorage?: QueueStorage\n}\n\nlet nextMessageId = 0\nfunction generateMessageId(): string {\n\treturn `msg-${Date.now()}-${nextMessageId++}`\n}\n\n/**\n * Core sync orchestrator. Manages the sync lifecycle:\n * disconnected → connecting → handshaking → syncing → streaming\n *\n * Coordinates handshake, delta exchange, and real-time streaming\n * between a local store and a remote sync server.\n */\nexport class SyncEngine {\n\tprivate state: SyncState = 'disconnected'\n\tprivate readonly transport: SyncTransport\n\tprivate readonly store: SyncStore\n\tprivate readonly config: SyncConfig\n\tprivate readonly serializer: MessageSerializer\n\tprivate readonly emitter: KoraEventEmitter | null\n\tprivate readonly outboundQueue: OutboundQueue\n\tprivate readonly batchSize: number\n\n\tprivate remoteVector: VersionVector = new Map()\n\tprivate lastSyncedAt: number | null = null\n\tprivate currentBatch: OutboundBatch | null = null\n\tprivate reconnecting = false\n\n\t// Track delta exchange state\n\tprivate deltaBatchesReceived = 0\n\tprivate deltaReceiveComplete = false\n\tprivate deltaSendComplete = false\n\n\tconstructor(options: SyncEngineOptions) {\n\t\tthis.transport = options.transport\n\t\tthis.store = options.store\n\t\tthis.config = options.config\n\t\tthis.serializer = options.serializer ?? new NegotiatedMessageSerializer('json')\n\t\tthis.emitter = options.emitter ?? null\n\t\tthis.batchSize = options.config.batchSize ?? DEFAULT_BATCH_SIZE\n\n\t\tconst queueStorage = options.queueStorage ?? new MemoryQueueStorage()\n\t\tthis.outboundQueue = new OutboundQueue(queueStorage)\n\t}\n\n\t/**\n\t * Start the sync engine: connect → handshake → delta exchange → streaming.\n\t */\n\tasync start(): Promise<void> {\n\t\tif (this.state !== 'disconnected') {\n\t\t\tthrow new SyncError('Cannot start sync engine: not in disconnected state', {\n\t\t\t\tcurrentState: this.state,\n\t\t\t})\n\t\t}\n\n\t\tawait this.outboundQueue.initialize()\n\n\t\t// Set up transport handlers\n\t\tthis.transport.onMessage((msg) => this.handleMessage(msg))\n\t\tthis.transport.onClose((reason) => this.handleTransportClose(reason))\n\t\tthis.transport.onError((err) => this.handleTransportError(err))\n\n\t\tthis.transitionTo('connecting')\n\n\t\ttry {\n\t\t\tconst authToken = this.config.auth ? (await this.config.auth()).token : undefined\n\n\t\t\tawait this.transport.connect(this.config.url, { authToken })\n\t\t\tthis.transitionTo('handshaking')\n\n\t\t\t// Send handshake\n\t\t\tconst localVector = this.store.getVersionVector()\n\t\t\tconst handshake: SyncMessage = {\n\t\t\t\ttype: 'handshake',\n\t\t\t\tmessageId: generateMessageId(),\n\t\t\t\tnodeId: this.store.getNodeId(),\n\t\t\t\tversionVector: versionVectorToWire(localVector),\n\t\t\t\tschemaVersion: this.config.schemaVersion ?? DEFAULT_SCHEMA_VERSION,\n\t\t\t\tauthToken,\n\t\t\t\tsupportedWireFormats: ['json', 'protobuf'],\n\t\t\t}\n\t\t\tthis.transport.send(handshake)\n\t\t} catch (err) {\n\t\t\t// Transport error/close handlers may have already transitioned to disconnected.\n\t\t\t// Guard against invalid state transitions.\n\t\t\tthis.ensureDisconnected()\n\t\t\tthrow err\n\t\t}\n\t}\n\n\t/**\n\t * Stop the sync engine. Disconnects the transport.\n\t */\n\tasync stop(): Promise<void> {\n\t\tif (this.state === 'disconnected') return\n\n\t\t// Return any in-flight batch back to queue\n\t\tif (this.currentBatch) {\n\t\t\tthis.outboundQueue.returnBatch(this.currentBatch.batchId)\n\t\t\tthis.currentBatch = null\n\t\t}\n\n\t\ttry {\n\t\t\tawait this.transport.disconnect()\n\t\t} finally {\n\t\t\t// The transport.disconnect() callback may have already transitioned\n\t\t\t// to 'disconnected' via handleTransportClose. Re-read the mutable field.\n\t\t\tthis.ensureDisconnected()\n\t\t}\n\t}\n\n\tprivate ensureDisconnected(): void {\n\t\tif (this.state !== 'disconnected') {\n\t\t\tthis.transitionTo('disconnected')\n\t\t}\n\t}\n\n\t/**\n\t * Push a local operation to the outbound queue.\n\t * If streaming, flushes immediately.\n\t */\n\tasync pushOperation(op: Operation): Promise<void> {\n\t\tawait this.outboundQueue.enqueue(op)\n\t\tif (this.state === 'streaming') {\n\t\t\tthis.flushQueue()\n\t\t}\n\t}\n\n\t/**\n\t * Mark the engine as being in a reconnection loop. When reconnecting,\n\t * `getStatus()` returns 'offline' instead of 'syncing' for intermediate\n\t * states (connecting, handshaking, syncing), since the user is effectively\n\t * disconnected until reconnection succeeds.\n\t */\n\tsetReconnecting(value: boolean): void {\n\t\tthis.reconnecting = value\n\t}\n\n\t/**\n\t * Get the current developer-facing sync status.\n\t */\n\tgetStatus(): SyncStatusInfo {\n\t\tconst pendingOperations = this.outboundQueue.totalPending\n\t\tswitch (this.state) {\n\t\t\tcase 'disconnected':\n\t\t\t\treturn { status: 'offline', pendingOperations, lastSyncedAt: this.lastSyncedAt }\n\t\t\tcase 'connecting':\n\t\t\tcase 'handshaking':\n\t\t\tcase 'syncing':\n\t\t\t\t// During reconnection attempts, show 'offline' instead of 'syncing'\n\t\t\t\t// since the user is disconnected and reconnection is in progress.\n\t\t\t\treturn {\n\t\t\t\t\tstatus: this.reconnecting ? 'offline' : 'syncing',\n\t\t\t\t\tpendingOperations,\n\t\t\t\t\tlastSyncedAt: this.lastSyncedAt,\n\t\t\t\t}\n\t\t\tcase 'streaming':\n\t\t\t\treturn {\n\t\t\t\t\tstatus: pendingOperations > 0 ? 'syncing' : 'synced',\n\t\t\t\t\tpendingOperations,\n\t\t\t\t\tlastSyncedAt: this.lastSyncedAt,\n\t\t\t\t}\n\t\t\tcase 'error':\n\t\t\t\treturn { status: 'error', pendingOperations, lastSyncedAt: this.lastSyncedAt }\n\t\t}\n\t}\n\n\t/**\n\t * Get the current internal state (for testing).\n\t */\n\tgetState(): SyncState {\n\t\treturn this.state\n\t}\n\n\t/**\n\t * Get the outbound queue (for testing).\n\t */\n\tgetOutboundQueue(): OutboundQueue {\n\t\treturn this.outboundQueue\n\t}\n\n\t// --- Private methods ---\n\n\tprivate handleMessage(message: SyncMessage): void {\n\t\tswitch (message.type) {\n\t\t\tcase 'handshake-response':\n\t\t\t\tthis.handleHandshakeResponse(message)\n\t\t\t\tbreak\n\t\t\tcase 'operation-batch':\n\t\t\t\tthis.handleOperationBatch(message)\n\t\t\t\tbreak\n\t\t\tcase 'acknowledgment':\n\t\t\t\tthis.handleAcknowledgment(message)\n\t\t\t\tbreak\n\t\t\tcase 'error':\n\t\t\t\tthis.handleError(message)\n\t\t\t\tbreak\n\t\t}\n\t}\n\n\tprivate handleHandshakeResponse(msg: HandshakeResponseMessage): void {\n\t\tif (this.state !== 'handshaking') return\n\n\t\tif (!msg.accepted) {\n\t\t\tthis.transitionTo('error')\n\t\t\tthis.emitter?.emit({\n\t\t\t\ttype: 'sync:disconnected',\n\t\t\t\treason: msg.rejectReason ?? 'Handshake rejected',\n\t\t\t})\n\t\t\tthis.transitionTo('disconnected')\n\t\t\treturn\n\t\t}\n\n\t\tthis.remoteVector = wireToVersionVector(msg.versionVector)\n\n\t\tif (msg.selectedWireFormat) {\n\t\t\tthis.setSerializerWireFormat(msg.selectedWireFormat)\n\t\t}\n\n\t\tthis.emitter?.emit({ type: 'sync:connected', nodeId: this.store.getNodeId() })\n\n\t\tthis.transitionTo('syncing')\n\t\tthis.deltaBatchesReceived = 0\n\t\tthis.deltaReceiveComplete = false\n\t\tthis.deltaSendComplete = false\n\n\t\t// Send our delta to the server\n\t\tthis.sendDelta()\n\t}\n\n\tprivate async sendDelta(): Promise<void> {\n\t\tconst localVector = this.store.getVersionVector()\n\t\tconst missingOps = await this.collectDelta(localVector, this.remoteVector)\n\n\t\tif (missingOps.length === 0) {\n\t\t\t// No ops to send — send empty final batch\n\t\t\tconst emptyBatch: SyncMessage = {\n\t\t\t\ttype: 'operation-batch',\n\t\t\t\tmessageId: generateMessageId(),\n\t\t\t\toperations: [],\n\t\t\t\tisFinal: true,\n\t\t\t\tbatchIndex: 0,\n\t\t\t}\n\t\t\tthis.transport.send(emptyBatch)\n\t\t\tthis.deltaSendComplete = true\n\t\t\tthis.checkDeltaComplete()\n\t\t\treturn\n\t\t}\n\n\t\t// Paginate into batches\n\t\tconst sorted = topologicalSort(missingOps)\n\t\tconst totalBatches = Math.ceil(sorted.length / this.batchSize)\n\n\t\tfor (let i = 0; i < totalBatches; i++) {\n\t\t\tconst start = i * this.batchSize\n\t\t\tconst batchOps = sorted.slice(start, start + this.batchSize)\n\t\t\tconst serializedOps = batchOps.map((op) => this.serializer.encodeOperation(op))\n\n\t\t\tconst batchMsg: SyncMessage = {\n\t\t\t\ttype: 'operation-batch',\n\t\t\t\tmessageId: generateMessageId(),\n\t\t\t\toperations: serializedOps,\n\t\t\t\tisFinal: i === totalBatches - 1,\n\t\t\t\tbatchIndex: i,\n\t\t\t}\n\t\t\tthis.transport.send(batchMsg)\n\n\t\t\tthis.emitter?.emit({\n\t\t\t\ttype: 'sync:sent',\n\t\t\t\toperations: batchOps,\n\t\t\t\tbatchSize: batchOps.length,\n\t\t\t})\n\t\t}\n\n\t\tthis.deltaSendComplete = true\n\t\tthis.checkDeltaComplete()\n\t}\n\n\tprivate async collectDelta(\n\t\tlocalVector: VersionVector,\n\t\tremoteVector: VersionVector,\n\t): Promise<Operation[]> {\n\t\tconst missing: Operation[] = []\n\t\tfor (const [nodeId, localSeq] of localVector) {\n\t\t\tconst remoteSeq = remoteVector.get(nodeId) ?? 0\n\t\t\tif (localSeq > remoteSeq) {\n\t\t\t\tconst ops = await this.store.getOperationRange(nodeId, remoteSeq + 1, localSeq)\n\t\t\t\tmissing.push(...ops)\n\t\t\t}\n\t\t}\n\t\treturn missing\n\t}\n\n\tprivate async handleOperationBatch(msg: OperationBatchMessage): Promise<void> {\n\t\tconst operations = msg.operations.map((s) => this.serializer.decodeOperation(s))\n\n\t\t// Apply each operation to the local store\n\t\tfor (const op of operations) {\n\t\t\tawait this.store.applyRemoteOperation(op)\n\t\t}\n\n\t\tif (operations.length > 0) {\n\t\t\tthis.emitter?.emit({\n\t\t\t\ttype: 'sync:received',\n\t\t\t\toperations,\n\t\t\t\tbatchSize: operations.length,\n\t\t\t})\n\t\t}\n\n\t\t// Send acknowledgment\n\t\tconst lastOp = operations[operations.length - 1]\n\t\tconst ack: SyncMessage = {\n\t\t\ttype: 'acknowledgment',\n\t\t\tmessageId: generateMessageId(),\n\t\t\tacknowledgedMessageId: msg.messageId,\n\t\t\tlastSequenceNumber: lastOp ? lastOp.sequenceNumber : 0,\n\t\t}\n\t\tthis.transport.send(ack)\n\n\t\tthis.emitter?.emit({\n\t\t\ttype: 'sync:acknowledged',\n\t\t\tsequenceNumber: lastOp ? lastOp.sequenceNumber : 0,\n\t\t})\n\n\t\tif (this.state === 'syncing') {\n\t\t\tthis.deltaBatchesReceived++\n\t\t\tif (msg.isFinal) {\n\t\t\t\tthis.deltaReceiveComplete = true\n\t\t\t\tthis.checkDeltaComplete()\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate handleAcknowledgment(msg: AcknowledgmentMessage): void {\n\t\tif (this.currentBatch) {\n\t\t\tthis.outboundQueue.acknowledge(this.currentBatch.batchId)\n\t\t\tthis.currentBatch = null\n\t\t\tthis.lastSyncedAt = Date.now()\n\t\t}\n\n\t\t// Continue flushing if more ops in queue\n\t\tif (this.state === 'streaming' && this.outboundQueue.hasOperations) {\n\t\t\tthis.flushQueue()\n\t\t}\n\t}\n\n\tprivate handleError(msg: { code: string; message: string; retriable: boolean }): void {\n\t\tthis.transitionTo('error')\n\t\tif (msg.code === 'AUTH_FAILED') {\n\t\t\tthis.emitter?.emit({ type: 'sync:auth-failed', reason: msg.message })\n\t\t}\n\t\tthis.emitter?.emit({ type: 'sync:disconnected', reason: msg.message })\n\t\tthis.transitionTo('disconnected')\n\t}\n\n\tprivate checkDeltaComplete(): void {\n\t\tif (this.deltaSendComplete && this.deltaReceiveComplete) {\n\t\t\tthis.lastSyncedAt = Date.now()\n\t\t\tthis.transitionTo('streaming')\n\n\t\t\t// Flush any queued operations accumulated during delta exchange\n\t\t\tif (this.outboundQueue.hasOperations) {\n\t\t\t\tthis.flushQueue()\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate flushQueue(): void {\n\t\tif (this.currentBatch) return // Already have an in-flight batch\n\t\tif (!this.outboundQueue.hasOperations) return\n\n\t\tconst batch = this.outboundQueue.takeBatch(this.batchSize)\n\t\tif (!batch) return\n\n\t\tthis.currentBatch = batch\n\n\t\tconst serializedOps = batch.operations.map((op) => this.serializer.encodeOperation(op))\n\t\tconst batchMsg: SyncMessage = {\n\t\t\ttype: 'operation-batch',\n\t\t\tmessageId: generateMessageId(),\n\t\t\toperations: serializedOps,\n\t\t\tisFinal: true,\n\t\t\tbatchIndex: 0,\n\t\t}\n\t\tthis.transport.send(batchMsg)\n\n\t\tthis.emitter?.emit({\n\t\t\ttype: 'sync:sent',\n\t\t\toperations: batch.operations,\n\t\t\tbatchSize: batch.operations.length,\n\t\t})\n\t}\n\n\tprivate handleTransportClose(reason: string): void {\n\t\t// Return in-flight batch to queue\n\t\tif (this.currentBatch) {\n\t\t\tthis.outboundQueue.returnBatch(this.currentBatch.batchId)\n\t\t\tthis.currentBatch = null\n\t\t}\n\n\t\tif (this.state !== 'disconnected') {\n\t\t\tthis.emitter?.emit({ type: 'sync:disconnected', reason })\n\t\t\tthis.transitionTo('disconnected')\n\t\t}\n\t}\n\n\tprivate handleTransportError(err: Error): void {\n\t\t// Transport errors during connecting should transition to error\n\t\tif (this.state !== 'disconnected') {\n\t\t\tthis.transitionTo('error')\n\t\t\tthis.emitter?.emit({ type: 'sync:disconnected', reason: err.message })\n\t\t\tthis.transitionTo('disconnected')\n\t\t}\n\t}\n\n\tprivate transitionTo(newState: SyncState): void {\n\t\tconst validTargets = VALID_TRANSITIONS[this.state]\n\t\tif (!validTargets.includes(newState)) {\n\t\t\tthrow new SyncError(`Invalid sync state transition: ${this.state} → ${newState}`, {\n\t\t\t\tfrom: this.state,\n\t\t\t\tto: newState,\n\t\t\t})\n\t\t}\n\t\tthis.state = newState\n\t}\n\n\tprivate setSerializerWireFormat(format: WireFormat): void {\n\t\tif (typeof this.serializer.setWireFormat === 'function') {\n\t\t\tthis.serializer.setWireFormat(format)\n\t\t}\n\t}\n}\n","import type { Operation } from '@korajs/core'\nimport type { QueueStorage } from '../types'\n\n/**\n * In-memory QueueStorage implementation for testing.\n * Operations are lost on process restart — production should use\n * IndexedDB or OPFS-backed storage.\n */\nexport class MemoryQueueStorage implements QueueStorage {\n\tprivate operations: Map<string, Operation> = new Map()\n\n\tasync load(): Promise<Operation[]> {\n\t\treturn [...this.operations.values()]\n\t}\n\n\tasync enqueue(op: Operation): Promise<void> {\n\t\tthis.operations.set(op.id, op)\n\t}\n\n\tasync dequeue(ids: string[]): Promise<void> {\n\t\tfor (const id of ids) {\n\t\t\tthis.operations.delete(id)\n\t\t}\n\t}\n\n\tasync count(): Promise<number> {\n\t\treturn this.operations.size\n\t}\n}\n","import type { Operation } from '@korajs/core'\nimport { topologicalSort } from '@korajs/core/internal'\nimport type { QueueStorage } from '../types'\n\n/**\n * A batch of operations taken from the queue for sending.\n */\nexport interface OutboundBatch {\n\t/** Unique identifier for this batch */\n\tbatchId: string\n\t/** Operations in this batch, in causal order */\n\toperations: Operation[]\n}\n\n/**\n * Outbound operation queue with pluggable persistence.\n * Manages operations waiting to be sent to the sync server.\n *\n * Operations are deduplicated by ID (content-addressed) and maintained\n * in causal order via topological sort.\n */\nexport class OutboundQueue {\n\tprivate queue: Operation[] = []\n\tprivate readonly seen: Set<string> = new Set()\n\tprivate readonly inFlight: Map<string, Operation[]> = new Map()\n\tprivate nextBatchId = 0\n\tprivate initialized = false\n\n\tconstructor(private readonly storage: QueueStorage) {}\n\n\t/**\n\t * Load persisted operations from storage.\n\t * Must be called before using the queue.\n\t */\n\tasync initialize(): Promise<void> {\n\t\tconst stored = await this.storage.load()\n\t\tfor (const op of stored) {\n\t\t\tif (!this.seen.has(op.id)) {\n\t\t\t\tthis.seen.add(op.id)\n\t\t\t\tthis.queue.push(op)\n\t\t\t}\n\t\t}\n\t\t// Ensure causal order\n\t\tif (this.queue.length > 1) {\n\t\t\tthis.queue = topologicalSort(this.queue)\n\t\t}\n\t\tthis.initialized = true\n\t}\n\n\t/**\n\t * Add an operation to the outbound queue.\n\t * Deduplicates by operation ID. Persists to storage.\n\t */\n\tasync enqueue(op: Operation): Promise<void> {\n\t\tif (this.seen.has(op.id)) return\n\n\t\tthis.seen.add(op.id)\n\t\tthis.queue.push(op)\n\t\tawait this.storage.enqueue(op)\n\n\t\t// Re-sort to maintain causal order when new ops arrive\n\t\tif (this.queue.length > 1) {\n\t\t\tthis.queue = topologicalSort(this.queue)\n\t\t}\n\t}\n\n\t/**\n\t * Take a batch of operations from the front of the queue.\n\t * Moves them to in-flight status. Returns null if queue is empty.\n\t *\n\t * @param batchSize - Maximum number of operations in the batch\n\t */\n\ttakeBatch(batchSize: number): OutboundBatch | null {\n\t\tif (this.queue.length === 0) return null\n\n\t\tconst ops = this.queue.splice(0, batchSize)\n\t\tconst batchId = `batch-${this.nextBatchId++}`\n\t\tthis.inFlight.set(batchId, ops)\n\n\t\treturn { batchId, operations: ops }\n\t}\n\n\t/**\n\t * Acknowledge a batch, removing its operations permanently.\n\t */\n\tasync acknowledge(batchId: string): Promise<void> {\n\t\tconst ops = this.inFlight.get(batchId)\n\t\tif (!ops) return\n\n\t\tthis.inFlight.delete(batchId)\n\t\tconst ids = ops.map((op) => op.id)\n\t\tawait this.storage.dequeue(ids)\n\t}\n\n\t/**\n\t * Return a failed batch to the front of the queue for retry.\n\t * Prepends the operations to maintain priority.\n\t */\n\treturnBatch(batchId: string): void {\n\t\tconst ops = this.inFlight.get(batchId)\n\t\tif (!ops) return\n\n\t\tthis.inFlight.delete(batchId)\n\t\t// Prepend returned ops, then re-sort for causal order\n\t\tthis.queue.unshift(...ops)\n\t\tif (this.queue.length > 1) {\n\t\t\tthis.queue = topologicalSort(this.queue)\n\t\t}\n\t}\n\n\t/**\n\t * Number of operations waiting in the queue (not counting in-flight).\n\t */\n\tget size(): number {\n\t\treturn this.queue.length\n\t}\n\n\t/**\n\t * Total operations including in-flight.\n\t */\n\tget totalPending(): number {\n\t\tlet inFlightCount = 0\n\t\tfor (const ops of this.inFlight.values()) {\n\t\t\tinFlightCount += ops.length\n\t\t}\n\t\treturn this.queue.length + inFlightCount\n\t}\n\n\t/**\n\t * Whether the queue has any operations to send.\n\t */\n\tget hasOperations(): boolean {\n\t\treturn this.queue.length > 0\n\t}\n\n\t/**\n\t * Peek at the first `count` operations without removing them.\n\t */\n\tpeek(count: number): Operation[] {\n\t\treturn this.queue.slice(0, count)\n\t}\n\n\t/**\n\t * Whether initialize() has been called.\n\t */\n\tget isInitialized(): boolean {\n\t\treturn this.initialized\n\t}\n}\n","import type { ConnectionQuality, TimeSource } from '@korajs/core'\n\n/**\n * Configuration for the connection monitor.\n */\nexport interface ConnectionMonitorConfig {\n\t/** Number of latency samples to keep in the rolling window. Defaults to 20. */\n\twindowSize?: number\n\t/** Time in ms after which the connection is considered stale. Defaults to 30000. */\n\tstaleThreshold?: number\n\t/** Injectable time source for deterministic testing */\n\ttimeSource?: TimeSource\n}\n\n/**\n * Monitors connection quality based on RTT latency samples,\n * missed acknowledgments, and activity timestamps.\n */\nexport class ConnectionMonitor {\n\tprivate readonly windowSize: number\n\tprivate readonly staleThreshold: number\n\tprivate readonly timeSource: TimeSource\n\n\tprivate latencies: number[] = []\n\tprivate missedAcks = 0\n\tprivate lastActivityTime: number\n\n\tconstructor(config?: ConnectionMonitorConfig) {\n\t\tthis.windowSize = config?.windowSize ?? 20\n\t\tthis.staleThreshold = config?.staleThreshold ?? 30000\n\t\tthis.timeSource = config?.timeSource ?? { now: () => Date.now() }\n\t\tthis.lastActivityTime = this.timeSource.now()\n\t}\n\n\t/**\n\t * Record a round-trip time sample.\n\t */\n\trecordLatency(ms: number): void {\n\t\tthis.latencies.push(ms)\n\t\tif (this.latencies.length > this.windowSize) {\n\t\t\tthis.latencies.shift()\n\t\t}\n\t\tthis.lastActivityTime = this.timeSource.now()\n\t\t// Successful response resets missed acks\n\t\tthis.missedAcks = 0\n\t}\n\n\t/**\n\t * Record a missed acknowledgment (message sent but no response received).\n\t */\n\trecordMissedAck(): void {\n\t\tthis.missedAcks++\n\t}\n\n\t/**\n\t * Record any activity (message sent or received).\n\t */\n\trecordActivity(): void {\n\t\tthis.lastActivityTime = this.timeSource.now()\n\t}\n\n\t/**\n\t * Assess current connection quality based on collected metrics.\n\t *\n\t * Quality thresholds (average RTT):\n\t * - excellent: < 100ms, 0 missed acks\n\t * - good: < 300ms, ≤ 1 missed ack\n\t * - fair: < 1000ms, ≤ 3 missed acks\n\t * - poor: < 5000ms or > 3 missed acks\n\t * - offline: no activity for staleThreshold ms\n\t */\n\tgetQuality(): ConnectionQuality {\n\t\tconst elapsed = this.timeSource.now() - this.lastActivityTime\n\t\tif (elapsed > this.staleThreshold) return 'offline'\n\n\t\tif (this.latencies.length === 0) {\n\t\t\t// No data yet — assume good until proven otherwise\n\t\t\treturn this.missedAcks > 3 ? 'poor' : 'good'\n\t\t}\n\n\t\tconst avgLatency = this.latencies.reduce((sum, l) => sum + l, 0) / this.latencies.length\n\n\t\tif (this.missedAcks > 3) return 'poor'\n\t\tif (avgLatency < 100 && this.missedAcks === 0) return 'excellent'\n\t\tif (avgLatency < 300 && this.missedAcks <= 1) return 'good'\n\t\tif (avgLatency < 1000 && this.missedAcks <= 3) return 'fair'\n\t\treturn 'poor'\n\t}\n\n\t/**\n\t * Reset all metrics. Call on disconnect.\n\t */\n\treset(): void {\n\t\tthis.latencies = []\n\t\tthis.missedAcks = 0\n\t\tthis.lastActivityTime = this.timeSource.now()\n\t}\n\n\t/**\n\t * Get the current average latency in ms. Returns null if no samples.\n\t */\n\tgetAverageLatency(): number | null {\n\t\tif (this.latencies.length === 0) return null\n\t\treturn this.latencies.reduce((sum, l) => sum + l, 0) / this.latencies.length\n\t}\n\n\t/**\n\t * Get the number of missed acks.\n\t */\n\tgetMissedAcks(): number {\n\t\treturn this.missedAcks\n\t}\n}\n","import type { TimeSource } from '@korajs/core'\n\n/**\n * Configuration for the reconnection manager.\n */\nexport interface ReconnectionConfig {\n\t/** Initial delay in ms before first reconnection attempt. Defaults to 1000. */\n\tinitialDelay?: number\n\t/** Maximum delay in ms between attempts. Defaults to 30000. */\n\tmaxDelay?: number\n\t/** Multiplier for exponential backoff. Defaults to 2. */\n\tmultiplier?: number\n\t/** Maximum number of reconnection attempts. 0 means unlimited. Defaults to 0. */\n\tmaxAttempts?: number\n\t/** Jitter factor (0-1). Random variation applied to delay. Defaults to 0.25. */\n\tjitter?: number\n\t/** Injectable time source for deterministic testing. */\n\ttimeSource?: TimeSource\n\t/** Injectable random source for deterministic jitter. Returns value in [0, 1). */\n\trandomSource?: () => number\n}\n\n/**\n * Manages reconnection attempts with exponential backoff and jitter.\n *\n * Formula: min(initialDelay * multiplier^attempt, maxDelay) * (1 + jitter * (random - 0.5) * 2)\n */\nexport class ReconnectionManager {\n\tprivate readonly initialDelay: number\n\tprivate readonly maxDelay: number\n\tprivate readonly multiplier: number\n\tprivate readonly maxAttempts: number\n\tprivate readonly jitter: number\n\tprivate readonly random: () => number\n\n\tprivate attempt = 0\n\tprivate timer: ReturnType<typeof setTimeout> | null = null\n\tprivate stopped = false\n\tprivate running = false\n\tprivate waitResolve: (() => void) | null = null\n\n\tconstructor(config?: ReconnectionConfig) {\n\t\tthis.initialDelay = config?.initialDelay ?? 1000\n\t\tthis.maxDelay = config?.maxDelay ?? 30000\n\t\tthis.multiplier = config?.multiplier ?? 2\n\t\tthis.maxAttempts = config?.maxAttempts ?? 0\n\t\tthis.jitter = config?.jitter ?? 0.25\n\t\tthis.random = config?.randomSource ?? Math.random\n\t}\n\n\t/**\n\t * Start reconnection attempts. Calls `onReconnect` with exponential backoff.\n\t *\n\t * @param onReconnect - Called on each attempt. Return `true` if reconnection succeeded.\n\t * @returns Promise that resolves when reconnection succeeds or maxAttempts reached.\n\t */\n\tasync start(onReconnect: () => Promise<boolean>): Promise<boolean> {\n\t\tthis.stopped = false\n\t\tthis.running = true\n\t\tthis.attempt = 0\n\n\t\ttry {\n\t\t\twhile (!this.stopped) {\n\t\t\t\tif (this.maxAttempts > 0 && this.attempt >= this.maxAttempts) {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\n\t\t\t\tconst delay = this.getNextDelay()\n\t\t\t\tthis.attempt++\n\n\t\t\t\tawait this.wait(delay)\n\n\t\t\t\tif (this.stopped) return false\n\n\t\t\t\ttry {\n\t\t\t\t\tconst success = await onReconnect()\n\t\t\t\t\tif (success) {\n\t\t\t\t\t\tthis.reset()\n\t\t\t\t\t\treturn true\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// Continue retrying on failure\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn false\n\t\t} finally {\n\t\t\tthis.running = false\n\t\t}\n\t}\n\n\t/**\n\t * Stop any pending reconnection attempt.\n\t */\n\tstop(): void {\n\t\tthis.stopped = true\n\t\tif (this.timer !== null) {\n\t\t\tclearTimeout(this.timer)\n\t\t\tthis.timer = null\n\t\t}\n\t\t// Resolve the pending wait promise so start() loop can exit\n\t\tif (this.waitResolve) {\n\t\t\tthis.waitResolve()\n\t\t\tthis.waitResolve = null\n\t\t}\n\t}\n\n\t/**\n\t * Reset the attempt counter. Call after a successful manual reconnection.\n\t */\n\treset(): void {\n\t\tthis.attempt = 0\n\t\tthis.stopped = false\n\t}\n\n\t/**\n\t * Compute the next delay for the current attempt.\n\t * Exposed for testing purposes.\n\t */\n\tgetNextDelay(): number {\n\t\tconst baseDelay = Math.min(this.initialDelay * this.multiplier ** this.attempt, this.maxDelay)\n\n\t\t// Apply jitter: varies the delay by ±jitter factor\n\t\tconst jitterRange = baseDelay * this.jitter\n\t\tconst jitterOffset = (this.random() - 0.5) * 2 * jitterRange\n\t\treturn Math.max(0, Math.round(baseDelay + jitterOffset))\n\t}\n\n\t/**\n\t * Whether the reconnection loop is currently running.\n\t */\n\tisRunning(): boolean {\n\t\treturn this.running\n\t}\n\n\t/**\n\t * Current attempt number (for testing).\n\t */\n\tgetAttemptCount(): number {\n\t\treturn this.attempt\n\t}\n\n\tprivate wait(ms: number): Promise<void> {\n\t\treturn new Promise((resolve) => {\n\t\t\tthis.waitResolve = resolve\n\t\t\tthis.timer = setTimeout(() => {\n\t\t\t\tthis.timer = null\n\t\t\t\tthis.waitResolve = null\n\t\t\t\tresolve()\n\t\t\t}, ms)\n\t\t})\n\t}\n}\n"],"mappings":"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","names":["protobuf","import_core","import_core","import_core","import_internal"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/types.ts","../src/scopes/scope-filter.ts","../src/protocol/messages.ts","../src/protocol/serializer.ts","../src/transport/websocket-transport.ts","../src/transport/http-long-polling-transport.ts","../src/transport/chaos-transport.ts","../src/engine/sync-engine.ts","../src/diagnostics/bandwidth-estimator.ts","../src/diagnostics/percentile.ts","../src/diagnostics/metrics-collector.ts","../src/awareness/awareness-manager.ts","../src/engine/memory-queue-storage.ts","../src/engine/outbound-queue.ts","../src/engine/connection-monitor.ts","../src/engine/reconnection-manager.ts","../src/encryption/sync-encryptor.ts","../src/encryption/key-derivation.ts"],"sourcesContent":["// @korajs/sync — public API\n// Every export here is a public API commitment. Be explicit.\n\n// === Types ===\nexport type {\n\tQueueStorage,\n\tSyncConfig,\n\tSyncEncryptionConfig,\n\tSyncScopeContext,\n\tSyncScopeMap,\n\tSyncState,\n\tSyncStatus,\n\tSyncStatusInfo,\n} from './types'\n\nexport { InvalidScopeError, ScopeViolationError, SYNC_STATES, SYNC_STATUSES } from './types'\n\n// === Scope Filtering ===\nexport { filterOperationsByScope, operationMatchesScope } from './scopes/scope-filter'\n\n// === SyncStore Interface ===\nexport type { ApplyResult, SyncStore } from './engine/sync-store'\n\n// === Protocol Messages ===\nexport type {\n\tAcknowledgmentMessage,\n\tErrorMessage,\n\tHandshakeMessage,\n\tHandshakeResponseMessage,\n\tOperationBatchMessage,\n\tSerializedOperation,\n\tSyncMessage,\n\tWireFormat,\n} from './protocol/messages'\n\nexport {\n\tisAcknowledgmentMessage,\n\tisErrorMessage,\n\tisHandshakeMessage,\n\tisHandshakeResponseMessage,\n\tisOperationBatchMessage,\n\tisSyncMessage,\n} from './protocol/messages'\n\n// === Serialization ===\nexport type { MessageSerializer } from './protocol/serializer'\n\nexport {\n\tJsonMessageSerializer,\n\tNegotiatedMessageSerializer,\n\tProtobufMessageSerializer,\n\tversionVectorToWire,\n\twireToVersionVector,\n} from './protocol/serializer'\n\n// === Transport ===\nexport type {\n\tSyncTransport,\n\tTransportCloseHandler,\n\tTransportErrorHandler,\n\tTransportMessageHandler,\n\tTransportOptions,\n} from './transport/transport'\n\nexport type {\n\tWebSocketConstructor,\n\tWebSocketLike,\n\tWebSocketTransportOptions,\n} from './transport/websocket-transport'\n\nexport type { HttpLongPollingTransportOptions } from './transport/http-long-polling-transport'\n\nexport { WebSocketTransport } from './transport/websocket-transport'\nexport { HttpLongPollingTransport } from './transport/http-long-polling-transport'\n\nexport type { ChaosConfig } from './transport/chaos-transport'\n\nexport { ChaosTransport } from './transport/chaos-transport'\n\n// === Engine ===\nexport type { SyncDiagnostics, SyncEngineOptions } from './engine/sync-engine'\n\nexport { SyncEngine } from './engine/sync-engine'\n\nexport type { OutboundBatch } from './engine/outbound-queue'\n\nexport { OutboundQueue } from './engine/outbound-queue'\n\nexport type { ConnectionMonitorConfig } from './engine/connection-monitor'\n\nexport { ConnectionMonitor } from './engine/connection-monitor'\n\nexport type { ReconnectionConfig } from './engine/reconnection-manager'\n\nexport { ReconnectionManager } from './engine/reconnection-manager'\n\n// === Awareness ===\nexport type {\n\tAwarenessChange,\n\tAwarenessCursor,\n\tAwarenessMessage,\n\tAwarenessState,\n\tAwarenessUser,\n\tCursorInfo,\n} from './awareness/types'\n\nexport { AwarenessManager } from './awareness/awareness-manager'\n\n// === Awareness Protocol Messages ===\nexport type {\n\tAwarenessStateWire,\n\tAwarenessUpdateMessage,\n} from './protocol/messages'\n\nexport { isAwarenessUpdateMessage } from './protocol/messages'\n\n// === Encryption ===\nexport type {\n\tEncryptedPayload,\n\tSyncEncryptionAlgorithm,\n\tVersionedKey,\n} from './encryption/types'\n\nexport { SyncEncryptor, EncryptionError, DecryptionError, isEncryptedPayload } from './encryption/sync-encryptor'\n\nexport { KeyDerivationError, deriveKey, deriveVersionedKey, generateSalt } from './encryption/key-derivation'\n","import type { Operation } from '@korajs/core'\nimport { KoraError } from '@korajs/core'\nimport type { SyncEncryptionConfig } from './encryption/types'\n\n// Re-export for convenience — consumers can import from '@korajs/sync' types\nexport type { SyncEncryptionConfig }\n\n/**\n * Internal sync engine states. Used for state machine transitions.\n */\nexport const SYNC_STATES = [\n\t'disconnected',\n\t'connecting',\n\t'handshaking',\n\t'syncing',\n\t'streaming',\n\t'error',\n] as const\nexport type SyncState = (typeof SYNC_STATES)[number]\n\n/**\n * Developer-facing sync status. Simplified view of the internal state.\n */\nexport const SYNC_STATUSES = ['connected', 'syncing', 'synced', 'offline', 'error'] as const\nexport type SyncStatus = (typeof SYNC_STATUSES)[number]\n\n/**\n * Sync status information exposed to developers.\n */\nexport interface SyncStatusInfo {\n\t/** Current developer-facing status */\n\tstatus: SyncStatus\n\t/** Number of operations waiting to be sent */\n\tpendingOperations: number\n\t/** Timestamp of last successful sync (null if never synced) */\n\tlastSyncedAt: number | null\n\t/** Timestamp of last successful push to the server (null if never pushed) */\n\tlastSuccessfulPush: number | null\n\t/** Timestamp of last successful pull from the server (null if never pulled) */\n\tlastSuccessfulPull: number | null\n\t/** Number of merge conflicts encountered during this session */\n\tconflicts: number\n}\n\n/**\n * Per-collection sync scope map. Maps collection names to field-value filters.\n * Empty filter `{}` means no restriction (all records visible).\n * Missing collection means hidden (no records visible for that collection).\n */\nexport type SyncScopeMap = Record<string, Record<string, unknown>>\n\n/**\n * Sync configuration provided by the developer.\n */\nexport interface SyncConfig {\n\t/** WebSocket or HTTP URL for the sync server */\n\turl: string\n\t/** Transport type to use. Defaults to 'websocket'. */\n\ttransport?: 'websocket' | 'http'\n\t/** Auth provider function. Called before each connection attempt. */\n\tauth?: () => Promise<{ token: string }>\n\t/** Sync scopes per collection. Limits which records sync to this client. */\n\tscopes?: Record<string, (ctx: SyncScopeContext) => Record<string, unknown>>\n\t/**\n\t * Pre-computed per-collection sync scope map. Sent to the server in the handshake.\n\t * Built automatically by createApp from schema scope declarations + flat scope values.\n\t */\n\tscopeMap?: SyncScopeMap\n\t/** Number of operations per batch. Defaults to 100. */\n\tbatchSize?: number\n\t/** Initial reconnection delay in ms. Defaults to 1000. */\n\treconnectInterval?: number\n\t/** Maximum reconnection delay in ms. Defaults to 30000. */\n\tmaxReconnectInterval?: number\n\t/** Schema version of this client. */\n\tschemaVersion?: number\n\t/**\n\t * End-to-end encryption configuration.\n\t * When enabled, `data` and `previousData` fields are encrypted before sending\n\t * over the wire. The server never sees plaintext user data.\n\t */\n\tencryption?: SyncEncryptionConfig\n}\n\n/**\n * Context passed to sync scope functions.\n */\nexport interface SyncScopeContext {\n\tuserId?: string\n\t[key: string]: unknown\n}\n\n/**\n * Interface for persisting the outbound operation queue.\n * Operations must survive page refreshes and be sent when connection is re-established.\n */\nexport interface QueueStorage {\n\t/** Load all queued operations from persistent storage */\n\tload(): Promise<Operation[]>\n\t/** Persist an operation to the queue */\n\tenqueue(op: Operation): Promise<void>\n\t/** Remove acknowledged operations by their IDs */\n\tdequeue(ids: string[]): Promise<void>\n\t/** Return number of operations in storage */\n\tcount(): Promise<number>\n}\n\n/**\n * Thrown when an operation violates sync scope constraints.\n * This can happen when:\n * - A client tries to push an operation outside its configured scope\n * - The server rejects an operation because it falls outside the client's scope\n */\nexport class ScopeViolationError extends KoraError {\n\tconstructor(\n\t\tpublic readonly operationId: string,\n\t\tpublic readonly collection: string,\n\t\tpublic readonly scope: Record<string, unknown>,\n\t\tmessage?: string,\n\t) {\n\t\tsuper(\n\t\t\tmessage ??\n\t\t\t\t`Operation \"${operationId}\" in collection \"${collection}\" violates sync scope`,\n\t\t\t'SCOPE_VIOLATION',\n\t\t\t{ operationId, collection, scope },\n\t\t)\n\t\tthis.name = 'ScopeViolationError'\n\t}\n}\n\n/**\n * Thrown when a sync scope configuration is invalid.\n */\nexport class InvalidScopeError extends KoraError {\n\tconstructor(message: string, context?: Record<string, unknown>) {\n\t\tsuper(message, 'INVALID_SCOPE', context)\n\t\tthis.name = 'InvalidScopeError'\n\t}\n}\n","import type { Operation } from '@korajs/core'\nimport type { SyncScopeMap } from '../types'\n\n/**\n * Check whether an operation matches the given scope map.\n *\n * Rules:\n * - No scope map configured: operation is always in scope.\n * - Collection not present in scope map: operation is out of scope.\n * - Empty scope for a collection `{}`: no field restrictions, operation is in scope.\n * - Scope has field/value pairs: all must match in the operation's data snapshot.\n *\n * For updates, the snapshot is built by merging `previousData` and `data` (data wins),\n * which represents the record's state after the operation is applied.\n *\n * @param op - The operation to check\n * @param scopeMap - Per-collection scope filters, or undefined for no filtering\n * @returns true if the operation is within scope\n */\nexport function operationMatchesScope(op: Operation, scopeMap: SyncScopeMap | undefined): boolean {\n\tif (!scopeMap) return true\n\n\tconst collectionScope = scopeMap[op.collection]\n\t// Collection not present in scope map means it's out of scope\n\tif (!collectionScope) return false\n\n\t// Empty scope means no field restrictions\n\tif (Object.keys(collectionScope).length === 0) return true\n\n\tconst snapshot = buildSnapshot(op)\n\tif (!snapshot) return false\n\n\tfor (const [field, expected] of Object.entries(collectionScope)) {\n\t\tif (snapshot[field] !== expected) {\n\t\t\treturn false\n\t\t}\n\t}\n\n\treturn true\n}\n\n/**\n * Filter operations to only those matching the given scope map.\n *\n * @param operations - Array of operations to filter\n * @param scopeMap - Per-collection scope filters\n * @returns Operations that match the scope\n */\nexport function filterOperationsByScope(\n\toperations: Operation[],\n\tscopeMap: SyncScopeMap | undefined,\n): Operation[] {\n\tif (!scopeMap) return operations\n\treturn operations.filter((op) => operationMatchesScope(op, scopeMap))\n}\n\nfunction buildSnapshot(op: Operation): Record<string, unknown> | null {\n\tconst previous = asRecord(op.previousData)\n\tconst next = asRecord(op.data)\n\n\tif (!previous && !next) return null\n\n\treturn {\n\t\t...(previous ?? {}),\n\t\t...(next ?? {}),\n\t}\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | null {\n\tif (typeof value !== 'object' || value === null || Array.isArray(value)) {\n\t\treturn null\n\t}\n\treturn value as Record<string, unknown>\n}\n","import type { AtomicOp, HLCTimestamp, OperationType } from '@korajs/core'\n\nexport type WireFormat = 'json' | 'protobuf'\n\n/**\n * Wire-format operation. Plain object (no Map) for JSON serialization.\n * Maps 1:1 with Operation, but uses Record instead of Map for version vectors.\n */\nexport interface SerializedOperation {\n\tid: string\n\tnodeId: string\n\ttype: OperationType\n\tcollection: string\n\trecordId: string\n\tdata: Record<string, unknown> | null\n\tpreviousData: Record<string, unknown> | null\n\ttimestamp: HLCTimestamp\n\tsequenceNumber: number\n\tcausalDeps: string[]\n\tschemaVersion: number\n\t/** Atomic operation intents, present only when atomic ops were used. */\n\tatomicOps?: Record<string, AtomicOp>\n\t/** Groups this operation with others in an atomic transaction. */\n\ttransactionId?: string\n\t/** Human-readable name for the mutation group. For DevTools display. */\n\tmutationName?: string\n}\n\n/**\n * Handshake message sent by client to initiate sync.\n */\nexport interface HandshakeMessage {\n\ttype: 'handshake'\n\tmessageId: string\n\tnodeId: string\n\t/** Version vector as plain object (nodeId -> sequence number) */\n\tversionVector: Record<string, number>\n\tschemaVersion: number\n\tauthToken?: string\n\tsupportedWireFormats?: WireFormat[]\n\t/** Per-collection sync scope filters. Limits which records are synced to this client. */\n\tsyncScope?: Record<string, Record<string, unknown>>\n}\n\n/**\n * Server response to a handshake.\n */\nexport interface HandshakeResponseMessage {\n\ttype: 'handshake-response'\n\tmessageId: string\n\tnodeId: string\n\tversionVector: Record<string, number>\n\tschemaVersion: number\n\taccepted: boolean\n\trejectReason?: string\n\tselectedWireFormat?: WireFormat\n\t/** The server-accepted per-collection sync scope. Confirms what data will be synced. */\n\tacceptedScope?: Record<string, Record<string, unknown>>\n}\n\n/**\n * Batch of operations sent during delta exchange or streaming.\n */\nexport interface OperationBatchMessage {\n\ttype: 'operation-batch'\n\tmessageId: string\n\toperations: SerializedOperation[]\n\t/** True if this is the last batch in the delta exchange phase */\n\tisFinal: boolean\n\t/** Index of this batch (0-based) for ordering */\n\tbatchIndex: number\n}\n\n/**\n * Acknowledgment of a received message.\n */\nexport interface AcknowledgmentMessage {\n\ttype: 'acknowledgment'\n\tmessageId: string\n\tacknowledgedMessageId: string\n\tlastSequenceNumber: number\n}\n\n/**\n * Error message from the server or client.\n */\nexport interface ErrorMessage {\n\ttype: 'error'\n\tmessageId: string\n\tcode: string\n\tmessage: string\n\tretriable: boolean\n}\n\n/**\n * Awareness state for a single client (cursor position, user info).\n * Wire-format representation for JSON transport.\n * Ephemeral -- not persisted, only shared with connected peers.\n */\nexport interface AwarenessStateWire {\n\tuser: {\n\t\tname: string\n\t\tcolor: string\n\t\tavatar?: string\n\t}\n\tcursor?: {\n\t\tcollection: string\n\t\trecordId: string\n\t\tfield: string\n\t\tanchor: number\n\t\thead: number\n\t}\n}\n\n/**\n * Awareness update message. Carries ephemeral presence data (cursors, user info).\n * Processed separately from operation sync -- never persisted.\n */\nexport interface AwarenessUpdateMessage {\n\ttype: 'awareness-update'\n\tmessageId: string\n\t/** Client ID of the sender */\n\tclientId: number\n\t/** Map of clientId -> state (null means removal) */\n\tstates: Record<string, AwarenessStateWire | null>\n}\n\n/**\n * Union of all sync protocol messages.\n */\nexport type SyncMessage =\n\t| HandshakeMessage\n\t| HandshakeResponseMessage\n\t| OperationBatchMessage\n\t| AcknowledgmentMessage\n\t| ErrorMessage\n\t| AwarenessUpdateMessage\n\n// --- Type Guards ---\n\n/**\n * Check if an unknown value is a valid SyncMessage.\n */\nexport function isSyncMessage(value: unknown): value is SyncMessage {\n\tif (typeof value !== 'object' || value === null) return false\n\tconst msg = value as Record<string, unknown>\n\tif (typeof msg.type !== 'string' || typeof msg.messageId !== 'string') return false\n\tswitch (msg.type) {\n\t\tcase 'handshake':\n\t\t\treturn isHandshakeMessage(value)\n\t\tcase 'handshake-response':\n\t\t\treturn isHandshakeResponseMessage(value)\n\t\tcase 'operation-batch':\n\t\t\treturn isOperationBatchMessage(value)\n\t\tcase 'acknowledgment':\n\t\t\treturn isAcknowledgmentMessage(value)\n\t\tcase 'error':\n\t\t\treturn isErrorMessage(value)\n\t\tcase 'awareness-update':\n\t\t\treturn isAwarenessUpdateMessage(value)\n\t\tdefault:\n\t\t\treturn false\n\t}\n}\n\n/**\n * Check if a value is a HandshakeMessage.\n */\nexport function isHandshakeMessage(value: unknown): value is HandshakeMessage {\n\tif (typeof value !== 'object' || value === null) return false\n\tconst msg = value as Record<string, unknown>\n\treturn (\n\t\tmsg.type === 'handshake' &&\n\t\ttypeof msg.messageId === 'string' &&\n\t\ttypeof msg.nodeId === 'string' &&\n\t\ttypeof msg.versionVector === 'object' &&\n\t\tmsg.versionVector !== null &&\n\t\t!Array.isArray(msg.versionVector) &&\n\t\ttypeof msg.schemaVersion === 'number'\n\t)\n}\n\n/**\n * Check if a value is a HandshakeResponseMessage.\n */\nexport function isHandshakeResponseMessage(value: unknown): value is HandshakeResponseMessage {\n\tif (typeof value !== 'object' || value === null) return false\n\tconst msg = value as Record<string, unknown>\n\treturn (\n\t\tmsg.type === 'handshake-response' &&\n\t\ttypeof msg.messageId === 'string' &&\n\t\ttypeof msg.nodeId === 'string' &&\n\t\ttypeof msg.versionVector === 'object' &&\n\t\tmsg.versionVector !== null &&\n\t\t!Array.isArray(msg.versionVector) &&\n\t\ttypeof msg.schemaVersion === 'number' &&\n\t\ttypeof msg.accepted === 'boolean'\n\t)\n}\n\n/**\n * Check if a value is an OperationBatchMessage.\n */\nexport function isOperationBatchMessage(value: unknown): value is OperationBatchMessage {\n\tif (typeof value !== 'object' || value === null) return false\n\tconst msg = value as Record<string, unknown>\n\treturn (\n\t\tmsg.type === 'operation-batch' &&\n\t\ttypeof msg.messageId === 'string' &&\n\t\tArray.isArray(msg.operations) &&\n\t\ttypeof msg.isFinal === 'boolean' &&\n\t\ttypeof msg.batchIndex === 'number'\n\t)\n}\n\n/**\n * Check if a value is an AcknowledgmentMessage.\n */\nexport function isAcknowledgmentMessage(value: unknown): value is AcknowledgmentMessage {\n\tif (typeof value !== 'object' || value === null) return false\n\tconst msg = value as Record<string, unknown>\n\treturn (\n\t\tmsg.type === 'acknowledgment' &&\n\t\ttypeof msg.messageId === 'string' &&\n\t\ttypeof msg.acknowledgedMessageId === 'string' &&\n\t\ttypeof msg.lastSequenceNumber === 'number'\n\t)\n}\n\n/**\n * Check if a value is an ErrorMessage.\n */\nexport function isErrorMessage(value: unknown): value is ErrorMessage {\n\tif (typeof value !== 'object' || value === null) return false\n\tconst msg = value as Record<string, unknown>\n\treturn (\n\t\tmsg.type === 'error' &&\n\t\ttypeof msg.messageId === 'string' &&\n\t\ttypeof msg.code === 'string' &&\n\t\ttypeof msg.message === 'string' &&\n\t\ttypeof msg.retriable === 'boolean'\n\t)\n}\n\n/**\n * Check if a value is an AwarenessUpdateMessage.\n */\nexport function isAwarenessUpdateMessage(value: unknown): value is AwarenessUpdateMessage {\n\tif (typeof value !== 'object' || value === null) return false\n\tconst msg = value as Record<string, unknown>\n\treturn (\n\t\tmsg.type === 'awareness-update' &&\n\t\ttypeof msg.messageId === 'string' &&\n\t\ttypeof msg.clientId === 'number' &&\n\t\ttypeof msg.states === 'object' &&\n\t\tmsg.states !== null &&\n\t\t!Array.isArray(msg.states)\n\t)\n}\n","import { SyncError } from '@korajs/core'\nimport type { Operation, VersionVector } from '@korajs/core'\n// protobufjs/minimal is CJS — named ESM imports fail in some runtimes (tsx, Node ESM).\n// Use a default import for the runtime values and type aliases for annotations.\nimport protobuf from 'protobufjs/minimal'\n\ntype Reader = protobuf.Reader\ntype Writer = protobuf.Writer\nconst { Reader, Writer } = protobuf\nimport type {\n\tAcknowledgmentMessage,\n\tErrorMessage,\n\tHandshakeMessage,\n\tHandshakeResponseMessage,\n\tOperationBatchMessage,\n\tSerializedOperation,\n\tSyncMessage,\n\tWireFormat,\n} from './messages'\nimport { isSyncMessage } from './messages'\n\nexport type EncodedMessage = string | Uint8Array\n\n/**\n * Interface for encoding/decoding sync protocol messages.\n */\nexport interface MessageSerializer {\n\tencode(message: SyncMessage): EncodedMessage\n\tdecode(data: string | Uint8Array | ArrayBuffer): SyncMessage\n\tencodeOperation(op: Operation): SerializedOperation\n\tdecodeOperation(serialized: SerializedOperation): Operation\n\tsetWireFormat?(format: WireFormat): void\n\tgetWireFormat?(): WireFormat\n}\n\n/**\n * Convert a VersionVector (Map) to a plain object for wire transmission.\n */\nexport function versionVectorToWire(vector: VersionVector): Record<string, number> {\n\tconst wire: Record<string, number> = {}\n\tfor (const [nodeId, seq] of vector) {\n\t\twire[nodeId] = seq\n\t}\n\treturn wire\n}\n\n/**\n * Convert a wire-format version vector (plain object) back to a VersionVector (Map).\n */\nexport function wireToVersionVector(wire: Record<string, number>): VersionVector {\n\treturn new Map(Object.entries(wire))\n}\n\n/**\n * JSON-based message serializer.\n */\nexport class JsonMessageSerializer implements MessageSerializer {\n\tencode(message: SyncMessage): string {\n\t\treturn JSON.stringify(message)\n\t}\n\n\tdecode(data: string | Uint8Array | ArrayBuffer): SyncMessage {\n\t\tconst text = decodeTextPayload(data)\n\n\t\tlet parsed: unknown\n\t\ttry {\n\t\t\tparsed = JSON.parse(text)\n\t\t} catch {\n\t\t\tthrow new SyncError('Failed to decode sync message: invalid JSON', {\n\t\t\t\tdataLength: text.length,\n\t\t\t})\n\t\t}\n\n\t\tif (!isSyncMessage(parsed)) {\n\t\t\tthrow new SyncError('Failed to decode sync message: invalid message structure', {\n\t\t\t\treceivedType:\n\t\t\t\t\ttypeof parsed === 'object' && parsed !== null\n\t\t\t\t\t\t? (parsed as Record<string, unknown>).type\n\t\t\t\t\t\t: typeof parsed,\n\t\t\t})\n\t\t}\n\n\t\treturn parsed\n\t}\n\n\tencodeOperation(op: Operation): SerializedOperation {\n\t\treturn {\n\t\t\tid: op.id,\n\t\t\tnodeId: op.nodeId,\n\t\t\ttype: op.type,\n\t\t\tcollection: op.collection,\n\t\t\trecordId: op.recordId,\n\t\t\tdata: op.data,\n\t\t\tpreviousData: op.previousData,\n\t\t\ttimestamp: {\n\t\t\t\twallTime: op.timestamp.wallTime,\n\t\t\t\tlogical: op.timestamp.logical,\n\t\t\t\tnodeId: op.timestamp.nodeId,\n\t\t\t},\n\t\t\tsequenceNumber: op.sequenceNumber,\n\t\t\tcausalDeps: [...op.causalDeps],\n\t\t\tschemaVersion: op.schemaVersion,\n\t\t\t...(op.atomicOps !== undefined ? { atomicOps: op.atomicOps } : {}),\n\t\t\t...(op.transactionId !== undefined ? { transactionId: op.transactionId } : {}),\n\t\t\t...(op.mutationName !== undefined ? { mutationName: op.mutationName } : {}),\n\t\t}\n\t}\n\n\tdecodeOperation(serialized: SerializedOperation): Operation {\n\t\treturn {\n\t\t\tid: serialized.id,\n\t\t\tnodeId: serialized.nodeId,\n\t\t\ttype: serialized.type,\n\t\t\tcollection: serialized.collection,\n\t\t\trecordId: serialized.recordId,\n\t\t\tdata: serialized.data,\n\t\t\tpreviousData: serialized.previousData,\n\t\t\ttimestamp: {\n\t\t\t\twallTime: serialized.timestamp.wallTime,\n\t\t\t\tlogical: serialized.timestamp.logical,\n\t\t\t\tnodeId: serialized.timestamp.nodeId,\n\t\t\t},\n\t\t\tsequenceNumber: serialized.sequenceNumber,\n\t\t\tcausalDeps: [...serialized.causalDeps],\n\t\t\tschemaVersion: serialized.schemaVersion,\n\t\t\t...(serialized.atomicOps !== undefined ? { atomicOps: serialized.atomicOps } : {}),\n\t\t\t...(serialized.transactionId !== undefined\n\t\t\t\t? { transactionId: serialized.transactionId }\n\t\t\t\t: {}),\n\t\t\t...(serialized.mutationName !== undefined ? { mutationName: serialized.mutationName } : {}),\n\t\t}\n\t}\n}\n\n/**\n * Protobuf-based serializer for sync messages.\n */\nexport class ProtobufMessageSerializer implements MessageSerializer {\n\tencode(message: SyncMessage): Uint8Array {\n\t\tconst envelope = toProtoEnvelope(message)\n\t\treturn encodeEnvelope(envelope)\n\t}\n\n\tdecode(data: string | Uint8Array | ArrayBuffer): SyncMessage {\n\t\tconst bytes = toBytes(data)\n\t\tconst envelope = decodeEnvelope(bytes)\n\t\treturn fromProtoEnvelope(envelope)\n\t}\n\n\tencodeOperation(op: Operation): SerializedOperation {\n\t\treturn new JsonMessageSerializer().encodeOperation(op)\n\t}\n\n\tdecodeOperation(serialized: SerializedOperation): Operation {\n\t\treturn new JsonMessageSerializer().decodeOperation(serialized)\n\t}\n}\n\n/**\n * Negotiated serializer that supports runtime wire-format switching.\n */\nexport class NegotiatedMessageSerializer implements MessageSerializer {\n\tprivate readonly json = new JsonMessageSerializer()\n\tprivate readonly protobuf = new ProtobufMessageSerializer()\n\tprivate wireFormat: WireFormat\n\n\tconstructor(initialWireFormat: WireFormat = 'json') {\n\t\tthis.wireFormat = initialWireFormat\n\t}\n\n\tencode(message: SyncMessage): EncodedMessage {\n\t\tif (this.wireFormat === 'protobuf') {\n\t\t\treturn this.protobuf.encode(message)\n\t\t}\n\n\t\treturn this.json.encode(message)\n\t}\n\n\tdecode(data: string | Uint8Array | ArrayBuffer): SyncMessage {\n\t\tif (typeof data === 'string') {\n\t\t\treturn this.json.decode(data)\n\t\t}\n\n\t\ttry {\n\t\t\treturn this.protobuf.decode(data)\n\t\t} catch {\n\t\t\treturn this.json.decode(data)\n\t\t}\n\t}\n\n\tencodeOperation(op: Operation): SerializedOperation {\n\t\treturn this.json.encodeOperation(op)\n\t}\n\n\tdecodeOperation(serialized: SerializedOperation): Operation {\n\t\treturn this.json.decodeOperation(serialized)\n\t}\n\n\tsetWireFormat(format: WireFormat): void {\n\t\tthis.wireFormat = format\n\t}\n\n\tgetWireFormat(): WireFormat {\n\t\treturn this.wireFormat\n\t}\n}\n\ninterface ProtoVectorEntry {\n\tkey: string\n\tvalue: number\n}\n\ninterface ProtoTimestamp {\n\twallTime: number\n\tlogical: number\n\tnodeId: string\n}\n\ninterface ProtoOperation {\n\tid: string\n\tnodeId: string\n\ttype: string\n\tcollection: string\n\trecordId: string\n\tdataJson: string\n\tpreviousDataJson: string\n\ttimestamp: ProtoTimestamp\n\tsequenceNumber: number\n\tcausalDeps: string[]\n\tschemaVersion: number\n\thasData: boolean\n\thasPreviousData: boolean\n}\n\ninterface ProtoEnvelope {\n\ttype: SyncMessage['type']\n\tmessageId: string\n\tnodeId?: string\n\tversionVector?: ProtoVectorEntry[]\n\tschemaVersion?: number\n\tauthToken?: string\n\tsupportedWireFormats?: string[]\n\taccepted?: boolean\n\trejectReason?: string\n\tselectedWireFormat?: string\n\toperations?: ProtoOperation[]\n\tisFinal?: boolean\n\tbatchIndex?: number\n\tacknowledgedMessageId?: string\n\tlastSequenceNumber?: number\n\terrorCode?: string\n\terrorMessage?: string\n\tretriable?: boolean\n}\n\nfunction toProtoEnvelope(message: SyncMessage): ProtoEnvelope {\n\tswitch (message.type) {\n\t\tcase 'handshake':\n\t\t\treturn {\n\t\t\t\ttype: message.type,\n\t\t\t\tmessageId: message.messageId,\n\t\t\t\tnodeId: message.nodeId,\n\t\t\t\tversionVector: Object.entries(message.versionVector).map(([key, value]) => ({\n\t\t\t\t\tkey,\n\t\t\t\t\tvalue,\n\t\t\t\t})),\n\t\t\t\tschemaVersion: message.schemaVersion,\n\t\t\t\tauthToken: message.authToken,\n\t\t\t\tsupportedWireFormats: message.supportedWireFormats,\n\t\t\t}\n\t\tcase 'handshake-response':\n\t\t\treturn {\n\t\t\t\ttype: message.type,\n\t\t\t\tmessageId: message.messageId,\n\t\t\t\tnodeId: message.nodeId,\n\t\t\t\tversionVector: Object.entries(message.versionVector).map(([key, value]) => ({\n\t\t\t\t\tkey,\n\t\t\t\t\tvalue,\n\t\t\t\t})),\n\t\t\t\tschemaVersion: message.schemaVersion,\n\t\t\t\taccepted: message.accepted,\n\t\t\t\trejectReason: message.rejectReason,\n\t\t\t\tselectedWireFormat: message.selectedWireFormat,\n\t\t\t}\n\t\tcase 'operation-batch':\n\t\t\treturn {\n\t\t\t\ttype: message.type,\n\t\t\t\tmessageId: message.messageId,\n\t\t\t\toperations: message.operations.map(serializeProtoOperation),\n\t\t\t\tisFinal: message.isFinal,\n\t\t\t\tbatchIndex: message.batchIndex,\n\t\t\t}\n\t\tcase 'acknowledgment':\n\t\t\treturn {\n\t\t\t\ttype: message.type,\n\t\t\t\tmessageId: message.messageId,\n\t\t\t\tacknowledgedMessageId: message.acknowledgedMessageId,\n\t\t\t\tlastSequenceNumber: message.lastSequenceNumber,\n\t\t\t}\n\t\tcase 'error':\n\t\t\treturn {\n\t\t\t\ttype: message.type,\n\t\t\t\tmessageId: message.messageId,\n\t\t\t\terrorCode: message.code,\n\t\t\t\terrorMessage: message.message,\n\t\t\t\tretriable: message.retriable,\n\t\t\t}\n\t\tcase 'awareness-update':\n\t\t\t// Awareness messages are ephemeral and not sent via protobuf.\n\t\t\t// They use JSON serialization only. Return a minimal envelope.\n\t\t\treturn {\n\t\t\t\ttype: message.type,\n\t\t\t\tmessageId: message.messageId,\n\t\t\t}\n\t}\n}\n\nfunction fromProtoEnvelope(envelope: ProtoEnvelope): SyncMessage {\n\tswitch (envelope.type) {\n\t\tcase 'handshake':\n\t\t\treturn {\n\t\t\t\ttype: 'handshake',\n\t\t\t\tmessageId: envelope.messageId,\n\t\t\t\tnodeId: envelope.nodeId ?? '',\n\t\t\t\tversionVector: Object.fromEntries(\n\t\t\t\t\t(envelope.versionVector ?? []).map((entry) => [entry.key, entry.value]),\n\t\t\t\t),\n\t\t\t\tschemaVersion: envelope.schemaVersion ?? 0,\n\t\t\t\tauthToken: envelope.authToken,\n\t\t\t\tsupportedWireFormats: envelope.supportedWireFormats?.filter(\n\t\t\t\t\t(format): format is WireFormat => format === 'json' || format === 'protobuf',\n\t\t\t\t),\n\t\t\t}\n\t\tcase 'handshake-response':\n\t\t\treturn {\n\t\t\t\ttype: 'handshake-response',\n\t\t\t\tmessageId: envelope.messageId,\n\t\t\t\tnodeId: envelope.nodeId ?? '',\n\t\t\t\tversionVector: Object.fromEntries(\n\t\t\t\t\t(envelope.versionVector ?? []).map((entry) => [entry.key, entry.value]),\n\t\t\t\t),\n\t\t\t\tschemaVersion: envelope.schemaVersion ?? 0,\n\t\t\t\taccepted: envelope.accepted ?? false,\n\t\t\t\trejectReason: envelope.rejectReason,\n\t\t\t\tselectedWireFormat:\n\t\t\t\t\tenvelope.selectedWireFormat === 'json' || envelope.selectedWireFormat === 'protobuf'\n\t\t\t\t\t\t? envelope.selectedWireFormat\n\t\t\t\t\t\t: undefined,\n\t\t\t}\n\t\tcase 'operation-batch':\n\t\t\treturn {\n\t\t\t\ttype: 'operation-batch',\n\t\t\t\tmessageId: envelope.messageId,\n\t\t\t\toperations: (envelope.operations ?? []).map(deserializeProtoOperation),\n\t\t\t\tisFinal: envelope.isFinal ?? false,\n\t\t\t\tbatchIndex: envelope.batchIndex ?? 0,\n\t\t\t}\n\t\tcase 'acknowledgment':\n\t\t\treturn {\n\t\t\t\ttype: 'acknowledgment',\n\t\t\t\tmessageId: envelope.messageId,\n\t\t\t\tacknowledgedMessageId: envelope.acknowledgedMessageId ?? '',\n\t\t\t\tlastSequenceNumber: envelope.lastSequenceNumber ?? 0,\n\t\t\t}\n\t\tcase 'error':\n\t\t\treturn {\n\t\t\t\ttype: 'error',\n\t\t\t\tmessageId: envelope.messageId,\n\t\t\t\tcode: envelope.errorCode ?? 'UNKNOWN',\n\t\t\t\tmessage: envelope.errorMessage ?? 'Unknown error',\n\t\t\t\tretriable: envelope.retriable ?? false,\n\t\t\t}\n\t\tdefault:\n\t\t\tthrow new SyncError('Failed to decode sync message: unknown protobuf type', {\n\t\t\t\ttype: envelope.type,\n\t\t\t})\n\t}\n}\n\nfunction serializeProtoOperation(operation: SerializedOperation): ProtoOperation {\n\t// Embed metadata in the data JSON when present (piggyback on existing field)\n\tconst hasMetadata = operation.transactionId !== undefined || operation.mutationName !== undefined\n\tlet dataJson = ''\n\tif (operation.data !== null) {\n\t\tconst dataPayload: Record<string, unknown> = { ...operation.data }\n\t\tif (operation.atomicOps !== undefined && Object.keys(operation.atomicOps).length > 0) {\n\t\t\tdataPayload.__kora_atomic_ops__ = operation.atomicOps\n\t\t}\n\t\tif (operation.transactionId !== undefined) {\n\t\t\tdataPayload.__kora_tx_id__ = operation.transactionId\n\t\t}\n\t\tif (operation.mutationName !== undefined) {\n\t\t\tdataPayload.__kora_mutation__ = operation.mutationName\n\t\t}\n\t\tdataJson = JSON.stringify(dataPayload)\n\t} else if (hasMetadata) {\n\t\t// For delete operations (data is null), still need to carry metadata\n\t\tconst meta: Record<string, unknown> = {}\n\t\tif (operation.transactionId !== undefined) meta.__kora_tx_id__ = operation.transactionId\n\t\tif (operation.mutationName !== undefined) meta.__kora_mutation__ = operation.mutationName\n\t\tdataJson = JSON.stringify(meta)\n\t}\n\n\treturn {\n\t\tid: operation.id,\n\t\tnodeId: operation.nodeId,\n\t\ttype: operation.type,\n\t\tcollection: operation.collection,\n\t\trecordId: operation.recordId,\n\t\tdataJson,\n\t\tpreviousDataJson: operation.previousData === null ? '' : JSON.stringify(operation.previousData),\n\t\ttimestamp: {\n\t\t\twallTime: operation.timestamp.wallTime,\n\t\t\tlogical: operation.timestamp.logical,\n\t\t\tnodeId: operation.timestamp.nodeId,\n\t\t},\n\t\tsequenceNumber: operation.sequenceNumber,\n\t\tcausalDeps: [...operation.causalDeps],\n\t\tschemaVersion: operation.schemaVersion,\n\t\thasData: operation.data !== null,\n\t\thasPreviousData: operation.previousData !== null,\n\t}\n}\n\nfunction deserializeProtoOperation(operation: ProtoOperation): SerializedOperation {\n\tlet data: Record<string, unknown> | null = null\n\tlet atomicOps: Record<string, unknown> | undefined\n\tlet transactionId: string | undefined\n\tlet mutationName: string | undefined\n\n\tif (operation.hasData || operation.dataJson.length > 0) {\n\t\tconst parsed = JSON.parse(operation.dataJson) as Record<string, unknown>\n\t\tif ('__kora_atomic_ops__' in parsed) {\n\t\t\tatomicOps = parsed.__kora_atomic_ops__ as Record<string, unknown>\n\t\t}\n\t\tif ('__kora_tx_id__' in parsed) {\n\t\t\ttransactionId = parsed.__kora_tx_id__ as string\n\t\t}\n\t\tif ('__kora_mutation__' in parsed) {\n\t\t\tmutationName = parsed.__kora_mutation__ as string\n\t\t}\n\t\tconst { __kora_atomic_ops__: _a, __kora_tx_id__: _t, __kora_mutation__: _m, ...rest } = parsed\n\t\tdata = operation.hasData && Object.keys(rest).length > 0 ? rest : null\n\t}\n\n\treturn {\n\t\tid: operation.id,\n\t\tnodeId: operation.nodeId,\n\t\ttype: operation.type as SerializedOperation['type'],\n\t\tcollection: operation.collection,\n\t\trecordId: operation.recordId,\n\t\tdata,\n\t\tpreviousData: operation.hasPreviousData\n\t\t\t? (JSON.parse(operation.previousDataJson) as Record<string, unknown>)\n\t\t\t: null,\n\t\ttimestamp: {\n\t\t\twallTime: operation.timestamp.wallTime,\n\t\t\tlogical: operation.timestamp.logical,\n\t\t\tnodeId: operation.timestamp.nodeId,\n\t\t},\n\t\tsequenceNumber: operation.sequenceNumber,\n\t\tcausalDeps: [...operation.causalDeps],\n\t\tschemaVersion: operation.schemaVersion,\n\t\t...(atomicOps !== undefined\n\t\t\t? { atomicOps: atomicOps as SerializedOperation['atomicOps'] }\n\t\t\t: {}),\n\t\t...(transactionId !== undefined ? { transactionId } : {}),\n\t\t...(mutationName !== undefined ? { mutationName } : {}),\n\t}\n}\n\nfunction decodeTextPayload(data: string | Uint8Array | ArrayBuffer): string {\n\tif (typeof data === 'string') return data\n\treturn new TextDecoder().decode(toBytes(data))\n}\n\nfunction toBytes(data: string | Uint8Array | ArrayBuffer): Uint8Array {\n\tif (typeof data === 'string') {\n\t\treturn new TextEncoder().encode(data)\n\t}\n\n\tif (data instanceof Uint8Array) {\n\t\treturn data\n\t}\n\n\tif (data instanceof ArrayBuffer) {\n\t\treturn new Uint8Array(data)\n\t}\n\n\tthrow new SyncError('Unsupported sync payload type', { receivedType: typeof data })\n}\n\nfunction encodeEnvelope(envelope: ProtoEnvelope): Uint8Array {\n\tconst writer = Writer.create()\n\tif (envelope.type.length > 0) writer.uint32(10).string(envelope.type)\n\tif (envelope.messageId.length > 0) writer.uint32(18).string(envelope.messageId)\n\tif (envelope.nodeId && envelope.nodeId.length > 0) writer.uint32(26).string(envelope.nodeId)\n\tfor (const entry of envelope.versionVector ?? []) {\n\t\twriter.uint32(34).fork()\n\t\twriter.uint32(10).string(entry.key)\n\t\twriter.uint32(16).int64(entry.value)\n\t\twriter.ldelim()\n\t}\n\tif (envelope.schemaVersion !== undefined) writer.uint32(40).int32(envelope.schemaVersion)\n\tif (envelope.authToken && envelope.authToken.length > 0)\n\t\twriter.uint32(50).string(envelope.authToken)\n\tfor (const format of envelope.supportedWireFormats ?? []) {\n\t\twriter.uint32(58).string(format)\n\t}\n\tif (envelope.accepted !== undefined) writer.uint32(64).bool(envelope.accepted)\n\tif (envelope.rejectReason && envelope.rejectReason.length > 0)\n\t\twriter.uint32(74).string(envelope.rejectReason)\n\tif (envelope.selectedWireFormat && envelope.selectedWireFormat.length > 0) {\n\t\twriter.uint32(82).string(envelope.selectedWireFormat)\n\t}\n\tfor (const operation of envelope.operations ?? []) {\n\t\twriter.uint32(90).fork()\n\t\tencodeProtoOperation(writer, operation)\n\t\twriter.ldelim()\n\t}\n\tif (envelope.isFinal !== undefined) writer.uint32(96).bool(envelope.isFinal)\n\tif (envelope.batchIndex !== undefined) writer.uint32(104).uint32(envelope.batchIndex)\n\tif (envelope.acknowledgedMessageId && envelope.acknowledgedMessageId.length > 0) {\n\t\twriter.uint32(114).string(envelope.acknowledgedMessageId)\n\t}\n\tif (envelope.lastSequenceNumber !== undefined)\n\t\twriter.uint32(120).int64(envelope.lastSequenceNumber)\n\tif (envelope.errorCode && envelope.errorCode.length > 0)\n\t\twriter.uint32(130).string(envelope.errorCode)\n\tif (envelope.errorMessage && envelope.errorMessage.length > 0) {\n\t\twriter.uint32(138).string(envelope.errorMessage)\n\t}\n\tif (envelope.retriable !== undefined) writer.uint32(144).bool(envelope.retriable)\n\treturn writer.finish()\n}\n\nfunction decodeEnvelope(bytes: Uint8Array): ProtoEnvelope {\n\tconst reader = Reader.create(bytes)\n\tconst envelope: ProtoEnvelope = { type: 'error', messageId: '' }\n\n\twhile (reader.pos < reader.len) {\n\t\tconst tag = reader.uint32()\n\t\tswitch (tag >>> 3) {\n\t\t\tcase 1:\n\t\t\t\tenvelope.type = reader.string() as SyncMessage['type']\n\t\t\t\tbreak\n\t\t\tcase 2:\n\t\t\t\tenvelope.messageId = reader.string()\n\t\t\t\tbreak\n\t\t\tcase 3:\n\t\t\t\tenvelope.nodeId = reader.string()\n\t\t\t\tbreak\n\t\t\tcase 4:\n\t\t\t\tenvelope.versionVector = [\n\t\t\t\t\t...(envelope.versionVector ?? []),\n\t\t\t\t\tdecodeVectorEntry(reader, reader.uint32()),\n\t\t\t\t]\n\t\t\t\tbreak\n\t\t\tcase 5:\n\t\t\t\tenvelope.schemaVersion = reader.int32()\n\t\t\t\tbreak\n\t\t\tcase 6:\n\t\t\t\tenvelope.authToken = reader.string()\n\t\t\t\tbreak\n\t\t\tcase 7:\n\t\t\t\tenvelope.supportedWireFormats = [...(envelope.supportedWireFormats ?? []), reader.string()]\n\t\t\t\tbreak\n\t\t\tcase 8:\n\t\t\t\tenvelope.accepted = reader.bool()\n\t\t\t\tbreak\n\t\t\tcase 9:\n\t\t\t\tenvelope.rejectReason = reader.string()\n\t\t\t\tbreak\n\t\t\tcase 10:\n\t\t\t\tenvelope.selectedWireFormat = reader.string()\n\t\t\t\tbreak\n\t\t\tcase 11:\n\t\t\t\tenvelope.operations = [\n\t\t\t\t\t...(envelope.operations ?? []),\n\t\t\t\t\tdecodeProtoOperation(reader, reader.uint32()),\n\t\t\t\t]\n\t\t\t\tbreak\n\t\t\tcase 12:\n\t\t\t\tenvelope.isFinal = reader.bool()\n\t\t\t\tbreak\n\t\t\tcase 13:\n\t\t\t\tenvelope.batchIndex = reader.uint32()\n\t\t\t\tbreak\n\t\t\tcase 14:\n\t\t\t\tenvelope.acknowledgedMessageId = reader.string()\n\t\t\t\tbreak\n\t\t\tcase 15:\n\t\t\t\tenvelope.lastSequenceNumber = longToNumber(reader.int64())\n\t\t\t\tbreak\n\t\t\tcase 16:\n\t\t\t\tenvelope.errorCode = reader.string()\n\t\t\t\tbreak\n\t\t\tcase 17:\n\t\t\t\tenvelope.errorMessage = reader.string()\n\t\t\t\tbreak\n\t\t\tcase 18:\n\t\t\t\tenvelope.retriable = reader.bool()\n\t\t\t\tbreak\n\t\t\tdefault:\n\t\t\t\treader.skipType(tag & 7)\n\t\t}\n\t}\n\n\treturn envelope\n}\n\nfunction encodeProtoOperation(writer: Writer, operation: ProtoOperation): void {\n\tif (operation.id.length > 0) writer.uint32(10).string(operation.id)\n\tif (operation.nodeId.length > 0) writer.uint32(18).string(operation.nodeId)\n\tif (operation.type.length > 0) writer.uint32(26).string(operation.type)\n\tif (operation.collection.length > 0) writer.uint32(34).string(operation.collection)\n\tif (operation.recordId.length > 0) writer.uint32(42).string(operation.recordId)\n\tif (operation.dataJson.length > 0) writer.uint32(50).string(operation.dataJson)\n\tif (operation.previousDataJson.length > 0) writer.uint32(58).string(operation.previousDataJson)\n\twriter.uint32(66).fork()\n\twriter.uint32(8).int64(operation.timestamp.wallTime)\n\twriter.uint32(16).uint32(operation.timestamp.logical)\n\twriter.uint32(26).string(operation.timestamp.nodeId)\n\twriter.ldelim()\n\twriter.uint32(72).int64(operation.sequenceNumber)\n\tfor (const dep of operation.causalDeps) {\n\t\twriter.uint32(82).string(dep)\n\t}\n\twriter.uint32(88).int32(operation.schemaVersion)\n\twriter.uint32(96).bool(operation.hasData)\n\twriter.uint32(104).bool(operation.hasPreviousData)\n}\n\nfunction decodeProtoOperation(reader: Reader, length: number): ProtoOperation {\n\tconst end = reader.pos + length\n\tconst operation: ProtoOperation = {\n\t\tid: '',\n\t\tnodeId: '',\n\t\ttype: 'insert',\n\t\tcollection: '',\n\t\trecordId: '',\n\t\tdataJson: '',\n\t\tpreviousDataJson: '',\n\t\ttimestamp: { wallTime: 0, logical: 0, nodeId: '' },\n\t\tsequenceNumber: 0,\n\t\tcausalDeps: [],\n\t\tschemaVersion: 0,\n\t\thasData: false,\n\t\thasPreviousData: false,\n\t}\n\n\twhile (reader.pos < end) {\n\t\tconst tag = reader.uint32()\n\t\tswitch (tag >>> 3) {\n\t\t\tcase 1:\n\t\t\t\toperation.id = reader.string()\n\t\t\t\tbreak\n\t\t\tcase 2:\n\t\t\t\toperation.nodeId = reader.string()\n\t\t\t\tbreak\n\t\t\tcase 3:\n\t\t\t\toperation.type = reader.string()\n\t\t\t\tbreak\n\t\t\tcase 4:\n\t\t\t\toperation.collection = reader.string()\n\t\t\t\tbreak\n\t\t\tcase 5:\n\t\t\t\toperation.recordId = reader.string()\n\t\t\t\tbreak\n\t\t\tcase 6:\n\t\t\t\toperation.dataJson = reader.string()\n\t\t\t\tbreak\n\t\t\tcase 7:\n\t\t\t\toperation.previousDataJson = reader.string()\n\t\t\t\tbreak\n\t\t\tcase 8: {\n\t\t\t\tconst timestampEnd = reader.pos + reader.uint32()\n\t\t\t\twhile (reader.pos < timestampEnd) {\n\t\t\t\t\tconst timestampTag = reader.uint32()\n\t\t\t\t\tswitch (timestampTag >>> 3) {\n\t\t\t\t\t\tcase 1:\n\t\t\t\t\t\t\toperation.timestamp.wallTime = longToNumber(reader.int64())\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\tcase 2:\n\t\t\t\t\t\t\toperation.timestamp.logical = reader.uint32()\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\tcase 3:\n\t\t\t\t\t\t\toperation.timestamp.nodeId = reader.string()\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\treader.skipType(timestampTag & 7)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 9:\n\t\t\t\toperation.sequenceNumber = longToNumber(reader.int64())\n\t\t\t\tbreak\n\t\t\tcase 10:\n\t\t\t\toperation.causalDeps.push(reader.string())\n\t\t\t\tbreak\n\t\t\tcase 11:\n\t\t\t\toperation.schemaVersion = reader.int32()\n\t\t\t\tbreak\n\t\t\tcase 12:\n\t\t\t\toperation.hasData = reader.bool()\n\t\t\t\tbreak\n\t\t\tcase 13:\n\t\t\t\toperation.hasPreviousData = reader.bool()\n\t\t\t\tbreak\n\t\t\tdefault:\n\t\t\t\treader.skipType(tag & 7)\n\t\t}\n\t}\n\n\treturn operation\n}\n\nfunction decodeVectorEntry(reader: Reader, length: number): ProtoVectorEntry {\n\tconst end = reader.pos + length\n\tconst entry: ProtoVectorEntry = { key: '', value: 0 }\n\twhile (reader.pos < end) {\n\t\tconst tag = reader.uint32()\n\t\tswitch (tag >>> 3) {\n\t\t\tcase 1:\n\t\t\t\tentry.key = reader.string()\n\t\t\t\tbreak\n\t\t\tcase 2:\n\t\t\t\tentry.value = longToNumber(reader.int64())\n\t\t\t\tbreak\n\t\t\tdefault:\n\t\t\t\treader.skipType(tag & 7)\n\t\t}\n\t}\n\treturn entry\n}\n\nfunction longToNumber(value: unknown): number {\n\tif (typeof value === 'number') return value\n\tif (typeof value === 'string') return Number.parseInt(value, 10)\n\tif (\n\t\ttypeof value === 'object' &&\n\t\tvalue !== null &&\n\t\t'toNumber' in value &&\n\t\ttypeof (value as { toNumber: unknown }).toNumber === 'function'\n\t) {\n\t\treturn (value as { toNumber(): number }).toNumber()\n\t}\n\n\tthrow new SyncError('Failed to decode int64 value', {\n\t\treceivedType: typeof value,\n\t})\n}\n","import { SyncError } from '@korajs/core'\nimport type { SyncMessage } from '../protocol/messages'\nimport { JsonMessageSerializer } from '../protocol/serializer'\nimport type { MessageSerializer } from '../protocol/serializer'\nimport type {\n\tSyncTransport,\n\tTransportCloseHandler,\n\tTransportErrorHandler,\n\tTransportMessageHandler,\n\tTransportOptions,\n} from './transport'\n\n/**\n * WebSocket event interface for dependency injection.\n * Matches the subset of the browser WebSocket API that we need.\n */\nexport interface WebSocketLike {\n\treadonly readyState: number\n\tsend(data: string | Uint8Array): void\n\tclose(code?: number, reason?: string): void\n\tonopen: ((event: unknown) => void) | null\n\tonmessage: ((event: { data: unknown }) => void) | null\n\tonclose: ((event: { reason: string; code: number }) => void) | null\n\tonerror: ((event: unknown) => void) | null\n}\n\n/**\n * Constructor for WebSocket-like objects. Allows injection of mock WebSocket for testing.\n */\nexport type WebSocketConstructor = new (url: string, protocols?: string | string[]) => WebSocketLike\n\n/**\n * Options for the WebSocket transport.\n */\nexport interface WebSocketTransportOptions {\n\t/** Custom serializer. Defaults to JSON. */\n\tserializer?: MessageSerializer\n\t/** Injectable WebSocket constructor for testing. Defaults to globalThis.WebSocket. */\n\tWebSocketImpl?: WebSocketConstructor\n\t/** Connection timeout in ms. Defaults to 10000 (10s). */\n\tconnectTimeout?: number\n}\n\n// WebSocket readyState constants\nconst WS_OPEN = 1\n\n/**\n * WebSocket-based sync transport implementation.\n */\nexport class WebSocketTransport implements SyncTransport {\n\tprivate ws: WebSocketLike | null = null\n\tprivate messageHandler: TransportMessageHandler | null = null\n\tprivate closeHandler: TransportCloseHandler | null = null\n\tprivate errorHandler: TransportErrorHandler | null = null\n\tprivate readonly serializer: MessageSerializer\n\tprivate readonly WebSocketImpl: WebSocketConstructor\n\tprivate readonly connectTimeout: number\n\n\tconstructor(options?: WebSocketTransportOptions) {\n\t\tthis.serializer = options?.serializer ?? new JsonMessageSerializer()\n\t\tthis.connectTimeout = options?.connectTimeout ?? 10000\n\n\t\tif (options?.WebSocketImpl) {\n\t\t\tthis.WebSocketImpl = options.WebSocketImpl\n\t\t} else if (typeof globalThis.WebSocket !== 'undefined') {\n\t\t\tthis.WebSocketImpl = globalThis.WebSocket as unknown as WebSocketConstructor\n\t\t} else {\n\t\t\t// Deferred — will throw on connect() if no implementation available\n\t\t\tthis.WebSocketImpl = null as unknown as WebSocketConstructor\n\t\t}\n\t}\n\n\tasync connect(url: string, options?: TransportOptions): Promise<void> {\n\t\tif (!this.WebSocketImpl) {\n\t\t\tthrow new SyncError('WebSocket is not available in this environment', {\n\t\t\t\thint: 'Provide a WebSocketImpl option or use a polyfill',\n\t\t\t})\n\t\t}\n\n\t\treturn new Promise<void>((resolve, reject) => {\n\t\t\tlet settled = false\n\n\t\t\tconst settle = (fn: () => void): void => {\n\t\t\t\tif (settled) return\n\t\t\t\tsettled = true\n\t\t\t\tclearTimeout(timer)\n\t\t\t\tfn()\n\t\t\t}\n\n\t\t\t// Connection timeout — prevents hanging for 30+ seconds on mobile when offline\n\t\t\tconst timer = setTimeout(() => {\n\t\t\t\tsettle(() => {\n\t\t\t\t\tconst err = new SyncError('WebSocket connection timed out', {\n\t\t\t\t\t\turl,\n\t\t\t\t\t\ttimeout: this.connectTimeout,\n\t\t\t\t\t})\n\t\t\t\t\t// Close the pending WebSocket\n\t\t\t\t\tif (this.ws) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tthis.ws.onclose = null\n\t\t\t\t\t\t\tthis.ws.onerror = null\n\t\t\t\t\t\t\tthis.ws.close()\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t// Ignore close errors\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthis.ws = null\n\t\t\t\t\t}\n\t\t\t\t\tthis.errorHandler?.(err)\n\t\t\t\t\treject(err)\n\t\t\t\t})\n\t\t\t}, this.connectTimeout)\n\n\t\t\ttry {\n\t\t\t\t// Append auth token as query param if provided\n\t\t\t\tconst connectUrl = options?.authToken\n\t\t\t\t\t? `${url}${url.includes('?') ? '&' : '?'}token=${encodeURIComponent(options.authToken)}`\n\t\t\t\t\t: url\n\n\t\t\t\tconst ws = new this.WebSocketImpl(connectUrl)\n\t\t\t\tthis.ws = ws\n\n\t\t\t\tws.onopen = () => {\n\t\t\t\t\tsettle(() => resolve())\n\t\t\t\t}\n\n\t\t\t\tws.onmessage = (event: { data: unknown }) => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\ttypeof event.data !== 'string' &&\n\t\t\t\t\t\t\t!(event.data instanceof Uint8Array) &&\n\t\t\t\t\t\t\t!(event.data instanceof ArrayBuffer)\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst message = this.serializer.decode(event.data)\n\t\t\t\t\t\tthis.messageHandler?.(message)\n\t\t\t\t\t} catch {\n\t\t\t\t\t\tthis.errorHandler?.(new SyncError('Failed to decode incoming message'))\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tws.onclose = (event: { reason: string; code: number }) => {\n\t\t\t\t\tthis.ws = null\n\t\t\t\t\tthis.closeHandler?.(event.reason || `WebSocket closed with code ${event.code}`)\n\t\t\t\t}\n\n\t\t\t\tws.onerror = (event: unknown) => {\n\t\t\t\t\tconst err = new SyncError('WebSocket error', {\n\t\t\t\t\t\turl,\n\t\t\t\t\t})\n\t\t\t\t\tthis.errorHandler?.(err)\n\t\t\t\t\t// If we haven't connected yet, reject the connect promise\n\t\t\t\t\tif (!this.isConnected()) {\n\t\t\t\t\t\tthis.ws = null\n\t\t\t\t\t\tsettle(() => reject(err))\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tsettle(() =>\n\t\t\t\t\treject(\n\t\t\t\t\t\terr instanceof SyncError\n\t\t\t\t\t\t\t? err\n\t\t\t\t\t\t\t: new SyncError('Failed to create WebSocket', {\n\t\t\t\t\t\t\t\t\turl,\n\t\t\t\t\t\t\t\t\terror: String(err),\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t}\n\t\t})\n\t}\n\n\tasync disconnect(): Promise<void> {\n\t\tif (this.ws) {\n\t\t\tthis.ws.onclose = null // Prevent close handler firing for intentional disconnect\n\t\t\tthis.ws.close(1000, 'Client disconnecting')\n\t\t\tthis.ws = null\n\t\t}\n\t}\n\n\tsend(message: SyncMessage): void {\n\t\tif (!this.ws || this.ws.readyState !== WS_OPEN) {\n\t\t\tthrow new SyncError('Cannot send message: WebSocket is not connected', {\n\t\t\t\tmessageType: message.type,\n\t\t\t})\n\t\t}\n\t\tconst encoded = this.serializer.encode(message)\n\t\tthis.ws.send(encoded)\n\t}\n\n\tonMessage(handler: TransportMessageHandler): void {\n\t\tthis.messageHandler = handler\n\t}\n\n\tonClose(handler: TransportCloseHandler): void {\n\t\tthis.closeHandler = handler\n\t}\n\n\tonError(handler: TransportErrorHandler): void {\n\t\tthis.errorHandler = handler\n\t}\n\n\tisConnected(): boolean {\n\t\treturn this.ws !== null && this.ws.readyState === WS_OPEN\n\t}\n}\n","import { SyncError } from '@korajs/core'\nimport { NegotiatedMessageSerializer } from '../protocol/serializer'\nimport type { MessageSerializer } from '../protocol/serializer'\nimport type {\n\tSyncTransport,\n\tTransportCloseHandler,\n\tTransportErrorHandler,\n\tTransportMessageHandler,\n\tTransportOptions,\n} from './transport'\nimport { WebSocketTransport } from './websocket-transport'\n\nconst DEFAULT_RETRY_DELAY_MS = 250\n\nexport interface HttpLongPollingTransportOptions {\n\tserializer?: MessageSerializer\n\tfetchImpl?: typeof fetch\n\tretryDelayMs?: number\n\tpreferWebSocket?: boolean\n\twebSocketFactory?: () => SyncTransport\n}\n\n/**\n * HTTP long-polling transport with optional WebSocket upgrade.\n */\nexport class HttpLongPollingTransport implements SyncTransport {\n\tprivate readonly serializer: MessageSerializer\n\tprivate readonly fetchImpl: typeof fetch\n\tprivate readonly retryDelayMs: number\n\tprivate readonly preferWebSocket: boolean\n\tprivate readonly webSocketFactory: () => SyncTransport\n\n\tprivate messageHandler: TransportMessageHandler | null = null\n\tprivate closeHandler: TransportCloseHandler | null = null\n\tprivate errorHandler: TransportErrorHandler | null = null\n\n\tprivate connected = false\n\tprivate polling = false\n\tprivate url: string | null = null\n\tprivate authToken: string | undefined\n\tprivate pollAbort: AbortController | null = null\n\tprivate upgradedTransport: SyncTransport | null = null\n\n\tconstructor(options?: HttpLongPollingTransportOptions) {\n\t\tthis.serializer = options?.serializer ?? new NegotiatedMessageSerializer('json')\n\t\tthis.fetchImpl = options?.fetchImpl ?? fetch\n\t\tthis.retryDelayMs = options?.retryDelayMs ?? DEFAULT_RETRY_DELAY_MS\n\t\tthis.preferWebSocket = options?.preferWebSocket ?? true\n\t\tthis.webSocketFactory =\n\t\t\toptions?.webSocketFactory ?? (() => new WebSocketTransport({ serializer: this.serializer }))\n\t}\n\n\tasync connect(url: string, options?: TransportOptions): Promise<void> {\n\t\tif (this.connected) {\n\t\t\tthrow new SyncError('HTTP long-poll transport already connected', { url })\n\t\t}\n\n\t\tthis.url = normalizeHttpUrl(url)\n\t\tthis.authToken = options?.authToken\n\n\t\tif (this.preferWebSocket) {\n\t\t\tconst upgraded = await this.tryUpgradeToWebSocket(url, options)\n\t\t\tif (upgraded) {\n\t\t\t\tthis.upgradedTransport = upgraded\n\t\t\t\tthis.connected = true\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\n\t\tthis.connected = true\n\t\tthis.polling = true\n\t\tthis.pollAbort = new AbortController()\n\t\tvoid this.runPollLoop()\n\t}\n\n\tasync disconnect(): Promise<void> {\n\t\tif (this.upgradedTransport) {\n\t\t\tawait this.upgradedTransport.disconnect()\n\t\t\tthis.upgradedTransport = null\n\t\t}\n\n\t\tthis.connected = false\n\t\tthis.polling = false\n\t\tthis.pollAbort?.abort()\n\t\tthis.pollAbort = null\n\t\tthis.url = null\n\t}\n\n\tsend(message: import('../protocol/messages').SyncMessage): void {\n\t\tif (!this.connected) {\n\t\t\tthrow new SyncError('Cannot send message: HTTP long-poll transport is not connected', {\n\t\t\t\tmessageType: message.type,\n\t\t\t})\n\t\t}\n\n\t\tif (this.upgradedTransport) {\n\t\t\tthis.upgradedTransport.send(message)\n\t\t\treturn\n\t\t}\n\n\t\tvoid this.postMessage(message)\n\t}\n\n\tonMessage(handler: TransportMessageHandler): void {\n\t\tthis.messageHandler = handler\n\t\tif (this.upgradedTransport) {\n\t\t\tthis.upgradedTransport.onMessage(handler)\n\t\t}\n\t}\n\n\tonClose(handler: TransportCloseHandler): void {\n\t\tthis.closeHandler = handler\n\t\tif (this.upgradedTransport) {\n\t\t\tthis.upgradedTransport.onClose(handler)\n\t\t}\n\t}\n\n\tonError(handler: TransportErrorHandler): void {\n\t\tthis.errorHandler = handler\n\t\tif (this.upgradedTransport) {\n\t\t\tthis.upgradedTransport.onError(handler)\n\t\t}\n\t}\n\n\tisConnected(): boolean {\n\t\tif (this.upgradedTransport) {\n\t\t\treturn this.upgradedTransport.isConnected()\n\t\t}\n\t\treturn this.connected\n\t}\n\n\tprivate async tryUpgradeToWebSocket(\n\t\turl: string,\n\t\toptions?: TransportOptions,\n\t): Promise<SyncTransport | null> {\n\t\tconst wsTransport = this.webSocketFactory()\n\n\t\tif (this.messageHandler) wsTransport.onMessage(this.messageHandler)\n\t\tif (this.closeHandler) wsTransport.onClose(this.closeHandler)\n\t\tif (this.errorHandler) wsTransport.onError(this.errorHandler)\n\n\t\ttry {\n\t\t\tawait wsTransport.connect(normalizeWebSocketUrl(url), options)\n\t\t\treturn wsTransport\n\t\t} catch {\n\t\t\treturn null\n\t\t}\n\t}\n\n\tprivate async postMessage(message: import('../protocol/messages').SyncMessage): Promise<void> {\n\t\tif (!this.url) return\n\n\t\tconst encoded = this.serializer.encode(message)\n\t\tconst headers = new Headers()\n\t\theaders.set('accept', 'application/json, application/x-protobuf')\n\t\tif (this.authToken) {\n\t\t\theaders.set('authorization', `Bearer ${this.authToken}`)\n\t\t}\n\n\t\tconst isBinary = encoded instanceof Uint8Array\n\t\theaders.set('content-type', isBinary ? 'application/x-protobuf' : 'application/json')\n\n\t\ttry {\n\t\t\tconst requestBody = isBinary ? toArrayBuffer(encoded) : encoded\n\n\t\t\tconst response = await this.fetchImpl(this.url, {\n\t\t\t\tmethod: 'POST',\n\t\t\t\theaders,\n\t\t\t\tbody: requestBody,\n\t\t\t})\n\n\t\t\tif (!response.ok) {\n\t\t\t\tthrow new SyncError('HTTP transport send failed', {\n\t\t\t\t\tstatus: response.status,\n\t\t\t\t\tmessageType: message.type,\n\t\t\t\t})\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tthis.errorHandler?.(error instanceof Error ? error : new Error(String(error)))\n\t\t}\n\t}\n\n\tprivate async runPollLoop(): Promise<void> {\n\t\twhile (this.polling && this.connected && this.url) {\n\t\t\ttry {\n\t\t\t\tconst response = await this.fetchImpl(this.url, {\n\t\t\t\t\tmethod: 'GET',\n\t\t\t\t\theaders: this.makePollHeaders(),\n\t\t\t\t\tsignal: this.pollAbort?.signal,\n\t\t\t\t})\n\n\t\t\t\tif (response.status === 204) {\n\t\t\t\t\tawait sleep(this.retryDelayMs)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\tthrow new SyncError('HTTP long-poll request failed', {\n\t\t\t\t\t\tstatus: response.status,\n\t\t\t\t\t})\n\t\t\t\t}\n\n\t\t\t\tconst payload = await readResponsePayload(response)\n\t\t\t\tif (payload === null) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tconst message = this.serializer.decode(payload)\n\t\t\t\tthis.messageHandler?.(message)\n\t\t\t} catch (error) {\n\t\t\t\tif (!this.connected || !this.polling) {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\tif (isAbortError(error)) {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\tthis.errorHandler?.(error instanceof Error ? error : new Error(String(error)))\n\t\t\t\tawait sleep(this.retryDelayMs)\n\t\t\t}\n\t\t}\n\n\t\tif (!this.connected) {\n\t\t\tthis.closeHandler?.('http long-polling disconnected')\n\t\t}\n\t}\n\n\tprivate makePollHeaders(): Headers {\n\t\tconst headers = new Headers()\n\t\theaders.set('accept', 'application/json, application/x-protobuf')\n\t\tif (this.authToken) {\n\t\t\theaders.set('authorization', `Bearer ${this.authToken}`)\n\t\t}\n\t\treturn headers\n\t}\n}\n\nfunction normalizeHttpUrl(url: string): string {\n\tif (url.startsWith('http://') || url.startsWith('https://')) {\n\t\treturn url\n\t}\n\n\tif (url.startsWith('ws://')) {\n\t\treturn `http://${url.slice('ws://'.length)}`\n\t}\n\n\tif (url.startsWith('wss://')) {\n\t\treturn `https://${url.slice('wss://'.length)}`\n\t}\n\n\treturn url\n}\n\nfunction normalizeWebSocketUrl(url: string): string {\n\tif (url.startsWith('ws://') || url.startsWith('wss://')) {\n\t\treturn url\n\t}\n\n\tif (url.startsWith('http://')) {\n\t\treturn `ws://${url.slice('http://'.length)}`\n\t}\n\n\tif (url.startsWith('https://')) {\n\t\treturn `wss://${url.slice('https://'.length)}`\n\t}\n\n\treturn url\n}\n\nasync function readResponsePayload(response: Response): Promise<string | Uint8Array | null> {\n\tconst contentType = response.headers.get('content-type') ?? ''\n\tif (contentType.includes('application/x-protobuf')) {\n\t\tconst buffer = await response.arrayBuffer()\n\t\tif (buffer.byteLength === 0) return null\n\t\treturn new Uint8Array(buffer)\n\t}\n\n\tconst text = await response.text()\n\tif (text.length === 0) return null\n\treturn text\n}\n\nfunction sleep(ms: number): Promise<void> {\n\treturn new Promise((resolve) => setTimeout(resolve, ms))\n}\n\nfunction isAbortError(error: unknown): boolean {\n\treturn (\n\t\ttypeof error === 'object' &&\n\t\terror !== null &&\n\t\t'name' in error &&\n\t\t(error as { name?: string }).name === 'AbortError'\n\t)\n}\n\nfunction toArrayBuffer(data: Uint8Array): ArrayBuffer {\n\tconst copied = new Uint8Array(data.byteLength)\n\tcopied.set(data)\n\treturn copied.buffer\n}\n","import type { SyncMessage } from '../protocol/messages'\nimport type {\n\tSyncTransport,\n\tTransportCloseHandler,\n\tTransportErrorHandler,\n\tTransportMessageHandler,\n\tTransportOptions,\n} from './transport'\n\n/**\n * Configuration for the chaos transport.\n */\nexport interface ChaosConfig {\n\t/** Probability of dropping a message (0-1). Defaults to 0. */\n\tdropRate?: number\n\t/** Probability of duplicating a message (0-1). Defaults to 0. */\n\tduplicateRate?: number\n\t/** Probability of reordering messages (0-1). Defaults to 0. */\n\treorderRate?: number\n\t/** Maximum latency in ms for delayed messages. Defaults to 0. */\n\tmaxLatency?: number\n\t/** Injectable random source for deterministic testing. Returns value in [0, 1). */\n\trandomSource?: () => number\n}\n\n/**\n * Chaos transport that wraps another transport and injects faults.\n * Used for testing sync convergence under unreliable network conditions.\n *\n * Supports message dropping, duplication, reordering, and latency injection.\n * All random behavior is injectable for deterministic, reproducible tests.\n */\nexport class ChaosTransport implements SyncTransport {\n\tprivate readonly inner: SyncTransport\n\tprivate readonly dropRate: number\n\tprivate readonly duplicateRate: number\n\tprivate readonly reorderRate: number\n\tprivate readonly maxLatency: number\n\tprivate readonly random: () => number\n\n\tprivate messageHandler: TransportMessageHandler | null = null\n\tprivate reorderBuffer: SyncMessage[] = []\n\tprivate timers: ReturnType<typeof setTimeout>[] = []\n\n\tconstructor(inner: SyncTransport, config?: ChaosConfig) {\n\t\tthis.inner = inner\n\t\tthis.dropRate = config?.dropRate ?? 0\n\t\tthis.duplicateRate = config?.duplicateRate ?? 0\n\t\tthis.reorderRate = config?.reorderRate ?? 0\n\t\tthis.maxLatency = config?.maxLatency ?? 0\n\t\tthis.random = config?.randomSource ?? Math.random\n\t}\n\n\tasync connect(url: string, options?: TransportOptions): Promise<void> {\n\t\t// Intercept incoming messages from the inner transport\n\t\tthis.inner.onMessage((msg) => this.handleIncoming(msg))\n\t\treturn this.inner.connect(url, options)\n\t}\n\n\tasync disconnect(): Promise<void> {\n\t\t// Flush reorder buffer\n\t\tthis.flushReorderBuffer()\n\t\t// Clear pending timers\n\t\tfor (const timer of this.timers) {\n\t\t\tclearTimeout(timer)\n\t\t}\n\t\tthis.timers = []\n\t\treturn this.inner.disconnect()\n\t}\n\n\tsend(message: SyncMessage): void {\n\t\t// Apply chaos to outgoing messages\n\t\tif (this.random() < this.dropRate) {\n\t\t\treturn // Dropped\n\t\t}\n\n\t\tif (this.random() < this.reorderRate) {\n\t\t\tthis.reorderBuffer.push(message)\n\t\t\t// Flush buffer on next non-reordered send\n\t\t\treturn\n\t\t}\n\n\t\t// Flush any buffered messages first\n\t\tthis.flushReorderBuffer()\n\n\t\tthis.inner.send(message)\n\n\t\t// Duplicate?\n\t\tif (this.random() < this.duplicateRate) {\n\t\t\tthis.inner.send(message)\n\t\t}\n\t}\n\n\tonMessage(handler: TransportMessageHandler): void {\n\t\tthis.messageHandler = handler\n\t}\n\n\tonClose(handler: TransportCloseHandler): void {\n\t\tthis.inner.onClose(handler)\n\t}\n\n\tonError(handler: TransportErrorHandler): void {\n\t\tthis.inner.onError(handler)\n\t}\n\n\tisConnected(): boolean {\n\t\treturn this.inner.isConnected()\n\t}\n\n\tprivate handleIncoming(message: SyncMessage): void {\n\t\tif (!this.messageHandler) return\n\n\t\t// Apply chaos to incoming messages\n\t\tif (this.random() < this.dropRate) {\n\t\t\treturn // Dropped\n\t\t}\n\n\t\tif (this.maxLatency > 0) {\n\t\t\tconst delay = Math.floor(this.random() * this.maxLatency)\n\t\t\tconst timer = setTimeout(() => {\n\t\t\t\tthis.deliverIncoming(message)\n\t\t\t}, delay)\n\t\t\tthis.timers.push(timer)\n\t\t\treturn\n\t\t}\n\n\t\tthis.deliverIncoming(message)\n\t}\n\n\tprivate deliverIncoming(message: SyncMessage): void {\n\t\tif (!this.messageHandler) return\n\n\t\tthis.messageHandler(message)\n\n\t\t// Duplicate incoming?\n\t\tif (this.random() < this.duplicateRate) {\n\t\t\tthis.messageHandler(message)\n\t\t}\n\t}\n\n\tprivate flushReorderBuffer(): void {\n\t\t// Send buffered messages in random order\n\t\tconst buffer = [...this.reorderBuffer]\n\t\tthis.reorderBuffer = []\n\n\t\t// Fisher-Yates shuffle with injectable random\n\t\tfor (let i = buffer.length - 1; i > 0; i--) {\n\t\t\tconst j = Math.floor(this.random() * (i + 1))\n\t\t\tconst temp = buffer[i] as SyncMessage\n\t\t\tbuffer[i] = buffer[j] as SyncMessage\n\t\t\tbuffer[j] = temp\n\t\t}\n\n\t\tfor (const msg of buffer) {\n\t\t\tthis.inner.send(msg)\n\t\t}\n\t}\n}\n","import type {\n\tKoraEventEmitter,\n\tOperation,\n\tSyncDiagnosticsSnapshot,\n\tVersionVector,\n} from '@korajs/core'\nimport { SyncError } from '@korajs/core'\nimport { topologicalSort } from '@korajs/core/internal'\nimport { SyncMetricsCollector } from '../diagnostics/metrics-collector'\nimport type { MetricsCollectorConfig } from '../diagnostics/metrics-collector'\nimport type { SyncEncryptor } from '../encryption/sync-encryptor'\nimport { AwarenessManager } from '../awareness/awareness-manager'\nimport type { AwarenessMessage, AwarenessState } from '../awareness/types'\nimport type {\n\tAcknowledgmentMessage,\n\tAwarenessStateWire,\n\tAwarenessUpdateMessage,\n\tHandshakeResponseMessage,\n\tOperationBatchMessage,\n\tSyncMessage,\n\tWireFormat,\n} from '../protocol/messages'\nimport {\n\tNegotiatedMessageSerializer,\n\tversionVectorToWire,\n\twireToVersionVector,\n} from '../protocol/serializer'\nimport type { MessageSerializer } from '../protocol/serializer'\nimport { operationMatchesScope } from '../scopes/scope-filter'\nimport type { SyncTransport } from '../transport/transport'\nimport type { QueueStorage, SyncConfig, SyncScopeMap, SyncState, SyncStatusInfo } from '../types'\nimport { MemoryQueueStorage } from './memory-queue-storage'\nimport type { OutboundBatch } from './outbound-queue'\nimport { OutboundQueue } from './outbound-queue'\nimport type { SyncStore } from './sync-store'\n\nconst DEFAULT_BATCH_SIZE = 100\nconst DEFAULT_SCHEMA_VERSION = 1\n\n/**\n * Valid state transitions for the sync engine state machine.\n */\nconst VALID_TRANSITIONS: Record<SyncState, SyncState[]> = {\n\tdisconnected: ['connecting'],\n\tconnecting: ['handshaking', 'error', 'disconnected'],\n\thandshaking: ['syncing', 'error', 'disconnected'],\n\tsyncing: ['streaming', 'error', 'disconnected'],\n\tstreaming: ['disconnected', 'error'],\n\terror: ['disconnected'],\n}\n\n/**\n * Options for creating a SyncEngine.\n */\nexport interface SyncEngineOptions {\n\t/** Transport implementation (WebSocket, memory, etc.) */\n\ttransport: SyncTransport\n\t/** Local store implementing SyncStore */\n\tstore: SyncStore\n\t/** Sync configuration */\n\tconfig: SyncConfig\n\t/** Message serializer. Defaults to JSON. */\n\tserializer?: MessageSerializer\n\t/** Event emitter for DevTools integration */\n\temitter?: KoraEventEmitter\n\t/** Queue storage for persistent outbound queue. Defaults to in-memory. */\n\tqueueStorage?: QueueStorage\n\t/**\n\t * Optional encryptor for end-to-end encryption.\n\t * When provided, `data` and `previousData` fields of operations are encrypted\n\t * before sending and decrypted after receiving. The server never sees plaintext data.\n\t */\n\tencryptor?: SyncEncryptor\n\t/** Optional configuration for the metrics collector. */\n\tmetricsConfig?: MetricsCollectorConfig\n}\n\n/**\n * Diagnostics snapshot for debugging and support.\n */\nexport interface SyncDiagnostics {\n\tstate: SyncState\n\tstatus: SyncStatusInfo\n\tnodeId: string\n\turl: string\n\tschemaVersion: number\n\tlastSyncedAt: number | null\n\tlastSuccessfulPush: number | null\n\tlastSuccessfulPull: number | null\n\tconflicts: number\n\tpendingOperations: number\n\thasInFlightBatch: boolean\n\treconnecting: boolean\n\ttimestamp: number\n}\n\nlet nextMessageId = 0\nfunction generateMessageId(): string {\n\treturn `msg-${Date.now()}-${nextMessageId++}`\n}\n\n/**\n * Core sync orchestrator. Manages the sync lifecycle:\n * disconnected → connecting → handshaking → syncing → streaming\n *\n * Coordinates handshake, delta exchange, and real-time streaming\n * between a local store and a remote sync server.\n */\nexport class SyncEngine {\n\tprivate state: SyncState = 'disconnected'\n\tprivate readonly transport: SyncTransport\n\tprivate readonly store: SyncStore\n\tprivate readonly config: SyncConfig\n\tprivate readonly serializer: MessageSerializer\n\tprivate readonly emitter: KoraEventEmitter | null\n\tprivate readonly outboundQueue: OutboundQueue\n\tprivate readonly batchSize: number\n\tprivate readonly encryptor: SyncEncryptor | null\n\tprivate readonly awarenessManager: AwarenessManager\n\tprivate readonly metricsCollector: SyncMetricsCollector\n\n\tprivate remoteVector: VersionVector = new Map()\n\tprivate lastSyncedAt: number | null = null\n\tprivate lastSuccessfulPush: number | null = null\n\tprivate lastSuccessfulPull: number | null = null\n\tprivate conflictCount = 0\n\tprivate currentBatch: OutboundBatch | null = null\n\tprivate reconnecting = false\n\n\t// Track delta exchange state\n\tprivate deltaBatchesReceived = 0\n\tprivate deltaReceiveComplete = false\n\tprivate deltaSendComplete = false\n\n\t/**\n\t * The effective scope for this sync session.\n\t * Starts as the configured scopeMap. After handshake, may be replaced\n\t * with the server-accepted scope (server is authoritative).\n\t */\n\tprivate activeScope: SyncScopeMap | undefined\n\n\tconstructor(options: SyncEngineOptions) {\n\t\tthis.transport = options.transport\n\t\tthis.store = options.store\n\t\tthis.config = options.config\n\t\tthis.serializer = options.serializer ?? new NegotiatedMessageSerializer('json')\n\t\tthis.emitter = options.emitter ?? null\n\t\tthis.batchSize = options.config.batchSize ?? DEFAULT_BATCH_SIZE\n\t\tthis.encryptor = options.encryptor ?? null\n\t\tthis.activeScope = options.config.scopeMap\n\n\t\tconst queueStorage = options.queueStorage ?? new MemoryQueueStorage()\n\t\tthis.outboundQueue = new OutboundQueue(queueStorage)\n\n\t\tthis.metricsCollector = new SyncMetricsCollector(options.metricsConfig)\n\t\tif (this.emitter) {\n\t\t\tthis.metricsCollector.attachEmitter(this.emitter)\n\t\t}\n\n\t\tthis.awarenessManager = new AwarenessManager({\n\t\t\temitter: this.emitter ?? undefined,\n\t\t})\n\n\t\t// Wire awareness manager to send messages through the transport\n\t\tthis.awarenessManager.onSend((message: AwarenessMessage) => {\n\t\t\tif (this.state !== 'streaming') return\n\n\t\t\tconst wireMessage: SyncMessage = {\n\t\t\t\ttype: 'awareness-update',\n\t\t\t\tmessageId: generateMessageId(),\n\t\t\t\tclientId: message.clientId,\n\t\t\t\tstates: awarenessStatesToWire(message.states),\n\t\t\t}\n\t\t\tthis.transport.send(wireMessage)\n\t\t})\n\t}\n\n\t/**\n\t * Start the sync engine: connect → handshake → delta exchange → streaming.\n\t */\n\tasync start(): Promise<void> {\n\t\tif (this.state !== 'disconnected') {\n\t\t\tthrow new SyncError('Cannot start sync engine: not in disconnected state', {\n\t\t\t\tcurrentState: this.state,\n\t\t\t})\n\t\t}\n\n\t\tawait this.outboundQueue.initialize()\n\n\t\t// Set up transport handlers\n\t\tthis.transport.onMessage((msg) => this.handleMessage(msg))\n\t\tthis.transport.onClose((reason) => this.handleTransportClose(reason))\n\t\tthis.transport.onError((err) => this.handleTransportError(err))\n\n\t\tthis.transitionTo('connecting')\n\n\t\ttry {\n\t\t\tconst authToken = this.config.auth ? (await this.config.auth()).token : undefined\n\n\t\t\tawait this.transport.connect(this.config.url, { authToken })\n\t\t\tthis.transitionTo('handshaking')\n\n\t\t\t// Send handshake\n\t\t\tconst localVector = this.store.getVersionVector()\n\t\t\tconst handshake: SyncMessage = {\n\t\t\t\ttype: 'handshake',\n\t\t\t\tmessageId: generateMessageId(),\n\t\t\t\tnodeId: this.store.getNodeId(),\n\t\t\t\tversionVector: versionVectorToWire(localVector),\n\t\t\t\tschemaVersion: this.config.schemaVersion ?? DEFAULT_SCHEMA_VERSION,\n\t\t\t\tauthToken,\n\t\t\t\tsupportedWireFormats: ['json', 'protobuf'],\n\t\t\t\t...(this.config.scopeMap ? { syncScope: this.config.scopeMap } : {}),\n\t\t\t}\n\t\t\tthis.transport.send(handshake)\n\t\t} catch (err) {\n\t\t\t// Transport error/close handlers may have already transitioned to disconnected.\n\t\t\t// Guard against invalid state transitions.\n\t\t\tthis.ensureDisconnected()\n\t\t\tthrow err\n\t\t}\n\t}\n\n\t/**\n\t * Stop the sync engine. Disconnects the transport.\n\t */\n\tasync stop(): Promise<void> {\n\t\tif (this.state === 'disconnected') return\n\n\t\t// Stop awareness tracking\n\t\tthis.awarenessManager.stopCleanupTimer()\n\n\t\t// Return any in-flight batch back to queue\n\t\tif (this.currentBatch) {\n\t\t\tthis.outboundQueue.returnBatch(this.currentBatch.batchId)\n\t\t\tthis.currentBatch = null\n\t\t}\n\n\t\ttry {\n\t\t\tawait this.transport.disconnect()\n\t\t} finally {\n\t\t\t// The transport.disconnect() callback may have already transitioned\n\t\t\t// to 'disconnected' via handleTransportClose. Re-read the mutable field.\n\t\t\tthis.ensureDisconnected()\n\t\t}\n\t}\n\n\tprivate ensureDisconnected(): void {\n\t\tif (this.state !== 'disconnected') {\n\t\t\tthis.transitionTo('disconnected')\n\t\t}\n\t}\n\n\t/**\n\t * Push a local operation to the outbound queue.\n\t * If streaming, flushes immediately.\n\t *\n\t * Operations outside the configured sync scope are silently skipped\n\t * because they should remain local-only and not be sent to the server.\n\t */\n\tasync pushOperation(op: Operation): Promise<void> {\n\t\t// Only push operations that match the client's scope.\n\t\t// Out-of-scope operations are local-only and should not be synced.\n\t\tif (!operationMatchesScope(op, this.activeScope)) {\n\t\t\treturn\n\t\t}\n\n\t\tawait this.outboundQueue.enqueue(op)\n\t\tif (this.state === 'streaming') {\n\t\t\tthis.flushQueue()\n\t\t}\n\t}\n\n\t/**\n\t * Mark the engine as being in a reconnection loop. When reconnecting,\n\t * `getStatus()` returns 'offline' instead of 'syncing' for intermediate\n\t * states (connecting, handshaking, syncing), since the user is effectively\n\t * disconnected until reconnection succeeds.\n\t */\n\tsetReconnecting(value: boolean): void {\n\t\tthis.reconnecting = value\n\t}\n\n\t/**\n\t * Get the current developer-facing sync status.\n\t */\n\tgetStatus(): SyncStatusInfo {\n\t\tconst pendingOperations = this.outboundQueue.totalPending\n\t\tconst base = {\n\t\t\tpendingOperations,\n\t\t\tlastSyncedAt: this.lastSyncedAt,\n\t\t\tlastSuccessfulPush: this.lastSuccessfulPush,\n\t\t\tlastSuccessfulPull: this.lastSuccessfulPull,\n\t\t\tconflicts: this.conflictCount,\n\t\t}\n\t\tswitch (this.state) {\n\t\t\tcase 'disconnected':\n\t\t\t\treturn { ...base, status: 'offline' }\n\t\t\tcase 'connecting':\n\t\t\tcase 'handshaking':\n\t\t\tcase 'syncing':\n\t\t\t\t// During reconnection attempts, show 'offline' instead of 'syncing'\n\t\t\t\t// since the user is disconnected and reconnection is in progress.\n\t\t\t\treturn { ...base, status: this.reconnecting ? 'offline' : 'syncing' }\n\t\t\tcase 'streaming':\n\t\t\t\treturn { ...base, status: pendingOperations > 0 ? 'syncing' : 'synced' }\n\t\t\tcase 'error':\n\t\t\t\treturn { ...base, status: 'error' }\n\t\t}\n\t}\n\n\t/**\n\t * Record a merge conflict. Called by the merge-aware sync store\n\t * to increment the conflict counter for status reporting.\n\t */\n\trecordConflict(): void {\n\t\tthis.conflictCount++\n\t}\n\n\t/**\n\t * Force an immediate reconnection attempt. If the engine is disconnected\n\t * or in error state, restarts the sync. If already connected, no-op.\n\t */\n\tasync retryNow(): Promise<void> {\n\t\tif (this.state === 'disconnected' || this.state === 'error') {\n\t\t\tthis.reconnecting = false\n\t\t\tawait this.start()\n\t\t}\n\t}\n\n\t/**\n\t * Export a diagnostics snapshot for debugging and support tickets.\n\t * Contains connection state, timing info, and queue metrics.\n\t */\n\texportDiagnostics(): SyncDiagnostics {\n\t\treturn {\n\t\t\tstate: this.state,\n\t\t\tstatus: this.getStatus(),\n\t\t\tnodeId: this.store.getNodeId(),\n\t\t\turl: this.config.url,\n\t\t\tschemaVersion: this.config.schemaVersion ?? DEFAULT_SCHEMA_VERSION,\n\t\t\tlastSyncedAt: this.lastSyncedAt,\n\t\t\tlastSuccessfulPush: this.lastSuccessfulPush,\n\t\t\tlastSuccessfulPull: this.lastSuccessfulPull,\n\t\t\tconflicts: this.conflictCount,\n\t\t\tpendingOperations: this.outboundQueue.totalPending,\n\t\t\thasInFlightBatch: this.currentBatch !== null,\n\t\t\treconnecting: this.reconnecting,\n\t\t\ttimestamp: Date.now(),\n\t\t}\n\t}\n\n\t/**\n\t * Get the current internal state (for testing).\n\t */\n\tgetState(): SyncState {\n\t\treturn this.state\n\t}\n\n\t/**\n\t * Get the outbound queue (for testing).\n\t */\n\tgetOutboundQueue(): OutboundQueue {\n\t\treturn this.outboundQueue\n\t}\n\n\t/**\n\t * Update the sync scope map. Takes effect on the next connection attempt.\n\t *\n\t * When the scope changes (e.g., user switches organization), call this method\n\t * then reconnect. The new scope will be sent in the handshake, and the server\n\t * will send back data matching the new scope.\n\t *\n\t * Data that no longer matches the new scope is NOT deleted locally.\n\t * It simply stops being synced.\n\t *\n\t * @param scopeMap - New per-collection scope filters, or undefined to remove scope\n\t */\n\tupdateScope(scopeMap: SyncScopeMap | undefined): void {\n\t\tthis.activeScope = scopeMap\n\t\t// Also update the config so that the next handshake sends the new scope\n\t\tthis.config.scopeMap = scopeMap\n\t}\n\n\t/**\n\t * Get the currently active scope map. Returns undefined if no scope is configured.\n\t */\n\tgetActiveScope(): SyncScopeMap | undefined {\n\t\treturn this.activeScope\n\t}\n\n\t/**\n\t * Get the awareness manager for collaborative presence.\n\t * Use this to set local presence, observe remote collaborators,\n\t * and track cursor positions in richtext fields.\n\t */\n\tgetAwarenessManager(): AwarenessManager {\n\t\treturn this.awarenessManager\n\t}\n\n\t// --- Private methods ---\n\n\tprivate handleMessage(message: SyncMessage): void {\n\t\tswitch (message.type) {\n\t\t\tcase 'handshake-response':\n\t\t\t\tthis.handleHandshakeResponse(message)\n\t\t\t\tbreak\n\t\t\tcase 'operation-batch':\n\t\t\t\tthis.handleOperationBatch(message)\n\t\t\t\tbreak\n\t\t\tcase 'acknowledgment':\n\t\t\t\tthis.handleAcknowledgment(message)\n\t\t\t\tbreak\n\t\t\tcase 'error':\n\t\t\t\tthis.handleError(message)\n\t\t\t\tbreak\n\t\t\tcase 'awareness-update':\n\t\t\t\tthis.handleAwarenessUpdate(message)\n\t\t\t\tbreak\n\t\t}\n\t}\n\n\tprivate handleHandshakeResponse(msg: HandshakeResponseMessage): void {\n\t\tif (this.state !== 'handshaking') return\n\n\t\tif (!msg.accepted) {\n\t\t\tthis.transitionTo('error')\n\t\t\tthis.emitter?.emit({\n\t\t\t\ttype: 'sync:disconnected',\n\t\t\t\treason: msg.rejectReason ?? 'Handshake rejected',\n\t\t\t})\n\t\t\tthis.transitionTo('disconnected')\n\t\t\treturn\n\t\t}\n\n\t\tthis.remoteVector = wireToVersionVector(msg.versionVector)\n\n\t\tif (msg.selectedWireFormat) {\n\t\t\tthis.setSerializerWireFormat(msg.selectedWireFormat)\n\t\t}\n\n\t\t// If the server sent back an accepted scope, use it as the authoritative scope.\n\t\t// The server may have narrowed or augmented the client's requested scope\n\t\t// based on the auth context.\n\t\tif (msg.acceptedScope) {\n\t\t\tthis.activeScope = msg.acceptedScope\n\t\t}\n\n\t\tthis.emitter?.emit({ type: 'sync:connected', nodeId: this.store.getNodeId() })\n\t\tthis.metricsCollector.recordConnected()\n\t\tthis.metricsCollector.updateStatus('syncing')\n\t\tthis.metricsCollector.recordSyncStarted()\n\n\t\tthis.transitionTo('syncing')\n\t\tthis.deltaBatchesReceived = 0\n\t\tthis.deltaReceiveComplete = false\n\t\tthis.deltaSendComplete = false\n\n\t\t// Send our delta to the server\n\t\tthis.sendDelta()\n\t}\n\n\tprivate async sendDelta(): Promise<void> {\n\t\tconst localVector = this.store.getVersionVector()\n\t\tconst allMissingOps = await this.collectDelta(localVector, this.remoteVector)\n\n\t\t// Only send operations that match the client's scope.\n\t\t// Local-only operations outside scope should not be sent to the server.\n\t\tconst missingOps = allMissingOps.filter((op) => operationMatchesScope(op, this.activeScope))\n\n\t\tif (missingOps.length === 0) {\n\t\t\t// No ops to send — send empty final batch\n\t\t\tconst emptyBatch: SyncMessage = {\n\t\t\t\ttype: 'operation-batch',\n\t\t\t\tmessageId: generateMessageId(),\n\t\t\t\toperations: [],\n\t\t\t\tisFinal: true,\n\t\t\t\tbatchIndex: 0,\n\t\t\t}\n\t\t\tthis.transport.send(emptyBatch)\n\t\t\tthis.deltaSendComplete = true\n\t\t\tthis.checkDeltaComplete()\n\t\t\treturn\n\t\t}\n\n\t\t// Paginate into batches\n\t\tconst sorted = topologicalSort(missingOps)\n\t\tconst totalBatches = Math.ceil(sorted.length / this.batchSize)\n\n\t\tfor (let i = 0; i < totalBatches; i++) {\n\t\t\tconst start = i * this.batchSize\n\t\t\tconst batchOps = sorted.slice(start, start + this.batchSize)\n\n\t\t\t// Encrypt data fields before serialization if E2E encryption is enabled\n\t\t\tconst opsToSerialize = this.encryptor\n\t\t\t\t? await this.encryptor.encryptBatch(batchOps)\n\t\t\t\t: batchOps\n\n\t\t\tconst serializedOps = opsToSerialize.map((op) => this.serializer.encodeOperation(op))\n\n\t\t\tconst batchMsg: SyncMessage = {\n\t\t\t\ttype: 'operation-batch',\n\t\t\t\tmessageId: generateMessageId(),\n\t\t\t\toperations: serializedOps,\n\t\t\t\tisFinal: i === totalBatches - 1,\n\t\t\t\tbatchIndex: i,\n\t\t\t}\n\t\t\tthis.transport.send(batchMsg)\n\n\t\t\tthis.emitter?.emit({\n\t\t\t\ttype: 'sync:sent',\n\t\t\t\toperations: batchOps,\n\t\t\t\tbatchSize: batchOps.length,\n\t\t\t})\n\t\t}\n\n\t\tthis.deltaSendComplete = true\n\t\tthis.checkDeltaComplete()\n\t}\n\n\tprivate async collectDelta(\n\t\tlocalVector: VersionVector,\n\t\tremoteVector: VersionVector,\n\t): Promise<Operation[]> {\n\t\tconst missing: Operation[] = []\n\t\tfor (const [nodeId, localSeq] of localVector) {\n\t\t\tconst remoteSeq = remoteVector.get(nodeId) ?? 0\n\t\t\tif (localSeq > remoteSeq) {\n\t\t\t\tconst ops = await this.store.getOperationRange(nodeId, remoteSeq + 1, localSeq)\n\t\t\t\tmissing.push(...ops)\n\t\t\t}\n\t\t}\n\t\treturn missing\n\t}\n\n\tprivate async handleOperationBatch(msg: OperationBatchMessage): Promise<void> {\n\t\tconst deserialized = msg.operations.map((s) => this.serializer.decodeOperation(s))\n\n\t\t// Decrypt data fields after deserialization if E2E encryption is enabled\n\t\tconst operations = this.encryptor\n\t\t\t? await this.encryptor.decryptBatch(deserialized)\n\t\t\t: deserialized\n\n\t\t// Defense in depth: validate received operations match our scope.\n\t\t// The server should already filter, but we verify client-side as well.\n\t\tconst inScopeOps = operations.filter((op) => operationMatchesScope(op, this.activeScope))\n\n\t\t// Apply each in-scope operation to the local store\n\t\tfor (const op of inScopeOps) {\n\t\t\tawait this.store.applyRemoteOperation(op)\n\t\t}\n\n\t\tif (inScopeOps.length > 0) {\n\t\t\tthis.lastSuccessfulPull = Date.now()\n\t\t\tthis.emitter?.emit({\n\t\t\t\ttype: 'sync:received',\n\t\t\t\toperations: inScopeOps,\n\t\t\t\tbatchSize: inScopeOps.length,\n\t\t\t})\n\t\t}\n\n\t\t// Send acknowledgment for the original batch (server tracks by batch, not per-op)\n\t\tconst lastOp = operations[operations.length - 1]\n\t\tconst ack: SyncMessage = {\n\t\t\ttype: 'acknowledgment',\n\t\t\tmessageId: generateMessageId(),\n\t\t\tacknowledgedMessageId: msg.messageId,\n\t\t\tlastSequenceNumber: lastOp ? lastOp.sequenceNumber : 0,\n\t\t}\n\t\tthis.transport.send(ack)\n\n\t\tthis.emitter?.emit({\n\t\t\ttype: 'sync:acknowledged',\n\t\t\tsequenceNumber: lastOp ? lastOp.sequenceNumber : 0,\n\t\t})\n\n\t\tif (this.state === 'syncing') {\n\t\t\tthis.deltaBatchesReceived++\n\t\t\tif (msg.isFinal) {\n\t\t\t\tthis.deltaReceiveComplete = true\n\t\t\t\tthis.checkDeltaComplete()\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate handleAcknowledgment(msg: AcknowledgmentMessage): void {\n\t\tif (this.currentBatch) {\n\t\t\tthis.outboundQueue.acknowledge(this.currentBatch.batchId)\n\t\t\tthis.currentBatch = null\n\t\t\tconst now = Date.now()\n\t\t\tthis.lastSyncedAt = now\n\t\t\tthis.lastSuccessfulPush = now\n\t\t}\n\n\t\t// Continue flushing if more ops in queue\n\t\tif (this.state === 'streaming' && this.outboundQueue.hasOperations) {\n\t\t\tthis.flushQueue()\n\t\t}\n\t}\n\n\tprivate handleError(msg: { code: string; message: string; retriable: boolean }): void {\n\t\tthis.transitionTo('error')\n\t\tif (msg.code === 'AUTH_FAILED') {\n\t\t\tthis.emitter?.emit({ type: 'sync:auth-failed', reason: msg.message })\n\t\t}\n\t\tthis.emitter?.emit({ type: 'sync:disconnected', reason: msg.message })\n\t\tthis.transitionTo('disconnected')\n\t}\n\n\tprivate checkDeltaComplete(): void {\n\t\tif (this.deltaSendComplete && this.deltaReceiveComplete) {\n\t\t\tthis.lastSyncedAt = Date.now()\n\t\t\tthis.transitionTo('streaming')\n\n\t\t\t// Start awareness cleanup timer now that we're streaming\n\t\t\tthis.awarenessManager.startCleanupTimer()\n\n\t\t\t// Re-broadcast local awareness state to the new connection\n\t\t\tconst localState = this.awarenessManager.getLocalState()\n\t\t\tif (localState) {\n\t\t\t\tthis.awarenessManager.setLocalState(localState)\n\t\t\t}\n\n\t\t\t// Flush any queued operations accumulated during delta exchange\n\t\t\tif (this.outboundQueue.hasOperations) {\n\t\t\t\tthis.flushQueue()\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate flushQueue(): void {\n\t\tif (this.currentBatch) return // Already have an in-flight batch\n\t\tif (!this.outboundQueue.hasOperations) return\n\n\t\tconst batch = this.outboundQueue.takeBatch(this.batchSize)\n\t\tif (!batch) return\n\n\t\tthis.currentBatch = batch\n\n\t\tif (this.encryptor) {\n\t\t\t// Encryption is async — encrypt then send. Errors return the batch to the queue.\n\t\t\tthis.encryptor.encryptBatch(batch.operations).then(\n\t\t\t\t(encrypted) => {\n\t\t\t\t\tconst serializedOps = encrypted.map((op) => this.serializer.encodeOperation(op))\n\t\t\t\t\tconst batchMsg: SyncMessage = {\n\t\t\t\t\t\ttype: 'operation-batch',\n\t\t\t\t\t\tmessageId: generateMessageId(),\n\t\t\t\t\t\toperations: serializedOps,\n\t\t\t\t\t\tisFinal: true,\n\t\t\t\t\t\tbatchIndex: 0,\n\t\t\t\t\t}\n\t\t\t\t\tthis.transport.send(batchMsg)\n\n\t\t\t\t\tthis.emitter?.emit({\n\t\t\t\t\t\ttype: 'sync:sent',\n\t\t\t\t\t\toperations: batch.operations,\n\t\t\t\t\t\tbatchSize: batch.operations.length,\n\t\t\t\t\t})\n\t\t\t\t},\n\t\t\t\t(err) => {\n\t\t\t\t\t// If encryption fails, return the batch to the queue so no data is lost\n\t\t\t\t\tthis.outboundQueue.returnBatch(batch.batchId)\n\t\t\t\t\tthis.currentBatch = null\n\t\t\t\t\tthis.emitter?.emit({\n\t\t\t\t\t\ttype: 'sync:disconnected',\n\t\t\t\t\t\treason: err instanceof Error ? err.message : 'Encryption failed',\n\t\t\t\t\t})\n\t\t\t\t},\n\t\t\t)\n\t\t} else {\n\t\t\tconst serializedOps = batch.operations.map((op) => this.serializer.encodeOperation(op))\n\t\t\tconst batchMsg: SyncMessage = {\n\t\t\t\ttype: 'operation-batch',\n\t\t\t\tmessageId: generateMessageId(),\n\t\t\t\toperations: serializedOps,\n\t\t\t\tisFinal: true,\n\t\t\t\tbatchIndex: 0,\n\t\t\t}\n\t\t\tthis.transport.send(batchMsg)\n\n\t\t\tthis.emitter?.emit({\n\t\t\t\ttype: 'sync:sent',\n\t\t\t\toperations: batch.operations,\n\t\t\t\tbatchSize: batch.operations.length,\n\t\t\t})\n\t\t}\n\t}\n\n\tprivate handleAwarenessUpdate(msg: AwarenessUpdateMessage): void {\n\t\tconst awarenessMessage: AwarenessMessage = {\n\t\t\ttype: 'awareness',\n\t\t\tclientId: msg.clientId,\n\t\t\tstates: wireToAwarenessStates(msg.states),\n\t\t}\n\t\tthis.awarenessManager.handleRemoteMessage(awarenessMessage)\n\t}\n\n\tprivate handleTransportClose(reason: string): void {\n\t\t// Return in-flight batch to queue\n\t\tif (this.currentBatch) {\n\t\t\tthis.outboundQueue.returnBatch(this.currentBatch.batchId)\n\t\t\tthis.currentBatch = null\n\t\t}\n\n\t\tif (this.state !== 'disconnected') {\n\t\t\tthis.emitter?.emit({ type: 'sync:disconnected', reason })\n\t\t\tthis.transitionTo('disconnected')\n\t\t}\n\t}\n\n\tprivate handleTransportError(err: Error): void {\n\t\t// Transport errors during connecting should transition to error\n\t\tif (this.state !== 'disconnected') {\n\t\t\tthis.transitionTo('error')\n\t\t\tthis.emitter?.emit({ type: 'sync:disconnected', reason: err.message })\n\t\t\tthis.transitionTo('disconnected')\n\t\t}\n\t}\n\n\tprivate transitionTo(newState: SyncState): void {\n\t\tconst validTargets = VALID_TRANSITIONS[this.state]\n\t\tif (!validTargets.includes(newState)) {\n\t\t\tthrow new SyncError(`Invalid sync state transition: ${this.state} → ${newState}`, {\n\t\t\t\tfrom: this.state,\n\t\t\t\tto: newState,\n\t\t\t})\n\t\t}\n\t\tthis.state = newState\n\t}\n\n\tprivate setSerializerWireFormat(format: WireFormat): void {\n\t\tif (typeof this.serializer.setWireFormat === 'function') {\n\t\t\tthis.serializer.setWireFormat(format)\n\t\t}\n\t}\n}\n\n// --- Awareness wire format conversion helpers ---\n\n/**\n * Convert internal awareness states to wire format for transport.\n */\nfunction awarenessStatesToWire(\n\tstates: Record<number, AwarenessState | null>,\n): Record<string, AwarenessStateWire | null> {\n\tconst wire: Record<string, AwarenessStateWire | null> = {}\n\tfor (const [clientId, state] of Object.entries(states)) {\n\t\tif (state === null) {\n\t\t\twire[clientId] = null\n\t\t} else {\n\t\t\tconst wireState: AwarenessStateWire = {\n\t\t\t\tuser: { ...state.user },\n\t\t\t}\n\t\t\tif (state.cursor) {\n\t\t\t\twireState.cursor = { ...state.cursor }\n\t\t\t}\n\t\t\twire[clientId] = wireState\n\t\t}\n\t}\n\treturn wire\n}\n\n/**\n * Convert wire format awareness states to internal representation.\n */\nfunction wireToAwarenessStates(\n\twire: Record<string, AwarenessStateWire | null>,\n): Record<number, AwarenessState | null> {\n\tconst states: Record<number, AwarenessState | null> = {}\n\tfor (const [clientId, wireState] of Object.entries(wire)) {\n\t\tif (wireState === null) {\n\t\t\tstates[Number(clientId)] = null\n\t\t} else {\n\t\t\tconst state: AwarenessState = {\n\t\t\t\tuser: { ...wireState.user },\n\t\t\t}\n\t\t\tif (wireState.cursor) {\n\t\t\t\tstate.cursor = { ...wireState.cursor }\n\t\t\t}\n\t\t\tstates[Number(clientId)] = state\n\t\t}\n\t}\n\treturn states\n}\n","import type { TimeSource } from '@korajs/core'\n\n/**\n * A single bandwidth measurement sample: bytes transferred over a known duration.\n */\ninterface BandwidthSample {\n\tbytes: number\n\tdurationMs: number\n\ttimestamp: number\n}\n\n/**\n * Estimates effective bandwidth by tracking byte transfers over time.\n *\n * Maintains a sliding window of transfer samples and computes a\n * weighted average bandwidth, giving more weight to recent samples.\n * This provides a smooth estimate that adapts to changing network conditions.\n */\nexport class BandwidthEstimator {\n\tprivate readonly maxSamples: number\n\tprivate readonly timeSource: TimeSource\n\tprivate readonly samples: BandwidthSample[] = []\n\n\t/**\n\t * @param maxSamples - Maximum number of samples to retain. Defaults to 20.\n\t * @param timeSource - Injectable time source for deterministic testing.\n\t */\n\tconstructor(maxSamples = 20, timeSource?: TimeSource) {\n\t\tthis.maxSamples = maxSamples\n\t\tthis.timeSource = timeSource ?? { now: () => Date.now() }\n\t}\n\n\t/**\n\t * Record a transfer of `bytes` that took `durationMs` to complete.\n\t * Samples with zero or negative duration are ignored to avoid division errors.\n\t */\n\trecordTransfer(bytes: number, durationMs: number): void {\n\t\tif (durationMs <= 0 || bytes <= 0) return\n\n\t\tthis.samples.push({\n\t\t\tbytes,\n\t\t\tdurationMs,\n\t\t\ttimestamp: this.timeSource.now(),\n\t\t})\n\n\t\t// Evict oldest samples beyond the window\n\t\twhile (this.samples.length > this.maxSamples) {\n\t\t\tthis.samples.shift()\n\t\t}\n\t}\n\n\t/**\n\t * Estimate current effective bandwidth in bytes per second.\n\t *\n\t * Uses exponential weighting so recent samples have more influence.\n\t * Returns null if fewer than 2 samples exist (not enough data).\n\t */\n\testimate(): number | null {\n\t\tif (this.samples.length < 2) return null\n\n\t\tlet weightedSum = 0\n\t\tlet totalWeight = 0\n\n\t\t// Exponential decay: most recent sample gets weight 1.0,\n\t\t// each older sample is multiplied by 0.9\n\t\tconst decayFactor = 0.9\n\t\tfor (let i = this.samples.length - 1; i >= 0; i--) {\n\t\t\tconst sample = this.samples[i]\n\t\t\tconst bytesPerSec = (sample.bytes / sample.durationMs) * 1000\n\t\t\tconst age = this.samples.length - 1 - i\n\t\t\tconst weight = decayFactor ** age\n\n\t\t\tweightedSum += bytesPerSec * weight\n\t\t\ttotalWeight += weight\n\t\t}\n\n\t\tif (totalWeight === 0) return null\n\t\treturn Math.round(weightedSum / totalWeight)\n\t}\n\n\t/**\n\t * Reset all recorded samples.\n\t */\n\treset(): void {\n\t\tthis.samples.length = 0\n\t}\n\n\t/**\n\t * Get the number of samples currently stored.\n\t */\n\tsampleCount(): number {\n\t\treturn this.samples.length\n\t}\n}\n","/**\n * Sliding window percentile calculator.\n *\n * Maintains a fixed-size circular buffer of numeric samples and\n * computes percentiles (p50, p95, p99, etc.) on demand by sorting\n * the current window. This approach is simple, correct, and fast\n * for the expected window sizes (100 samples).\n */\nexport class SlidingWindowPercentile {\n\tprivate readonly samples: number[]\n\tprivate readonly maxSize: number\n\tprivate writeIndex = 0\n\tprivate count = 0\n\n\t/**\n\t * @param maxSize - Maximum number of samples in the sliding window.\n\t * Older samples are overwritten when the buffer is full.\n\t */\n\tconstructor(maxSize: number) {\n\t\tif (maxSize < 1) {\n\t\t\tthrow new Error(`SlidingWindowPercentile maxSize must be >= 1, got ${maxSize}`)\n\t\t}\n\t\tthis.maxSize = maxSize\n\t\tthis.samples = new Array<number>(maxSize)\n\t}\n\n\t/**\n\t * Add a sample to the sliding window.\n\t * If the window is full, the oldest sample is overwritten.\n\t */\n\taddSample(value: number): void {\n\t\tthis.samples[this.writeIndex] = value\n\t\tthis.writeIndex = (this.writeIndex + 1) % this.maxSize\n\t\tif (this.count < this.maxSize) {\n\t\t\tthis.count++\n\t\t}\n\t}\n\n\t/**\n\t * Compute a percentile value from the current window.\n\t *\n\t * Uses the nearest-rank method: the percentile value is the smallest\n\t * value in the dataset such that at least p% of the data is <= that value.\n\t *\n\t * @param p - Percentile to compute (0-100). E.g., 50 for median, 95 for p95.\n\t * @returns The percentile value, or 0 if no samples have been recorded.\n\t */\n\tpercentile(p: number): number {\n\t\tif (this.count === 0) return 0\n\n\t\t// Extract only the valid portion of the buffer and sort\n\t\tconst sorted = this.samples.slice(0, this.count).sort((a, b) => a - b)\n\n\t\t// Nearest-rank method: index = ceil(p/100 * n) - 1, clamped to [0, n-1]\n\t\tconst rank = Math.ceil((p / 100) * sorted.length) - 1\n\t\tconst index = Math.max(0, Math.min(rank, sorted.length - 1))\n\t\treturn sorted[index]\n\t}\n\n\t/**\n\t * Get the most recently added sample, or 0 if no samples exist.\n\t */\n\tlatest(): number {\n\t\tif (this.count === 0) return 0\n\t\t// writeIndex points to the next write position, so the last written is one behind\n\t\tconst lastIndex = (this.writeIndex - 1 + this.maxSize) % this.maxSize\n\t\treturn this.samples[lastIndex]\n\t}\n\n\t/**\n\t * Get the number of samples currently in the window.\n\t */\n\tsize(): number {\n\t\treturn this.count\n\t}\n\n\t/**\n\t * Reset the sliding window, clearing all samples.\n\t */\n\treset(): void {\n\t\tthis.writeIndex = 0\n\t\tthis.count = 0\n\t}\n}\n","import type {\n\tConnectionQuality,\n\tKoraEventEmitter,\n\tSyncDiagnosticsSnapshot,\n\tTimeSource,\n} from '@korajs/core'\nimport type { SyncStatus } from '../types'\nimport { BandwidthEstimator } from './bandwidth-estimator'\nimport { SlidingWindowPercentile } from './percentile'\n\n/**\n * Configuration for the SyncMetricsCollector.\n */\nexport interface MetricsCollectorConfig {\n\t/** Number of RTT samples to keep for percentile calculations. Defaults to 100. */\n\trttWindowSize?: number\n\t/** Number of bandwidth samples to keep. Defaults to 20. */\n\tbandwidthWindowSize?: number\n\t/** Interval in ms between periodic diagnostics emissions. Defaults to 5000. */\n\tdiagnosticsInterval?: number\n\t/** Injectable time source for deterministic testing. */\n\ttimeSource?: TimeSource\n}\n\n/**\n * Collects and aggregates sync metrics for diagnostics and DevTools integration.\n *\n * Tracks connection timing, RTT percentiles, throughput counters, queue depth,\n * initial sync progress, errors, and connection quality. Periodically emits\n * a `sync:diagnostics` event with a full snapshot.\n */\nexport class SyncMetricsCollector {\n\tprivate readonly rttWindow: SlidingWindowPercentile\n\tprivate readonly inboundBandwidth: BandwidthEstimator\n\tprivate readonly outboundBandwidth: BandwidthEstimator\n\tprivate readonly timeSource: TimeSource\n\tprivate readonly diagnosticsInterval: number\n\n\t// Connection\n\tprivate connectedAt: number | null = null\n\tprivate disconnectedAt: number | null = null\n\tprivate reconnectAttempts = 0\n\n\t// Throughput\n\tprivate operationsSent = 0\n\tprivate operationsReceived = 0\n\tprivate bytesSent = 0\n\tprivate bytesReceived = 0\n\n\t// Queue\n\tprivate pendingOperations = 0\n\tprivate outboundQueueSize = 0\n\n\t// Sync progress\n\tprivate lastSyncedAt: number | null = null\n\tprivate syncStartTime: number | null = null\n\tprivate syncDuration: number | null = null\n\tprivate initialSyncComplete = false\n\tprivate initialSyncTotalBatches = 0\n\tprivate initialSyncReceivedBatches = 0\n\n\t// Errors\n\tprivate lastError: string | null = null\n\tprivate errorCount = 0\n\n\t// Status\n\tprivate currentStatus: SyncStatus = 'offline'\n\tprivate currentQuality: ConnectionQuality = 'offline'\n\n\t// Periodic emission\n\tprivate emitter: KoraEventEmitter | null = null\n\tprivate periodicTimer: ReturnType<typeof setInterval> | null = null\n\n\tconstructor(config?: MetricsCollectorConfig) {\n\t\tthis.rttWindow = new SlidingWindowPercentile(config?.rttWindowSize ?? 100)\n\t\tthis.inboundBandwidth = new BandwidthEstimator(\n\t\t\tconfig?.bandwidthWindowSize ?? 20,\n\t\t\tconfig?.timeSource,\n\t\t)\n\t\tthis.outboundBandwidth = new BandwidthEstimator(\n\t\t\tconfig?.bandwidthWindowSize ?? 20,\n\t\t\tconfig?.timeSource,\n\t\t)\n\t\tthis.timeSource = config?.timeSource ?? { now: () => Date.now() }\n\t\tthis.diagnosticsInterval = config?.diagnosticsInterval ?? 5000\n\t}\n\n\t/**\n\t * Attach an event emitter for periodic diagnostics emission.\n\t * Starts emitting `sync:diagnostics` events at the configured interval\n\t * while connected.\n\t */\n\tattachEmitter(emitter: KoraEventEmitter): void {\n\t\tthis.emitter = emitter\n\t}\n\n\t/**\n\t * Record that a connection has been established.\n\t */\n\trecordConnected(): void {\n\t\tthis.connectedAt = this.timeSource.now()\n\t\tthis.reconnectAttempts = 0\n\t\tthis.startPeriodicEmission()\n\t}\n\n\t/**\n\t * Record that the connection has been lost.\n\t */\n\trecordDisconnected(): void {\n\t\tthis.disconnectedAt = this.timeSource.now()\n\t\tthis.stopPeriodicEmission()\n\t}\n\n\t/**\n\t * Record a reconnection attempt.\n\t */\n\trecordReconnectAttempt(): void {\n\t\tthis.reconnectAttempts++\n\t}\n\n\t/**\n\t * Record a round-trip time measurement.\n\t */\n\trecordRtt(ms: number): void {\n\t\tthis.rttWindow.addSample(ms)\n\t}\n\n\t/**\n\t * Record operations sent with their serialized byte size.\n\t */\n\trecordSent(operationCount: number, byteSize: number, durationMs: number): void {\n\t\tthis.operationsSent += operationCount\n\t\tthis.bytesSent += byteSize\n\t\tif (durationMs > 0 && byteSize > 0) {\n\t\t\tthis.outboundBandwidth.recordTransfer(byteSize, durationMs)\n\t\t\tthis.emitBandwidthEvent('out')\n\t\t}\n\t}\n\n\t/**\n\t * Record operations received with their serialized byte size.\n\t */\n\trecordReceived(operationCount: number, byteSize: number, durationMs: number): void {\n\t\tthis.operationsReceived += operationCount\n\t\tthis.bytesReceived += byteSize\n\t\tif (durationMs > 0 && byteSize > 0) {\n\t\t\tthis.inboundBandwidth.recordTransfer(byteSize, durationMs)\n\t\t\tthis.emitBandwidthEvent('in')\n\t\t}\n\t}\n\n\t/**\n\t * Update the pending operations count and estimated outbound queue size.\n\t */\n\tupdateQueue(pendingOps: number, estimatedBytes: number): void {\n\t\tthis.pendingOperations = pendingOps\n\t\tthis.outboundQueueSize = estimatedBytes\n\t}\n\n\t/**\n\t * Record that sync has started (for measuring sync duration).\n\t */\n\trecordSyncStarted(): void {\n\t\tthis.syncStartTime = this.timeSource.now()\n\t}\n\n\t/**\n\t * Record that a sync cycle has completed.\n\t */\n\trecordSyncCompleted(): void {\n\t\tif (this.syncStartTime !== null) {\n\t\t\tthis.syncDuration = this.timeSource.now() - this.syncStartTime\n\t\t\tthis.syncStartTime = null\n\t\t}\n\t\tthis.lastSyncedAt = this.timeSource.now()\n\t\tif (!this.initialSyncComplete) {\n\t\t\tthis.initialSyncComplete = true\n\t\t}\n\t}\n\n\t/**\n\t * Update initial sync progress.\n\t * @param receivedBatches - Number of delta batches received so far.\n\t * @param totalBatches - Estimated total batches (0 if unknown).\n\t */\n\tupdateInitialSyncProgress(receivedBatches: number, totalBatches: number): void {\n\t\tthis.initialSyncReceivedBatches = receivedBatches\n\t\tthis.initialSyncTotalBatches = totalBatches\n\n\t\tconst progress =\n\t\t\ttotalBatches > 0 ? Math.min(1, receivedBatches / totalBatches) : receivedBatches > 0 ? 0.5 : 0\n\n\t\tthis.emitter?.emit({\n\t\t\ttype: 'sync:initial-sync-progress',\n\t\t\tprogress,\n\t\t\ttotalBatches,\n\t\t\treceivedBatches,\n\t\t})\n\t}\n\n\t/**\n\t * Record an error.\n\t */\n\trecordError(message: string): void {\n\t\tthis.lastError = message\n\t\tthis.errorCount++\n\t}\n\n\t/**\n\t * Update the current developer-facing status.\n\t */\n\tupdateStatus(status: SyncStatus): void {\n\t\tthis.currentStatus = status\n\t}\n\n\t/**\n\t * Update the connection quality.\n\t */\n\tupdateQuality(quality: ConnectionQuality): void {\n\t\tthis.currentQuality = quality\n\t}\n\n\t/**\n\t * Compute and return a full diagnostics snapshot.\n\t */\n\tgetSnapshot(): SyncDiagnosticsSnapshot {\n\t\treturn {\n\t\t\t// Connection\n\t\t\tstatus: this.currentStatus,\n\t\t\tconnectedAt: this.connectedAt,\n\t\t\tdisconnectedAt: this.disconnectedAt,\n\t\t\treconnectAttempts: this.reconnectAttempts,\n\n\t\t\t// Latency\n\t\t\trttMs: this.rttWindow.latest(),\n\t\t\trttP50Ms: this.rttWindow.percentile(50),\n\t\t\trttP95Ms: this.rttWindow.percentile(95),\n\t\t\trttP99Ms: this.rttWindow.percentile(99),\n\n\t\t\t// Throughput\n\t\t\toperationsSent: this.operationsSent,\n\t\t\toperationsReceived: this.operationsReceived,\n\t\t\tbytesSent: this.bytesSent,\n\t\t\tbytesReceived: this.bytesReceived,\n\n\t\t\t// Queue\n\t\t\tpendingOperations: this.pendingOperations,\n\t\t\toutboundQueueSize: this.outboundQueueSize,\n\n\t\t\t// Sync Progress\n\t\t\tlastSyncedAt: this.lastSyncedAt,\n\t\t\tsyncDuration: this.syncDuration,\n\t\t\tinitialSyncComplete: this.initialSyncComplete,\n\t\t\tinitialSyncProgress: this.computeInitialSyncProgress(),\n\n\t\t\t// Errors\n\t\t\tlastError: this.lastError,\n\t\t\terrorCount: this.errorCount,\n\n\t\t\t// Connection Quality\n\t\t\tquality: this.currentQuality,\n\t\t\teffectiveBandwidth: this.computeEffectiveBandwidth(),\n\t\t}\n\t}\n\n\t/**\n\t * Assess connection quality from current metrics.\n\t *\n\t * Quality is derived from RTT percentiles, error rate, and bandwidth:\n\t * - excellent: p95 < 100ms, no errors\n\t * - good: p95 < 300ms, errorCount <= 1\n\t * - fair: p95 < 1000ms, errorCount <= 3\n\t * - poor: p95 >= 1000ms or errorCount > 3\n\t * - offline: no connection\n\t */\n\tassessQuality(): ConnectionQuality {\n\t\tif (this.currentStatus === 'offline') return 'offline'\n\n\t\tconst p95 = this.rttWindow.percentile(95)\n\t\tconst hasSamples = this.rttWindow.size() > 0\n\n\t\tif (!hasSamples) {\n\t\t\t// No RTT data yet, fall back to error-based assessment\n\t\t\tif (this.errorCount > 3) return 'poor'\n\t\t\tif (this.errorCount > 0) return 'fair'\n\t\t\treturn 'good'\n\t\t}\n\n\t\tif (this.errorCount > 3) return 'poor'\n\t\tif (p95 < 100 && this.errorCount === 0) return 'excellent'\n\t\tif (p95 < 300 && this.errorCount <= 1) return 'good'\n\t\tif (p95 < 1000 && this.errorCount <= 3) return 'fair'\n\t\treturn 'poor'\n\t}\n\n\t/**\n\t * Reset all collected metrics. Call when starting a new session.\n\t */\n\treset(): void {\n\t\tthis.rttWindow.reset()\n\t\tthis.inboundBandwidth.reset()\n\t\tthis.outboundBandwidth.reset()\n\n\t\tthis.connectedAt = null\n\t\tthis.disconnectedAt = null\n\t\tthis.reconnectAttempts = 0\n\n\t\tthis.operationsSent = 0\n\t\tthis.operationsReceived = 0\n\t\tthis.bytesSent = 0\n\t\tthis.bytesReceived = 0\n\n\t\tthis.pendingOperations = 0\n\t\tthis.outboundQueueSize = 0\n\n\t\tthis.lastSyncedAt = null\n\t\tthis.syncStartTime = null\n\t\tthis.syncDuration = null\n\t\tthis.initialSyncComplete = false\n\t\tthis.initialSyncTotalBatches = 0\n\t\tthis.initialSyncReceivedBatches = 0\n\n\t\tthis.lastError = null\n\t\tthis.errorCount = 0\n\n\t\tthis.currentStatus = 'offline'\n\t\tthis.currentQuality = 'offline'\n\n\t\tthis.stopPeriodicEmission()\n\t}\n\n\t/**\n\t * Stop periodic emission and clean up resources.\n\t */\n\tdispose(): void {\n\t\tthis.stopPeriodicEmission()\n\t\tthis.emitter = null\n\t}\n\n\t// --- Private helpers ---\n\n\tprivate computeInitialSyncProgress(): number {\n\t\tif (this.initialSyncComplete) return 1\n\t\tif (this.initialSyncTotalBatches > 0) {\n\t\t\treturn Math.min(1, this.initialSyncReceivedBatches / this.initialSyncTotalBatches)\n\t\t}\n\t\t// Unknown total: if we have received some batches, report 0.5 as indeterminate progress\n\t\treturn this.initialSyncReceivedBatches > 0 ? 0.5 : 0\n\t}\n\n\tprivate computeEffectiveBandwidth(): number | null {\n\t\t// Use the lower of inbound and outbound as effective bandwidth,\n\t\t// since the bottleneck determines the effective rate.\n\t\tconst inbound = this.inboundBandwidth.estimate()\n\t\tconst outbound = this.outboundBandwidth.estimate()\n\n\t\tif (inbound === null && outbound === null) return null\n\t\tif (inbound === null) return outbound\n\t\tif (outbound === null) return inbound\n\t\treturn Math.min(inbound, outbound)\n\t}\n\n\tprivate startPeriodicEmission(): void {\n\t\tif (this.periodicTimer !== null) return\n\t\tif (!this.emitter) return\n\n\t\tthis.periodicTimer = setInterval(() => {\n\t\t\tthis.emitDiagnostics()\n\t\t}, this.diagnosticsInterval)\n\t}\n\n\tprivate stopPeriodicEmission(): void {\n\t\tif (this.periodicTimer !== null) {\n\t\t\tclearInterval(this.periodicTimer)\n\t\t\tthis.periodicTimer = null\n\t\t}\n\t}\n\n\tprivate emitDiagnostics(): void {\n\t\tthis.emitter?.emit({\n\t\t\ttype: 'sync:diagnostics',\n\t\t\tdiagnostics: this.getSnapshot(),\n\t\t})\n\t}\n\n\tprivate emitBandwidthEvent(direction: 'in' | 'out'): void {\n\t\tconst estimator = direction === 'in' ? this.inboundBandwidth : this.outboundBandwidth\n\t\tconst bps = estimator.estimate()\n\t\tif (bps !== null) {\n\t\t\tthis.emitter?.emit({\n\t\t\t\ttype: 'sync:bandwidth',\n\t\t\t\tbytesPerSecond: bps,\n\t\t\t\tdirection,\n\t\t\t})\n\t\t}\n\t}\n}\n","import type { KoraEventEmitter } from '@korajs/core'\nimport type { AwarenessChange, AwarenessMessage, AwarenessState } from './types'\n\n/**\n * Callback for awareness change events.\n */\ntype AwarenessChangeListener = (change: AwarenessChange) => void\n\n// Timeout after which a remote client's awareness is considered stale\n// and will be cleaned up. This is a safety net -- normally the server\n// sends explicit removal on disconnect.\nconst DEFAULT_TIMEOUT_MS = 30_000\n\nlet nextLocalClientId = 1\n\n/**\n * Manages collaborative awareness state (cursor positions, user presence).\n *\n * Awareness is ephemeral -- states are never persisted, only shared with\n * currently connected peers via the sync transport. This implements a\n * lightweight protocol compatible with Yjs awareness semantics.\n *\n * Each AwarenessManager has a unique client ID and tracks both its own\n * local state and all remote clients' states.\n */\nexport class AwarenessManager {\n\t/** Unique client ID for this instance */\n\treadonly clientId: number\n\n\tprivate localState: AwarenessState | null = null\n\tprivate readonly remoteStates = new Map<number, AwarenessState>()\n\tprivate readonly listeners = new Set<AwarenessChangeListener>()\n\tprivate readonly emitter: KoraEventEmitter | null\n\tprivate readonly timeoutMs: number\n\n\t// Track when we last received an update from each remote client.\n\t// Used for timeout-based cleanup as a safety net in case the server\n\t// does not send an explicit removal on disconnect.\n\tprivate readonly lastUpdated = new Map<number, number>()\n\tprivate cleanupTimer: ReturnType<typeof setInterval> | null = null\n\n\tprivate sendHandler: ((message: AwarenessMessage) => void) | null = null\n\tprivate destroyed = false\n\n\tconstructor(options?: {\n\t\tclientId?: number\n\t\temitter?: KoraEventEmitter\n\t\ttimeoutMs?: number\n\t}) {\n\t\tthis.clientId = options?.clientId ?? nextLocalClientId++\n\t\tthis.emitter = options?.emitter ?? null\n\t\tthis.timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS\n\t}\n\n\t/**\n\t * Set the local user's awareness state and broadcast to peers.\n\t *\n\t * @param state - The awareness state to share. Pass null to clear presence.\n\t */\n\tsetLocalState(state: AwarenessState | null): void {\n\t\tif (this.destroyed) return\n\n\t\tthis.localState = state\n\n\t\tconst message: AwarenessMessage = {\n\t\t\ttype: 'awareness',\n\t\t\tclientId: this.clientId,\n\t\t\tstates: { [this.clientId]: state },\n\t\t}\n\n\t\tthis.sendHandler?.(message)\n\n\t\tthis.emitAwarenessEvent()\n\t}\n\n\t/**\n\t * Get the local awareness state.\n\t */\n\tgetLocalState(): AwarenessState | null {\n\t\treturn this.localState\n\t}\n\n\t/**\n\t * Get all known awareness states (local + remote).\n\t * Returns a new Map on each call.\n\t */\n\tgetStates(): Map<number, AwarenessState> {\n\t\tconst result = new Map<number, AwarenessState>()\n\t\tif (this.localState) {\n\t\t\tresult.set(this.clientId, this.localState)\n\t\t}\n\t\tfor (const [id, state] of this.remoteStates) {\n\t\t\tresult.set(id, state)\n\t\t}\n\t\treturn result\n\t}\n\n\t/**\n\t * Handle an incoming awareness message from the transport.\n\t * This processes remote state updates and notifies listeners.\n\t */\n\thandleRemoteMessage(message: AwarenessMessage): void {\n\t\tif (this.destroyed) return\n\n\t\tconst added: number[] = []\n\t\tconst updated: number[] = []\n\t\tconst removed: number[] = []\n\t\tconst now = Date.now()\n\n\t\tfor (const [clientIdStr, state] of Object.entries(message.states)) {\n\t\t\tconst clientId = Number(clientIdStr)\n\n\t\t\t// Ignore our own state echoed back\n\t\t\tif (clientId === this.clientId) continue\n\n\t\t\tif (state === null) {\n\t\t\t\t// Removal\n\t\t\t\tif (this.remoteStates.has(clientId)) {\n\t\t\t\t\tthis.remoteStates.delete(clientId)\n\t\t\t\t\tthis.lastUpdated.delete(clientId)\n\t\t\t\t\tremoved.push(clientId)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (this.remoteStates.has(clientId)) {\n\t\t\t\t\tthis.remoteStates.set(clientId, state)\n\t\t\t\t\tthis.lastUpdated.set(clientId, now)\n\t\t\t\t\tupdated.push(clientId)\n\t\t\t\t} else {\n\t\t\t\t\tthis.remoteStates.set(clientId, state)\n\t\t\t\t\tthis.lastUpdated.set(clientId, now)\n\t\t\t\t\tadded.push(clientId)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (added.length > 0 || updated.length > 0 || removed.length > 0) {\n\t\t\tconst change: AwarenessChange = { added, updated, removed }\n\t\t\tthis.notifyListeners(change)\n\t\t\tthis.emitAwarenessEvent()\n\t\t}\n\t}\n\n\t/**\n\t * Remove a specific remote client's awareness state.\n\t * Called when the server notifies that a client has disconnected.\n\t */\n\tremoveClient(clientId: number): void {\n\t\tif (this.destroyed) return\n\t\tif (!this.remoteStates.has(clientId)) return\n\n\t\tthis.remoteStates.delete(clientId)\n\t\tthis.lastUpdated.delete(clientId)\n\n\t\tconst change: AwarenessChange = {\n\t\t\tadded: [],\n\t\t\tupdated: [],\n\t\t\tremoved: [clientId],\n\t\t}\n\t\tthis.notifyListeners(change)\n\t\tthis.emitAwarenessEvent()\n\t}\n\n\t/**\n\t * Register a handler for sending awareness messages through the transport.\n\t * The sync engine calls this to wire outgoing awareness messages to the transport.\n\t */\n\tonSend(handler: (message: AwarenessMessage) => void): void {\n\t\tthis.sendHandler = handler\n\t}\n\n\t/**\n\t * Register a listener for awareness state changes.\n\t * Returns an unsubscribe function.\n\t */\n\ton(_event: 'change', listener: AwarenessChangeListener): () => void {\n\t\tthis.listeners.add(listener)\n\t\treturn () => {\n\t\t\tthis.listeners.delete(listener)\n\t\t}\n\t}\n\n\t/**\n\t * Remove a specific change listener.\n\t */\n\toff(_event: 'change', listener: AwarenessChangeListener): void {\n\t\tthis.listeners.delete(listener)\n\t}\n\n\t/**\n\t * Start the cleanup timer that removes stale remote states.\n\t * Called when the sync engine transitions to streaming state.\n\t */\n\tstartCleanupTimer(): void {\n\t\tif (this.cleanupTimer) return\n\n\t\tthis.cleanupTimer = setInterval(() => {\n\t\t\tthis.cleanupStaleStates()\n\t\t}, this.timeoutMs)\n\t}\n\n\t/**\n\t * Stop the cleanup timer.\n\t */\n\tstopCleanupTimer(): void {\n\t\tif (this.cleanupTimer) {\n\t\t\tclearInterval(this.cleanupTimer)\n\t\t\tthis.cleanupTimer = null\n\t\t}\n\t}\n\n\t/**\n\t * Clean up all resources. After calling destroy(), the manager\n\t * will no longer send or receive awareness updates.\n\t * Broadcasts removal of local state before shutting down.\n\t */\n\tdestroy(): void {\n\t\tif (this.destroyed) return\n\t\tthis.destroyed = true\n\n\t\t// Broadcast removal of our local state before shutting down\n\t\tif (this.localState) {\n\t\t\tconst message: AwarenessMessage = {\n\t\t\t\ttype: 'awareness',\n\t\t\t\tclientId: this.clientId,\n\t\t\t\tstates: { [this.clientId]: null },\n\t\t\t}\n\t\t\tthis.sendHandler?.(message)\n\t\t}\n\n\t\tthis.localState = null\n\t\tthis.remoteStates.clear()\n\t\tthis.lastUpdated.clear()\n\t\tthis.listeners.clear()\n\t\tthis.sendHandler = null\n\t\tthis.stopCleanupTimer()\n\t}\n\n\t// --- Private ---\n\n\tprivate cleanupStaleStates(): void {\n\t\tconst now = Date.now()\n\t\tconst removed: number[] = []\n\n\t\tfor (const [clientId, lastTime] of this.lastUpdated) {\n\t\t\tif (now - lastTime > this.timeoutMs) {\n\t\t\t\tthis.remoteStates.delete(clientId)\n\t\t\t\tthis.lastUpdated.delete(clientId)\n\t\t\t\tremoved.push(clientId)\n\t\t\t}\n\t\t}\n\n\t\tif (removed.length > 0) {\n\t\t\tconst change: AwarenessChange = { added: [], updated: [], removed }\n\t\t\tthis.notifyListeners(change)\n\t\t\tthis.emitAwarenessEvent()\n\t\t}\n\t}\n\n\tprivate notifyListeners(change: AwarenessChange): void {\n\t\tfor (const listener of this.listeners) {\n\t\t\tlistener(change)\n\t\t}\n\t}\n\n\tprivate emitAwarenessEvent(): void {\n\t\t// Cast states to Map<number, unknown> to satisfy KoraEvent's generic type\n\t\tconst states: Map<number, unknown> = this.getStates()\n\t\tthis.emitter?.emit({ type: 'awareness:updated', states })\n\t}\n}\n","import type { Operation } from '@korajs/core'\nimport type { QueueStorage } from '../types'\n\n/**\n * In-memory QueueStorage implementation for testing.\n * Operations are lost on process restart — production should use\n * IndexedDB or OPFS-backed storage.\n */\nexport class MemoryQueueStorage implements QueueStorage {\n\tprivate operations: Map<string, Operation> = new Map()\n\n\tasync load(): Promise<Operation[]> {\n\t\treturn [...this.operations.values()]\n\t}\n\n\tasync enqueue(op: Operation): Promise<void> {\n\t\tthis.operations.set(op.id, op)\n\t}\n\n\tasync dequeue(ids: string[]): Promise<void> {\n\t\tfor (const id of ids) {\n\t\t\tthis.operations.delete(id)\n\t\t}\n\t}\n\n\tasync count(): Promise<number> {\n\t\treturn this.operations.size\n\t}\n}\n","import type { Operation } from '@korajs/core'\nimport { topologicalSort } from '@korajs/core/internal'\nimport type { QueueStorage } from '../types'\n\n/**\n * A batch of operations taken from the queue for sending.\n */\nexport interface OutboundBatch {\n\t/** Unique identifier for this batch */\n\tbatchId: string\n\t/** Operations in this batch, in causal order */\n\toperations: Operation[]\n}\n\n/**\n * Outbound operation queue with pluggable persistence.\n * Manages operations waiting to be sent to the sync server.\n *\n * Operations are deduplicated by ID (content-addressed) and maintained\n * in causal order via topological sort.\n */\nexport class OutboundQueue {\n\tprivate queue: Operation[] = []\n\tprivate readonly seen: Set<string> = new Set()\n\tprivate readonly inFlight: Map<string, Operation[]> = new Map()\n\tprivate nextBatchId = 0\n\tprivate initialized = false\n\n\tconstructor(private readonly storage: QueueStorage) {}\n\n\t/**\n\t * Load persisted operations from storage.\n\t * Must be called before using the queue.\n\t */\n\tasync initialize(): Promise<void> {\n\t\tconst stored = await this.storage.load()\n\t\tfor (const op of stored) {\n\t\t\tif (!this.seen.has(op.id)) {\n\t\t\t\tthis.seen.add(op.id)\n\t\t\t\tthis.queue.push(op)\n\t\t\t}\n\t\t}\n\t\t// Ensure causal order\n\t\tif (this.queue.length > 1) {\n\t\t\tthis.queue = topologicalSort(this.queue)\n\t\t}\n\t\tthis.initialized = true\n\t}\n\n\t/**\n\t * Add an operation to the outbound queue.\n\t * Deduplicates by operation ID. Persists to storage.\n\t */\n\tasync enqueue(op: Operation): Promise<void> {\n\t\tif (this.seen.has(op.id)) return\n\n\t\tthis.seen.add(op.id)\n\t\tthis.queue.push(op)\n\t\tawait this.storage.enqueue(op)\n\n\t\t// Re-sort to maintain causal order when new ops arrive\n\t\tif (this.queue.length > 1) {\n\t\t\tthis.queue = topologicalSort(this.queue)\n\t\t}\n\t}\n\n\t/**\n\t * Take a batch of operations from the front of the queue.\n\t * Moves them to in-flight status. Returns null if queue is empty.\n\t *\n\t * @param batchSize - Maximum number of operations in the batch\n\t */\n\ttakeBatch(batchSize: number): OutboundBatch | null {\n\t\tif (this.queue.length === 0) return null\n\n\t\tconst ops = this.queue.splice(0, batchSize)\n\t\tconst batchId = `batch-${this.nextBatchId++}`\n\t\tthis.inFlight.set(batchId, ops)\n\n\t\treturn { batchId, operations: ops }\n\t}\n\n\t/**\n\t * Acknowledge a batch, removing its operations permanently.\n\t */\n\tasync acknowledge(batchId: string): Promise<void> {\n\t\tconst ops = this.inFlight.get(batchId)\n\t\tif (!ops) return\n\n\t\tthis.inFlight.delete(batchId)\n\t\tconst ids = ops.map((op) => op.id)\n\t\tawait this.storage.dequeue(ids)\n\t}\n\n\t/**\n\t * Return a failed batch to the front of the queue for retry.\n\t * Prepends the operations to maintain priority.\n\t */\n\treturnBatch(batchId: string): void {\n\t\tconst ops = this.inFlight.get(batchId)\n\t\tif (!ops) return\n\n\t\tthis.inFlight.delete(batchId)\n\t\t// Prepend returned ops, then re-sort for causal order\n\t\tthis.queue.unshift(...ops)\n\t\tif (this.queue.length > 1) {\n\t\t\tthis.queue = topologicalSort(this.queue)\n\t\t}\n\t}\n\n\t/**\n\t * Number of operations waiting in the queue (not counting in-flight).\n\t */\n\tget size(): number {\n\t\treturn this.queue.length\n\t}\n\n\t/**\n\t * Total operations including in-flight.\n\t */\n\tget totalPending(): number {\n\t\tlet inFlightCount = 0\n\t\tfor (const ops of this.inFlight.values()) {\n\t\t\tinFlightCount += ops.length\n\t\t}\n\t\treturn this.queue.length + inFlightCount\n\t}\n\n\t/**\n\t * Whether the queue has any operations to send.\n\t */\n\tget hasOperations(): boolean {\n\t\treturn this.queue.length > 0\n\t}\n\n\t/**\n\t * Peek at the first `count` operations without removing them.\n\t */\n\tpeek(count: number): Operation[] {\n\t\treturn this.queue.slice(0, count)\n\t}\n\n\t/**\n\t * Whether initialize() has been called.\n\t */\n\tget isInitialized(): boolean {\n\t\treturn this.initialized\n\t}\n}\n","import type { ConnectionQuality, TimeSource } from '@korajs/core'\n\n/**\n * Configuration for the connection monitor.\n */\nexport interface ConnectionMonitorConfig {\n\t/** Number of latency samples to keep in the rolling window. Defaults to 20. */\n\twindowSize?: number\n\t/** Time in ms after which the connection is considered stale. Defaults to 30000. */\n\tstaleThreshold?: number\n\t/** Injectable time source for deterministic testing */\n\ttimeSource?: TimeSource\n}\n\n/**\n * Monitors connection quality based on RTT latency samples,\n * missed acknowledgments, and activity timestamps.\n */\nexport class ConnectionMonitor {\n\tprivate readonly windowSize: number\n\tprivate readonly staleThreshold: number\n\tprivate readonly timeSource: TimeSource\n\n\tprivate latencies: number[] = []\n\tprivate missedAcks = 0\n\tprivate lastActivityTime: number\n\n\tconstructor(config?: ConnectionMonitorConfig) {\n\t\tthis.windowSize = config?.windowSize ?? 20\n\t\tthis.staleThreshold = config?.staleThreshold ?? 30000\n\t\tthis.timeSource = config?.timeSource ?? { now: () => Date.now() }\n\t\tthis.lastActivityTime = this.timeSource.now()\n\t}\n\n\t/**\n\t * Record a round-trip time sample.\n\t */\n\trecordLatency(ms: number): void {\n\t\tthis.latencies.push(ms)\n\t\tif (this.latencies.length > this.windowSize) {\n\t\t\tthis.latencies.shift()\n\t\t}\n\t\tthis.lastActivityTime = this.timeSource.now()\n\t\t// Successful response resets missed acks\n\t\tthis.missedAcks = 0\n\t}\n\n\t/**\n\t * Record a missed acknowledgment (message sent but no response received).\n\t */\n\trecordMissedAck(): void {\n\t\tthis.missedAcks++\n\t}\n\n\t/**\n\t * Record any activity (message sent or received).\n\t */\n\trecordActivity(): void {\n\t\tthis.lastActivityTime = this.timeSource.now()\n\t}\n\n\t/**\n\t * Assess current connection quality based on collected metrics.\n\t *\n\t * Quality thresholds (average RTT):\n\t * - excellent: < 100ms, 0 missed acks\n\t * - good: < 300ms, ≤ 1 missed ack\n\t * - fair: < 1000ms, ≤ 3 missed acks\n\t * - poor: < 5000ms or > 3 missed acks\n\t * - offline: no activity for staleThreshold ms\n\t */\n\tgetQuality(): ConnectionQuality {\n\t\tconst elapsed = this.timeSource.now() - this.lastActivityTime\n\t\tif (elapsed > this.staleThreshold) return 'offline'\n\n\t\tif (this.latencies.length === 0) {\n\t\t\t// No data yet — assume good until proven otherwise\n\t\t\treturn this.missedAcks > 3 ? 'poor' : 'good'\n\t\t}\n\n\t\tconst avgLatency = this.latencies.reduce((sum, l) => sum + l, 0) / this.latencies.length\n\n\t\tif (this.missedAcks > 3) return 'poor'\n\t\tif (avgLatency < 100 && this.missedAcks === 0) return 'excellent'\n\t\tif (avgLatency < 300 && this.missedAcks <= 1) return 'good'\n\t\tif (avgLatency < 1000 && this.missedAcks <= 3) return 'fair'\n\t\treturn 'poor'\n\t}\n\n\t/**\n\t * Reset all metrics. Call on disconnect.\n\t */\n\treset(): void {\n\t\tthis.latencies = []\n\t\tthis.missedAcks = 0\n\t\tthis.lastActivityTime = this.timeSource.now()\n\t}\n\n\t/**\n\t * Get the current average latency in ms. Returns null if no samples.\n\t */\n\tgetAverageLatency(): number | null {\n\t\tif (this.latencies.length === 0) return null\n\t\treturn this.latencies.reduce((sum, l) => sum + l, 0) / this.latencies.length\n\t}\n\n\t/**\n\t * Get the number of missed acks.\n\t */\n\tgetMissedAcks(): number {\n\t\treturn this.missedAcks\n\t}\n}\n","import type { TimeSource } from '@korajs/core'\n\n/**\n * Configuration for the reconnection manager.\n */\nexport interface ReconnectionConfig {\n\t/** Initial delay in ms before first reconnection attempt. Defaults to 1000. */\n\tinitialDelay?: number\n\t/** Maximum delay in ms between attempts. Defaults to 30000. */\n\tmaxDelay?: number\n\t/** Multiplier for exponential backoff. Defaults to 2. */\n\tmultiplier?: number\n\t/** Maximum number of reconnection attempts. 0 means unlimited. Defaults to 0. */\n\tmaxAttempts?: number\n\t/** Jitter factor (0-1). Random variation applied to delay. Defaults to 0.25. */\n\tjitter?: number\n\t/** Injectable time source for deterministic testing. */\n\ttimeSource?: TimeSource\n\t/** Injectable random source for deterministic jitter. Returns value in [0, 1). */\n\trandomSource?: () => number\n}\n\n/**\n * Manages reconnection attempts with exponential backoff and jitter.\n *\n * Formula: min(initialDelay * multiplier^attempt, maxDelay) * (1 + jitter * (random - 0.5) * 2)\n */\nexport class ReconnectionManager {\n\tprivate readonly initialDelay: number\n\tprivate readonly maxDelay: number\n\tprivate readonly multiplier: number\n\tprivate readonly maxAttempts: number\n\tprivate readonly jitter: number\n\tprivate readonly random: () => number\n\n\tprivate attempt = 0\n\tprivate timer: ReturnType<typeof setTimeout> | null = null\n\tprivate stopped = false\n\tprivate running = false\n\tprivate waitResolve: (() => void) | null = null\n\n\tconstructor(config?: ReconnectionConfig) {\n\t\tthis.initialDelay = config?.initialDelay ?? 1000\n\t\tthis.maxDelay = config?.maxDelay ?? 30000\n\t\tthis.multiplier = config?.multiplier ?? 2\n\t\tthis.maxAttempts = config?.maxAttempts ?? 0\n\t\tthis.jitter = config?.jitter ?? 0.25\n\t\tthis.random = config?.randomSource ?? Math.random\n\t}\n\n\t/**\n\t * Start reconnection attempts. Calls `onReconnect` with exponential backoff.\n\t *\n\t * @param onReconnect - Called on each attempt. Return `true` if reconnection succeeded.\n\t * @returns Promise that resolves when reconnection succeeds or maxAttempts reached.\n\t */\n\tasync start(onReconnect: () => Promise<boolean>): Promise<boolean> {\n\t\tthis.stopped = false\n\t\tthis.running = true\n\t\tthis.attempt = 0\n\n\t\ttry {\n\t\t\twhile (!this.stopped) {\n\t\t\t\tif (this.maxAttempts > 0 && this.attempt >= this.maxAttempts) {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\n\t\t\t\tconst delay = this.getNextDelay()\n\t\t\t\tthis.attempt++\n\n\t\t\t\tawait this.wait(delay)\n\n\t\t\t\tif (this.stopped) return false\n\n\t\t\t\ttry {\n\t\t\t\t\tconst success = await onReconnect()\n\t\t\t\t\tif (success) {\n\t\t\t\t\t\tthis.reset()\n\t\t\t\t\t\treturn true\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// Continue retrying on failure\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn false\n\t\t} finally {\n\t\t\tthis.running = false\n\t\t}\n\t}\n\n\t/**\n\t * Stop any pending reconnection attempt.\n\t */\n\tstop(): void {\n\t\tthis.stopped = true\n\t\tif (this.timer !== null) {\n\t\t\tclearTimeout(this.timer)\n\t\t\tthis.timer = null\n\t\t}\n\t\t// Resolve the pending wait promise so start() loop can exit\n\t\tif (this.waitResolve) {\n\t\t\tthis.waitResolve()\n\t\t\tthis.waitResolve = null\n\t\t}\n\t}\n\n\t/**\n\t * Reset the attempt counter. Call after a successful manual reconnection.\n\t */\n\treset(): void {\n\t\tthis.attempt = 0\n\t\tthis.stopped = false\n\t}\n\n\t/**\n\t * Compute the next delay for the current attempt.\n\t * Exposed for testing purposes.\n\t */\n\tgetNextDelay(): number {\n\t\tconst baseDelay = Math.min(this.initialDelay * this.multiplier ** this.attempt, this.maxDelay)\n\n\t\t// Apply jitter: varies the delay by ±jitter factor\n\t\tconst jitterRange = baseDelay * this.jitter\n\t\tconst jitterOffset = (this.random() - 0.5) * 2 * jitterRange\n\t\treturn Math.max(0, Math.round(baseDelay + jitterOffset))\n\t}\n\n\t/**\n\t * Whether the reconnection loop is currently running.\n\t */\n\tisRunning(): boolean {\n\t\treturn this.running\n\t}\n\n\t/**\n\t * Current attempt number (for testing).\n\t */\n\tgetAttemptCount(): number {\n\t\treturn this.attempt\n\t}\n\n\tprivate wait(ms: number): Promise<void> {\n\t\treturn new Promise((resolve) => {\n\t\t\tthis.waitResolve = resolve\n\t\t\tthis.timer = setTimeout(() => {\n\t\t\t\tthis.timer = null\n\t\t\t\tthis.waitResolve = null\n\t\t\t\tresolve()\n\t\t\t}, ms)\n\t\t})\n\t}\n}\n","import { SyncError } from '@korajs/core'\nimport type { Operation } from '@korajs/core'\nimport type { SerializedOperation } from '../protocol/messages'\nimport { deriveVersionedKey } from './key-derivation'\nimport type { EncryptedPayload, SyncEncryptionConfig, VersionedKey } from './types'\n\n/**\n * Thrown when encryption of operation data fails.\n */\nexport class EncryptionError extends SyncError {\n\tconstructor(message: string, context?: Record<string, unknown>) {\n\t\tsuper(message, { ...context, errorType: 'ENCRYPTION_ERROR' })\n\t\tthis.name = 'EncryptionError'\n\t}\n}\n\n/**\n * Thrown when decryption of operation data fails.\n * This typically indicates a wrong key, tampered ciphertext, or corrupted data.\n */\nexport class DecryptionError extends SyncError {\n\tconstructor(message: string, context?: Record<string, unknown>) {\n\t\tsuper(message, { ...context, errorType: 'DECRYPTION_ERROR' })\n\t\tthis.name = 'DecryptionError'\n\t}\n}\n\n/** AES-GCM initialization vector length in bytes (96 bits). NIST recommended. */\nconst IV_LENGTH = 12\n\n/** Marker field to identify encrypted payloads during deserialization. */\nconst ENCRYPTED_MARKER = '__kora_e2e_encrypted' as const\n\n/**\n * Encrypts and decrypts operation `data` and `previousData` fields for\n * end-to-end encryption in the sync layer.\n *\n * **Design principles:**\n * - Only `data` and `previousData` are encrypted. Metadata (id, nodeId,\n * collection, timestamps, causalDeps, etc.) stays in cleartext so the\n * server can route, deduplicate, and order operations.\n * - Each field encryption uses a unique random IV (12 bytes for AES-GCM),\n * ensuring that encrypting the same data twice produces different ciphertext.\n * - Key rotation is supported via versioned keys. The key version is embedded\n * in the {@link EncryptedPayload} so the decryptor can select the correct key.\n * - Unencrypted fields pass through during decryption (backward compatibility).\n *\n * @example\n * ```typescript\n * const encryptor = await SyncEncryptor.create({\n * enabled: true,\n * key: 'user-passphrase'\n * })\n *\n * // Encrypt before sending\n * const encrypted = await encryptor.encryptOperation(operation)\n *\n * // Decrypt after receiving\n * const decrypted = await encryptor.decryptOperation(encrypted)\n * ```\n */\nexport class SyncEncryptor {\n\t/**\n\t * Map of key version -> VersionedKey. The current (latest) version is used\n\t * for encryption. All versions are available for decryption (key rotation).\n\t */\n\tprivate readonly keys: Map<number, VersionedKey>\n\t/** The current key version used for encryption. */\n\tprivate currentVersion: number\n\n\tprivate constructor(keys: Map<number, VersionedKey>, currentVersion: number) {\n\t\tthis.keys = keys\n\t\tthis.currentVersion = currentVersion\n\t}\n\n\t/**\n\t * Creates a SyncEncryptor from a {@link SyncEncryptionConfig}.\n\t *\n\t * Derives the encryption key from the passphrase using PBKDF2. The key\n\t * derivation is async because it uses the Web Crypto API.\n\t *\n\t * @param config - Encryption configuration with passphrase\n\t * @param salt - Optional salt for deterministic key derivation (mainly for testing).\n\t * If omitted, a random salt is generated.\n\t * @returns A configured SyncEncryptor instance\n\t * @throws {EncryptionError} If configuration is invalid\n\t * @throws {KeyDerivationError} If key derivation fails\n\t */\n\tstatic async create(config: SyncEncryptionConfig, salt?: Uint8Array): Promise<SyncEncryptor> {\n\t\tif (!config.enabled) {\n\t\t\tthrow new EncryptionError(\n\t\t\t\t'Cannot create SyncEncryptor with encryption disabled. ' +\n\t\t\t\t\t'Set enabled: true in the encryption config.',\n\t\t\t)\n\t\t}\n\n\t\tconst passphrase = typeof config.key === 'function' ? await config.key() : config.key\n\n\t\tif (passphrase.length === 0) {\n\t\t\tthrow new EncryptionError(\n\t\t\t\t'Encryption key/passphrase must not be empty. ' +\n\t\t\t\t\t'Provide a non-empty string or key provider function.',\n\t\t\t)\n\t\t}\n\n\t\tconst versionedKey = await deriveVersionedKey(passphrase, 1, salt)\n\t\tconst keys = new Map<number, VersionedKey>()\n\t\tkeys.set(1, versionedKey)\n\n\t\treturn new SyncEncryptor(keys, 1)\n\t}\n\n\t/**\n\t * Creates a SyncEncryptor from pre-derived versioned keys.\n\t *\n\t * Use this when you need to support multiple key versions for key rotation,\n\t * or when you have already derived the keys externally.\n\t *\n\t * @param versionedKeys - Array of versioned keys. The highest version is used for encryption.\n\t * @returns A configured SyncEncryptor instance\n\t * @throws {EncryptionError} If no keys are provided\n\t */\n\tstatic fromKeys(versionedKeys: VersionedKey[]): SyncEncryptor {\n\t\tif (versionedKeys.length === 0) {\n\t\t\tthrow new EncryptionError('At least one versioned key must be provided.')\n\t\t}\n\n\t\tconst keys = new Map<number, VersionedKey>()\n\t\tlet maxVersion = 0\n\n\t\tfor (const vk of versionedKeys) {\n\t\t\tkeys.set(vk.version, vk)\n\t\t\tif (vk.version > maxVersion) {\n\t\t\t\tmaxVersion = vk.version\n\t\t\t}\n\t\t}\n\n\t\treturn new SyncEncryptor(keys, maxVersion)\n\t}\n\n\t/**\n\t * Add a new key version for key rotation.\n\t *\n\t * After adding, the new key becomes the current version used for encryption\n\t * if its version number is higher than the current version. Previously-versioned\n\t * keys remain available for decrypting older operations.\n\t *\n\t * @param key - The new versioned key to add\n\t * @throws {EncryptionError} If the key version already exists\n\t */\n\taddKey(key: VersionedKey): void {\n\t\tif (this.keys.has(key.version)) {\n\t\t\tthrow new EncryptionError(\n\t\t\t\t`Key version ${key.version} already exists. Use a higher version number for rotation.`,\n\t\t\t\t{ existingVersion: key.version },\n\t\t\t)\n\t\t}\n\n\t\tthis.keys.set(key.version, key)\n\t\tif (key.version > this.currentVersion) {\n\t\t\tthis.currentVersion = key.version\n\t\t}\n\t}\n\n\t/**\n\t * Get the current encryption key version number.\n\t */\n\tgetCurrentKeyVersion(): number {\n\t\treturn this.currentVersion\n\t}\n\n\t/**\n\t * Encrypt an operation's `data` and `previousData` fields.\n\t *\n\t * Returns a new Operation with encrypted field values. The original\n\t * operation is not mutated (operations are immutable).\n\t *\n\t * Fields that are null (e.g., delete operations) remain null.\n\t *\n\t * @param operation - The operation to encrypt\n\t * @returns A new operation with encrypted data fields\n\t * @throws {EncryptionError} If encryption fails\n\t */\n\tasync encryptOperation(operation: Operation): Promise<Operation> {\n\t\tconst [encryptedData, encryptedPreviousData] = await Promise.all([\n\t\t\tthis.encryptField(operation.data, operation.id, 'data'),\n\t\t\tthis.encryptField(operation.previousData, operation.id, 'previousData'),\n\t\t])\n\n\t\treturn {\n\t\t\t...operation,\n\t\t\tdata: encryptedData,\n\t\t\tpreviousData: encryptedPreviousData,\n\t\t}\n\t}\n\n\t/**\n\t * Decrypt an operation's `data` and `previousData` fields.\n\t *\n\t * Returns a new Operation with the original field values restored.\n\t * The original operation is not mutated.\n\t *\n\t * If a field is null or not encrypted (no marker), it passes through unchanged.\n\t * This enables mixed plaintext/encrypted operations during migration.\n\t *\n\t * @param operation - The operation to decrypt\n\t * @returns A new operation with decrypted data fields\n\t * @throws {DecryptionError} If decryption fails (wrong key, tampered data, unsupported version)\n\t */\n\tasync decryptOperation(operation: Operation): Promise<Operation> {\n\t\tconst [decryptedData, decryptedPreviousData] = await Promise.all([\n\t\t\tthis.decryptField(operation.data, operation.id, 'data'),\n\t\t\tthis.decryptField(operation.previousData, operation.id, 'previousData'),\n\t\t])\n\n\t\treturn {\n\t\t\t...operation,\n\t\t\tdata: decryptedData,\n\t\t\tpreviousData: decryptedPreviousData,\n\t\t}\n\t}\n\n\t/**\n\t * Encrypt a serialized operation's `data` and `previousData` fields.\n\t *\n\t * Same as {@link encryptOperation} but works with the wire-format\n\t * {@link SerializedOperation} type used by the serializer.\n\t *\n\t * @param serialized - The serialized operation to encrypt\n\t * @returns A new serialized operation with encrypted data fields\n\t * @throws {EncryptionError} If encryption fails\n\t */\n\tasync encryptSerializedOperation(serialized: SerializedOperation): Promise<SerializedOperation> {\n\t\tconst [encryptedData, encryptedPreviousData] = await Promise.all([\n\t\t\tthis.encryptField(serialized.data, serialized.id, 'data'),\n\t\t\tthis.encryptField(serialized.previousData, serialized.id, 'previousData'),\n\t\t])\n\n\t\treturn {\n\t\t\t...serialized,\n\t\t\tdata: encryptedData,\n\t\t\tpreviousData: encryptedPreviousData,\n\t\t}\n\t}\n\n\t/**\n\t * Decrypt a serialized operation's `data` and `previousData` fields.\n\t *\n\t * Same as {@link decryptOperation} but works with the wire-format\n\t * {@link SerializedOperation} type used by the serializer.\n\t *\n\t * @param serialized - The serialized operation to decrypt\n\t * @returns A new serialized operation with decrypted data fields\n\t * @throws {DecryptionError} If decryption fails\n\t */\n\tasync decryptSerializedOperation(serialized: SerializedOperation): Promise<SerializedOperation> {\n\t\tconst [decryptedData, decryptedPreviousData] = await Promise.all([\n\t\t\tthis.decryptField(serialized.data, serialized.id, 'data'),\n\t\t\tthis.decryptField(serialized.previousData, serialized.id, 'previousData'),\n\t\t])\n\n\t\treturn {\n\t\t\t...serialized,\n\t\t\tdata: decryptedData,\n\t\t\tpreviousData: decryptedPreviousData,\n\t\t}\n\t}\n\n\t/**\n\t * Encrypt a batch of operations in parallel.\n\t *\n\t * @param operations - Operations to encrypt\n\t * @returns New operations with encrypted data fields\n\t */\n\tasync encryptBatch(operations: Operation[]): Promise<Operation[]> {\n\t\treturn Promise.all(operations.map((op) => this.encryptOperation(op)))\n\t}\n\n\t/**\n\t * Decrypt a batch of operations in parallel.\n\t *\n\t * @param operations - Operations to decrypt\n\t * @returns New operations with decrypted data fields\n\t */\n\tasync decryptBatch(operations: Operation[]): Promise<Operation[]> {\n\t\treturn Promise.all(operations.map((op) => this.decryptOperation(op)))\n\t}\n\n\t/**\n\t * Check if a field value contains an encrypted payload.\n\t *\n\t * @param field - An operation's `data` or `previousData` field\n\t * @returns true if the field contains an encrypted payload\n\t */\n\tstatic isEncryptedPayload(field: Record<string, unknown> | null): boolean {\n\t\treturn isEncryptedPayload(field)\n\t}\n\n\t// --- Private helpers ---\n\n\tprivate async encryptField(\n\t\tfield: Record<string, unknown> | null,\n\t\toperationId: string,\n\t\tfieldName: string,\n\t): Promise<Record<string, unknown> | null> {\n\t\tif (field === null) {\n\t\t\treturn null\n\t\t}\n\n\t\tconst currentKey = this.keys.get(this.currentVersion)\n\t\tif (!currentKey) {\n\t\t\tthrow new EncryptionError(\n\t\t\t\t`Current encryption key version ${this.currentVersion} not found.`,\n\t\t\t\t{ operationId, fieldName },\n\t\t\t)\n\t\t}\n\n\t\ttry {\n\t\t\tconst plaintext = new TextEncoder().encode(JSON.stringify(field))\n\n\t\t\t// Generate a fresh random IV for each field encryption.\n\t\t\t// AES-GCM with a 96-bit IV is the recommended configuration per NIST SP 800-38D.\n\t\t\tconst iv = globalThis.crypto.getRandomValues(new Uint8Array(IV_LENGTH))\n\n\t\t\tconst ciphertextBuffer = await globalThis.crypto.subtle.encrypt(\n\t\t\t\t{ name: 'AES-GCM', iv: iv as unknown as ArrayBuffer },\n\t\t\t\tcurrentKey.key,\n\t\t\t\tplaintext as unknown as ArrayBuffer,\n\t\t\t)\n\n\t\t\tconst payload: EncryptedPayload = {\n\t\t\t\tv: this.currentVersion,\n\t\t\t\tiv: toBase64(iv),\n\t\t\t\tct: toBase64(new Uint8Array(ciphertextBuffer)),\n\t\t\t\talg: 'aes-256-gcm',\n\t\t\t}\n\n\t\t\t// Wrap in an object with the encrypted marker so we can detect it later\n\t\t\treturn {\n\t\t\t\t[ENCRYPTED_MARKER]: true,\n\t\t\t\t...payload,\n\t\t\t}\n\t\t} catch (cause) {\n\t\t\tif (cause instanceof EncryptionError) {\n\t\t\t\tthrow cause\n\t\t\t}\n\t\t\tthrow new EncryptionError(\n\t\t\t\t`Failed to encrypt operation ${fieldName} field. Ensure the encryption key is valid and crypto.subtle is available.`,\n\t\t\t\t{\n\t\t\t\t\toperationId,\n\t\t\t\t\tfieldName,\n\t\t\t\t\tcause: cause instanceof Error ? cause.message : String(cause),\n\t\t\t\t},\n\t\t\t)\n\t\t}\n\t}\n\n\tprivate async decryptField(\n\t\tfield: Record<string, unknown> | null,\n\t\toperationId: string,\n\t\tfieldName: string,\n\t): Promise<Record<string, unknown> | null> {\n\t\tif (field === null) {\n\t\t\treturn null\n\t\t}\n\n\t\t// Pass through unencrypted fields (backward compatibility / mixed mode)\n\t\tif (!isEncryptedPayload(field)) {\n\t\t\treturn field\n\t\t}\n\n\t\tconst payload = field as unknown as EncryptedPayload & { [ENCRYPTED_MARKER]: true }\n\n\t\tconst keyVersion = payload.v\n\t\tconst key = this.keys.get(keyVersion)\n\n\t\tif (!key) {\n\t\t\tthrow new DecryptionError(\n\t\t\t\t`No encryption key available for version ${keyVersion}. This operation was encrypted with a key that is not registered. If you rotated keys, ensure all previous key versions are provided.`,\n\t\t\t\t{ operationId, fieldName, keyVersion, availableVersions: [...this.keys.keys()] },\n\t\t\t)\n\t\t}\n\n\t\tif (payload.alg !== 'aes-256-gcm') {\n\t\t\tthrow new DecryptionError(\n\t\t\t\t`Unsupported encryption algorithm: \"${payload.alg}\". Only \"aes-256-gcm\" is supported. Update your @korajs/sync package.`,\n\t\t\t\t{ operationId, fieldName, algorithm: payload.alg },\n\t\t\t)\n\t\t}\n\n\t\ttry {\n\t\t\tconst iv = fromBase64(payload.iv)\n\t\t\tconst ciphertext = fromBase64(payload.ct)\n\n\t\t\tconst plaintextBuffer = await globalThis.crypto.subtle.decrypt(\n\t\t\t\t{ name: 'AES-GCM', iv: iv as unknown as ArrayBuffer },\n\t\t\t\tkey.key,\n\t\t\t\tciphertext as unknown as ArrayBuffer,\n\t\t\t)\n\n\t\t\tconst json = new TextDecoder().decode(plaintextBuffer)\n\t\t\tconst parsed: unknown = JSON.parse(json)\n\n\t\t\tif (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n\t\t\t\tthrow new DecryptionError(`Decrypted ${fieldName} is not a valid record object.`, {\n\t\t\t\t\toperationId,\n\t\t\t\t\tfieldName,\n\t\t\t\t})\n\t\t\t}\n\n\t\t\treturn parsed as Record<string, unknown>\n\t\t} catch (cause) {\n\t\t\tif (cause instanceof DecryptionError) {\n\t\t\t\tthrow cause\n\t\t\t}\n\t\t\tthrow new DecryptionError(\n\t\t\t\t`Failed to decrypt operation ${fieldName} field. This may indicate a wrong encryption key, tampered ciphertext, or corrupted data.`,\n\t\t\t\t{\n\t\t\t\t\toperationId,\n\t\t\t\t\tfieldName,\n\t\t\t\t\tkeyVersion,\n\t\t\t\t\tcause: cause instanceof Error ? cause.message : String(cause),\n\t\t\t\t},\n\t\t\t)\n\t\t}\n\t}\n}\n\n// --- Utility functions ---\n\n/**\n * Check if a field value contains an encrypted payload.\n *\n * @param field - An operation's `data` or `previousData` field\n * @returns true if the field contains an encrypted payload\n */\nexport function isEncryptedPayload(field: Record<string, unknown> | null): boolean {\n\tif (field === null || typeof field !== 'object') {\n\t\treturn false\n\t}\n\treturn (\n\t\tfield[ENCRYPTED_MARKER] === true &&\n\t\ttypeof field.v === 'number' &&\n\t\ttypeof field.iv === 'string' &&\n\t\ttypeof field.ct === 'string' &&\n\t\ttypeof field.alg === 'string'\n\t)\n}\n\n// --- Base64 helpers ---\n\n/**\n * Encode a Uint8Array to a base64 string.\n * Uses standard base64 (not URL-safe) for compatibility with JSON serialization.\n */\nfunction toBase64(bytes: Uint8Array): string {\n\tlet binary = ''\n\tfor (let i = 0; i < bytes.length; i++) {\n\t\tbinary += String.fromCharCode(bytes[i] as number)\n\t}\n\treturn btoa(binary)\n}\n\n/**\n * Decode a base64 string to a Uint8Array.\n */\nfunction fromBase64(str: string): Uint8Array {\n\tconst binary = atob(str)\n\tconst bytes = new Uint8Array(binary.length)\n\tfor (let i = 0; i < binary.length; i++) {\n\t\tbytes[i] = binary.charCodeAt(i)\n\t}\n\treturn bytes\n}\n","import { SyncError } from '@korajs/core'\nimport type { VersionedKey } from './types'\n\n/**\n * Thrown when key derivation fails.\n */\nexport class KeyDerivationError extends SyncError {\n\tconstructor(message: string, context?: Record<string, unknown>) {\n\t\tsuper(message, { ...context, errorType: 'KEY_DERIVATION_ERROR' })\n\t\tthis.name = 'KeyDerivationError'\n\t}\n}\n\n/** Salt length in bytes. 32 bytes (256 bits) provides sufficient randomness. */\nconst SALT_LENGTH = 32\n\n/**\n * PBKDF2 iteration count. 600,000 iterations is the OWASP-recommended minimum\n * for SHA-256 as of 2024, providing strong resistance against brute-force attacks.\n */\nconst PBKDF2_ITERATIONS = 600_000\n\n/** Derived key length in bits (AES-256). */\nconst DERIVED_KEY_LENGTH = 256\n\n/**\n * Asserts that `crypto.subtle` is available, throwing a clear error if not.\n */\nfunction assertCryptoAvailable(): void {\n\tif (typeof globalThis.crypto === 'undefined' || typeof globalThis.crypto.subtle === 'undefined') {\n\t\tthrow new KeyDerivationError(\n\t\t\t'Web Crypto API (crypto.subtle) is not available in this environment. ' +\n\t\t\t\t'Sync encryption requires crypto.subtle, which is available in modern browsers and Node.js 20+.',\n\t\t)\n\t}\n}\n\n/**\n * Generates a cryptographically random salt for PBKDF2 key derivation.\n *\n * @returns A random 32-byte Uint8Array\n * @throws {KeyDerivationError} If crypto.getRandomValues is unavailable\n */\nexport function generateSalt(): Uint8Array {\n\tif (typeof globalThis.crypto === 'undefined') {\n\t\tthrow new KeyDerivationError(\n\t\t\t'Web Crypto API (crypto) is not available. Cannot generate random salt.',\n\t\t)\n\t}\n\n\treturn globalThis.crypto.getRandomValues(new Uint8Array(SALT_LENGTH))\n}\n\n/**\n * Derives an AES-256-GCM encryption key from a passphrase using PBKDF2.\n *\n * Uses PBKDF2 with SHA-256 and 600,000 iterations (OWASP-recommended minimum)\n * to derive a 256-bit key. The derived key is deterministic: the same passphrase\n * and salt always produce the same key.\n *\n * @param passphrase - The user's passphrase (must be non-empty)\n * @param salt - Optional salt bytes. If omitted, a random 32-byte salt is generated.\n * @returns The derived CryptoKey and the salt used\n * @throws {KeyDerivationError} If the passphrase is empty, crypto is unavailable, or derivation fails\n *\n * @example\n * ```typescript\n * // First time: derive key with a new salt\n * const { key, salt } = await deriveKey('my-secure-passphrase')\n *\n * // Later: re-derive the same key using the stored salt\n * const { key: sameKey } = await deriveKey('my-secure-passphrase', salt)\n * ```\n */\nexport async function deriveKey(\n\tpassphrase: string,\n\tsalt?: Uint8Array,\n): Promise<{ key: CryptoKey; salt: Uint8Array }> {\n\tassertCryptoAvailable()\n\n\tif (passphrase.length === 0) {\n\t\tthrow new KeyDerivationError(\n\t\t\t'Passphrase must not be empty. Provide a non-empty string for encryption key derivation.',\n\t\t)\n\t}\n\n\tconst usedSalt = salt ?? generateSalt()\n\n\ttry {\n\t\t// Import the passphrase as raw key material for PBKDF2\n\t\tconst passphraseBytes = new TextEncoder().encode(passphrase)\n\t\tconst baseKey = await globalThis.crypto.subtle.importKey(\n\t\t\t'raw',\n\t\t\tpassphraseBytes,\n\t\t\t'PBKDF2',\n\t\t\tfalse,\n\t\t\t['deriveBits', 'deriveKey'],\n\t\t)\n\n\t\t// Derive an AES-256-GCM key using PBKDF2 with SHA-256\n\t\tconst derivedKey = await globalThis.crypto.subtle.deriveKey(\n\t\t\t{\n\t\t\t\tname: 'PBKDF2',\n\t\t\t\tsalt: usedSalt as unknown as ArrayBuffer,\n\t\t\t\titerations: PBKDF2_ITERATIONS,\n\t\t\t\thash: 'SHA-256',\n\t\t\t},\n\t\t\tbaseKey,\n\t\t\t{ name: 'AES-GCM', length: DERIVED_KEY_LENGTH },\n\t\t\t// extractable: true so the derived key can be exported for testing/debugging\n\t\t\ttrue,\n\t\t\t['encrypt', 'decrypt'],\n\t\t)\n\n\t\treturn { key: derivedKey, salt: usedSalt }\n\t} catch (cause) {\n\t\tif (cause instanceof KeyDerivationError) {\n\t\t\tthrow cause\n\t\t}\n\n\t\tthrow new KeyDerivationError(\n\t\t\t'Failed to derive encryption key from passphrase using PBKDF2. ' +\n\t\t\t\t'Ensure the runtime supports PBKDF2 with SHA-256.',\n\t\t\t{ cause: cause instanceof Error ? cause.message : String(cause) },\n\t\t)\n\t}\n}\n\n/**\n * Derives a versioned encryption key from a passphrase.\n *\n * Wraps {@link deriveKey} with a version number for key rotation support.\n * When the passphrase changes, create a new versioned key with a higher\n * version number.\n *\n * @param passphrase - The user's passphrase\n * @param version - Key version number (must be a positive integer)\n * @param salt - Optional salt bytes. If omitted, a random salt is generated.\n * @returns A {@link VersionedKey} containing the key, version, and salt\n * @throws {KeyDerivationError} If parameters are invalid or derivation fails\n */\nexport async function deriveVersionedKey(\n\tpassphrase: string,\n\tversion: number,\n\tsalt?: Uint8Array,\n): Promise<VersionedKey> {\n\tif (!Number.isInteger(version) || version < 1) {\n\t\tthrow new KeyDerivationError(`Key version must be a positive integer, received: ${version}`, {\n\t\t\tversion,\n\t\t})\n\t}\n\n\tconst { key, salt: usedSalt } = await deriveKey(passphrase, salt)\n\n\treturn { version, key, salt: usedSalt }\n}\n"],"mappings":"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","names":["import_core","protobuf","import_core","import_core","import_core","import_internal","import_core","import_core"]}
|