@korajs/core 1.0.0-beta.12 → 1.0.0-beta.14

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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/errors/error-fixes.ts","../src/errors/errors.ts","../src/clock/hlc.ts","../src/operations/op-data-binary.ts","../src/operations/content-hash.ts","../src/operations/operation.ts","../src/operations/canonical-body.ts","../src/fold/field-kind.ts","../src/fold/stamp.ts","../src/schema/quote-ident.ts","../src/schema/sql-gen.ts","../src/version-vector/topological-sort.ts"],"sourcesContent":["/**\n * Human-readable remediation hints keyed by {@link KoraError} `code`.\n */\nexport const KORA_ERROR_FIX_SUGGESTIONS: Record<string, string> = {\n\tSCHEMA_VALIDATION:\n\t\t'Review your defineSchema() definition: every collection needs at least one field and a positive version.',\n\tOPERATION_ERROR:\n\t\t'Check the operation payload matches your schema field types and required fields.',\n\tMERGE_CONFLICT:\n\t\t'Add a custom resolver for the conflicting field in defineSchema(), or adjust constraint onConflict rules.',\n\tSYNC_ERROR:\n\t\t'Verify the sync server URL, auth token, and that the server accepts your schema version.',\n\tSTORAGE_ERROR:\n\t\t'Confirm the storage adapter is supported in this environment and the database path is writable.',\n\tCLOCK_DRIFT:\n\t\t'Sync device wall-clock time (NTP). Kora refuses new timestamps when drift exceeds five minutes.',\n\tINVALID_TIMESTAMP_FIELDS:\n\t\t'HLC timestamps need non-negative integer wallTime (< 10^15) and logical (<= 99999). Generate timestamps through HybridLogicalClock instead of building them by hand.',\n\tPERSISTENCE_ERROR:\n\t\t'IndexedDB persistence failed; check browser storage settings and available disk quota.',\n\tMISSING_WORKER_URL:\n\t\t'Pass store.workerUrl pointing to sqlite-wasm-worker.js (see create-kora-app templates).',\n\tINVALID_SYNC_URL:\n\t\t'Use ws:// or wss:// for WebSocket transport, or http(s):// for HTTP long-polling.',\n\tAPP_NOT_READY:\n\t\t'Await app.ready before querying or mutating collections, or wrap the tree in <KoraProvider app={app}>.',\n}\n\n/**\n * Returns a suggested fix for a Kora error code, if one is known.\n */\nexport function getKoraErrorFix(code: string): string | undefined {\n\treturn KORA_ERROR_FIX_SUGGESTIONS[code]\n}\n","import { getKoraErrorFix } from './error-fixes'\n\n/**\n * Base error class for all Kora errors.\n * Every error includes a machine-readable code and optional context for debugging.\n */\nexport class KoraError extends Error {\n\tconstructor(\n\t\tmessage: string,\n\t\tpublic readonly code: string,\n\t\tpublic readonly context?: Record<string, unknown>,\n\t) {\n\t\tsuper(message)\n\t\tthis.name = 'KoraError'\n\t}\n\n\t/**\n\t * Actionable hint for resolving this error (from registry or error context).\n\t */\n\tget fix(): string | undefined {\n\t\tconst fromContext = this.context?.fix\n\t\tif (typeof fromContext === 'string' && fromContext.length > 0) {\n\t\t\treturn fromContext\n\t\t}\n\t\treturn getKoraErrorFix(this.code)\n\t}\n}\n\n/**\n * Thrown when schema validation fails during defineSchema() or at app initialization.\n */\nexport class SchemaValidationError extends KoraError {\n\tconstructor(message: string, context?: Record<string, unknown>) {\n\t\tsuper(message, 'SCHEMA_VALIDATION', context)\n\t\tthis.name = 'SchemaValidationError'\n\t}\n}\n\n/**\n * Thrown when an operation is invalid or cannot be created.\n */\nexport class OperationError extends KoraError {\n\tconstructor(message: string, context?: Record<string, unknown>) {\n\t\tsuper(message, 'OPERATION_ERROR', context)\n\t\tthis.name = 'OperationError'\n\t}\n}\n\n/**\n * Thrown by the local write path when an operation would exceed `maxOperationBytes`\n * (RT-86): the server refuses such an operation, so the write is refused before it is\n * accepted, with nothing written.\n */\nexport class OperationTooLargeError extends KoraError {\n\tconstructor(\n\t\tpublic readonly collection: string,\n\t\tpublic readonly recordId: string,\n\t\tpublic readonly bytes: number,\n\t\tpublic readonly maxBytes: number,\n\t) {\n\t\tsuper(\n\t\t\t`A write to ${collection}/${recordId} would produce an operation of ${bytes} bytes, more than the ${maxBytes}-byte limit (maxOperationBytes). Nothing was written. Store large content as a blob (t.blob()) or split it across records.`,\n\t\t\t'OPERATION_TOO_LARGE',\n\t\t\t{ collection, recordId, bytes, maxBytes },\n\t\t)\n\t\tthis.name = 'OperationTooLargeError'\n\t}\n}\n\n/**\n * Thrown when a merge conflict cannot be automatically resolved.\n */\nexport class MergeConflictError extends KoraError {\n\tconstructor(\n\t\tpublic readonly operationA: { id: string; collection: string },\n\t\tpublic readonly operationB: { id: string; collection: string },\n\t\tpublic readonly field: string,\n\t) {\n\t\tsuper(\n\t\t\t`Merge conflict on field \"${field}\" in collection \"${operationA.collection}\"`,\n\t\t\t'MERGE_CONFLICT',\n\t\t\t{ operationA: operationA.id, operationB: operationB.id, field },\n\t\t)\n\t\tthis.name = 'MergeConflictError'\n\t}\n}\n\n/**\n * Thrown when a sync error occurs.\n */\nexport class SyncError extends KoraError {\n\tconstructor(message: string, context?: Record<string, unknown>) {\n\t\tsuper(message, 'SYNC_ERROR', context)\n\t\tthis.name = 'SyncError'\n\t}\n}\n\n/**\n * Thrown when a storage operation fails.\n */\nexport class StorageError extends KoraError {\n\tconstructor(message: string, context?: Record<string, unknown>) {\n\t\tsuper(message, 'STORAGE_ERROR', context)\n\t\tthis.name = 'StorageError'\n\t}\n}\n\n/**\n * Thrown when collection/query APIs are used before {@link KoraApp.ready} resolves.\n */\nexport class AppNotReadyError extends KoraError {\n\tconstructor(detail: string) {\n\t\tsuper(detail, 'APP_NOT_READY', {\n\t\t\tfix: 'Await app.ready, or wrap your UI in <KoraProvider app={app}> before calling useQuery().',\n\t\t})\n\t\tthis.name = 'AppNotReadyError'\n\t}\n}\n\n/**\n * Thrown when the HLC detects excessive clock drift.\n * Drift > 60s: warning. Drift > 5min: this error is thrown, refusing to generate timestamps.\n */\nexport class RemoteClockDriftError extends KoraError {\n\tconstructor(\n\t\tpublic readonly remoteWallTime: number,\n\t\tpublic readonly localReferenceTime: number,\n\t) {\n\t\tconst aheadSeconds = Math.round((remoteWallTime - localReferenceTime) / 1000)\n\t\tsuper(\n\t\t\t`Rejected remote timestamp ${aheadSeconds}s ahead of local reference time. The sending device's clock is set too far in the future.`,\n\t\t\t'REMOTE_CLOCK_DRIFT',\n\t\t\t{ remoteWallTime, localReferenceTime, aheadSeconds },\n\t\t)\n\t\tthis.name = 'RemoteClockDriftError'\n\t}\n}\n\n/**\n * Thrown when an HLC timestamp has structurally invalid fields: non-integer or\n * negative wallTime/logical, or a logical counter beyond the serializable cap.\n * Rejected BEFORE any clock state changes, so a malformed remote timestamp can\n * never corrupt a replica's clock or break the lexicographic ordering of the\n * serialized form.\n */\nexport class InvalidTimestampError extends KoraError {\n\tconstructor(\n\t\tmessage: string,\n\t\tpublic readonly wallTime: number,\n\t\tpublic readonly logical: number,\n\t) {\n\t\tsuper(message, 'INVALID_TIMESTAMP_FIELDS', { wallTime, logical })\n\t\tthis.name = 'InvalidTimestampError'\n\t}\n}\n\nexport class ClockDriftError extends KoraError {\n\tconstructor(\n\t\tpublic readonly currentHlcTime: number,\n\t\tpublic readonly physicalTime: number,\n\t) {\n\t\tconst driftSeconds = Math.round((currentHlcTime - physicalTime) / 1000)\n\t\tsuper(\n\t\t\t`Clock drift of ${driftSeconds}s detected. Physical time is behind HLC by more than 5 minutes. This indicates a severe clock issue.`,\n\t\t\t'CLOCK_DRIFT',\n\t\t\t{ currentHlcTime, physicalTime, driftSeconds },\n\t\t)\n\t\tthis.name = 'ClockDriftError'\n\t}\n}\n","import { ClockDriftError, InvalidTimestampError, RemoteClockDriftError } from '../errors/errors'\nimport type { HLCTimestamp, TimeSource } from '../types'\n\n/** Default time source using the system clock */\nconst systemTimeSource: TimeSource = { now: () => Date.now() }\n\n/**\n * Highest logical counter value that fits the 5-digit zero-padded slot in the\n * serialized timestamp form. The serialized string must sort lexicographically\n * in exactly the same order as {@link HybridLogicalClock.compare}; a 6-digit\n * logical value would shift the padding and silently break that invariant for\n * every stored `_version` column and operation timestamp. When the counter\n * would exceed this cap, the clock carries into wallTime instead\n * (wallTime + 1, logical = 0), which preserves both monotonicity and the\n * serialized ordering.\n */\nexport const MAX_LOGICAL = 99_999\n\n/** Number of distinct logical values; the modulus used when carrying into wallTime. */\nconst LOGICAL_MODULUS = MAX_LOGICAL + 1\n\n/**\n * Exclusive upper bound on serializable wallTime: the serialized form\n * zero-pads wallTime to 15 digits, so a 16-digit value would break the\n * lexicographic ordering. 10^15 ms is roughly the year 33658 — unreachable by\n * honest clocks, only by hand-built timestamps.\n */\nconst WALL_TIME_LIMIT = 10 ** 15\n\n/** Maximum allowed drift before warning (60 seconds) */\nconst DRIFT_WARN_MS = 60_000\n\n/** Drift beyond which the error-severity callback fires (5 minutes) */\nconst DRIFT_ERROR_MS = 5 * 60_000\n\n/** Maximum future skew accepted from a remote timestamp before it is rejected (5 minutes) */\nconst MAX_REMOTE_FUTURE_MS = 5 * 60_000\n\n/**\n * Hybrid Logical Clock implementation based on Kulkarni et al.\n *\n * Provides a total order that respects causality without requiring synchronized clocks.\n * Each call to now() returns a timestamp strictly greater than the previous one.\n *\n * @example\n * ```typescript\n * const clock = new HybridLogicalClock('node-1')\n * const ts1 = clock.now()\n * const ts2 = clock.now()\n * // HybridLogicalClock.compare(ts1, ts2) < 0 (ts1 is earlier)\n * ```\n */\nexport class HybridLogicalClock {\n\tprivate wallTime = 0\n\tprivate logical = 0\n\tprivate referenceOffsetMs: number | null = null\n\n\tconstructor(\n\t\tprivate readonly nodeId: string,\n\t\tprivate readonly timeSource: TimeSource = systemTimeSource,\n\t\tprivate readonly onDriftWarning?: (driftMs: number) => void,\n\t\tprivate readonly onDriftError?: (driftMs: number) => void,\n\t) {}\n\n\t/**\n\t * Records the known offset between an external time reference (usually the\n\t * sync server, learned at handshake) and this device's physical clock:\n\t * `referenceTime - localPhysicalTime`. Once set, drift evaluation and remote\n\t * timestamp validation are performed against reference-corrected time, so a\n\t * device with a wrong local clock still validates remote timestamps correctly.\n\t */\n\tsetReferenceOffset(offsetMs: number): void {\n\t\tthis.referenceOffsetMs = offsetMs\n\t}\n\n\tgetReferenceOffset(): number | null {\n\t\treturn this.referenceOffsetMs\n\t}\n\n\t/** Physical time corrected by the known reference offset, when available. */\n\tprivate effectiveTime(physicalTime: number): number {\n\t\treturn physicalTime + (this.referenceOffsetMs ?? 0)\n\t}\n\n\t/**\n\t * Generate a new timestamp for a local event.\n\t * Guarantees monotonicity: each call returns a timestamp strictly greater than the previous.\n\t *\n\t * Never throws and never blocks a local write: if the physical clock has\n\t * fallen behind the HLC (e.g. the user corrected a fast clock), the HLC\n\t * freezes wallTime and advances the logical counter, and drift is reported\n\t * through the onDriftWarning / onDriftError callbacks instead.\n\t */\n\tnow(): HLCTimestamp {\n\t\tconst physicalTime = this.timeSource.now()\n\t\tthis.checkDrift(physicalTime)\n\n\t\tif (physicalTime > this.wallTime) {\n\t\t\tthis.wallTime = physicalTime\n\t\t\tthis.logical = 0\n\t\t} else {\n\t\t\tthis.logical++\n\t\t}\n\t\tthis.carryLogicalOverflow()\n\n\t\treturn { wallTime: this.wallTime, logical: this.logical, nodeId: this.nodeId }\n\t}\n\n\t/**\n\t * Update clock on receiving a remote timestamp.\n\t * Merges the remote clock state with the local state to maintain causal ordering.\n\t *\n\t * @throws {InvalidTimestampError} If the remote timestamp has non-integer or\n\t * negative wallTime/logical, or logical beyond {@link MAX_LOGICAL}. Checked\n\t * BEFORE any state change, so malformed input cannot corrupt this clock.\n\t * @throws {RemoteClockDriftError} If the remote timestamp is more than 5 minutes\n\t * ahead of reference-corrected local time. Validation happens BEFORE any state\n\t * is adopted, so a rejected timestamp cannot poison this clock. When no\n\t * reference offset is known and this clock is uninitialized (cold start with\n\t * a possibly-wrong local clock), validation is skipped, matching the previous\n\t * cold-start behavior but now without a corrupting failure mode afterward.\n\t */\n\treceive(remote: HLCTimestamp): HLCTimestamp {\n\t\tconst physicalTime = this.timeSource.now()\n\t\tconst wasColdStart = this.wallTime === 0\n\n\t\t// Validate before adopting anything. Malformed fields would corrupt the\n\t\t// clock's arithmetic (NaN/fractional wallTime) or overflow the serialized\n\t\t// form's 5-digit logical slot, so they are rejected outright.\n\t\tif (\n\t\t\t!Number.isInteger(remote.wallTime) ||\n\t\t\tremote.wallTime < 0 ||\n\t\t\t!Number.isInteger(remote.logical) ||\n\t\t\tremote.logical < 0 ||\n\t\t\tremote.logical > MAX_LOGICAL\n\t\t) {\n\t\t\tthrow new InvalidTimestampError(\n\t\t\t\t`Rejected remote HLC timestamp with invalid fields (wallTime=${remote.wallTime}, logical=${remote.logical}). wallTime and logical must be non-negative integers and logical must not exceed ${MAX_LOGICAL}.`,\n\t\t\t\tremote.wallTime,\n\t\t\t\tremote.logical,\n\t\t\t)\n\t\t}\n\n\t\t// A far-future remote timestamp must never become this clock's state.\n\t\tconst canValidate = this.referenceOffsetMs !== null || !wasColdStart\n\t\tif (canValidate) {\n\t\t\tconst reference = this.effectiveTime(physicalTime)\n\t\t\tif (remote.wallTime > reference + MAX_REMOTE_FUTURE_MS) {\n\t\t\t\tthrow new RemoteClockDriftError(remote.wallTime, reference)\n\t\t\t}\n\t\t}\n\n\t\tif (physicalTime > this.wallTime && physicalTime > remote.wallTime) {\n\t\t\tthis.wallTime = physicalTime\n\t\t\tthis.logical = 0\n\t\t} else if (remote.wallTime > this.wallTime) {\n\t\t\tthis.wallTime = remote.wallTime\n\t\t\tthis.logical = remote.logical + 1\n\t\t} else if (this.wallTime === remote.wallTime) {\n\t\t\tthis.logical = Math.max(this.logical, remote.logical) + 1\n\t\t} else {\n\t\t\t// this.wallTime > remote.wallTime && this.wallTime >= physicalTime\n\t\t\tthis.logical++\n\t\t}\n\t\tthis.carryLogicalOverflow()\n\n\t\t// Report (never throw) drift after merging. Cold start is exempt from\n\t\t// reporting to avoid false positives when the local clock is simply wrong.\n\t\tif (!wasColdStart) {\n\t\t\tthis.checkDrift(physicalTime)\n\t\t}\n\n\t\treturn { wallTime: this.wallTime, logical: this.logical, nodeId: this.nodeId }\n\t}\n\n\t/**\n\t * Advance this clock to at least the given timestamp.\n\t *\n\t * Used after a timestamp rebase rewrites unsynced operations: future `now()`\n\t * timestamps must sort after every rebased operation, otherwise a write issued\n\t * immediately after the rebase could interleave with (or precede) rebased ops\n\t * and break the log's total order. Never moves the clock backward — a\n\t * timestamp at or before the current state is a no-op, preserving the\n\t * monotonicity guarantee of `now()`.\n\t *\n\t * Inputs with logical > MAX_LOGICAL are normalized deterministically by\n\t * carrying the excess into wallTime, so the adopted state always leaves room\n\t * for the next increment inside the serializable range.\n\t */\n\tadvanceTo(ts: HLCTimestamp): void {\n\t\t// Deterministic normalization: adopting given values verbatim could plant\n\t\t// an unserializable logical counter inside the clock.\n\t\tconst normalized: HLCTimestamp = {\n\t\t\twallTime: ts.wallTime + Math.floor(ts.logical / LOGICAL_MODULUS),\n\t\t\tlogical: ts.logical % LOGICAL_MODULUS,\n\t\t\tnodeId: ts.nodeId,\n\t\t}\n\t\tconst current: HLCTimestamp = {\n\t\t\twallTime: this.wallTime,\n\t\t\tlogical: this.logical,\n\t\t\tnodeId: this.nodeId,\n\t\t}\n\t\tif (HybridLogicalClock.compare(normalized, current) > 0) {\n\t\t\tthis.wallTime = normalized.wallTime\n\t\t\tthis.logical = normalized.logical\n\t\t}\n\t}\n\n\t/**\n\t * Carry the logical counter into wallTime when an increment pushed it past\n\t * MAX_LOGICAL. Bumping wallTime by 1ms keeps the timestamp strictly greater\n\t * than everything issued before (monotonicity) while keeping the logical\n\t * counter inside the 5-digit slot the serialized form depends on.\n\t */\n\tprivate carryLogicalOverflow(): void {\n\t\tif (this.logical > MAX_LOGICAL) {\n\t\t\tthis.wallTime += 1\n\t\t\tthis.logical = 0\n\t\t}\n\t}\n\n\t/**\n\t * Compare two timestamps. Returns negative if a < b, positive if a > b, zero if equal.\n\t * Total order: wallTime first, then logical, then nodeId (lexicographic).\n\t */\n\tstatic compare(a: HLCTimestamp, b: HLCTimestamp): number {\n\t\tif (a.wallTime !== b.wallTime) return a.wallTime - b.wallTime\n\t\tif (a.logical !== b.logical) return a.logical - b.logical\n\t\tif (a.nodeId < b.nodeId) return -1\n\t\tif (a.nodeId > b.nodeId) return 1\n\t\treturn 0\n\t}\n\n\t/**\n\t * Serialize an HLC timestamp to a string that sorts lexicographically.\n\t * Format: zero-padded wallTime:logical:nodeId\n\t *\n\t * @throws {InvalidTimestampError} If wallTime does not fit 15 digits or\n\t * logical does not fit 5 digits (or either is negative/non-integer). Such a\n\t * value would overflow its zero-padded slot and the serialized string would\n\t * no longer sort in the same order as {@link HybridLogicalClock.compare} —\n\t * silently corrupting every LWW comparison on stored `_version` columns.\n\t * Internal clocks can no longer produce such values (the logical counter\n\t * carries into wallTime); this guards against hand-built timestamps.\n\t */\n\tstatic serialize(ts: HLCTimestamp): string {\n\t\tif (\n\t\t\t!Number.isInteger(ts.wallTime) ||\n\t\t\tts.wallTime < 0 ||\n\t\t\tts.wallTime >= WALL_TIME_LIMIT ||\n\t\t\t!Number.isInteger(ts.logical) ||\n\t\t\tts.logical < 0 ||\n\t\t\tts.logical > MAX_LOGICAL\n\t\t) {\n\t\t\tthrow new InvalidTimestampError(\n\t\t\t\t`Cannot serialize HLC timestamp (wallTime=${ts.wallTime}, logical=${ts.logical}): wallTime must be an integer in [0, 10^15) and logical an integer in [0, ${MAX_LOGICAL}]. Values outside these ranges overflow the zero-padded serialized form, which must sort lexicographically identically to HybridLogicalClock.compare.`,\n\t\t\t\tts.wallTime,\n\t\t\t\tts.logical,\n\t\t\t)\n\t\t}\n\t\tconst wall = ts.wallTime.toString().padStart(15, '0')\n\t\tconst log = ts.logical.toString().padStart(5, '0')\n\t\treturn `${wall}:${log}:${ts.nodeId}`\n\t}\n\n\t/**\n\t * Deserialize an HLC timestamp from its serialized string form.\n\t */\n\tstatic deserialize(s: string): HLCTimestamp {\n\t\tconst parts = s.split(':')\n\t\tif (parts.length < 3) {\n\t\t\tthrow new Error(`Invalid HLC timestamp string: \"${s}\"`)\n\t\t}\n\t\treturn {\n\t\t\twallTime: Number.parseInt(parts[0] ?? '0', 10),\n\t\t\tlogical: Number.parseInt(parts[1] ?? '0', 10),\n\t\t\t// nodeId may contain colons, so rejoin remaining parts\n\t\t\tnodeId: parts.slice(2).join(':'),\n\t\t}\n\t}\n\n\t/**\n\t * Reports drift between the HLC and (reference-corrected) physical time.\n\t * Reporting only: local timestamp generation is never blocked, because the\n\t * user's data always outranks the quality of its timestamps.\n\t */\n\tprivate checkDrift(physicalTime: number): void {\n\t\tconst drift = this.wallTime - this.effectiveTime(physicalTime)\n\t\tif (drift > DRIFT_ERROR_MS) {\n\t\t\tthis.onDriftError?.(drift)\n\t\t\treturn\n\t\t}\n\t\tif (drift > DRIFT_WARN_MS) {\n\t\t\tthis.onDriftWarning?.(drift)\n\t\t}\n\t}\n}\n","import { OperationError } from '../errors/errors'\n\n/**\n * Canonical JSON-safe encoding of binary bytes stored inside `op.data` /\n * `op.previousData` (currently richtext field values). A raw Uint8Array\n * JSON-serializes to a numeric-key object and an ArrayBuffer to `{}` (silent\n * data loss), which breaks content-hash stability, persistence round-trips,\n * remote application, and merge. Tagging the bytes as base64 at\n * operation-creation time makes the hashed value, the persisted JSON, the wire\n * payload, and the value the merge engine sees the identical canonical value.\n *\n * This convention lives in `@korajs/core` because `op.data` is a core concept:\n * both `@korajs/store` (persistence, creation) and `@korajs/merge` (CRDT merge)\n * must agree on it, and neither may depend on the other.\n */\nexport interface KoraBytesValue {\n\t$koraBytes: string\n}\n\n/**\n * Type guard for the tagged binary form. Requires exactly the single\n * `$koraBytes` key so arbitrary user objects that happen to contain the key\n * are never silently reinterpreted as bytes.\n */\nexport function isKoraBytesValue(value: unknown): value is KoraBytesValue {\n\tif (typeof value !== 'object' || value === null) {\n\t\treturn false\n\t}\n\tconst record = value as Record<string, unknown>\n\treturn Object.keys(record).length === 1 && typeof record.$koraBytes === 'string'\n}\n\n/**\n * Detects the numeric-key object shape a raw Uint8Array produced when\n * JSON-serialized before the tagged encoding existed ({\"0\":1,\"1\":2,...}).\n */\nexport function isLegacyNumericByteObject(value: unknown): value is Record<string, number> {\n\tif (typeof value !== 'object' || value === null || ArrayBuffer.isView(value)) {\n\t\treturn false\n\t}\n\tconst record = value as Record<string, unknown>\n\tconst keys = Object.keys(record)\n\tif (keys.length === 0) {\n\t\treturn false\n\t}\n\tfor (let i = 0; i < keys.length; i++) {\n\t\tconst byte = record[String(i)]\n\t\tif (typeof byte !== 'number' || !Number.isInteger(byte) || byte < 0 || byte > 255) {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\nconst BASE64_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'\n\nconst BASE64_REVERSE: ReadonlyMap<string, number> = new Map(\n\tArray.from(BASE64_ALPHABET, (char, index) => [char, index]),\n)\n\n/**\n * Dependency-free base64 encoder. btoa is unavailable for bytes in Node and\n * Buffer is unavailable in browsers, so a manual implementation is the only\n * deterministic option that works in every runtime Kora targets.\n */\nexport function bytesToBase64(bytes: Uint8Array): string {\n\tlet out = ''\n\tfor (let i = 0; i < bytes.length; i += 3) {\n\t\tconst b0 = bytes[i] ?? 0\n\t\tconst b1 = bytes[i + 1] ?? 0\n\t\tconst b2 = bytes[i + 2] ?? 0\n\t\tconst triple = (b0 << 16) | (b1 << 8) | b2\n\t\tout += BASE64_ALPHABET[(triple >> 18) & 63] ?? ''\n\t\tout += BASE64_ALPHABET[(triple >> 12) & 63] ?? ''\n\t\tout += i + 1 < bytes.length ? (BASE64_ALPHABET[(triple >> 6) & 63] ?? '') : '='\n\t\tout += i + 2 < bytes.length ? (BASE64_ALPHABET[triple & 63] ?? '') : '='\n\t}\n\treturn out\n}\n\n/**\n * Inverse of {@link bytesToBase64}.\n */\nexport function base64ToBytes(base64: string): Uint8Array {\n\tconst cleaned = base64.replace(/=+$/, '')\n\tconst out = new Uint8Array(Math.floor((cleaned.length * 6) / 8))\n\tlet buffer = 0\n\tlet bits = 0\n\tlet index = 0\n\tfor (const char of cleaned) {\n\t\tconst value = BASE64_REVERSE.get(char)\n\t\tif (value === undefined) {\n\t\t\tthrow new OperationError(`Invalid base64 character \"${char}\" in tagged binary value.`, {\n\t\t\t\tchar,\n\t\t\t})\n\t\t}\n\t\tbuffer = (buffer << 6) | value\n\t\tbits += 6\n\t\tif (bits >= 8) {\n\t\t\tbits -= 8\n\t\t\tout[index] = (buffer >> bits) & 0xff\n\t\t\tindex += 1\n\t\t}\n\t}\n\treturn out\n}\n\n/**\n * Normalize a validated binary-or-string value into the canonical form stored\n * in `op.data`: strings pass through unchanged (backward compatible with every\n * existing operation), binary values become the tagged base64 form.\n */\nexport function encodeBytesForOpData(\n\tvalue: string | Uint8Array | ArrayBuffer,\n): string | KoraBytesValue {\n\tif (typeof value === 'string') {\n\t\treturn value\n\t}\n\tconst bytes = value instanceof Uint8Array ? value : new Uint8Array(value)\n\treturn { $koraBytes: bytesToBase64(bytes) }\n}\n\n/**\n * Reverse of {@link encodeBytesForOpData}, tolerant of every shape a binary\n * op-data value has ever taken: canonical strings and tagged bytes, in-memory\n * Uint8Array/ArrayBuffer (ops that never round-tripped through JSON), and\n * pre-fix numeric-key objects.\n */\nexport function decodeBytesFromOpData(value: unknown): string | Uint8Array {\n\tif (typeof value === 'string') {\n\t\treturn value\n\t}\n\tif (value instanceof Uint8Array) {\n\t\treturn value\n\t}\n\tif (value instanceof ArrayBuffer) {\n\t\treturn new Uint8Array(value)\n\t}\n\tif (isKoraBytesValue(value)) {\n\t\treturn base64ToBytes(value.$koraBytes)\n\t}\n\t// Pre-fix era: a raw Uint8Array in op.data JSON-serialized to a numeric-key\n\t// object. Nothing shipped relies on that shape, but dev databases may still\n\t// contain such operations — reconstructing the bytes here is cheap and\n\t// prevents those databases from crashing on replay/apply/merge. No migration\n\t// is written for this; new operations always use the tagged form.\n\tif (isLegacyNumericByteObject(value)) {\n\t\tconst keys = Object.keys(value)\n\t\tconst bytes = new Uint8Array(keys.length)\n\t\tfor (let i = 0; i < keys.length; i++) {\n\t\t\tbytes[i] = value[String(i)] ?? 0\n\t\t}\n\t\treturn bytes\n\t}\n\tthrow new OperationError(\n\t\t'Binary op-data value must be a string, Uint8Array, ArrayBuffer, tagged { $koraBytes } object, or legacy numeric-key byte object.',\n\t\t{ receivedType: typeof value },\n\t)\n}\n","import { HybridLogicalClock } from '../clock/hlc'\nimport type { AtomicOp, HLCTimestamp, OperationInput } from '../types'\nimport { canonicalizeOperationBody } from './canonical-body'\n\n/**\n * Content-hash versions for operation ids.\n *\n * - **1** (Kora <= beta.12): hashes type, collection, recordId,\n * data, timestamp, nodeId and atomicOps. previousData, sequenceNumber,\n * causalDeps and schemaVersion are NOT covered (CORE-1).\n * - **2**: additionally hashes previousData, sequenceNumber, causalDeps (as a\n * set) and schemaVersion, with the version itself as a domain tag, and binary\n * values in their canonical tagged form. Operations carry `hashVersion: 2`.\n */\nexport type OperationHashVersion = 1 | 2\n\n/** Hash version new operations get: 2 since protocol v2 (beta.13). */\nexport const DEFAULT_OPERATION_HASH_VERSION: OperationHashVersion = 2\n\n/** The operation fields a content hash can cover. */\nexport interface HashableOperation {\n\tnodeId: string\n\ttype: OperationInput['type']\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: readonly string[]\n\tschemaVersion: number\n\tatomicOps?: Record<string, AtomicOp>\n}\n\n/**\n * Compute the content-addressed ID for an operation using SHA-256.\n * The same operation content always produces the same hash, ensuring deduplication.\n *\n * Two call forms:\n * - `computeOperationId(input, serializedTimestamp)`: the version-1 hash (legacy\n * form, used by the store's rebase and node-id rotation).\n * - `computeOperationId(op, version)`: the hash of the given version over a full\n * operation (with its HLC timestamp).\n *\n * @returns A hex-encoded SHA-256 hash\n */\nexport async function computeOperationId(input: OperationInput, timestamp: string): Promise<string>\nexport async function computeOperationId(\n\top: HashableOperation,\n\tversion: OperationHashVersion,\n): Promise<string>\nexport async function computeOperationId(\n\tinput: OperationInput | HashableOperation,\n\ttimestampOrVersion: string | OperationHashVersion,\n): Promise<string> {\n\tif (typeof timestampOrVersion === 'string') {\n\t\treturn sha256Hex(canonicalize(v1HashInput(input, timestampOrVersion)))\n\t}\n\tconst op = input as HashableOperation\n\tconst serializedTs = HybridLogicalClock.serialize(op.timestamp)\n\tif (timestampOrVersion === 1) return sha256Hex(canonicalize(v1HashInput(op, serializedTs)))\n\treturn sha256Hex(canonicalize(v2HashInput(op, serializedTs)))\n}\n\nfunction v1HashInput(\n\tinput: OperationInput | HashableOperation,\n\ttimestamp: string,\n): Record<string, unknown> {\n\t// Only include atomicOps when present — ensures backward compatibility\n\t// (existing operations without atomicOps produce identical hashes).\n\tconst hashInput: Record<string, unknown> = {\n\t\ttype: input.type,\n\t\tcollection: input.collection,\n\t\trecordId: input.recordId,\n\t\tdata: input.data,\n\t\ttimestamp,\n\t\tnodeId: input.nodeId,\n\t}\n\tif (input.atomicOps !== undefined && Object.keys(input.atomicOps).length > 0) {\n\t\thashInput.atomicOps = input.atomicOps\n\t}\n\treturn hashInput\n}\n\nfunction v2HashInput(op: HashableOperation, timestamp: string): Record<string, unknown> {\n\t// The canonical body (core canonical-body.ts) is what is hashed: the same function\n\t// produced the body the op log and the wire carry, so the hashed content and the\n\t// stored content are one by construction (RT-72, RT-79, RT-80).\n\tconst body = canonicalizeOperationBody(op)\n\tconst atomicOps =\n\t\tbody.atomicOps !== undefined && Object.keys(body.atomicOps).length > 0 ? body.atomicOps : null\n\treturn {\n\t\thashVersion: 2,\n\t\ttype: op.type,\n\t\tcollection: op.collection,\n\t\trecordId: op.recordId,\n\t\tdata: body.data,\n\t\tpreviousData: body.previousData,\n\t\ttimestamp,\n\t\tnodeId: op.nodeId,\n\t\tsequenceNumber: op.sequenceNumber,\n\t\t// A set of parents: their order carries no meaning, so a relay that reorders\n\t\t// them neither breaks verification nor creates a second id for one op.\n\t\tcausalDeps: [...op.causalDeps].sort(),\n\t\tschemaVersion: op.schemaVersion,\n\t\tatomicOps,\n\t}\n}\n\nasync function sha256Hex(canonical: string): Promise<string> {\n\tconst encoded = new TextEncoder().encode(canonical)\n\tconst hashBuffer = await globalThis.crypto.subtle.digest('SHA-256', encoded)\n\treturn bufferToHex(hashBuffer)\n}\n\n/**\n * Deterministic JSON serialization with sorted keys.\n * Ensures identical objects always produce identical strings regardless of property insertion order.\n *\n * @param obj - The value to serialize\n * @returns A deterministic JSON string\n */\nexport function canonicalize(obj: unknown): string {\n\tif (obj === null) {\n\t\treturn 'null'\n\t}\n\n\tif (obj === undefined) {\n\t\treturn 'null'\n\t}\n\n\tif (typeof obj !== 'object') {\n\t\treturn JSON.stringify(obj)\n\t}\n\n\tif (Array.isArray(obj)) {\n\t\tconst items = obj.map((item) => canonicalize(item))\n\t\treturn `[${items.join(',')}]`\n\t}\n\n\tconst keys = Object.keys(obj as Record<string, unknown>).sort()\n\tconst pairs = keys.map((key) => {\n\t\tconst value = (obj as Record<string, unknown>)[key]\n\t\t// Serialize undefined values as null for deterministic output\n\t\treturn `${JSON.stringify(key)}:${canonicalize(value === undefined ? null : value)}`\n\t})\n\treturn `{${pairs.join(',')}}`\n}\n\nfunction bufferToHex(buffer: ArrayBuffer): string {\n\tconst bytes = new Uint8Array(buffer)\n\treturn Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('')\n}\n","import { HybridLogicalClock } from '../clock/hlc'\nimport { OperationError } from '../errors/errors'\nimport type { HLCTimestamp, Operation, OperationInput } from '../types'\nimport { canonicalizeOperationBody } from './canonical-body'\nimport {\n\tDEFAULT_OPERATION_HASH_VERSION,\n\ttype OperationHashVersion,\n\tcomputeOperationId,\n} from './content-hash'\n\n/** Options for {@link createOperation}. */\nexport interface CreateOperationOptions {\n\t/**\n\t * Content-hash version of the new operation's id. Defaults to 2 (protocol v2),\n\t * which commits the id to every semantic field (CORE-1); 1 is the legacy hash.\n\t */\n\thashVersion?: OperationHashVersion\n}\n\n/**\n * Creates an immutable, content-addressed Operation from the given parameters.\n * The operation is deep-frozen after creation — it cannot be modified.\n *\n * @param input - The operation parameters (without id, which is computed)\n * @param clock - The HLC clock to generate the timestamp\n * @param options - Optional hash version (default 2)\n * @returns A frozen Operation with a content-addressed id\n *\n * @example\n * ```typescript\n * const op = await createOperation({\n * nodeId: 'device-1',\n * type: 'insert',\n * collection: 'todos',\n * recordId: 'rec-1',\n * data: { title: 'Ship it' },\n * previousData: null,\n * sequenceNumber: 1,\n * causalDeps: [],\n * schemaVersion: 1,\n * }, clock)\n * ```\n */\nexport async function createOperation(\n\trawInput: OperationInput,\n\tclock: HybridLogicalClock,\n\toptions: CreateOperationOptions = {},\n): Promise<Operation> {\n\tvalidateOperationParams(rawInput)\n\t// One canonical body (canonical-body.ts), applied once, here: the id is computed over\n\t// it and it is what the operation carries, so the hashed content is exactly what the\n\t// op log, the wire and the fold see (RT-72, RT-79, RT-80).\n\tconst input = canonicalizeOperationBody(rawInput)\n\tconst hashVersion = options.hashVersion ?? DEFAULT_OPERATION_HASH_VERSION\n\n\tconst timestamp = clock.now()\n\tconst id =\n\t\thashVersion === 1\n\t\t\t? await computeOperationId(input, HybridLogicalClock.serialize(timestamp))\n\t\t\t: await computeOperationId({ ...input, timestamp }, hashVersion)\n\n\tconst operation: Operation = {\n\t\tid,\n\t\tnodeId: input.nodeId,\n\t\ttype: input.type,\n\t\tcollection: input.collection,\n\t\trecordId: input.recordId,\n\t\tdata: input.data ? { ...input.data } : null,\n\t\tpreviousData: input.previousData ? { ...input.previousData } : null,\n\t\ttimestamp,\n\t\tsequenceNumber: input.sequenceNumber,\n\t\tcausalDeps: [...input.causalDeps],\n\t\tschemaVersion: input.schemaVersion,\n\t\t...(input.atomicOps !== undefined && Object.keys(input.atomicOps).length > 0\n\t\t\t? { atomicOps: { ...input.atomicOps } }\n\t\t\t: {}),\n\t\t...(input.transactionId !== undefined ? { transactionId: input.transactionId } : {}),\n\t\t...(input.mutationName !== undefined ? { mutationName: input.mutationName } : {}),\n\t\t...(hashVersion !== 1 ? { hashVersion } : {}),\n\t}\n\n\treturn deepFreeze(operation)\n}\n\n/**\n * Validates operation input parameters. Throws OperationError with\n * contextual information on validation failure.\n */\nexport function validateOperationParams(input: OperationInput): void {\n\tif (!input.nodeId || typeof input.nodeId !== 'string') {\n\t\tthrow new OperationError('nodeId is required and must be a non-empty string', {\n\t\t\treceived: input.nodeId,\n\t\t})\n\t}\n\n\tif (!input.type || !['insert', 'update', 'delete'].includes(input.type)) {\n\t\tthrow new OperationError('type must be \"insert\", \"update\", or \"delete\"', {\n\t\t\treceived: input.type,\n\t\t})\n\t}\n\n\tif (!input.collection || typeof input.collection !== 'string') {\n\t\tthrow new OperationError('collection is required and must be a non-empty string', {\n\t\t\treceived: input.collection,\n\t\t})\n\t}\n\n\tif (!input.recordId || typeof input.recordId !== 'string') {\n\t\tthrow new OperationError('recordId is required and must be a non-empty string', {\n\t\t\treceived: input.recordId,\n\t\t})\n\t}\n\n\tif (input.type === 'insert' && input.data === null) {\n\t\tthrow new OperationError('insert operations must include data', {\n\t\t\ttype: input.type,\n\t\t\tcollection: input.collection,\n\t\t})\n\t}\n\n\tif (input.type === 'update' && input.data === null) {\n\t\tthrow new OperationError('update operations must include data with changed fields', {\n\t\t\ttype: input.type,\n\t\t\tcollection: input.collection,\n\t\t})\n\t}\n\n\tif (input.type === 'update' && input.previousData === null) {\n\t\tthrow new OperationError(\n\t\t\t'update operations must include previousData for 3-way merge support',\n\t\t\t{\n\t\t\t\ttype: input.type,\n\t\t\t\tcollection: input.collection,\n\t\t\t},\n\t\t)\n\t}\n\n\tif (input.type === 'delete' && input.data !== null) {\n\t\tthrow new OperationError('delete operations must have null data', {\n\t\t\ttype: input.type,\n\t\t\tcollection: input.collection,\n\t\t})\n\t}\n\n\tif (typeof input.sequenceNumber !== 'number' || input.sequenceNumber < 0) {\n\t\tthrow new OperationError('sequenceNumber must be a non-negative number', {\n\t\t\treceived: input.sequenceNumber,\n\t\t})\n\t}\n\n\tif (!Array.isArray(input.causalDeps)) {\n\t\tthrow new OperationError('causalDeps must be an array of operation IDs', {\n\t\t\treceived: typeof input.causalDeps,\n\t\t})\n\t}\n\n\tif (typeof input.schemaVersion !== 'number' || input.schemaVersion < 1) {\n\t\tthrow new OperationError('schemaVersion must be a positive number', {\n\t\t\treceived: input.schemaVersion,\n\t\t})\n\t}\n}\n\n/**\n * Verify an operation's id against its content, using the hash version the\n * operation declares (`hashVersion`, absent = 1). A version-1 id does not cover\n * previousData, sequenceNumber, causalDeps or schemaVersion (CORE-1), so only a\n * version-2 operation is protected against rewriting those.\n *\n * Returns false for an unknown hash version.\n *\n * @param op - The operation to verify\n * @returns true when `op.id` is the content hash of `op`\n */\nexport async function verifyOperationId(op: Operation): Promise<boolean> {\n\tconst version = op.hashVersion ?? 1\n\tif (version !== 1 && version !== 2) return false\n\tlet expectedId: string\n\ttry {\n\t\texpectedId = await computeOperationId(\n\t\t\t{\n\t\t\t\tnodeId: op.nodeId,\n\t\t\t\ttype: op.type,\n\t\t\t\tcollection: op.collection,\n\t\t\t\trecordId: op.recordId,\n\t\t\t\tdata: op.data,\n\t\t\t\tpreviousData: op.previousData,\n\t\t\t\ttimestamp: op.timestamp,\n\t\t\t\tsequenceNumber: op.sequenceNumber,\n\t\t\t\tcausalDeps: op.causalDeps,\n\t\t\t\tschemaVersion: op.schemaVersion,\n\t\t\t\t...(op.atomicOps !== undefined ? { atomicOps: op.atomicOps } : {}),\n\t\t\t},\n\t\t\tversion,\n\t\t)\n\t} catch {\n\t\t// A body with no canonical form (never produced by createOperation, never\n\t\t// decoded from JSON) cannot be the content of any id.\n\t\treturn false\n\t}\n\treturn op.id === expectedId\n}\n\n/**\n * Verify the integrity of an operation by recomputing its content hash.\n * Returns true if the id matches the recomputed hash. Same as\n * {@link verifyOperationId}.\n */\nexport async function verifyOperationIntegrity(op: Operation): Promise<boolean> {\n\treturn verifyOperationId(op)\n}\n\n/**\n * Type guard for Operation interface.\n */\nexport function isValidOperation(value: unknown): value is Operation {\n\tif (typeof value !== 'object' || value === null) return false\n\tconst op = value as Record<string, unknown>\n\treturn (\n\t\ttypeof op.id === 'string' &&\n\t\ttypeof op.nodeId === 'string' &&\n\t\t(op.type === 'insert' || op.type === 'update' || op.type === 'delete') &&\n\t\ttypeof op.collection === 'string' &&\n\t\ttypeof op.recordId === 'string' &&\n\t\ttypeof op.sequenceNumber === 'number' &&\n\t\tArray.isArray(op.causalDeps) &&\n\t\ttypeof op.schemaVersion === 'number' &&\n\t\ttypeof op.timestamp === 'object' &&\n\t\top.timestamp !== null\n\t)\n}\n\nfunction deepFreeze<T>(obj: T): T {\n\tif (typeof obj !== 'object' || obj === null) return obj\n\t// Typed arrays (e.g. richtext Yjs blobs) cannot be frozen in JS engines.\n\tif (ArrayBuffer.isView(obj)) return obj\n\tObject.freeze(obj)\n\tfor (const value of Object.values(obj)) {\n\t\tif (typeof value === 'object' && value !== null && !Object.isFrozen(value)) {\n\t\t\tdeepFreeze(value)\n\t\t}\n\t}\n\treturn obj\n}\n","import { KoraError } from '../errors/errors'\nimport type { AtomicOp, Operation, OperationInput } from '../types'\nimport { bytesToBase64 } from './op-data-binary'\nimport { verifyOperationId } from './operation'\n\n/**\n * Thrown when an operation (or a record value) holds a value that has no canonical\n * JSON form: the op log and the wire are JSON, so such a value would be stored and\n * synced as something other than what was written and hashed.\n */\nexport class NonCanonicalValueError extends KoraError {\n\tconstructor(\n\t\tmessage: string,\n\t\tpublic readonly path: string,\n\t\tpublic readonly receivedType: string,\n\t) {\n\t\tsuper(message, 'NON_CANONICAL_VALUE', { path, receivedType })\n\t\tthis.name = 'NonCanonicalValueError'\n\t}\n}\n\n/**\n * The one canonical form of an operation body (RT-72 family: RT-79, RT-80, RT-83).\n *\n * The op log, the wire (JSON and protobuf, whose data is JSON) and every store hold an\n * operation as JSON. An operation's id is a hash of its body. So the body is put in its\n * canonical form ONCE, when the operation is created (and when a legacy operation is\n * ingested or rebuilt), and the canonical body is what is hashed, stored, sent and\n * folded: the four can never disagree, by construction.\n *\n * | Value | Canonical form |\n * |-----------------------------------------|-------------------------------------------------|\n * | `undefined` member of an insert's data | absent |\n * | `undefined` member of an update's data | `null`: the field is CLEARED (beta.12 meaning) |\n * | `undefined` member of an update's `previousData` | `null` (the field held no value) |\n * | `undefined` member inside an object value | absent (as JSON drops it); a `t.json()` field refuses it at validation |\n * | `undefined` array element | `null` (as JSON writes it) |\n * | `undefined` atomic op | absent |\n * | `-0` | `0` (JSON writes `0`) |\n * | valid `Date` | its ISO 8601 string (`toISOString()`), as JSON |\n * | `Uint8Array` / `ArrayBuffer` | `{ $koraBytes: <base64> }` (the op-log binary form) |\n * | plain object (`Object.prototype` or `null` prototype) | plain object, members canonical |\n * | array (dense) | array, elements canonical |\n * | string, finite number, boolean, `null` | itself |\n * | invalid `Date`, `NaN`, `±Infinity`, `BigInt`, function, symbol, `Map`, `Set`, `WeakMap`, `RegExp`, `Promise`, any other class instance, an object with a `toJSON` method, an own `__proto__` key, a circular reference | refused: {@link NonCanonicalValueError} naming the path and the fix |\n *\n * Canonicalization is idempotent: a canonical body is returned unchanged (same\n * references where nothing changed).\n *\n * @param input - The operation body (as given to `createOperation`, or a stored operation)\n * @returns The body with `data`, `previousData` and `atomicOps` canonical\n * @throws {NonCanonicalValueError} For a value with no canonical form\n */\nexport function canonicalizeOperationBody<T extends CanonicalizableBody>(input: T): T {\n\tconst isUpdate = input.type === 'update'\n\tconst where = `${input.collection}/${input.recordId}`\n\tconst data = canonicalTopLevel(input.data, isUpdate, 'data', where)\n\tconst previousData = canonicalTopLevel(input.previousData, isUpdate, 'previousData', where)\n\tlet atomicOps = input.atomicOps\n\tif (atomicOps !== undefined) {\n\t\tconst canonical = canonicalTopLevel(\n\t\t\tatomicOps as Record<string, unknown>,\n\t\t\tfalse,\n\t\t\t'atomicOps',\n\t\t\twhere,\n\t\t) as Record<string, AtomicOp> | null\n\t\tatomicOps = canonical ?? undefined\n\t}\n\tif (data === input.data && previousData === input.previousData && atomicOps === input.atomicOps) {\n\t\treturn input\n\t}\n\treturn {\n\t\t...input,\n\t\tdata,\n\t\tpreviousData,\n\t\t...(atomicOps !== undefined ? { atomicOps } : {}),\n\t}\n}\n\n/** The members of an operation body that {@link canonicalizeOperationBody} reads. */\nexport interface CanonicalizableBody {\n\ttype: OperationInput['type']\n\tcollection: string\n\trecordId: string\n\tdata: Record<string, unknown> | null\n\tpreviousData: Record<string, unknown> | null\n\tatomicOps?: Record<string, AtomicOp>\n}\n\n/**\n * The canonical form of one value inside an operation body or a record field (see\n * {@link canonicalizeOperationBody} for the table). Exported so schema validation\n * produces exactly the values an operation will carry.\n *\n * @param value - Any value\n * @param path - Where the value is, for the error message (e.g. `notes.extra.when`)\n * @returns The canonical value (the same reference when it already is)\n * @throws {NonCanonicalValueError} For a value with no canonical form\n */\nexport function canonicalValue(value: unknown, path: string): unknown {\n\treturn canonical(value, path, new Set())\n}\n\nfunction canonicalTopLevel(\n\trecord: Record<string, unknown> | null,\n\tundefinedIsNull: boolean,\n\tlabel: string,\n\twhere: string,\n): Record<string, unknown> | null {\n\tif (record === null || record === undefined) return null\n\tif (!isPlainObject(record)) {\n\t\tthrow new NonCanonicalValueError(\n\t\t\t`Operation ${label} of ${where} must be a plain object, got ${describe(record)}.`,\n\t\t\tlabel,\n\t\t\tdescribe(record),\n\t\t)\n\t}\n\tlet changed = false\n\tconst out: Record<string, unknown> = {}\n\tfor (const [key, member] of Object.entries(record)) {\n\t\tif (member === undefined) {\n\t\t\tchanged = true\n\t\t\t// In an update, `field: undefined` is a clear (as beta.12 applied it); the\n\t\t\t// canonical form says so explicitly. Elsewhere it is simply absent.\n\t\t\tif (undefinedIsNull) out[key] = null\n\t\t\tcontinue\n\t\t}\n\t\tconst next = canonical(member, `${where}.${key}`, new Set())\n\t\tif (!Object.is(next, member)) changed = true\n\t\tout[key] = next\n\t}\n\tif (Object.getPrototypeOf(record) !== Object.prototype) changed = true\n\treturn changed ? out : record\n}\n\nfunction canonical(value: unknown, path: string, ancestors: Set<object>): unknown {\n\tswitch (typeof value) {\n\t\tcase 'string':\n\t\tcase 'boolean':\n\t\t\treturn value\n\t\tcase 'number':\n\t\t\tif (!Number.isFinite(value)) {\n\t\t\t\tthrow refusal(path, String(value), 'Use a finite number, or null for \"no value\".')\n\t\t\t}\n\t\t\treturn Object.is(value, -0) ? 0 : value\n\t\tcase 'undefined':\n\t\t\t// Only reachable for array elements and the top level (members are handled by\n\t\t\t// the caller): JSON writes an undefined array element as null.\n\t\t\treturn null\n\t\tcase 'bigint':\n\t\t\tthrow refusal(path, 'bigint', 'Convert it to a number or a string.')\n\t\tcase 'function':\n\t\t\tthrow refusal(path, 'function', 'Store data only, not functions.')\n\t\tcase 'symbol':\n\t\t\tthrow refusal(path, 'symbol', 'Use a string instead.')\n\t}\n\tif (value === null) return null\n\tconst object = value as object\n\tif (object instanceof Uint8Array) return { $koraBytes: bytesToBase64(object) }\n\tif (object instanceof ArrayBuffer) return { $koraBytes: bytesToBase64(new Uint8Array(object)) }\n\tif (object instanceof Date) {\n\t\tconst time = object.getTime()\n\t\tif (Number.isNaN(time)) {\n\t\t\tthrow refusal(path, 'invalid Date', 'Pass a valid Date, or null.')\n\t\t}\n\t\treturn object.toISOString()\n\t}\n\tif (ancestors.has(object)) {\n\t\tthrow refusal(path, 'circular reference', 'Remove the cycle: JSON cannot hold it.')\n\t}\n\tif (Array.isArray(object)) {\n\t\tancestors.add(object)\n\t\tlet changed = false\n\t\tconst out: unknown[] = []\n\t\tfor (let index = 0; index < object.length; index++) {\n\t\t\tif (!(index in object)) {\n\t\t\t\tancestors.delete(object)\n\t\t\t\tthrow refusal(\n\t\t\t\t\t`${path}[${String(index)}]`,\n\t\t\t\t\t'array hole',\n\t\t\t\t\t'Use a dense array (fill the gap with null).',\n\t\t\t\t)\n\t\t\t}\n\t\t\tconst item = object[index]\n\t\t\tconst next = canonical(item, `${path}[${String(index)}]`, ancestors)\n\t\t\tif (!Object.is(next, item)) changed = true\n\t\t\tout.push(next)\n\t\t}\n\t\tancestors.delete(object)\n\t\treturn changed ? out : object\n\t}\n\tif (!isPlainObject(object)) {\n\t\tconst type = describe(object)\n\t\tthrow refusal(\n\t\t\tpath,\n\t\t\ttype,\n\t\t\ttype === 'Map'\n\t\t\t\t? 'Convert it with Object.fromEntries(map).'\n\t\t\t\t: type === 'Set'\n\t\t\t\t\t? 'Convert it with [...set].'\n\t\t\t\t\t: 'Convert it to a plain object (JSON data only).',\n\t\t)\n\t}\n\tif (typeof (object as { toJSON?: unknown }).toJSON === 'function') {\n\t\tthrow refusal(path, 'object with toJSON', 'Store the value toJSON() returns instead.')\n\t}\n\t// JSON can carry an own \"__proto__\" key, but assigning it to an object sets the\n\t// prototype instead, so it would be lost on some replicas (the fold, any object\n\t// rebuilt by assignment). Refused everywhere, never silently dropped.\n\tif (Object.prototype.hasOwnProperty.call(object, '__proto__')) {\n\t\tthrow refusal(`${path}.__proto__`, '\"__proto__\" key', 'Rename the key.')\n\t}\n\tancestors.add(object)\n\tlet changed = Object.getPrototypeOf(object) !== Object.prototype\n\tconst out: Record<string, unknown> = {}\n\tfor (const [key, member] of Object.entries(object)) {\n\t\tif (member === undefined) {\n\t\t\tchanged = true\n\t\t\tcontinue\n\t\t}\n\t\tconst next = canonical(member, `${path}.${key}`, ancestors)\n\t\tif (!Object.is(next, member)) changed = true\n\t\tout[key] = next\n\t}\n\tancestors.delete(object)\n\treturn changed ? out : object\n}\n\nfunction refusal(path: string, receivedType: string, fix: string): NonCanonicalValueError {\n\treturn new NonCanonicalValueError(\n\t\t`Value at \"${path}\" (${receivedType}) has no JSON form, so it cannot be stored or synced unchanged. ${fix}`,\n\t\tpath,\n\t\treceivedType,\n\t)\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n\tif (value === null || typeof value !== 'object' || Array.isArray(value)) return false\n\tconst proto = Object.getPrototypeOf(value)\n\treturn proto === Object.prototype || proto === null\n}\n\nfunction describe(value: unknown): string {\n\tif (value === null) return 'null'\n\tif (Array.isArray(value)) return 'array'\n\tif (typeof value !== 'object') return typeof value\n\tconst ctor = (value as { constructor?: { name?: unknown } }).constructor\n\treturn typeof ctor?.name === 'string' && ctor.name.length > 0 ? ctor.name : 'object'\n}\n\n/**\n * A legacy update in its canonical body when its id PROVES the beta.12 clear (RT-85):\n * the id is the content hash of the body with every `previousData` key absent from\n * `data` restored as `null` (version 1, or version 2 with a lost declaration), and not\n * of the body as it is. Such an id can only come from a writer that hashed the clear,\n * so the restored body is the one its author wrote and applied; a body a schema\n * transform or anything else rewrote never proves it.\n *\n * Used where a legacy body enters a replica without a known provenance: a device's\n * inbound delivery, and the one-time canonicalization of stored logs. The server's\n * ingest of a protocol-1 upload applies the same rule (plus the unverifiable\n * protocol-1 case, for the session's own node).\n *\n * @param op - Any operation\n * @returns The canonical operation, or `op` itself when nothing is proven\n */\nexport async function canonicalizeProvenLegacyClear<T extends Operation>(op: T): Promise<T> {\n\tconst restored = canonicalizeLegacyOperation(op)\n\tif (restored === op) return op\n\tif (await verifyOperationId(op)) return op\n\tif (await verifyOperationId(restored)) return restored\n\tif (op.hashVersion === undefined && (await verifyOperationId({ ...restored, hashVersion: 2 }))) {\n\t\treturn restored\n\t}\n\treturn op\n}\n\n/**\n * The canonical body of a legacy (version-1, beta.12) update (RT-71, RT-83): every\n * `previousData` key absent from `data` is a clear, restored as `null`. beta.12 wrote\n * `previousData[key]` for every key it validated, so such a key held `undefined` in\n * `data`: beta.12 hashed it as `null`, applied it as a cleared field, and its JSON log\n * and upload dropped it. `null` and `undefined` hash identically under version 1, so\n * the id is unchanged.\n *\n * Applied ONCE, where a genuine beta.12 body is identified (RT-85), never at fold time:\n * the server's ingest of a protocol-1 upload, a device's own beta.12 log at the\n * upgrade, and any body whose id proves the clear\n * ({@link canonicalizeProvenLegacyClear}). The result is stored, so the server, peers\n * and the upgraded writer fold the same body. A no-op\n * for anything else (a declared version 2, an envelope, an insert or delete, an update\n * whose data covers its previousData). Idempotent.\n *\n * @param op - Any operation\n * @returns The operation with the restored data, or `op` itself\n */\nexport function canonicalizeLegacyOperation<T extends LegacyBody>(op: T): T {\n\tif (op.type !== 'update' || op.hashVersion === 2 || op.encrypted !== undefined) return op\n\tconst previous = op.previousData\n\tif (previous === null || previous === undefined) return op\n\tconst data = op.data ?? {}\n\tconst missing = Object.keys(previous).filter((key) => !(key in data))\n\tif (missing.length === 0) return op\n\tconst out: Record<string, unknown> = { ...data }\n\tfor (const key of missing) out[key] = null\n\treturn { ...op, data: out }\n}\n\n/** The members of an operation {@link canonicalizeLegacyOperation} reads. */\nexport interface LegacyBody {\n\ttype: Operation['type']\n\tdata: Record<string, unknown> | null\n\tpreviousData: Record<string, unknown> | null\n\thashVersion?: Operation['hashVersion']\n\tencrypted?: Operation['encrypted']\n}\n","import type { CollectionDefinition, CustomResolver } from '../types'\nimport type { FoldFieldKind } from './types'\n\n/** How the fold merges one field, derived from the schema. */\nexport interface FieldPlan {\n\tkind: FoldFieldKind\n\t/** For 'set': removals are ignored (`merge('append-only')`). */\n\tappendOnly: boolean\n\t/** For 'res': the custom resolver. */\n\tresolver?: CustomResolver\n\t/** Name of the strategy for traces. */\n\tstrategy: string\n\t/** Tier for traces: 3 for custom resolvers, 1 otherwise. */\n\ttier: 1 | 3\n\t/** Secret field: values are redacted from traces. */\n\tsecret: boolean\n\t/** `merge('server-authoritative')`: writes of authoritative nodes win (class 1 stamps). */\n\tauthoritative?: boolean\n}\n\nconst LWW_PLAN: FieldPlan = {\n\tkind: 'reg',\n\tappendOnly: false,\n\tstrategy: 'lww',\n\ttier: 1,\n\tsecret: false,\n}\n\n/**\n * Decide how a field is folded. Precedence matches the pairwise engine it\n * replaces: a custom resolver (tier 3), then a schema-declared merge strategy,\n * then the field kind's default.\n *\n * | Schema | Fold kind |\n * |---|---|\n * | `resolve: { field }` | 'res' (resolver over the write log) |\n * | `merge('counter')` | 'ctr' (base + deltas) |\n * | `merge('max')` / `merge('min')` | 'max' / 'min' |\n * | array, `merge('append-only')` | 'set' with removals ignored |\n * | array (default or `merge('union')`) | 'set' (LWW element set) |\n * | object / json | 'map' (per-top-level-key LWW) |\n * | richtext | 'rt' (Yjs updates + string reset register) |\n * | `merge('server-authoritative')` | 'reg' with authority-classed stamps |\n * | everything else, `merge('lww')` | 'reg' |\n *\n * A field that is not in the schema (an older schema version's field, or an\n * unknown collection) folds as a last-write-wins register.\n *\n * @param collection - The collection definition, if the schema has it\n * @param field - The field name\n */\nexport function planField(collection: CollectionDefinition | undefined, field: string): FieldPlan {\n\tconst descriptor = collection?.fields[field]\n\tconst secret = descriptor?.kind === 'secret'\n\tconst resolver = collection?.resolvers?.[field]\n\tif (resolver) {\n\t\treturn { kind: 'res', appendOnly: false, resolver, strategy: 'custom', tier: 3, secret }\n\t}\n\tif (!descriptor) return LWW_PLAN\n\tswitch (descriptor.mergeStrategy) {\n\t\tcase 'counter':\n\t\t\treturn { kind: 'ctr', appendOnly: false, strategy: 'schema-counter', tier: 1, secret }\n\t\tcase 'max':\n\t\t\treturn { kind: 'max', appendOnly: false, strategy: 'schema-max', tier: 1, secret }\n\t\tcase 'min':\n\t\t\treturn { kind: 'min', appendOnly: false, strategy: 'schema-min', tier: 1, secret }\n\t\tcase 'append-only':\n\t\t\tif (descriptor.kind === 'array') {\n\t\t\t\treturn {\n\t\t\t\t\tkind: 'set',\n\t\t\t\t\tappendOnly: true,\n\t\t\t\t\tstrategy: 'schema-append-only',\n\t\t\t\t\ttier: 1,\n\t\t\t\t\tsecret,\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn { ...LWW_PLAN, secret }\n\t\tcase 'lww':\n\t\t\treturn { ...LWW_PLAN, secret }\n\t\tcase 'server-authoritative':\n\t\t\t// A register whose writes from authoritative nodes (FoldOptions.\n\t\t\t// authoritativeNodeIds: the server's node ids) beat every other write,\n\t\t\t// whatever their HLC. Within a class, last write wins.\n\t\t\treturn {\n\t\t\t\t...LWW_PLAN,\n\t\t\t\tstrategy: 'schema-server-authoritative',\n\t\t\t\tsecret,\n\t\t\t\tauthoritative: true,\n\t\t\t}\n\t\tdefault:\n\t\t\tbreak\n\t}\n\tswitch (descriptor.kind) {\n\t\tcase 'array':\n\t\t\treturn { kind: 'set', appendOnly: false, strategy: 'lww-element-set', tier: 1, secret }\n\t\tcase 'object':\n\t\tcase 'json':\n\t\t\treturn { kind: 'map', appendOnly: false, strategy: 'object-key-lww', tier: 1, secret }\n\t\tcase 'richtext':\n\t\t\treturn { kind: 'rt', appendOnly: false, strategy: 'crdt-text', tier: 1, secret }\n\t\tdefault:\n\t\t\treturn { ...LWW_PLAN, secret }\n\t}\n}\n","import { HybridLogicalClock } from '../clock/hlc'\nimport type { HLCTimestamp } from '../types'\nimport type { Stamp } from './types'\n\n/**\n * Total order on stamps: authority class (only `merge('server-authoritative')`\n * fields carry one), then serialized HLC (which sorts exactly like\n * `HybridLogicalClock.compare`), then operation id.\n *\n * @returns Negative if a < b, positive if a > b, 0 if equal\n */\nexport function compareStamps(a: Stamp, b: Stamp): number {\n\tconst ca = a.c ?? 0\n\tconst cb = b.c ?? 0\n\tif (ca !== cb) return ca - cb\n\tif (a.t !== b.t) return a.t < b.t ? -1 : 1\n\tif (a.o !== b.o) return a.o < b.o ? -1 : 1\n\treturn 0\n}\n\n/** The later of two stamps (null counts as \"never\"). */\nexport function maxStamp(a: Stamp | null, b: Stamp | null): Stamp | null {\n\tif (a === null) return b\n\tif (b === null) return a\n\treturn compareStamps(a, b) >= 0 ? a : b\n}\n\n/** The earlier of two stamps (null counts as \"never\"). */\nexport function minStamp(a: Stamp | null, b: Stamp | null): Stamp | null {\n\tif (a === null) return b\n\tif (b === null) return a\n\treturn compareStamps(a, b) <= 0 ? a : b\n}\n\n/** True when `a` is strictly later than `b` (anything is later than null). */\nexport function isAfter(a: Stamp | null, b: Stamp | null): boolean {\n\tif (a === null) return false\n\tif (b === null) return true\n\treturn compareStamps(a, b) > 0\n}\n\n/**\n * Build a stamp from an HLC timestamp and an operation id. Throws\n * `InvalidTimestampError` for a timestamp that cannot be serialized (for example\n * a null wallTime left by a beta.12 backup restore): such an op must be repaired\n * by the log-integrity scan (W8) before it is folded, never folded with a guess.\n */\nexport function stampOf(timestamp: HLCTimestamp, opId: string): Stamp {\n\treturn { t: HybridLogicalClock.serialize(timestamp), o: opId }\n}\n\n/** The HLC timestamp a stamp was built from. */\nexport function stampTimestamp(stamp: Stamp): HLCTimestamp {\n\treturn HybridLogicalClock.deserialize(stamp.t)\n}\n","/**\n * Quote a SQL identifier (table or column name) for safe interpolation into\n * generated SQL.\n *\n * Uses standard double-quote quoting, which both SQLite and PostgreSQL honor,\n * and doubles any embedded double-quote per the SQL standard. Quoting is what\n * lets a valid JavaScript identifier — camelCase (`formResponses`), PascalCase\n * (`UserProfiles`), or a word that happens to be a SQL keyword (`order`,\n * `select`) — round-trip through generated DDL and queries without ever\n * producing invalid or ambiguous SQL.\n *\n * Schema validation (see `validateCollectionName` / `validateFieldName`)\n * already restricts identifiers to `[A-Za-z][A-Za-z0-9_]*`, so the escape here\n * never actually fires in practice; it is defense in depth so this helper is\n * correct for any input rather than only for pre-validated names.\n *\n * Consistency is the contract: every path that emits an identifier for a\n * user-defined collection or field MUST go through this helper, because a\n * quoted `CREATE TABLE \"order\"` paired with an unquoted `SELECT ... FROM order`\n * would reintroduce the exact keyword-collision bug this guards against.\n *\n * @param name - The raw identifier (collection name, field/column name).\n * @returns The identifier wrapped in double quotes, ready to splice into SQL.\n *\n * @example\n * ```typescript\n * quoteIdent('formResponses') // => '\"formResponses\"'\n * quoteIdent('order') // => '\"order\"'\n * ```\n */\nexport function quoteIdent(name: string): string {\n\treturn `\"${name.replace(/\"/g, '\"\"')}\"`\n}\n","import type {\n\tCollectionDefinition,\n\tFieldDescriptor,\n\tRelationDefinition,\n\tSchemaDefinition,\n} from '../types'\nimport { quoteIdent } from './quote-ident'\n\n/**\n * Generate CREATE TABLE and CREATE INDEX SQL for a single collection.\n *\n * @param collectionName - The collection name\n * @param collection - The collection definition\n * @param relations - Optional relations for FK references\n * @returns An array of SQL statements (CREATE TABLE + CREATE INDEX)\n */\nexport function generateSQL(\n\tcollectionName: string,\n\tcollection: CollectionDefinition,\n\trelations?: Record<string, RelationDefinition>,\n): string[] {\n\tconst statements: string[] = []\n\tconst columns: string[] = ['id TEXT PRIMARY KEY NOT NULL']\n\n\t// Track which fields already have indexes\n\tconst indexedFields = new Set(collection.indexes)\n\n\t// Collect FK fields for auto-indexing\n\tconst fkFields: string[] = []\n\n\tfor (const [fieldName, descriptor] of Object.entries(collection.fields)) {\n\t\tlet colDef = columnDefinition(fieldName, descriptor)\n\n\t\t// Add FK reference if a relation exists for this field\n\t\tif (relations) {\n\t\t\tfor (const rel of Object.values(relations)) {\n\t\t\t\tif (rel.from === collectionName && rel.field === fieldName) {\n\t\t\t\t\tcolDef += ` REFERENCES ${quoteIdent(rel.to)}(id)`\n\t\t\t\t\tfkFields.push(fieldName)\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tcolumns.push(colDef)\n\t}\n\n\t// Auto metadata columns\n\tcolumns.push('_created_at INTEGER NOT NULL')\n\tcolumns.push('_updated_at INTEGER NOT NULL')\n\tcolumns.push(\"_version TEXT NOT NULL DEFAULT ''\")\n\t// Per-field last-writer HLC versions (JSON: { field -> serialized HLC }).\n\t// Enables deterministic, order-independent field-level LWW so concurrent\n\t// edits to different fields of one record never clobber each other and\n\t// same-field conflicts converge to the max-timestamp writer on every node.\n\tcolumns.push(\"_field_versions TEXT NOT NULL DEFAULT '{}'\")\n\tcolumns.push('_deleted INTEGER NOT NULL DEFAULT 0')\n\n\tstatements.push(\n\t\t`CREATE TABLE IF NOT EXISTS ${quoteIdent(collectionName)} (\\n ${columns.join(',\\n ')}\\n)`,\n\t)\n\n\t// Add ALTER TABLE statements so new columns are added to existing tables.\n\t// These are tagged with --kora:safe-alter so the runtime can ignore \"duplicate column\" errors.\n\tfor (const [fieldName, descriptor] of Object.entries(collection.fields)) {\n\t\tconst colDef = columnDefinition(fieldName, descriptor)\n\t\tstatements.push(\n\t\t\t`--kora:safe-alter\\nALTER TABLE ${quoteIdent(collectionName)} ADD COLUMN ${colDef}`,\n\t\t)\n\t}\n\tstatements.push(\n\t\t`--kora:safe-alter\\nALTER TABLE ${quoteIdent(collectionName)} ADD COLUMN _version TEXT NOT NULL DEFAULT ''`,\n\t)\n\tstatements.push(\n\t\t`--kora:safe-alter\\nALTER TABLE ${quoteIdent(collectionName)} ADD COLUMN _field_versions TEXT NOT NULL DEFAULT '{}'`,\n\t)\n\n\t// Create indexes. Names come from collectionIndexName, which cannot collide\n\t// across collections (STORE-15); table and column are quoted so mixed-case /\n\t// keyword names resolve correctly.\n\tfor (const indexField of collection.indexes) {\n\t\tstatements.push(\n\t\t\t`CREATE INDEX IF NOT EXISTS ${quoteIdent(collectionIndexName(collectionName, indexField))} ON ${quoteIdent(collectionName)} (${quoteIdent(indexField)})`,\n\t\t)\n\t}\n\n\t// Auto-create indexes on FK columns not already indexed\n\tfor (const fkField of fkFields) {\n\t\tif (!indexedFields.has(fkField)) {\n\t\t\tstatements.push(\n\t\t\t\t`CREATE INDEX IF NOT EXISTS ${quoteIdent(collectionIndexName(collectionName, fkField))} ON ${quoteIdent(collectionName)} (${quoteIdent(fkField)})`,\n\t\t\t)\n\t\t}\n\t}\n\n\t// Per-collection operations log table. The table name carries the collection\n\t// name, so it is quoted too (a collection named `order` would otherwise make\n\t// `_kora_ops_order` collide with reserved-word handling on some engines).\n\tstatements.push(\n\t\t`CREATE TABLE IF NOT EXISTS ${quoteIdent(`_kora_ops_${collectionName}`)} (\n id TEXT PRIMARY KEY NOT NULL,\n node_id TEXT NOT NULL,\n type TEXT NOT NULL,\n record_id TEXT NOT NULL,\n data TEXT,\n previous_data TEXT,\n timestamp TEXT NOT NULL,\n sequence_number INTEGER NOT NULL,\n causal_deps TEXT NOT NULL,\n schema_version INTEGER NOT NULL\n)`,\n\t)\n\t// Record-scoped lookups run on every remote apply (latest-op-for-record,\n\t// orphaned-op fold on out-of-order inserts) — index them.\n\tstatements.push(\n\t\t`CREATE INDEX IF NOT EXISTS idx_kora_ops_${collectionName}_record_id ON ${quoteIdent(`_kora_ops_${collectionName}`)} (record_id)`,\n\t)\n\n\treturn statements\n}\n\n/**\n * Name of the index on `field` of `collection`.\n *\n * The collection name's length is part of the name, so two (collection, field)\n * pairs can never produce the same index name. The previous scheme,\n * `idx_<collection>_<field>`, gave `a_b`.`c` and `a`.`b_c` the same name, and the\n * second `CREATE INDEX IF NOT EXISTS` silently did nothing (STORE-15).\n *\n * @param collection - Collection (table) name\n * @param field - Indexed field (column) name\n * @returns A collision-free index name\n */\nexport function collectionIndexName(collection: string, field: string): string {\n\treturn `idx_${collection.length}_${collection}_${field}`\n}\n\n/**\n * Name the pre-beta.13 scheme gave the index on `field` of `collection`. Only\n * used to find and drop those indexes once their replacements exist.\n */\nexport function legacyCollectionIndexName(collection: string, field: string): string {\n\treturn `idx_${collection}_${field}`\n}\n\n/**\n * Prefix of the `generateFullDDL` statement `--kora:schema-ceiling <version>` (RT-109).\n * It is a SQL comment, so executing it does nothing; Kora's storage adapters read the\n * database's stored schema version there and refuse to run the rest of the DDL against a\n * database a newer build already migrated.\n */\nexport const SCHEMA_CEILING_DIRECTIVE = '--kora:schema-ceiling'\n\n/**\n * Generate the full DDL for all collections plus metadata tables.\n *\n * @param schema - The complete schema definition\n * @returns An array of all SQL statements needed to initialize the database\n */\nexport function generateFullDDL(schema: SchemaDefinition): string[] {\n\tconst statements: string[] = []\n\n\t// Metadata table\n\tstatements.push(\n\t\t'CREATE TABLE IF NOT EXISTS _kora_meta (\\n' +\n\t\t\t' key TEXT PRIMARY KEY NOT NULL,\\n' +\n\t\t\t' value TEXT NOT NULL\\n' +\n\t\t\t')',\n\t)\n\t// A SQL comment (a no-op for any executor): Kora's storage adapters refuse here, before\n\t// any other DDL touches it, a database whose stored schema version is newer than this\n\t// schema's (a newer build already migrated it, RT-109).\n\tstatements.push(`${SCHEMA_CEILING_DIRECTIVE} ${schema.version}`)\n\n\t// Version vector table\n\tstatements.push(\n\t\t'CREATE TABLE IF NOT EXISTS _kora_version_vector (\\n' +\n\t\t\t' node_id TEXT PRIMARY KEY NOT NULL,\\n' +\n\t\t\t' sequence_number INTEGER NOT NULL\\n' +\n\t\t\t')',\n\t)\n\n\t// Sequence counters table (offline-safe sequences)\n\tstatements.push(\n\t\t'CREATE TABLE IF NOT EXISTS _kora_sequences (\\n' +\n\t\t\t' name TEXT NOT NULL,\\n' +\n\t\t\t\" scope TEXT NOT NULL DEFAULT '',\\n\" +\n\t\t\t' node_id TEXT NOT NULL,\\n' +\n\t\t\t' counter INTEGER NOT NULL DEFAULT 0,\\n' +\n\t\t\t' PRIMARY KEY (name, scope, node_id)\\n' +\n\t\t\t')',\n\t)\n\n\t// Durable outbound sync queue (survives page refresh)\n\tstatements.push(\n\t\t'CREATE TABLE IF NOT EXISTS _kora_sync_queue (\\n' +\n\t\t\t' id TEXT PRIMARY KEY NOT NULL,\\n' +\n\t\t\t' payload TEXT NOT NULL\\n' +\n\t\t\t')',\n\t)\n\n\t// Durable record of operations the server rejected (survives page refresh).\n\t// An op lands here after being diverted out of the outbound queue, so it is\n\t// never retried yet stays explainable to the app until reconciled.\n\tstatements.push(\n\t\t'CREATE TABLE IF NOT EXISTS _kora_sync_rejected (\\n' +\n\t\t\t' operation_id TEXT PRIMARY KEY NOT NULL,\\n' +\n\t\t\t' collection TEXT NOT NULL,\\n' +\n\t\t\t' record_id TEXT NOT NULL,\\n' +\n\t\t\t' code TEXT NOT NULL,\\n' +\n\t\t\t' message TEXT NOT NULL,\\n' +\n\t\t\t' retriable INTEGER NOT NULL,\\n' +\n\t\t\t' rejected_at INTEGER NOT NULL\\n' +\n\t\t\t')',\n\t)\n\n\t// Durable merge / constraint audit trail (enterprise audit export)\n\tstatements.push(\n\t\t'CREATE TABLE IF NOT EXISTS _kora_audit_traces (\\n' +\n\t\t\t' id TEXT PRIMARY KEY NOT NULL,\\n' +\n\t\t\t' recorded_at INTEGER NOT NULL,\\n' +\n\t\t\t' event_type TEXT NOT NULL,\\n' +\n\t\t\t' collection TEXT NOT NULL,\\n' +\n\t\t\t' record_id TEXT NOT NULL,\\n' +\n\t\t\t' field TEXT NOT NULL,\\n' +\n\t\t\t' strategy TEXT NOT NULL,\\n' +\n\t\t\t' tier INTEGER NOT NULL,\\n' +\n\t\t\t' constraint_name TEXT,\\n' +\n\t\t\t' trace_json TEXT NOT NULL\\n' +\n\t\t\t')',\n\t)\n\tstatements.push(\n\t\t'CREATE INDEX IF NOT EXISTS idx_kora_audit_traces_recorded_at ON _kora_audit_traces (recorded_at)',\n\t)\n\tstatements.push(\n\t\t'CREATE INDEX IF NOT EXISTS idx_kora_audit_traces_collection ON _kora_audit_traces (collection)',\n\t)\n\n\tfor (const [name, collection] of Object.entries(schema.collections)) {\n\t\tstatements.push(...generateSQL(name, collection, schema.relations))\n\t}\n\n\treturn statements\n}\n\n/**\n * A schema field's column: its type and default only. Requiredness and enum membership\n * are value-domain rules, enforced by validation at write time on every replica; they\n * are never restated as `NOT NULL` / `CHECK` constraints, which a table cannot evolve\n * when the schema does (RT-101: an added enum value, a field made optional).\n */\nfunction columnDefinition(fieldName: string, descriptor: FieldDescriptor): string {\n\tconst sqlType = mapFieldType(descriptor)\n\tconst parts = [quoteIdent(fieldName), sqlType]\n\n\tif (descriptor.defaultValue !== undefined) {\n\t\tparts.push(`DEFAULT ${sqlDefaultLiteral(descriptor.defaultValue)}`)\n\t}\n\n\treturn parts.join(' ')\n}\n\n/**\n * Render a string as a SQL string literal, doubling embedded single quotes\n * (SEC-9b). Valid in SQLite and in Postgres with standard_conforming_strings\n * (the default since 9.1), where a backslash is an ordinary character.\n *\n * @param value - The string to quote\n * @returns The quoted literal, e.g. `'don''t know'`\n */\nexport function sqlStringLiteral(value: string): string {\n\treturn `'${value.replaceAll(\"'\", \"''\")}'`\n}\n\n/**\n * Render a schema default value as a SQL literal for a `DEFAULT` clause. Strings\n * and JSON-serialized arrays/objects are quoted with `sqlStringLiteral`, so a\n * default containing a quote yields valid DDL instead of breaking it (SEC-9b).\n *\n * @param value - The field's default value\n * @returns A SQL literal\n */\nexport function sqlDefaultLiteral(value: unknown): string {\n\tif (value === null) return 'NULL'\n\tif (typeof value === 'string') return sqlStringLiteral(value)\n\tif (typeof value === 'number') {\n\t\t// Non-finite numbers have no SQL literal; NULL is the only safe default.\n\t\treturn Number.isFinite(value) ? String(value) : 'NULL'\n\t}\n\tif (typeof value === 'boolean') return value ? '1' : '0'\n\t// Arrays and objects are stored as JSON strings\n\treturn sqlStringLiteral(JSON.stringify(value) ?? 'null')\n}\n\n/**\n * Render the `CHECK (col IN (...))` constraint of an enum field, each value\n * quoted with `sqlStringLiteral` (SEC-9b). No longer emitted by Kora's DDL (RT-101:\n * enum membership is enforced by validation only); kept for tooling and tests.\n *\n * @param fieldName - The enum column\n * @param values - The enum's allowed values\n * @returns The CHECK clause\n */\nexport function enumCheckConstraint(fieldName: string, values: readonly string[]): string {\n\treturn `CHECK (${quoteIdent(fieldName)} IN (${values.map(sqlStringLiteral).join(', ')}))`\n}\n\nfunction mapFieldType(descriptor: FieldDescriptor): string {\n\tswitch (descriptor.kind) {\n\t\tcase 'string':\n\t\t\treturn 'TEXT'\n\t\tcase 'number':\n\t\t\treturn 'REAL'\n\t\tcase 'boolean':\n\t\t\treturn 'INTEGER'\n\t\tcase 'enum':\n\t\t\treturn 'TEXT'\n\t\tcase 'timestamp':\n\t\t\treturn 'INTEGER'\n\t\tcase 'array':\n\t\t\treturn 'TEXT' // JSON-serialized\n\t\tcase 'object':\n\t\t\treturn 'TEXT' // JSON-serialized structured object\n\t\tcase 'json':\n\t\t\treturn 'TEXT' // JSON-serialized dynamic-key value\n\t\tcase 'blob':\n\t\t\treturn 'TEXT' // JSON-serialized content-addressed BlobRef (bytes stored out of band)\n\t\tcase 'secret':\n\t\t\treturn 'TEXT'\n\t\tcase 'richtext':\n\t\t\treturn 'BLOB' // Yjs state\n\t}\n}\n","import { HybridLogicalClock } from '../clock/hlc'\nimport { OperationError } from '../errors/errors'\nimport type { Operation } from '../types'\n\n/**\n * Topological sort of operations based on their causal dependency DAG.\n * Uses Kahn's algorithm with a binary heap for O(V log V + E) performance.\n * Deterministic tie-breaking via HLC timestamp ensures identical output\n * regardless of input order.\n *\n * @param operations - The operations to sort\n * @returns Operations in causal order (dependencies before dependents)\n * @throws {OperationError} If a cycle is detected in the dependency graph\n */\nexport function topologicalSort(operations: Operation[]): Operation[] {\n\tif (operations.length <= 1) return [...operations]\n\n\t// Build adjacency list and in-degree map\n\tconst opMap = new Map<string, Operation>()\n\tfor (const op of operations) {\n\t\topMap.set(op.id, op)\n\t}\n\n\t// Only count edges where both ends are in the operation set\n\tconst inDegree = new Map<string, number>()\n\tconst dependents = new Map<string, string[]>()\n\n\tfor (const op of operations) {\n\t\tif (!inDegree.has(op.id)) {\n\t\t\tinDegree.set(op.id, 0)\n\t\t}\n\t\tif (!dependents.has(op.id)) {\n\t\t\tdependents.set(op.id, [])\n\t\t}\n\n\t\tfor (const depId of op.causalDeps) {\n\t\t\tif (opMap.has(depId)) {\n\t\t\t\t// depId -> op.id edge (depId must come before op.id)\n\t\t\t\tinDegree.set(op.id, (inDegree.get(op.id) ?? 0) + 1)\n\t\t\t\tconst deps = dependents.get(depId)\n\t\t\t\tif (deps) {\n\t\t\t\t\tdeps.push(op.id)\n\t\t\t\t} else {\n\t\t\t\t\tdependents.set(depId, [op.id])\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Initialize min-heap with nodes that have no in-set dependencies\n\tconst heap = new MinHeap(compareByTimestamp)\n\tfor (const op of operations) {\n\t\tif ((inDegree.get(op.id) ?? 0) === 0) {\n\t\t\theap.push(op)\n\t\t}\n\t}\n\n\tconst result: Operation[] = []\n\n\twhile (heap.size > 0) {\n\t\t// Extract the earliest operation (deterministic tie-breaking by HLC)\n\t\tconst current = heap.pop()\n\t\tresult.push(current)\n\n\t\tconst deps = dependents.get(current.id) ?? []\n\n\t\tfor (const depId of deps) {\n\t\t\tconst deg = (inDegree.get(depId) ?? 0) - 1\n\t\t\tinDegree.set(depId, deg)\n\t\t\tif (deg === 0) {\n\t\t\t\tconst op = opMap.get(depId)\n\t\t\t\tif (op) heap.push(op)\n\t\t\t}\n\t\t}\n\t}\n\n\tif (result.length !== operations.length) {\n\t\tthrow new OperationError(\n\t\t\t`Cycle detected in operation dependency graph. Sorted ${result.length} of ${operations.length} operations.`,\n\t\t\t{\n\t\t\t\tsortedCount: result.length,\n\t\t\t\ttotalCount: operations.length,\n\t\t\t},\n\t\t)\n\t}\n\n\treturn result\n}\n\nfunction compareByTimestamp(a: Operation, b: Operation): number {\n\treturn HybridLogicalClock.compare(a.timestamp, b.timestamp)\n}\n\n/**\n * Binary min-heap for efficient priority queue operations.\n * push: O(log n), pop: O(log n) — replaces the O(n) sorted array approach.\n */\nclass MinHeap {\n\tprivate readonly data: Operation[] = []\n\tprivate readonly cmp: (a: Operation, b: Operation) => number\n\n\tconstructor(comparator: (a: Operation, b: Operation) => number) {\n\t\tthis.cmp = comparator\n\t}\n\n\tget size(): number {\n\t\treturn this.data.length\n\t}\n\n\tpush(item: Operation): void {\n\t\tthis.data.push(item)\n\t\tthis.bubbleUp(this.data.length - 1)\n\t}\n\n\tpop(): Operation {\n\t\tconst top = this.data[0] as Operation\n\t\tconst last = this.data.pop() as Operation\n\t\tif (this.data.length > 0) {\n\t\t\tthis.data[0] = last\n\t\t\tthis.sinkDown(0)\n\t\t}\n\t\treturn top\n\t}\n\n\tprivate bubbleUp(index: number): void {\n\t\tlet current = index\n\t\twhile (current > 0) {\n\t\t\tconst parentIndex = (current - 1) >> 1\n\t\t\tif (this.cmp(this.data[current] as Operation, this.data[parentIndex] as Operation) >= 0) break\n\t\t\tthis.swap(current, parentIndex)\n\t\t\tcurrent = parentIndex\n\t\t}\n\t}\n\n\tprivate sinkDown(index: number): void {\n\t\tconst length = this.data.length\n\t\tlet current = index\n\t\twhile (true) {\n\t\t\tlet smallest = current\n\t\t\tconst left = 2 * current + 1\n\t\t\tconst right = 2 * current + 2\n\n\t\t\tif (\n\t\t\t\tleft < length &&\n\t\t\t\tthis.cmp(this.data[left] as Operation, this.data[smallest] as Operation) < 0\n\t\t\t) {\n\t\t\t\tsmallest = left\n\t\t\t}\n\t\t\tif (\n\t\t\t\tright < length &&\n\t\t\t\tthis.cmp(this.data[right] as Operation, this.data[smallest] as Operation) < 0\n\t\t\t) {\n\t\t\t\tsmallest = right\n\t\t\t}\n\n\t\t\tif (smallest === current) break\n\t\t\tthis.swap(current, smallest)\n\t\t\tcurrent = smallest\n\t\t}\n\t}\n\n\tprivate swap(i: number, j: number): void {\n\t\tconst tmp = this.data[i] as Operation\n\t\tthis.data[i] = this.data[j] as Operation\n\t\tthis.data[j] = tmp\n\t}\n}\n"],"mappings":"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","names":["canonical","canonical","changed","out"]}