@korajs/sync 0.3.2 → 0.5.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 +2350 -199
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +684 -7
- package/dist/index.d.ts +684 -7
- package/dist/index.js +2334 -205
- package/dist/index.js.map +1 -1
- package/dist/internal.d.cts +1 -1
- package/dist/internal.d.ts +1 -1
- package/dist/transport-BrdBj7rH.d.cts +465 -0
- package/dist/transport-BrdBj7rH.d.ts +465 -0
- package/package.json +5 -4
- package/dist/transport-B5EFsr5F.d.cts +0 -215
- package/dist/transport-B5EFsr5F.d.ts +0 -215
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../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/outbound-queue.ts","../src/engine/connection-monitor.ts","../src/engine/reconnection-manager.ts"],"sourcesContent":["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 { 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":["SyncError","SyncError","SyncError","SyncError","SyncError","topologicalSort","SyncError","topologicalSort"]}
|
|
1
|
+
{"version":3,"sources":["../src/types.ts","../src/scopes/scope-filter.ts","../src/scopes/query-subset.ts","../src/delta/delta-cursor.ts","../src/protocol/schema-version.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/awareness/awareness-manager.ts","../src/diagnostics/bandwidth-estimator.ts","../src/diagnostics/percentile.ts","../src/diagnostics/metrics-collector.ts","../src/richtext/richtext-doc-channel.ts","../src/richtext/doc-channel-wire.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":["import type { Operation, VersionVector } 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 = [\n\t'connected',\n\t'syncing',\n\t'synced',\n\t'offline',\n\t'error',\n\t'schema-mismatch',\n] 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/** Start sync automatically when the engine is created. Defaults to false. */\n\tautoConnect?: boolean\n\t/**\n\t * When true, wait for server ACKs on all outbound handshake delta batches before\n\t * entering streaming. Improves backpressure for large initial syncs.\n\t */\n\tstrictHandshake?: boolean\n\t/** Optional operation transforms for cross-schema-version sync. */\n\toperationTransforms?: import('@korajs/core').OperationTransform[]\n\t/**\n\t * Richtext snapshot size (bytes) at which the optional Yjs doc channel is used.\n\t * Defaults to 4096.\n\t */\n\trichtextDocChannelThreshold?: 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 * Persists last-acked server version vector and computes unsynced operations from the op log.\n */\nexport interface DeltaCursor {\n\t/** ID of the last fully applied operation in the previous delta stream */\n\tlastOperationId: string\n\t/** Zero-based batch index where the cursor was recorded */\n\tbatchIndex: number\n}\n\nexport interface SyncStatePersistence {\n\tloadLastAckedServerVector(): Promise<VersionVector>\n\tsaveLastAckedServerVector(vector: VersionVector): Promise<void>\n\tmergeServerVectors(a: VersionVector, b: VersionVector): VersionVector\n\tcountUnsyncedOperations(serverVector: VersionVector): Promise<number>\n\tgetUnsyncedOperations(serverVector: VersionVector): Promise<Operation[]>\n\t/** Resume position for paginated initial sync (optional). */\n\tloadDeltaCursor?(): Promise<DeltaCursor | null>\n\tsaveDeltaCursor?(cursor: DeltaCursor | null): Promise<void>\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 ?? `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. When an optional\n * `fullRecord` is provided (e.g., from the local store), its values fill in scope fields\n * that weren't included in the operation's data (critical for update operations where\n * `data` only contains changed fields).\n *\n * @param op - The operation to check\n * @param scopeMap - Per-collection scope filters, or undefined for no filtering\n * @param fullRecord - Optional full record state from the store, used to fill in scope\n * fields not present in the operation's partial data\n * @returns true if the operation is within scope\n */\nexport function operationMatchesScope(\n\top: Operation,\n\tscopeMap: SyncScopeMap | undefined,\n\tfullRecord?: Record<string, unknown> | null,\n): 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, fullRecord ?? undefined)\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(\n\top: Operation,\n\tfullRecord?: Record<string, unknown> | null,\n): Record<string, unknown> | null {\n\tconst previous = asRecord(op.previousData)\n\tconst next = asRecord(op.data)\n\n\tif (!previous && !next && !fullRecord) return null\n\n\treturn {\n\t\t...(fullRecord ?? {}),\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 { Operation } from '@korajs/core'\n\n/**\n * A live query filter that narrows which operations sync for a collection.\n */\nexport interface SyncQuerySubset {\n\tcollection: string\n\twhere: Record<string, unknown>\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\nfunction buildSnapshot(\n\top: Operation,\n\tfullRecord?: Record<string, unknown> | null,\n): Record<string, unknown> | null {\n\tconst previous = asRecord(op.previousData)\n\tconst next = asRecord(op.data)\n\n\tif (!previous && !next && !fullRecord) {\n\t\treturn null\n\t}\n\n\treturn {\n\t\t...(fullRecord ?? {}),\n\t\t...(previous ?? {}),\n\t\t...(next ?? {}),\n\t}\n}\n\nfunction recordMatchesWhere(\n\tsnapshot: Record<string, unknown>,\n\twhere: Record<string, unknown>,\n): boolean {\n\tfor (const [field, expected] of Object.entries(where)) {\n\t\tif (snapshot[field] !== expected) {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\n/**\n * Returns true when an operation matches at least one active query subset\n * for its collection. Collections without query subsets pass through.\n */\nexport function operationMatchesQuerySubsets(\n\top: Operation,\n\tsubsets: SyncQuerySubset[] | undefined,\n\tfullRecord?: Record<string, unknown> | null,\n): boolean {\n\tif (!subsets || subsets.length === 0) {\n\t\treturn true\n\t}\n\n\tconst collectionSubsets = subsets.filter((subset) => subset.collection === op.collection)\n\tif (collectionSubsets.length === 0) {\n\t\treturn true\n\t}\n\n\tconst snapshot = buildSnapshot(op, fullRecord)\n\tif (!snapshot) {\n\t\treturn false\n\t}\n\n\treturn collectionSubsets.some((subset) => recordMatchesWhere(snapshot, subset.where))\n}\n\n/**\n * Deduplicate query subsets by collection + where JSON key.\n */\nexport function dedupeQuerySubsets(subsets: SyncQuerySubset[]): SyncQuerySubset[] {\n\tconst seen = new Set<string>()\n\tconst result: SyncQuerySubset[] = []\n\n\tfor (const subset of subsets) {\n\t\tconst key = `${subset.collection}:${JSON.stringify(subset.where)}`\n\t\tif (seen.has(key)) {\n\t\t\tcontinue\n\t\t}\n\t\tseen.add(key)\n\t\tresult.push(subset)\n\t}\n\n\treturn result\n}\n","import type { DeltaCursor } from '../types'\n\nexport type { DeltaCursor }\n\nfunction bytesToBase64Url(bytes: Uint8Array): string {\n\tlet binary = ''\n\tfor (const byte of bytes) {\n\t\tbinary += String.fromCharCode(byte)\n\t}\n\treturn btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '')\n}\n\nfunction base64UrlToBytes(value: string): Uint8Array {\n\tconst base64 = value.replace(/-/g, '+').replace(/_/g, '/')\n\tconst padded = base64 + '='.repeat((4 - (base64.length % 4)) % 4)\n\tconst binary = atob(padded)\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\n/**\n * Encode a delta cursor for wire transfer or `_kora_meta` persistence.\n */\nexport function encodeDeltaCursor(cursor: DeltaCursor): string {\n\tconst json = JSON.stringify(cursor)\n\treturn bytesToBase64Url(new TextEncoder().encode(json))\n}\n\n/**\n * Decode a delta cursor string. Returns null when malformed.\n */\nexport function decodeDeltaCursor(value: string | undefined | null): DeltaCursor | null {\n\tif (!value) {\n\t\treturn null\n\t}\n\n\ttry {\n\t\tconst json = new TextDecoder().decode(base64UrlToBytes(value))\n\t\tconst parsed: unknown = JSON.parse(json)\n\t\tif (\n\t\t\ttypeof parsed !== 'object' ||\n\t\t\tparsed === null ||\n\t\t\ttypeof (parsed as DeltaCursor).lastOperationId !== 'string' ||\n\t\t\ttypeof (parsed as DeltaCursor).batchIndex !== 'number'\n\t\t) {\n\t\t\treturn null\n\t\t}\n\t\treturn parsed as DeltaCursor\n\t} catch {\n\t\treturn null\n\t}\n}\n\n/**\n * Slice a causally sorted operation list to resume after a cursor.\n */\nexport function sliceOperationsAfterCursor(\n\toperations: import('@korajs/core').Operation[],\n\tcursor: DeltaCursor | null,\n): import('@korajs/core').Operation[] {\n\tif (!cursor) {\n\t\treturn operations\n\t}\n\n\tconst index = operations.findIndex((op) => op.id === cursor.lastOperationId)\n\tif (index === -1) {\n\t\treturn operations\n\t}\n\n\treturn operations.slice(index + 1)\n}\n\n/**\n * Build a cursor from the last operation in a delta batch.\n */\nexport function createDeltaCursorFromBatch(\n\toperations: import('@korajs/core').Operation[],\n\tbatchIndex: number,\n): DeltaCursor | null {\n\tconst last = operations[operations.length - 1]\n\tif (!last) {\n\t\treturn null\n\t}\n\n\treturn {\n\t\tlastOperationId: last.id,\n\t\tbatchIndex,\n\t}\n}\n","/** Prefix for handshake rejection when client schema version is unsupported. */\nexport const SCHEMA_MISMATCH_PREFIX = 'SCHEMA_MISMATCH'\n\n/**\n * Returns true when a handshake `rejectReason` indicates unsupported schema version.\n */\nexport function isSchemaMismatchReject(rejectReason: string | undefined): boolean {\n\treturn rejectReason?.startsWith(SCHEMA_MISMATCH_PREFIX) === true\n}\n\n/**\n * Returns true when the client schema version is within the inclusive supported range.\n */\nexport function isClientSchemaVersionSupported(\n\tclientVersion: number,\n\tsupported: { min: number; max: number },\n): boolean {\n\treturn clientVersion >= supported.min && clientVersion <= supported.max\n}\n","import type { AtomicOp, HLCTimestamp, OperationType } from '@korajs/core'\nimport type { SyncQuerySubset } from '../scopes/query-subset'\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\t/** Base64url-encoded delta cursor for resuming paginated initial sync */\n\tdeltaCursor?: string\n\t/** Live query filters that further narrow synced data within auth/schema scope */\n\tsyncQueries?: SyncQuerySubset[]\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\t/** Inclusive minimum schema version the server accepts (present when rejected for schema mismatch). */\n\tsupportedSchemaMin?: number\n\t/** Inclusive maximum schema version the server accepts (present when rejected for schema mismatch). */\n\tsupportedSchemaMax?: number\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\t/** Base64url-encoded cursor marking the last operation in this batch */\n\tcursor?: string\n\t/** Total batches in this delta exchange (for progress reporting) */\n\ttotalBatches?: 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 * Incremental Yjs update for a richtext field. Ephemeral side channel for large documents.\n * JSON transport only; not persisted on the server operation log.\n */\nexport interface YjsDocUpdateMessage {\n\ttype: 'yjs-doc-update'\n\tmessageId: string\n\tcollection: string\n\trecordId: string\n\tfield: string\n\t/** Base64-encoded Yjs update binary */\n\tupdate: string\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\t| YjsDocUpdateMessage\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\tcase 'yjs-doc-update':\n\t\t\treturn isYjsDocUpdateMessage(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\n/**\n * Check if a value is a YjsDocUpdateMessage.\n */\nexport function isYjsDocUpdateMessage(value: unknown): value is YjsDocUpdateMessage {\n\tif (typeof value !== 'object' || value === null) return false\n\tconst msg = value as Record<string, unknown>\n\treturn (\n\t\tmsg.type === 'yjs-doc-update' &&\n\t\ttypeof msg.messageId === 'string' &&\n\t\ttypeof msg.collection === 'string' &&\n\t\ttypeof msg.recordId === 'string' &&\n\t\ttypeof msg.field === 'string' &&\n\t\ttypeof msg.update === 'string'\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\nconst WIRE_BYTES_KEY = '__kora_bytes__'\n\nfunction toBase64(bytes: Uint8Array): string {\n\tlet binary = ''\n\tfor (const byte of bytes) {\n\t\tbinary += String.fromCharCode(byte)\n\t}\n\treturn btoa(binary)\n}\n\nfunction fromBase64(value: string): Uint8Array {\n\tconst binary = atob(value)\n\tconst bytes = new Uint8Array(binary.length)\n\tfor (let index = 0; index < binary.length; index++) {\n\t\tbytes[index] = binary.charCodeAt(index)\n\t}\n\treturn bytes\n}\n\nfunction serializeWireRecord(\n\trecord: Record<string, unknown> | null,\n): Record<string, unknown> | null {\n\tif (!record) {\n\t\treturn null\n\t}\n\n\tconst out: Record<string, unknown> = {}\n\tfor (const [key, value] of Object.entries(record)) {\n\t\tout[key] = serializeWireValue(value)\n\t}\n\treturn out\n}\n\nfunction serializeWireValue(value: unknown): unknown {\n\tif (value instanceof Uint8Array) {\n\t\treturn { [WIRE_BYTES_KEY]: toBase64(value) }\n\t}\n\tif (value instanceof ArrayBuffer) {\n\t\treturn { [WIRE_BYTES_KEY]: toBase64(new Uint8Array(value)) }\n\t}\n\treturn value\n}\n\nfunction deserializeWireRecord(\n\trecord: Record<string, unknown> | null,\n): Record<string, unknown> | null {\n\tif (!record) {\n\t\treturn null\n\t}\n\n\tconst out: Record<string, unknown> = {}\n\tfor (const [key, value] of Object.entries(record)) {\n\t\tout[key] = deserializeWireValue(value)\n\t}\n\treturn out\n}\n\nfunction deserializeWireValue(value: unknown): unknown {\n\tif (typeof value === 'object' && value !== null && WIRE_BYTES_KEY in value) {\n\t\tconst encoded = (value as Record<string, unknown>)[WIRE_BYTES_KEY]\n\t\tif (typeof encoded === 'string') {\n\t\t\treturn fromBase64(encoded)\n\t\t}\n\t}\n\n\tif (isLegacyIndexedByteRecord(value)) {\n\t\treturn legacyIndexedByteRecordToUint8Array(value)\n\t}\n\n\treturn value\n}\n\nfunction isLegacyIndexedByteRecord(value: unknown): value is Record<string, number> {\n\tif (typeof value !== 'object' || value === null || Array.isArray(value)) {\n\t\treturn false\n\t}\n\n\tconst entries = Object.entries(value)\n\tif (entries.length === 0) {\n\t\treturn false\n\t}\n\n\treturn entries.every(([key, entryValue]) => {\n\t\tconst index = Number(key)\n\t\treturn Number.isInteger(index) && index >= 0 && typeof entryValue === 'number'\n\t})\n}\n\nfunction legacyIndexedByteRecordToUint8Array(value: Record<string, number>): Uint8Array {\n\tconst maxIndex = Math.max(...Object.keys(value).map((key) => Number(key)))\n\tconst bytes = new Uint8Array(maxIndex + 1)\n\tfor (const [key, entryValue] of Object.entries(value)) {\n\t\tbytes[Number(key)] = entryValue\n\t}\n\treturn bytes\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: serializeWireRecord(op.data),\n\t\t\tpreviousData: serializeWireRecord(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: deserializeWireRecord(serialized.data),\n\t\t\tpreviousData: deserializeWireRecord(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\tcase 'yjs-doc-update':\n\t\t\t// Ephemeral messages 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\tApplyFailureReason,\n\tApplyResult,\n\tKoraEventEmitter,\n\tOperation,\n\tSyncDiagnosticsSnapshot,\n\tVersionVector,\n} from '@korajs/core'\nimport {\n\tAPPLY_FAILURE_CODES,\n\tClockDriftError,\n\tKoraError,\n\tSyncError,\n\tapplyOperationTransforms,\n\tdefaultApplyFailureReason,\n} from '@korajs/core'\nimport { topologicalSort } from '@korajs/core/internal'\nimport { AwarenessManager } from '../awareness/awareness-manager'\nimport type { AwarenessMessage, AwarenessState } from '../awareness/types'\nimport {\n\tcreateDeltaCursorFromBatch,\n\tdecodeDeltaCursor,\n\tencodeDeltaCursor,\n\tsliceOperationsAfterCursor,\n} from '../delta/delta-cursor'\nimport { SyncMetricsCollector } from '../diagnostics/metrics-collector'\nimport type { MetricsCollectorConfig } from '../diagnostics/metrics-collector'\nimport type { SyncEncryptor } from '../encryption/sync-encryptor'\nimport type {\n\tAcknowledgmentMessage,\n\tAwarenessStateWire,\n\tAwarenessUpdateMessage,\n\tHandshakeResponseMessage,\n\tOperationBatchMessage,\n\tSyncMessage,\n\tWireFormat,\n\tYjsDocUpdateMessage,\n} from '../protocol/messages'\nimport { isSchemaMismatchReject } from '../protocol/schema-version'\nimport {\n\tNegotiatedMessageSerializer,\n\tversionVectorToWire,\n\twireToVersionVector,\n} from '../protocol/serializer'\nimport type { MessageSerializer } from '../protocol/serializer'\nimport { RichtextDocChannel } from '../richtext/richtext-doc-channel'\nimport {\n\ttype SyncQuerySubset,\n\tdedupeQuerySubsets,\n\toperationMatchesQuerySubsets,\n} from '../scopes/query-subset'\nimport { operationMatchesScope } from '../scopes/scope-filter'\nimport type { SyncTransport } from '../transport/transport'\nimport type { DeltaCursor } from '../types'\nimport type {\n\tQueueStorage,\n\tSyncConfig,\n\tSyncScopeMap,\n\tSyncState,\n\tSyncStatePersistence,\n\tSyncStatusInfo,\n} 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\t/** Op-log backed sync state (last acked server vector, unsynced counts). */\n\tsyncState?: SyncStatePersistence\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\nlet nextQuerySubsetId = 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 richtextDocChannel: RichtextDocChannel\n\tprivate readonly metricsCollector: SyncMetricsCollector\n\tprivate readonly syncState: SyncStatePersistence | null\n\n\tprivate remoteVector: VersionVector = new Map()\n\tprivate lastAckedServerVector: VersionVector = new Map()\n\tprivate cachedUnsyncedCount = 0\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\tprivate schemaBlocked = false\n\n\t// Track delta exchange state\n\tprivate deltaBatchesReceived = 0\n\tprivate deltaReceiveComplete = false\n\tprivate deltaSendComplete = false\n\t/** Op ids sent during handshake delta — removed from outbound queue to avoid duplicate send */\n\tprivate deltaSentOpIds: string[] = []\n\t/** Outbound delta batch message IDs awaiting ACK when strictHandshake is enabled */\n\tprivate pendingDeltaBatchAcks = new Set<string>()\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\t/** Live query subsets registered from reactive subscriptions */\n\tprivate querySubsets = new Map<string, SyncQuerySubset>()\n\tprivate querySubsetReconnectTimer: ReturnType<typeof setTimeout> | null = null\n\n\t/** Resume cursor for paginated initial sync (persisted across reconnects) */\n\tprivate resumeDeltaCursor: DeltaCursor | null = null\n\tprivate initialSyncTotalBatches = 0\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.syncState = options.syncState ?? 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\tthis.richtextDocChannel = new RichtextDocChannel({\n\t\t\tlargeDocThreshold: options.config.richtextDocChannelThreshold,\n\t\t\tonSend: (message: YjsDocUpdateMessage) => {\n\t\t\t\tif (this.state !== 'streaming') {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tthis.transport.send(message)\n\t\t\t},\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\t\tif (this.syncState) {\n\t\t\tthis.lastAckedServerVector = await this.syncState.loadLastAckedServerVector()\n\t\t\tif (this.syncState.loadDeltaCursor) {\n\t\t\t\tthis.resumeDeltaCursor = await this.syncState.loadDeltaCursor()\n\t\t\t}\n\t\t}\n\t\tawait this.reconcileOutboundFromOpLog()\n\t\tawait this.refreshPendingCount()\n\n\t\t// Set up transport handlers\n\t\tthis.transport.onMessage((msg) => this.enqueueMessage(msg))\n\t\tthis.transport.onClose((reason) => this.handleTransportClose(reason))\n\t\tthis.transport.onError((err) => this.handleTransportError(err))\n\n\t\tif (this.schemaBlocked) {\n\t\t\tthrow new SyncError(\n\t\t\t\t'Sync is blocked due to schema version mismatch. Upgrade the app schema or align sync.schemaVersion with the server.',\n\t\t\t\t{ code: 'SCHEMA_MISMATCH_BLOCKED' },\n\t\t\t)\n\t\t}\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 activeQuerySubsets = this.getActiveQuerySubsets()\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\t...(activeQuerySubsets.length > 0 ? { syncQueries: activeQuerySubsets } : {}),\n\t\t\t\t...(this.resumeDeltaCursor\n\t\t\t\t\t? { deltaCursor: encodeDeltaCursor(this.resumeDeltaCursor) }\n\t\t\t\t\t: {}),\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\tif (!this.operationAllowedForSync(op)) {\n\t\t\treturn\n\t\t}\n\n\t\tif (this.syncState) {\n\t\t\tthis.cachedUnsyncedCount++\n\t\t}\n\n\t\tawait this.outboundQueue.enqueue(op)\n\t\tif (this.syncState) {\n\t\t\tawait this.refreshPendingCount()\n\t\t}\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.syncState\n\t\t\t? this.cachedUnsyncedCount\n\t\t\t: 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: this.schemaBlocked ? 'schema-mismatch' : 'error' }\n\t\t}\n\t}\n\n\t/**\n\t * True when the server rejected the client's schema version at handshake.\n\t * Sync stays blocked until the app schema is upgraded or sync config changes.\n\t */\n\tisSchemaBlocked(): boolean {\n\t\treturn this.schemaBlocked\n\t}\n\n\t/**\n\t * Clears schema-mismatch block after upgrading the local schema / sync config.\n\t * Moves the engine back to `disconnected` so `start()` can run again.\n\t */\n\tclearSchemaBlock(): void {\n\t\tthis.schemaBlocked = false\n\t\tif (this.state === 'error') {\n\t\t\tthis.transitionTo('disconnected')\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 * Count of local operations not yet covered by the last acked server vector (op-log source of truth).\n\t */\n\tasync getUnsyncedOperationCount(): Promise<number> {\n\t\tawait this.refreshPendingCount()\n\t\treturn this.getStatus().pendingOperations\n\t}\n\n\tprivate emitApplyFailure(\n\t\top: Operation,\n\t\tresult: Exclude<ApplyResult, 'applied' | 'duplicate'>,\n\t\toverrides?: Partial<ApplyFailureReason>,\n\t): void {\n\t\tconst reason = defaultApplyFailureReason(result, overrides)\n\t\tthis.emitter?.emit({\n\t\t\ttype: 'sync:apply-failed',\n\t\t\toperationId: op.id,\n\t\t\tcollection: op.collection,\n\t\t\trecordId: op.recordId,\n\t\t\tcode: reason.code,\n\t\t\tmessage: reason.message,\n\t\t\tretriable: reason.retriable,\n\t\t})\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.schemaBlocked) return\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 * Register a live query subset that narrows synced data for a collection.\n\t * Takes effect on the next connection; reconnects when already connected.\n\t */\n\tregisterQuerySubset(subset: SyncQuerySubset): () => void {\n\t\tconst id = `query-${nextQuerySubsetId++}`\n\t\tthis.querySubsets.set(id, subset)\n\t\tthis.scheduleQuerySubsetReconnect()\n\t\treturn () => {\n\t\t\tthis.querySubsets.delete(id)\n\t\t\tthis.scheduleQuerySubsetReconnect()\n\t\t}\n\t}\n\n\t/**\n\t * Returns deduplicated active query subsets from registered subscriptions.\n\t */\n\tgetActiveQuerySubsets(): SyncQuerySubset[] {\n\t\treturn dedupeQuerySubsets([...this.querySubsets.values()])\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/**\n\t * Optional side channel for incremental Yjs updates on large richtext fields.\n\t */\n\tgetRichtextDocChannel(): RichtextDocChannel {\n\t\treturn this.richtextDocChannel\n\t}\n\n\t// --- Private methods ---\n\n\tprivate messageChain: Promise<void> = Promise.resolve()\n\n\tprivate enqueueMessage(message: SyncMessage): void {\n\t\tthis.messageChain = this.messageChain\n\t\t\t.then(() => this.handleMessageAsync(message))\n\t\t\t.catch((error) => this.handleMessageFailure(error))\n\t}\n\n\tprivate async handleMessageAsync(message: SyncMessage): Promise<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\tawait this.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\tcase 'yjs-doc-update':\n\t\t\t\tthis.richtextDocChannel.deliver(message)\n\t\t\t\tbreak\n\t\t}\n\t}\n\n\tprivate handleMessageFailure(error: unknown): void {\n\t\tconst reason = error instanceof Error ? error.message : 'Message handling failed'\n\t\tthis.handleTransportClose(reason)\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\tconst reason = msg.rejectReason ?? 'Handshake rejected'\n\t\t\tif (isSchemaMismatchReject(msg.rejectReason)) {\n\t\t\t\tthis.schemaBlocked = true\n\t\t\t\tconst supportedMin = msg.supportedSchemaMin ?? msg.schemaVersion\n\t\t\t\tconst supportedMax = msg.supportedSchemaMax ?? msg.schemaVersion\n\t\t\t\tthis.emitter?.emit({\n\t\t\t\t\ttype: 'sync:schema-mismatch',\n\t\t\t\t\tclientSchemaVersion: this.config.schemaVersion ?? DEFAULT_SCHEMA_VERSION,\n\t\t\t\t\tserverSchemaVersion: msg.schemaVersion,\n\t\t\t\t\tsupportedMin,\n\t\t\t\t\tsupportedMax,\n\t\t\t\t\treason,\n\t\t\t\t})\n\t\t\t\tthis.metricsCollector.updateStatus('error')\n\t\t\t\tthis.transitionTo('error')\n\t\t\t\tvoid this.transport.disconnect()\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.transitionTo('error')\n\t\t\tthis.emitter?.emit({\n\t\t\t\ttype: 'sync:disconnected',\n\t\t\t\treason,\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\t\tvoid this.persistLastAckedServerVector(this.remoteVector)\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\t\tthis.deltaSentOpIds = []\n\t\tthis.pendingDeltaBatchAcks.clear()\n\t\tthis.initialSyncTotalBatches = 0\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\tconst missingOps = allMissingOps.filter((op) => this.operationAllowedForSync(op))\n\n\t\tthis.deltaSentOpIds = missingOps.map((op) => op.id)\n\n\t\tif (missingOps.length === 0) {\n\t\t\tconst messageId = generateMessageId()\n\t\t\tif (this.config.strictHandshake) {\n\t\t\t\tthis.pendingDeltaBatchAcks.add(messageId)\n\t\t\t}\n\t\t\tconst emptyBatch: SyncMessage = {\n\t\t\t\ttype: 'operation-batch',\n\t\t\t\tmessageId,\n\t\t\t\toperations: [],\n\t\t\t\tisFinal: true,\n\t\t\t\tbatchIndex: 0,\n\t\t\t\ttotalBatches: 1,\n\t\t\t}\n\t\t\tthis.transport.send(emptyBatch)\n\t\t\tif (!this.config.strictHandshake) {\n\t\t\t\tthis.deltaSendComplete = true\n\t\t\t\tvoid this.checkDeltaComplete()\n\t\t\t}\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\t\tthis.initialSyncTotalBatches = Math.max(this.initialSyncTotalBatches, totalBatches)\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 batchCursor = createDeltaCursorFromBatch(batchOps, i)\n\n\t\t\t// Encrypt data fields before serialization if E2E encryption is enabled\n\t\t\tconst opsToSerialize = this.encryptor ? await this.encryptor.encryptBatch(batchOps) : batchOps\n\n\t\t\tconst serializedOps = opsToSerialize.map((op) => this.serializer.encodeOperation(op))\n\n\t\t\tconst messageId = generateMessageId()\n\t\t\tif (this.config.strictHandshake) {\n\t\t\t\tthis.pendingDeltaBatchAcks.add(messageId)\n\t\t\t}\n\t\t\tconst batchMsg: SyncMessage = {\n\t\t\t\ttype: 'operation-batch',\n\t\t\t\tmessageId,\n\t\t\t\toperations: serializedOps,\n\t\t\t\tisFinal: i === totalBatches - 1,\n\t\t\t\tbatchIndex: i,\n\t\t\t\ttotalBatches,\n\t\t\t\t...(batchCursor ? { cursor: encodeDeltaCursor(batchCursor) } : {}),\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\tif (!this.config.strictHandshake) {\n\t\t\tthis.deltaSendComplete = true\n\t\t\tvoid this.checkDeltaComplete()\n\t\t}\n\t}\n\n\tprivate markDeltaSendCompleteIfReady(): void {\n\t\tif (this.config.strictHandshake && this.pendingDeltaBatchAcks.size > 0) {\n\t\t\treturn\n\t\t}\n\t\tthis.deltaSendComplete = true\n\t\tvoid this.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\tconst inScopeOps = operations.filter((op) => this.operationAllowedForSync(op))\n\n\t\tconst targetSchemaVersion = this.config.schemaVersion ?? DEFAULT_SCHEMA_VERSION\n\t\tconst transforms = this.config.operationTransforms ?? []\n\n\t\t// Apply each in-scope operation; per-op failures must not block batch ACK\n\t\tfor (const op of inScopeOps) {\n\t\t\tconst transformed =\n\t\t\t\ttransforms.length > 0 ? applyOperationTransforms(op, targetSchemaVersion, transforms) : op\n\t\t\tif (transformed === null) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst result = await this.store.applyRemoteOperation(transformed)\n\t\t\t\tif (result === 'skipped' || result === 'rejected' || result === 'deferred') {\n\t\t\t\t\tthis.emitApplyFailure(transformed, result)\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof ClockDriftError) {\n\t\t\t\t\tthis.emitApplyFailure(transformed, 'rejected', {\n\t\t\t\t\t\tcode: APPLY_FAILURE_CODES.CLOCK_DRIFT,\n\t\t\t\t\t\tmessage: error.message,\n\t\t\t\t\t\tretriable: false,\n\t\t\t\t\t})\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tconst message = error instanceof Error ? error.message : 'Apply failed'\n\t\t\t\tconst code =\n\t\t\t\t\terror instanceof SyncError\n\t\t\t\t\t\t? error.code\n\t\t\t\t\t\t: error instanceof KoraError\n\t\t\t\t\t\t\t? error.code\n\t\t\t\t\t\t\t: error instanceof Error && 'code' in error && typeof error.code === 'string'\n\t\t\t\t\t\t\t\t? error.code\n\t\t\t\t\t\t\t\t: APPLY_FAILURE_CODES.APPLY_FAILED\n\t\t\t\tthis.emitApplyFailure(transformed, 'rejected', {\n\t\t\t\t\tcode,\n\t\t\t\t\tmessage,\n\t\t\t\t\tretriable: code !== APPLY_FAILURE_CODES.REFERENTIAL_INTEGRITY,\n\t\t\t\t})\n\t\t\t}\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\tconst totalBatches = msg.totalBatches ?? this.initialSyncTotalBatches\n\t\t\tif (msg.totalBatches !== undefined) {\n\t\t\t\tthis.initialSyncTotalBatches = msg.totalBatches\n\t\t\t}\n\t\t\tthis.metricsCollector.updateInitialSyncProgress(this.deltaBatchesReceived, totalBatches)\n\n\t\t\tconst cursorFromBatch =\n\t\t\t\tmsg.cursor !== undefined\n\t\t\t\t\t? decodeDeltaCursor(msg.cursor)\n\t\t\t\t\t: createDeltaCursorFromBatch(\n\t\t\t\t\t\t\tinScopeOps.length > 0 ? inScopeOps : operations,\n\t\t\t\t\t\t\tmsg.batchIndex,\n\t\t\t\t\t\t)\n\t\t\tif (cursorFromBatch) {\n\t\t\t\tthis.resumeDeltaCursor = cursorFromBatch\n\t\t\t\tawait this.persistDeltaCursor(cursorFromBatch)\n\t\t\t}\n\n\t\t\tif (msg.isFinal) {\n\t\t\t\tthis.deltaReceiveComplete = true\n\t\t\t\tthis.resumeDeltaCursor = null\n\t\t\t\tawait this.persistDeltaCursor(null)\n\t\t\t\tthis.metricsCollector.recordSyncCompleted()\n\t\t\t\tvoid this.checkDeltaComplete()\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate handleAcknowledgment(msg: AcknowledgmentMessage): void {\n\t\tif (this.state === 'syncing' && this.config.strictHandshake) {\n\t\t\tthis.pendingDeltaBatchAcks.delete(msg.acknowledgedMessageId)\n\t\t\tthis.markDeltaSendCompleteIfReady()\n\t\t}\n\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\tvoid this.advanceLastAckedForLocalNode(msg.lastSequenceNumber).then(() =>\n\t\t\tthis.refreshPendingCount(),\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 async checkDeltaComplete(): Promise<void> {\n\t\tif (!this.deltaSendComplete || !this.deltaReceiveComplete) {\n\t\t\treturn\n\t\t}\n\n\t\t// Idempotent: multiple final delta batches can race during handshake.\n\t\tif (this.state !== 'syncing') {\n\t\t\treturn\n\t\t}\n\n\t\tthis.lastSyncedAt = Date.now()\n\t\tthis.transitionTo('streaming')\n\n\t\t// Start awareness cleanup timer now that we're streaming\n\t\tthis.awarenessManager.startCleanupTimer()\n\n\t\t// Re-broadcast local awareness state to the new connection\n\t\tconst localState = this.awarenessManager.getLocalState()\n\t\tif (localState) {\n\t\t\tthis.awarenessManager.setLocalState(localState)\n\t\t}\n\n\t\t// Ops already sent in sendDelta() must not be flushed again from the outbound queue\n\t\tif (this.deltaSentOpIds.length > 0) {\n\t\t\tawait this.outboundQueue.removeByIds(this.deltaSentOpIds)\n\t\t\tthis.deltaSentOpIds = []\n\t\t}\n\n\t\tif (this.syncState) {\n\t\t\tconst localNodeId = this.store.getNodeId()\n\t\t\tconst localSeq = this.store.getVersionVector().get(localNodeId) ?? 0\n\t\t\tif (localSeq > 0) {\n\t\t\t\tawait this.advanceLastAckedForLocalNode(localSeq)\n\t\t\t}\n\t\t}\n\n\t\t// Flush any queued operations accumulated during delta exchange\n\t\tif (this.outboundQueue.hasOperations) {\n\t\t\tthis.flushQueue()\n\t\t}\n\n\t\tawait this.refreshPendingCount()\n\t}\n\n\t/**\n\t * Effective server vector: persisted last-ack merged with live handshake remote vector.\n\t */\n\tprivate getEffectiveServerVector(): VersionVector {\n\t\tif (!this.syncState) {\n\t\t\treturn this.remoteVector\n\t\t}\n\t\treturn this.syncState.mergeServerVectors(this.lastAckedServerVector, this.remoteVector)\n\t}\n\n\tprivate async persistLastAckedServerVector(vector: VersionVector): Promise<void> {\n\t\tif (!this.syncState) {\n\t\t\treturn\n\t\t}\n\t\tthis.lastAckedServerVector = this.syncState.mergeServerVectors(\n\t\t\tthis.lastAckedServerVector,\n\t\t\tvector,\n\t\t)\n\t\tawait this.syncState.saveLastAckedServerVector(this.lastAckedServerVector)\n\t}\n\n\tprivate async advanceLastAckedForLocalNode(lastSequenceNumber: number): Promise<void> {\n\t\tif (!this.syncState || lastSequenceNumber <= 0) {\n\t\t\treturn\n\t\t}\n\t\tconst nodeId = this.store.getNodeId()\n\t\tconst merged = new Map(this.lastAckedServerVector)\n\t\tmerged.set(nodeId, Math.max(merged.get(nodeId) ?? 0, lastSequenceNumber))\n\t\tthis.lastAckedServerVector = merged\n\t\tawait this.syncState.saveLastAckedServerVector(merged)\n\t}\n\n\t/**\n\t * Refresh cached unsynced count from op log vs effective server vector.\n\t */\n\tasync refreshPendingCount(): Promise<void> {\n\t\tif (!this.syncState) {\n\t\t\tthis.cachedUnsyncedCount = this.outboundQueue.totalPending\n\t\t\treturn\n\t\t}\n\t\tthis.cachedUnsyncedCount = await this.syncState.countUnsyncedOperations(\n\t\t\tthis.getEffectiveServerVector(),\n\t\t)\n\t}\n\n\t/**\n\t * Returns operations the server has not yet acknowledged (op-log source of truth).\n\t */\n\tasync getPendingSyncOperations(): Promise<Operation[]> {\n\t\tif (!this.syncState) {\n\t\t\treturn this.outboundQueue.peek(Number.MAX_SAFE_INTEGER)\n\t\t}\n\t\treturn this.syncState.getUnsyncedOperations(this.getEffectiveServerVector())\n\t}\n\n\t/**\n\t * Hydrate the outbound queue from unsynced ops in the op log (deduped by operation id).\n\t */\n\tprivate async reconcileOutboundFromOpLog(): Promise<void> {\n\t\tif (this.syncState) {\n\t\t\tconst unsynced = await this.syncState.getUnsyncedOperations(this.getEffectiveServerVector())\n\t\t\tfor (const op of unsynced) {\n\t\t\t\tawait this.outboundQueue.enqueue(op)\n\t\t\t}\n\t\t\treturn\n\t\t}\n\n\t\tconst localNodeId = this.store.getNodeId()\n\t\tconst localVector = this.store.getVersionVector()\n\t\tconst localSeq = localVector.get(localNodeId) ?? 0\n\t\tif (localSeq === 0) {\n\t\t\treturn\n\t\t}\n\n\t\tconst ops = await this.store.getOperationRange(localNodeId, 1, localSeq)\n\t\tconst inScope = ops.filter((op) => this.operationAllowedForSync(op))\n\t\tfor (const op of inScope) {\n\t\t\tawait this.outboundQueue.enqueue(op)\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.schemaBlocked) {\n\t\t\treturn\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\tprivate operationAllowedForSync(op: Operation): boolean {\n\t\tif (!operationMatchesScope(op, this.activeScope)) {\n\t\t\treturn false\n\t\t}\n\t\treturn operationMatchesQuerySubsets(op, this.getActiveQuerySubsets())\n\t}\n\n\tprivate async persistDeltaCursor(cursor: DeltaCursor | null): Promise<void> {\n\t\tif (!this.syncState?.saveDeltaCursor) {\n\t\t\treturn\n\t\t}\n\t\tawait this.syncState.saveDeltaCursor(cursor)\n\t}\n\n\tprivate scheduleQuerySubsetReconnect(): void {\n\t\tif (this.querySubsetReconnectTimer) {\n\t\t\tclearTimeout(this.querySubsetReconnectTimer)\n\t\t}\n\n\t\tthis.querySubsetReconnectTimer = setTimeout(() => {\n\t\t\tthis.querySubsetReconnectTimer = null\n\t\t\tif (this.state === 'streaming' || this.state === 'syncing' || this.state === 'handshaking') {\n\t\t\t\tvoid this.reconnectForQuerySubsets()\n\t\t\t}\n\t\t}, 500)\n\t}\n\n\tprivate async reconnectForQuerySubsets(): Promise<void> {\n\t\tawait this.stop()\n\t\tawait this.start()\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 { 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 { 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\tif (!sample) continue\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] ?? 0\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] ?? 0\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 { generateUUIDv7 } from '@korajs/core'\nimport type { YjsDocUpdateMessage } from '../protocol/messages'\nimport { decodeYjsUpdate, encodeYjsUpdate, richtextDocKey } from './doc-channel-wire'\n\n/** Default snapshot size above which the doc channel is preferred. */\nexport const DEFAULT_RICHTEXT_DOC_CHANNEL_THRESHOLD = 4096\n\nexport type RichtextDocListener = (update: Uint8Array) => void\n\nexport interface RichtextDocChannelOptions {\n\t/** Snapshot byte length at which incremental channel sync is recommended. */\n\tlargeDocThreshold?: number\n\t/** Called when a local update should be sent on the wire. */\n\tonSend?: (message: YjsDocUpdateMessage) => void\n}\n\n/**\n * Side channel for incremental Yjs updates on large richtext fields.\n * Ephemeral — not persisted in the operation log (durable state still flows via ops).\n */\nexport class RichtextDocChannel {\n\tprivate readonly threshold: number\n\tprivate readonly onSend: ((message: YjsDocUpdateMessage) => void) | null\n\tprivate readonly listeners = new Map<string, Set<RichtextDocListener>>()\n\n\tconstructor(options?: RichtextDocChannelOptions) {\n\t\tthis.threshold = options?.largeDocThreshold ?? DEFAULT_RICHTEXT_DOC_CHANNEL_THRESHOLD\n\t\tthis.onSend = options?.onSend ?? null\n\t}\n\n\t/**\n\t * Whether the doc channel should be used for a field.\n\t * @param preference - `true` forces on, `false` forces off, `undefined` uses size threshold\n\t */\n\tshouldUseChannel(snapshotByteLength: number, preference?: boolean): boolean {\n\t\tif (preference === false) {\n\t\t\treturn false\n\t\t}\n\t\tif (preference === true) {\n\t\t\treturn true\n\t\t}\n\t\treturn snapshotByteLength >= this.threshold\n\t}\n\n\tgetThreshold(): number {\n\t\treturn this.threshold\n\t}\n\n\t/**\n\t * Subscribe to incremental updates for a document key.\n\t */\n\tsubscribe(\n\t\tcollection: string,\n\t\trecordId: string,\n\t\tfield: string,\n\t\tlistener: RichtextDocListener,\n\t): () => void {\n\t\tconst key = richtextDocKey(collection, recordId, field)\n\t\tlet set = this.listeners.get(key)\n\t\tif (!set) {\n\t\t\tset = new Set()\n\t\t\tthis.listeners.set(key, set)\n\t\t}\n\t\tset.add(listener)\n\n\t\treturn () => {\n\t\t\tconst current = this.listeners.get(key)\n\t\t\tif (!current) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tcurrent.delete(listener)\n\t\t\tif (current.size === 0) {\n\t\t\t\tthis.listeners.delete(key)\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Publish a local incremental update to peers.\n\t */\n\tsend(collection: string, recordId: string, field: string, update: Uint8Array): void {\n\t\tif (!this.onSend || update.length === 0) {\n\t\t\treturn\n\t\t}\n\n\t\tthis.onSend({\n\t\t\ttype: 'yjs-doc-update',\n\t\t\tmessageId: generateUUIDv7(),\n\t\t\tcollection,\n\t\t\trecordId,\n\t\t\tfield,\n\t\t\tupdate: encodeYjsUpdate(update),\n\t\t})\n\t}\n\n\t/**\n\t * Deliver a remote incremental update to local subscribers.\n\t */\n\tdeliver(message: YjsDocUpdateMessage): void {\n\t\tconst key = richtextDocKey(message.collection, message.recordId, message.field)\n\t\tconst set = this.listeners.get(key)\n\t\tif (!set || set.size === 0) {\n\t\t\treturn\n\t\t}\n\n\t\tconst update = decodeYjsUpdate(message.update)\n\t\tfor (const listener of set) {\n\t\t\tlistener(update)\n\t\t}\n\t}\n}\n","const WIRE_BYTES_KEY = '__kora_bytes__'\n\n/**\n * Encode a Yjs update for the doc channel wire (base64).\n */\nexport function encodeYjsUpdate(update: Uint8Array): string {\n\tlet binary = ''\n\tfor (let i = 0; i < update.length; i++) {\n\t\tbinary += String.fromCharCode(update[i] as number)\n\t}\n\treturn btoa(binary)\n}\n\n/**\n * Decode a base64 Yjs update from the doc channel wire.\n */\nexport function decodeYjsUpdate(encoded: string): Uint8Array {\n\tconst binary = atob(encoded)\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\n/**\n * Build a stable key for a richtext field document.\n */\nexport function richtextDocKey(collection: string, recordId: string, field: string): string {\n\treturn `${collection}:${recordId}:${field}`\n}\n\nexport { WIRE_BYTES_KEY }\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\t/**\n\t * Remove operations by id from queue and persistent storage.\n\t * Used when ops were already sent during handshake delta exchange.\n\t */\n\tasync removeByIds(ids: string[]): Promise<void> {\n\t\tif (ids.length === 0) return\n\t\tconst idSet = new Set(ids)\n\t\tthis.queue = this.queue.filter((op) => !idSet.has(op.id))\n\t\tfor (const id of ids) {\n\t\t\tthis.seen.delete(id)\n\t\t}\n\t\tawait this.storage.dequeue(ids)\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 * Cancel the current backoff wait and proceed to the next reconnect attempt immediately.\n\t * No-op if not waiting.\n\t */\n\twake(): void {\n\t\tif (this.timer !== null) {\n\t\t\tclearTimeout(this.timer)\n\t\t\tthis.timer = null\n\t\t}\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 * 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":["asRecord","buildSnapshot","SyncError","SyncError","SyncError","SyncError","KoraError","SyncError","topologicalSort","SyncError","topologicalSort","KoraError","SyncError","SyncError","SyncError","toBase64","fromBase64"]}
|