@korajs/store 1.0.0-beta.11 → 1.0.0-beta.13
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/README.md +29 -37
- package/dist/adapters/better-sqlite3.cjs +90 -4
- package/dist/adapters/better-sqlite3.cjs.map +1 -1
- package/dist/adapters/better-sqlite3.d.cts +21 -12
- package/dist/adapters/better-sqlite3.d.ts +21 -12
- package/dist/adapters/better-sqlite3.js +69 -5
- package/dist/adapters/better-sqlite3.js.map +1 -1
- package/dist/adapters/indexeddb.cjs +1316 -610
- package/dist/adapters/indexeddb.cjs.map +1 -1
- package/dist/adapters/indexeddb.d.cts +29 -3
- package/dist/adapters/indexeddb.d.ts +29 -3
- package/dist/adapters/indexeddb.js +247 -221
- package/dist/adapters/indexeddb.js.map +1 -1
- package/dist/adapters/sqlite-wasm-worker.cjs +803 -62
- package/dist/adapters/sqlite-wasm-worker.cjs.map +1 -1
- package/dist/adapters/sqlite-wasm-worker.js +480 -62
- package/dist/adapters/sqlite-wasm-worker.js.map +1 -1
- package/dist/adapters/sqlite-wasm.cjs +1032 -344
- package/dist/adapters/sqlite-wasm.cjs.map +1 -1
- package/dist/adapters/sqlite-wasm.d.cts +239 -18
- package/dist/adapters/sqlite-wasm.d.ts +239 -18
- package/dist/adapters/sqlite-wasm.js +111 -5
- package/dist/adapters/sqlite-wasm.js.map +1 -1
- package/dist/backup-4NUPDEMB.js +25 -0
- package/dist/chunk-32EDKWMI.js +876 -0
- package/dist/chunk-32EDKWMI.js.map +1 -0
- package/dist/{chunk-CYO3YKFL.js → chunk-5ZRRF6R2.js} +2 -2
- package/dist/chunk-A6GFH5IG.js +36 -0
- package/dist/chunk-A6GFH5IG.js.map +1 -0
- package/dist/chunk-DUKTWVZW.js +175 -0
- package/dist/chunk-DUKTWVZW.js.map +1 -0
- package/dist/chunk-HZTDBLDB.js +607 -0
- package/dist/chunk-HZTDBLDB.js.map +1 -0
- package/dist/{chunk-GSJ7EEUC.js → chunk-J5AGXF3D.js} +58 -9
- package/dist/chunk-J5AGXF3D.js.map +1 -0
- package/dist/chunk-MCQKEHOD.js +112 -0
- package/dist/chunk-MCQKEHOD.js.map +1 -0
- package/dist/chunk-P4V375FY.js +810 -0
- package/dist/chunk-P4V375FY.js.map +1 -0
- package/dist/chunk-QDUSJMFV.js +1095 -0
- package/dist/chunk-QDUSJMFV.js.map +1 -0
- package/dist/chunk-SJP2HTYZ.js +1003 -0
- package/dist/chunk-SJP2HTYZ.js.map +1 -0
- package/dist/chunk-W5F2LWG6.js +591 -0
- package/dist/chunk-W5F2LWG6.js.map +1 -0
- package/dist/chunk-Y5LRH7KI.js +5341 -0
- package/dist/chunk-Y5LRH7KI.js.map +1 -0
- package/dist/{export-audit-ODGQTQIK.js → export-audit-J2QXRHD2.js} +3 -3
- package/dist/index.cjs +9354 -4157
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1064 -108
- package/dist/index.d.ts +1064 -108
- package/dist/index.js +249 -3092
- package/dist/index.js.map +1 -1
- package/dist/internal.cjs +580 -264
- package/dist/internal.cjs.map +1 -1
- package/dist/internal.d.cts +15 -85
- package/dist/internal.d.ts +15 -85
- package/dist/internal.js +10 -8
- package/dist/restore-FR7XIKT2.js +299 -0
- package/dist/restore-FR7XIKT2.js.map +1 -0
- package/dist/sql-builder-C4u55jKW.d.cts +608 -0
- package/dist/sql-builder-CGckdBDL.d.ts +608 -0
- package/dist/sqlite-wasm-channel-DVX93Uiq.d.cts +141 -0
- package/dist/sqlite-wasm-channel-DVX93Uiq.d.ts +141 -0
- package/dist/sqlite-wasm-channel-MLHLKEED.js +12 -0
- package/dist/store-IMWKZLWB.js +16 -0
- package/dist/store-IMWKZLWB.js.map +1 -0
- package/dist/{types-BslDOTk0.d.ts → types-Dh-xyUjP.d.cts} +99 -26
- package/dist/{types-BslDOTk0.d.cts → types-Dh-xyUjP.d.ts} +99 -26
- package/package.json +3 -2
- package/dist/backup-5S7K2Z35.js +0 -14
- package/dist/chunk-GSJ7EEUC.js.map +0 -1
- package/dist/chunk-HS6DBMST.js +0 -383
- package/dist/chunk-HS6DBMST.js.map +0 -1
- package/dist/chunk-RJIEKEN4.js +0 -751
- package/dist/chunk-RJIEKEN4.js.map +0 -1
- package/dist/chunk-TUR7RGEP.js +0 -84
- package/dist/chunk-TUR7RGEP.js.map +0 -1
- package/dist/chunk-VDBJQ75K.js +0 -78
- package/dist/chunk-VDBJQ75K.js.map +0 -1
- package/dist/chunk-YT7MRFCP.js +0 -687
- package/dist/chunk-YT7MRFCP.js.map +0 -1
- package/dist/sqlite-wasm-channel-GGHA2BXU.js +0 -12
- package/dist/sqlite-wasm-channel-L6o3bWQK.d.cts +0 -92
- package/dist/sqlite-wasm-channel-L6o3bWQK.d.ts +0 -92
- package/dist/types-BOO9EPt1.d.ts +0 -170
- package/dist/types-C_GDavG-.d.cts +0 -170
- /package/dist/{backup-5S7K2Z35.js.map → backup-4NUPDEMB.js.map} +0 -0
- /package/dist/{chunk-CYO3YKFL.js.map → chunk-5ZRRF6R2.js.map} +0 -0
- /package/dist/{export-audit-ODGQTQIK.js.map → export-audit-J2QXRHD2.js.map} +0 -0
- /package/dist/{sqlite-wasm-channel-GGHA2BXU.js.map → sqlite-wasm-channel-MLHLKEED.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/sync/rehash-operation.ts","../src/store/sequence-allocator.ts","../src/store/sequence-repair.ts","../src/fold/record-folder.ts"],"sourcesContent":["import { quoteIdent } from '@korajs/core'\nimport type { Operation } from '@korajs/core'\nimport { computeOperationId } from '@korajs/core/internal'\nimport { buildInsertQuery } from '../query/sql-builder'\nimport { deserializeOperationWithCollection, serializeOperation } from '../serialization/serializer'\nimport type { OperationRow, Transaction } from '../types'\n\n/** Result of `Store.resequenceOperation` (RT-35 renumbering). */\nexport interface ResequenceResult {\n\t/** The renumbered operation (a version-2 one under a new id). */\n\toperation: Operation\n\t/** Never-sent dependents rewritten to name the new id (re-hashed), in sequence order. */\n\tdependents: Operation[]\n\t/** Old id -> new id, for the operation and every re-hashed dependent. */\n\tidMapping: Record<string, string>\n}\n\n/**\n * The content-addressed id of an operation whose stamp, node, sequence or causal deps\n * were rewritten locally before it was ever shared (clock rebase, node rotation,\n * SEQUENCE_CONFLICT renumbering). Uses the operation's own hash version: a version-2\n * operation (protocol v2) gets a version-2 id over all its semantic fields, and a\n * version-1 operation (written before beta.13) keeps the version-1 hash, so neither\n * fails id verification on its receivers.\n *\n * @param op - The operation with its new content (its `id` is ignored)\n * @returns The id matching that content under the operation's hash version\n */\nexport async function rehashOperation(op: Operation): Promise<string> {\n\treturn computeOperationId(\n\t\t{\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: op.timestamp,\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},\n\t\top.hashVersion === 2 ? 2 : 1,\n\t)\n}\n\n/**\n * Give a logged operation row a new sequence number inside `tx` (SEQUENCE_CONFLICT\n * recovery, RT-35; legacy duplicate repair, W6). A version-1 operation keeps its id:\n * its hash never covered the sequence number. A version-2 operation's id does cover it\n * (CORE-1), so it is re-hashed and its row replaced under the new id; it was never\n * stored by the server (that is why it is renumbered), so no replica knows the old id.\n *\n * @returns The operation as it is now logged\n */\nexport async function renumberOperationRow(\n\ttx: Transaction,\n\tcollection: string,\n\trow: OperationRow,\n\tsequenceNumber: number,\n): Promise<Operation> {\n\tconst table = quoteIdent(`_kora_ops_${collection}`)\n\tconst current = deserializeOperationWithCollection(row, collection)\n\tconst renumbered: Operation = { ...current, sequenceNumber }\n\tif (current.hashVersion !== 2) {\n\t\tawait tx.execute(`UPDATE ${table} SET sequence_number = ? WHERE id = ?`, [\n\t\t\tsequenceNumber,\n\t\t\trow.id,\n\t\t])\n\t\treturn renumbered\n\t}\n\tconst id = await rehashOperation(renumbered)\n\tconst moved: Operation = { ...renumbered, id }\n\tawait replaceOperationRow(tx, collection, row.id, moved)\n\treturn moved\n}\n\nasync function replaceOperationRow(\n\ttx: Transaction,\n\tcollection: string,\n\toldId: string,\n\tnext: Operation,\n): Promise<void> {\n\tawait tx.execute(`DELETE FROM ${quoteIdent(`_kora_ops_${collection}`)} WHERE id = ?`, [oldId])\n\tconst insert = buildInsertQuery(\n\t\t`_kora_ops_${collection}`,\n\t\tserializeOperation(next) as unknown as Record<string, unknown>,\n\t)\n\tawait tx.execute(insert.sql, insert.params)\n}\n\n/**\n * After operations were re-hashed under new ids (`idMapping`, old id -> new id), make\n * the local operations that name an old id in `causalDeps` name the new one, inside\n * `tx`. Only operations in `rewritable` are touched: those the server never stored\n * (never sent). Each rewritten operation covers its causalDeps in its id (version 2),\n * so it is re-hashed too and its own dependents follow, transitively, in sequence\n * order (sequence order is authoring order, so a dependency is always rewritten before\n * its dependents). A version-1 operation keeps its id (its hash does not cover\n * causalDeps) but still gets the new dep. `idMapping` is extended in place.\n *\n * An operation outside `rewritable` (already sent: the server may hold it under its\n * id) is never rewritten; its dep on an old id resolves through `_kora_seq_conflicts`\n * (`reemitted_as`) on this device.\n *\n * @returns The rewritten operations, in sequence order\n */\nexport async function rewriteDependentsInTx(\n\ttx: Transaction,\n\tcollections: readonly string[],\n\tnodeId: string,\n\tidMapping: Record<string, string>,\n\trewritable: ReadonlySet<string>,\n): Promise<Operation[]> {\n\tif (rewritable.size === 0) return []\n\tconst candidates: Array<{ collection: string; row: OperationRow; op: Operation }> = []\n\tfor (const collection of collections) {\n\t\tconst rows = await tx.query<OperationRow>(\n\t\t\t`SELECT * FROM ${quoteIdent(`_kora_ops_${collection}`)} WHERE node_id = ?`,\n\t\t\t[nodeId],\n\t\t)\n\t\tfor (const row of rows) {\n\t\t\tif (!rewritable.has(row.id)) continue\n\t\t\tcandidates.push({ collection, row, op: deserializeOperationWithCollection(row, collection) })\n\t\t}\n\t}\n\tcandidates.sort((a, b) => a.op.sequenceNumber - b.op.sequenceNumber)\n\tconst rewritten: Operation[] = []\n\tfor (const { collection, row, op } of candidates) {\n\t\tif (!op.causalDeps.some((dep) => idMapping[dep] !== undefined)) continue\n\t\tconst causalDeps = op.causalDeps.map((dep) => idMapping[dep] ?? dep)\n\t\tconst updated: Operation = { ...op, causalDeps }\n\t\tconst id = op.hashVersion === 2 ? await rehashOperation(updated) : op.id\n\t\tconst next: Operation = { ...updated, id }\n\t\tawait replaceOperationRow(tx, collection, row.id, next)\n\t\tif (id !== op.id) idMapping[op.id] = id\n\t\trewritten.push(next)\n\t}\n\treturn rewritten\n}\n","import type { StorageAdapter, Transaction } from '../types'\n\ninterface SequenceRow {\n\tsequence_number: number\n}\n\n/**\n * Reserve the next sequence number for a node inside a write transaction\n * (UPSERT ... RETURNING on `_kora_version_vector`).\n *\n * This is the ONLY way a local operation gets its number: the reservation\n * commits or rolls back with the operation that uses it, and transactions are\n * serialized, so the numbers of one commit are contiguous and never shared. There\n * is deliberately no variant that allocates outside a transaction (W6).\n */\nexport async function allocateNextSequenceInTransaction(\n\ttx: Transaction,\n\tnodeId: string,\n): Promise<number> {\n\tconst rows = await tx.query<SequenceRow>(\n\t\t`INSERT INTO _kora_version_vector (node_id, sequence_number) VALUES (?, 1)\n ON CONFLICT(node_id) DO UPDATE SET sequence_number = sequence_number + 1\n RETURNING sequence_number`,\n\t\t[nodeId],\n\t)\n\tconst seq = rows[0]?.sequence_number\n\tif (seq === undefined) {\n\t\tthrow new Error(`Failed to allocate sequence number for node \"${nodeId}\" in transaction`)\n\t}\n\treturn seq\n}\n\n/**\n * Read the current sequence for a node without incrementing.\n */\nexport async function readSequenceNumber(adapter: StorageAdapter, nodeId: string): Promise<number> {\n\tconst rows = await adapter.query<SequenceRow>(\n\t\t'SELECT sequence_number FROM _kora_version_vector WHERE node_id = ?',\n\t\t[nodeId],\n\t)\n\treturn rows[0]?.sequence_number ?? 0\n}\n","import { quoteIdent } from '@korajs/core'\nimport type { SchemaDefinition } from '@korajs/core'\nimport { deserializeOperationWithCollection } from '../serialization/serializer'\nimport { renumberOperationRow } from '../sync/rehash-operation'\nimport type { OperationRow, StorageAdapter, Transaction } from '../types'\nimport { allocateNextSequenceInTransaction } from './sequence-allocator'\n\n/**\n * Audit table for operation rows whose `(node_id, sequence_number)` identity\n * collided with another operation (STORE-1 / STORE-2 duplicates written by\n * beta.12, or a conflicting remote operation). Rows here are never deleted.\n *\n * - `reemitted_as` set: the operation was given a fresh sequence number and still\n * lives in the operation log under that number (`new_sequence_number`).\n * - `reemitted_as` NULL: the operation is kept ONLY here (another node's\n * operation whose number this log already holds). It still takes part in\n * dedup and in record folds, so no data is lost.\n */\nexport const SEQ_CONFLICTS_TABLE = '_kora_seq_conflicts'\n\nconst REPAIR_DONE_META_KEY = 'seq_unique_repair_v1'\n\n/** DDL for {@link SEQ_CONFLICTS_TABLE}. */\nconst CREATE_SEQ_CONFLICTS_SQL = `CREATE TABLE IF NOT EXISTS ${SEQ_CONFLICTS_TABLE} (\n id TEXT PRIMARY KEY NOT NULL,\n collection TEXT 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 reason TEXT NOT NULL,\n reemitted_as TEXT,\n new_sequence_number INTEGER,\n recorded_at INTEGER NOT NULL\n)`\n\n/** Name of the unique `(node_id, sequence_number)` index on a collection's op log. */\nexport function uniqueSequenceIndexName(collection: string): string {\n\treturn `uidx_kora_ops_${collection.length}_${collection}_node_seq`\n}\n\n/** Outcome of {@link repairSequenceUniqueness}. */\nexport interface SequenceRepairResult {\n\t/** Own-node operations that were given a fresh sequence number. */\n\tresequenced: number\n\t/** Other nodes' operations moved out of the log into the conflicts table. */\n\tretained: number\n}\n\n/**\n * Make `(node_id, sequence_number)` unique in the local operation log, then\n * enforce it with a UNIQUE index on every operation table (W6 step 2).\n *\n * beta.12 could give two different operations of this device the same sequence\n * number (STORE-1/2). A plain UNIQUE index cannot be created over such a log, and\n * dropping either row would lose a write. The repair, in one transaction:\n *\n * 1. Raises this node's persisted counter to at least the highest sequence number\n * in its log (beta.12 could leave it behind, which would make the next write\n * collide).\n * 2. For every duplicated `(node, seq)` — across all collections, since one node\n * numbers all its operations in one sequence — keeps the first row by id.\n * 3. Every other row of THIS node is re-emitted with a fresh sequence number from\n * the counter, keeping its id and content (see the note below), and recorded\n * in {@link SEQ_CONFLICTS_TABLE}.\n * 4. Rows of OTHER nodes (this device cannot number them) move to\n * {@link SEQ_CONFLICTS_TABLE} with `reemitted_as` NULL; the store keeps using\n * them for dedup and record folds.\n * 5. Creates the UNIQUE index on every operation table.\n *\n * Why the re-emitted operation keeps its id: protocol v1 content-addresses\n * operations without the sequence number, and changing any hashed content (data\n * or HLC timestamp) would change what the write means under last-write-wins.\n * With the id kept, a server that already stored the operation deduplicates it\n * (acknowledging the new number), and a server that never got it — beta.12 could\n * skip the second of two same-numbered operations — stores it. Either way atomic\n * increments are never applied twice and no write is lost.\n *\n * Idempotent: the scan runs once per database (a meta flag records completion);\n * the index creation runs on every open so collections added later are covered.\n *\n * @param adapter - The store's adapter (already opened)\n * @param schema - The schema whose operation tables are repaired\n * @param nodeId - This device's node id\n */\nexport async function repairSequenceUniqueness(\n\tadapter: StorageAdapter,\n\tschema: SchemaDefinition,\n\tnodeId: string,\n): Promise<SequenceRepairResult> {\n\tawait adapter.execute(CREATE_SEQ_CONFLICTS_SQL)\n\tconst collections = Object.keys(schema.collections)\n\tconst result: SequenceRepairResult = { resequenced: 0, retained: 0 }\n\n\tconst done = await adapter.query<{ value: string }>(\n\t\t'SELECT value FROM _kora_meta WHERE key = ?',\n\t\t[REPAIR_DONE_META_KEY],\n\t)\n\tif (done.length === 0 && collections.length > 0) {\n\t\tawait runRepair(adapter, collections, nodeId, result)\n\t}\n\n\tfor (const collection of collections) {\n\t\tconst createIndex = `CREATE UNIQUE INDEX IF NOT EXISTS ${quoteIdent(uniqueSequenceIndexName(collection))} ON ${quoteIdent(`_kora_ops_${collection}`)} (node_id, sequence_number)`\n\t\ttry {\n\t\t\tawait adapter.execute(createIndex)\n\t\t} catch (error) {\n\t\t\t// Duplicates written after an earlier repair (for example by an older\n\t\t\t// Kora version opening this database again): repair once more, then\n\t\t\t// create the index. A second failure propagates.\n\t\t\tif (!/UNIQUE/i.test(error instanceof Error ? error.message : String(error))) throw error\n\t\t\tawait runRepair(adapter, collections, nodeId, result)\n\t\t\tawait adapter.execute(createIndex)\n\t\t}\n\t}\n\treturn result\n}\n\nasync function runRepair(\n\tadapter: StorageAdapter,\n\tcollections: string[],\n\tnodeId: string,\n\tresult: SequenceRepairResult,\n): Promise<void> {\n\tlet resequenced = 0\n\tlet retained = 0\n\tawait adapter.transaction(async (tx) => {\n\t\tawait raiseOwnCounterToLog(tx, collections, nodeId)\n\t\tconst repaired = await repairDuplicates(tx, collections, nodeId)\n\t\tresequenced = repaired.resequenced\n\t\tretained = repaired.retained\n\t\tawait tx.execute('INSERT OR REPLACE INTO _kora_meta (key, value) VALUES (?, ?)', [\n\t\t\tREPAIR_DONE_META_KEY,\n\t\t\tString(Date.now()),\n\t\t])\n\t})\n\tresult.resequenced += resequenced\n\tresult.retained += retained\n\tif (resequenced > 0 || retained > 0) {\n\t\tconsole.warn(\n\t\t\t`[kora] Repaired ${resequenced + retained} operation(s) that shared a sequence number (written by an earlier Kora version). ${resequenced} were given fresh sequence numbers; ${retained} from other devices were kept in ${SEQ_CONFLICTS_TABLE}. No data was removed.`,\n\t\t)\n\t}\n}\n\nasync function raiseOwnCounterToLog(\n\ttx: Transaction,\n\tcollections: string[],\n\tnodeId: string,\n): Promise<void> {\n\tlet maxSeq = 0\n\tfor (const collection of collections) {\n\t\tconst rows = await tx.query<{ max_seq: number | null }>(\n\t\t\t`SELECT MAX(sequence_number) AS max_seq FROM ${quoteIdent(`_kora_ops_${collection}`)} WHERE node_id = ?`,\n\t\t\t[nodeId],\n\t\t)\n\t\tmaxSeq = Math.max(maxSeq, rows[0]?.max_seq ?? 0)\n\t}\n\tif (maxSeq > 0) {\n\t\tawait tx.execute(\n\t\t\t`INSERT INTO _kora_version_vector (node_id, sequence_number) VALUES (?, ?)\n ON CONFLICT(node_id) DO UPDATE SET sequence_number = MAX(sequence_number, excluded.sequence_number)`,\n\t\t\t[nodeId, maxSeq],\n\t\t)\n\t}\n}\n\ninterface LoggedIdentity {\n\tcollection: string\n\tid: string\n\tnode_id: string\n\tsequence_number: number\n}\n\nasync function repairDuplicates(\n\ttx: Transaction,\n\tcollections: string[],\n\tnodeId: string,\n): Promise<SequenceRepairResult> {\n\t// One node numbers all its operations in one sequence, so duplicates are\n\t// found across every collection's table, not per table.\n\tconst all: LoggedIdentity[] = []\n\tfor (const collection of collections) {\n\t\tconst rows = await tx.query<Omit<LoggedIdentity, 'collection'>>(\n\t\t\t`SELECT id, node_id, sequence_number FROM ${quoteIdent(`_kora_ops_${collection}`)}`,\n\t\t)\n\t\tfor (const row of rows) all.push({ collection, ...row })\n\t}\n\tconst groups = new Map<string, LoggedIdentity[]>()\n\tfor (const row of all) {\n\t\tconst key = `${row.node_id}\\u0000${row.sequence_number}`\n\t\tconst group = groups.get(key)\n\t\tif (group) group.push(row)\n\t\telse groups.set(key, [row])\n\t}\n\n\tconst losers: LoggedIdentity[] = []\n\tfor (const group of groups.values()) {\n\t\tif (group.length < 2) continue\n\t\t// A version-2 operation (beta.13+) keeps its place: renumbering would re-hash it\n\t\t// under a new id, and if the server already stored it under the old id the new\n\t\t// copy would be stored as a second write (an atomic increment applied twice). A\n\t\t// version-1 loser keeps its id, which the server deduplicates (RT-31). Ties by id.\n\t\tconst version2 = new Set<string>()\n\t\tfor (const member of group) {\n\t\t\tif (await isVersion2Row(tx, member)) version2.add(member.id)\n\t\t}\n\t\tgroup.sort((a, b) => {\n\t\t\tconst va = version2.has(a.id) ? 0 : 1\n\t\t\tconst vb = version2.has(b.id) ? 0 : 1\n\t\t\tif (va !== vb) return va - vb\n\t\t\treturn a.id < b.id ? -1 : a.id > b.id ? 1 : 0\n\t\t})\n\t\tlosers.push(...group.slice(1))\n\t}\n\t// Re-emit in original order so the new numbers keep the authoring order.\n\tlosers.sort((a, b) =>\n\t\ta.sequence_number !== b.sequence_number\n\t\t\t? a.sequence_number - b.sequence_number\n\t\t\t: a.id < b.id\n\t\t\t\t? -1\n\t\t\t\t: a.id > b.id\n\t\t\t\t\t? 1\n\t\t\t\t\t: 0,\n\t)\n\n\tconst result: SequenceRepairResult = { resequenced: 0, retained: 0 }\n\tconst now = Date.now()\n\tfor (const loser of losers) {\n\t\tconst table = quoteIdent(`_kora_ops_${loser.collection}`)\n\t\tconst rows = await tx.query<OperationRow>(`SELECT * FROM ${table} WHERE id = ?`, [loser.id])\n\t\tconst row = rows[0]\n\t\tif (!row) continue\n\t\tif (loser.node_id === nodeId) {\n\t\t\tconst newSeq = await allocateNextSequenceInTransaction(tx, nodeId)\n\t\t\tconst moved = await renumberOperationRow(tx, loser.collection, row, newSeq)\n\t\t\tawait insertConflictRow(\n\t\t\t\ttx,\n\t\t\t\tloser.collection,\n\t\t\t\trow,\n\t\t\t\t'duplicate-sequence',\n\t\t\t\tmoved.id,\n\t\t\t\tnewSeq,\n\t\t\t\tnow,\n\t\t\t)\n\t\t\tresult.resequenced++\n\t\t} else {\n\t\t\tawait insertConflictRow(tx, loser.collection, row, 'duplicate-sequence', null, null, now)\n\t\t\tawait tx.execute(`DELETE FROM ${table} WHERE id = ?`, [loser.id])\n\t\t\tresult.retained++\n\t\t}\n\t}\n\treturn result\n}\n\n/** Whether a logged operation declares content-hash version 2. */\nasync function isVersion2Row(tx: Transaction, identity: LoggedIdentity): Promise<boolean> {\n\tconst rows = await tx.query<OperationRow>(\n\t\t`SELECT * FROM ${quoteIdent(`_kora_ops_${identity.collection}`)} WHERE id = ?`,\n\t\t[identity.id],\n\t)\n\tconst row = rows[0]\n\tif (!row) return false\n\treturn deserializeOperationWithCollection(row, identity.collection).hashVersion === 2\n}\n\n/**\n * Record an operation row in {@link SEQ_CONFLICTS_TABLE}.\n *\n * @param reemittedAs - Id of the operation that carries it in the log, or null\n * when the row is kept only in the conflicts table\n * @param newSequenceNumber - The sequence number it was re-emitted under\n */\nexport async function insertConflictRow(\n\ttx: Transaction,\n\tcollection: string,\n\trow: OperationRow,\n\treason: string,\n\treemittedAs: string | null,\n\tnewSequenceNumber: number | null,\n\trecordedAt: number,\n): Promise<void> {\n\tawait tx.execute(\n\t\t`INSERT OR IGNORE INTO ${SEQ_CONFLICTS_TABLE} (id, collection, node_id, type, record_id, data, previous_data, timestamp, sequence_number, causal_deps, schema_version, reason, reemitted_as, new_sequence_number, recorded_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n\t\t[\n\t\t\trow.id,\n\t\t\tcollection,\n\t\t\trow.node_id,\n\t\t\trow.type,\n\t\t\trow.record_id,\n\t\t\trow.data,\n\t\t\trow.previous_data,\n\t\t\trow.timestamp,\n\t\t\trow.sequence_number,\n\t\t\trow.causal_deps,\n\t\t\trow.schema_version,\n\t\t\treason,\n\t\t\treemittedAs,\n\t\t\tnewSequenceNumber,\n\t\t\trecordedAt,\n\t\t],\n\t)\n}\n\n/**\n * Operation rows kept only in the conflicts table for a record (other nodes'\n * operations whose sequence number collided). Record folds include them.\n */\nexport async function loadRetainedConflictRows(\n\tquery: <T>(sql: string, params?: unknown[]) => Promise<T[]>,\n\tcollection: string,\n\trecordId: string,\n\ttypes?: readonly string[],\n): Promise<OperationRow[]> {\n\tconst typeFilter =\n\t\ttypes && types.length > 0 ? ` AND type IN (${types.map(() => '?').join(', ')})` : ''\n\treturn query<OperationRow>(\n\t\t`SELECT id, node_id, type, record_id, data, previous_data, timestamp, sequence_number, causal_deps, schema_version FROM ${SEQ_CONFLICTS_TABLE} WHERE collection = ? AND record_id = ? AND reemitted_as IS NULL${typeFilter}`,\n\t\t[collection, recordId, ...(types ?? [])],\n\t)\n}\n\n/** Whether an operation id is already recorded (log or retained conflict). */\nexport async function isOperationLogged(\n\ttx: Transaction,\n\tcollection: string,\n\topId: string,\n): Promise<boolean> {\n\tconst inLog = await tx.query<{ id: string }>(\n\t\t`SELECT id FROM ${quoteIdent(`_kora_ops_${collection}`)} WHERE id = ?`,\n\t\t[opId],\n\t)\n\tif (inLog.length > 0) return true\n\tconst retained = await tx.query<{ id: string }>(\n\t\t`SELECT id FROM ${SEQ_CONFLICTS_TABLE} WHERE id = ? AND reemitted_as IS NULL`,\n\t\t[opId],\n\t)\n\treturn retained.length > 0\n}\n","import {\n\tFOLD_STATE_VERSION,\n\ttype FoldOptions,\n\ttype FoldState,\n\tFoldStateError,\n\ttype FoldTrace,\n\tHybridLogicalClock,\n\ttype MergeTrace,\n\ttype Operation,\n\ttype OperationTransform,\n\ttype SchemaDefinition,\n\tadaptFoldState,\n\tbase64ToBytes,\n\tcreateFoldState,\n\tdeserializeFoldState,\n\tgetFoldFieldVersionStrings,\n\tisFoldStateLive,\n\tjoinStates,\n\tmaterialize,\n\tmergeOp,\n\tmismatchedFoldFields,\n\tquoteIdent,\n\tserializeFoldState,\n\ttoMergeTrace,\n} from '@korajs/core'\nimport * as Y from 'yjs'\nimport { buildInsertQuery } from '../query/sql-builder'\nimport { deserializeOperationWithCollection, serializeRecord } from '../serialization/serializer'\nimport { loadRetainedConflictRows } from '../store/sequence-repair'\nimport { TERMINAL_REJECTIONS_TABLE } from '../sync/local-sync-records'\nimport type { OperationRow, RawCollectionRow, Transaction } from '../types'\n\n/** Per-record fold state (serialized `FoldState`) of every record this database holds. */\nexport const FOLD_STATE_TABLE = '_kora_fold_state'\n/**\n * Per-record base state of operations no longer in the log (compacted, or a snapshot\n * of a row whose history was compacted or quarantined before W7). A record's state\n * is always `join(base, fold(log))`.\n */\nexport const FOLD_BASE_TABLE = '_kora_fold_base'\n/** Per-node sequence prefix removed by compaction: ids at or below it are duplicates. */\nexport const COMPACTED_THROUGH_TABLE = '_kora_compacted_through'\n/**\n * Per-record row snapshots (RT-68): the base built from a materialized row when the\n * record's history is not all in the log (a pre-W7 compaction, quarantined log rows).\n * Kept apart from `_kora_fold_base` (which holds only exact, operation-built states)\n * so the approximation can be dropped once the record's history is complete again:\n * when the server's fold state arrives in a scope entry, or after a full resync.\n * A record's state is `join(base, snapshot, fold(log))`.\n */\nexport const FOLD_SNAPSHOT_TABLE = '_kora_fold_snapshot'\n/**\n * Local-only provisional side effects (RT-69): the cascades / set-nulls a device\n * derives for a REMOTE delete. They fold into the record like operations but are\n * never logged, sequenced or uploaded (the server derives and relays its own\n * copy); each is retired when the server's copy for the same parent and record\n * arrives, or when the device's delivery stream has caught up.\n\n */\nexport const PROVISIONAL_OPS_TABLE = '_kora_provisional_ops'\n/**\n * Terminal-rejection codes the fold does NOT exclude: the user discarded a held\n * node's writes (they stay in the local database; only their upload stops).\n */\nconst KEPT_REJECTION_CODES: readonly string[] = ['HELD_DISCARDED']\n/** `_kora_meta` key recording how the rows of this database are materialized. */\nexport const FOLD_MATERIALIZATION_META_KEY = 'fold_materialization'\n/** Value of {@link FOLD_MATERIALIZATION_META_KEY} once rows are materializations of the current fold. */\nexport const FOLD_MATERIALIZATION_CURRENT = `fold-v${FOLD_STATE_VERSION}`\n/** Value of {@link FOLD_MATERIALIZATION_META_KEY} while the legacy (beta.12) paths write rows. */\nexport const FOLD_MATERIALIZATION_LEGACY = 'legacy'\n\n/** DDL for the fold tables. Idempotent. */\nexport const FOLD_TABLES_DDL: readonly string[] = [\n\t`CREATE TABLE IF NOT EXISTS ${FOLD_STATE_TABLE} (collection TEXT NOT NULL, record_id TEXT NOT NULL, state TEXT NOT NULL, PRIMARY KEY (collection, record_id))`,\n\t`CREATE TABLE IF NOT EXISTS ${FOLD_BASE_TABLE} (collection TEXT NOT NULL, record_id TEXT NOT NULL, state TEXT NOT NULL, PRIMARY KEY (collection, record_id))`,\n\t`CREATE TABLE IF NOT EXISTS ${COMPACTED_THROUGH_TABLE} (node_id TEXT PRIMARY KEY, sequence_number INTEGER NOT NULL)`,\n\t`CREATE TABLE IF NOT EXISTS ${FOLD_SNAPSHOT_TABLE} (collection TEXT NOT NULL, record_id TEXT NOT NULL, state TEXT NOT NULL, PRIMARY KEY (collection, record_id))`,\n\t`CREATE TABLE IF NOT EXISTS ${PROVISIONAL_OPS_TABLE} (id TEXT PRIMARY KEY, collection TEXT NOT NULL, record_id TEXT NOT NULL, parent_id TEXT NOT NULL, operation TEXT NOT NULL)`,\n\t`CREATE INDEX IF NOT EXISTS ${PROVISIONAL_OPS_TABLE}_record ON ${PROVISIONAL_OPS_TABLE} (collection, record_id)`,\n]\n\n/**\n * Merges richtext Yjs updates for the fold (core has no Yjs dependency): applies\n * every update to one fresh document and encodes its state. The encoding depends\n * only on the document's content, not on how it was split into updates, so every\n * replica materializes byte-identical richtext.\n */\nexport function mergeYjsUpdates(updates: Uint8Array[]): Uint8Array {\n\tconst doc = new Y.Doc()\n\tfor (const update of updates) Y.applyUpdate(doc, update)\n\treturn Y.encodeStateAsUpdate(doc)\n}\n\nfunction sameBytes(a: Uint8Array, b: Uint8Array): boolean {\n\tif (a.length !== b.length) return false\n\tfor (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false\n\treturn true\n}\n\n/**\n * Whether Yjs update `a` adds nothing to update `b` (the fold's richtext space\n * bound): the canonical encoding of `b` alone equals that of `a` and `b` merged.\n */\nexport function yjsSubsumes(a: Uint8Array, b: Uint8Array): boolean {\n\treturn sameBytes(mergeYjsUpdates([b]), mergeYjsUpdates([a, b]))\n}\n\n/**\n * Whether an operation lies in a node's compacted prefix: its row is gone from the\n * log, but its effect is in the record's base state, so it is a duplicate (STORE-14).\n */\nexport async function isCompacted(tx: Transaction, op: Operation): Promise<boolean> {\n\tconst rows = await tx.query<{ sequence_number: number }>(\n\t\t`SELECT sequence_number FROM ${COMPACTED_THROUGH_TABLE} WHERE node_id = ?`,\n\t\t[op.nodeId],\n\t)\n\tconst through = rows[0]?.sequence_number\n\treturn through !== undefined && op.sequenceNumber <= through\n}\n\n/** Which fields of a row to (re)write from the fold state. */\nexport type MaterializeFields = 'all' | ReadonlySet<string>\n\n/** Result of merging one operation into its record. */\nexport interface FoldApplyOutcome {\n\t/** The merge changed the record's state. */\n\tchanged: boolean\n\t/** Merge traces (MergeTrace form), for `merge:*` events. */\n\ttraces: MergeTrace[]\n}\n\n/**\n * The client side of the W7 fold: every write to a materialized row — local\n * writes, remote operations, scope entries, rejection re-merges, re-materialization\n * — goes through this class, inside the write transaction that appends the\n * operation (\"append, then merge\"). A row is always the materialization of its\n * record's fold state.\n */\nexport class RecordFolder {\n\tprivate authoritative: ReadonlySet<string> = new Set()\n\n\tconstructor(\n\t\tprivate readonly schema: SchemaDefinition,\n\t\tprivate readonly transforms: readonly OperationTransform[] = [],\n\t) {}\n\n\t/** The schema transforms every merge applies (transforms at fold time, RT-84). */\n\tgetOperationTransforms(): readonly OperationTransform[] {\n\t\treturn this.transforms\n\t}\n\n\t/**\n\t * The fields an operation's merge can change: its own data's keys, or every field\n\t * when the fold reads it through a schema transform (whose view may name others).\n\t */\n\tprivate touchedFields(op: Operation): MaterializeFields {\n\t\tif (this.transforms.length > 0 && op.schemaVersion !== this.schema.version) return 'all'\n\t\treturn new Set(Object.keys(op.data ?? {}))\n\t}\n\n\t/** Node ids whose writes win `merge('server-authoritative')` fields. */\n\tgetAuthoritativeNodeIds(): ReadonlySet<string> {\n\t\treturn this.authoritative\n\t}\n\n\t/** @internal Set by the store from persisted meta / the sync handshake. */\n\tsetAuthoritativeNodeIds(ids: Iterable<string>): void {\n\t\tthis.authoritative = new Set(ids)\n\t}\n\n\t/** Fold options every merge of this database uses. */\n\toptions(traces: FoldOptions['traces'] = 'none'): FoldOptions {\n\t\treturn {\n\t\t\trichtext: mergeYjsUpdates,\n\t\t\trichtextSubsumes: yjsSubsumes,\n\t\t\ttraces,\n\t\t\t...(this.authoritative.size > 0 ? { authoritativeNodeIds: this.authoritative } : {}),\n\t\t\t...(this.transforms.length > 0 ? { transforms: this.transforms } : {}),\n\t\t}\n\t}\n\n\t/** Whether the schema has a `merge('server-authoritative')` field in `collection`. */\n\thasAuthoritativeFields(collection: string): boolean {\n\t\tconst definition = this.schema.collections[collection]\n\t\tif (!definition) return false\n\t\treturn Object.values(definition.fields).some(\n\t\t\t(field) => field.mergeStrategy === 'server-authoritative',\n\t\t)\n\t}\n\n\t/**\n\t * Merge one operation (already appended to the log) into its record and\n\t * re-materialize the row.\n\t *\n\t * @param tx - The write transaction that appended the operation\n\t * @param op - The operation\n\t * @param mode - 'remote' emits merge traces; 'local' does not (a local write is\n\t * computed from the row it updates, so it is never concurrent with it)\n\t */\n\tasync applyInTx(\n\t\ttx: Transaction,\n\t\top: Operation,\n\t\tmode: 'local' | 'remote',\n\t): Promise<FoldApplyOutcome> {\n\t\tconst scopeEntry = op.type === 'insert'\n\t\tif (mode === 'remote') {\n\t\t\t// The record's approximations end here: a provisional cascade of this parent\n\t\t\t// is replaced by the real one (RT-69), and a row snapshot by the server's\n\t\t\t// complete fold state (RT-68). The operation is already in the log, so the\n\t\t\t// record is re-folded without them.\n\t\t\tconst retired = await this.deleteProvisional(tx, op.collection, op.recordId, op.causalDeps)\n\t\t\tconst replaced = await this.dropSnapshotForCarriedState(tx, op)\n\t\t\tif (retired > 0 || replaced) {\n\t\t\t\tawait this.refoldInTx(tx, op.collection, op.recordId, { clearRetraction: scopeEntry })\n\t\t\t\treturn { changed: true, traces: [] }\n\t\t\t}\n\t\t}\n\t\t// A local insert has a fresh UUIDv7 record id: no state, log or row precedes it.\n\t\tconst fresh = mode === 'local' && op.type === 'insert'\n\t\tconst prior = fresh\n\t\t\t? { state: createFoldState(op.collection, op.recordId), rebuilt: false }\n\t\t\t: await this.loadOrRebuild(tx, op.collection, op.recordId, op.id)\n\t\tlet result: ReturnType<typeof mergeOp>\n\t\ttry {\n\t\t\tresult = mergeOp(\n\t\t\t\tprior.state,\n\t\t\t\top,\n\t\t\t\tthis.schema,\n\t\t\t\tthis.options(mode === 'remote' ? 'conflicts' : 'none'),\n\t\t\t)\n\t\t} catch (error) {\n\t\t\tif (!(error instanceof FoldStateError)) throw error\n\t\t\t// A stored state the current plan cannot take (RT-63): re-fold the record from\n\t\t\t// its base and log (the operation is already appended) once. A second\n\t\t\t// FoldStateError propagates; the sync engine then quarantines the operation\n\t\t\t// instead of stalling its delivery stream.\n\t\t\tawait this.refoldInTx(tx, op.collection, op.recordId, { clearRetraction: scopeEntry })\n\t\t\treturn { changed: true, traces: [] }\n\t\t}\n\t\tif (!result.changed && !prior.rebuilt && !scopeEntry) {\n\t\t\treturn { changed: false, traces: await this.toMergeTraces(tx, result.traces) }\n\t\t}\n\t\tawait this.saveState(tx, result.state)\n\t\tconst revived = isDeadState(prior.state) && !isDeadState(result.state)\n\t\tconst fields: MaterializeFields =\n\t\t\tprior.rebuilt || revived || op.foldState !== undefined ? 'all' : this.touchedFields(op)\n\t\tawait this.materializeRow(tx, result.state, fields, {\n\t\t\tclearRetraction: scopeEntry,\n\t\t\t...(fresh ? { absent: true } : {}),\n\t\t})\n\t\treturn { changed: result.changed, traces: await this.toMergeTraces(tx, result.traces) }\n\t}\n\n\t/**\n\t * Fold a record from its base state and its log, leaving out operations the\n\t * server terminally rejected, and re-materialize its row (all fields).\n\t *\n\t * @returns The new state (null when nothing of the record remains)\n\t */\n\tasync refoldInTx(\n\t\ttx: Transaction,\n\t\tcollection: string,\n\t\trecordId: string,\n\t\toptions: { clearRetraction?: boolean } = {},\n\t): Promise<FoldState | null> {\n\t\tconst state = await this.foldFromLog(tx, collection, recordId)\n\t\tif (state === null) {\n\t\t\tawait tx.execute(`DELETE FROM ${FOLD_STATE_TABLE} WHERE collection = ? AND record_id = ?`, [\n\t\t\t\tcollection,\n\t\t\t\trecordId,\n\t\t\t])\n\t\t\t// Nothing of the record remains (its insert was refused): hide the row.\n\t\t\tawait tx.execute(`UPDATE ${quoteIdent(collection)} SET _deleted = 1 WHERE id = ?`, [recordId])\n\t\t\treturn null\n\t\t}\n\t\tawait this.saveState(tx, state)\n\t\tawait this.materializeRow(tx, state, 'all', {\n\t\t\tclearRetraction: options.clearRetraction ?? false,\n\t\t})\n\t\treturn state\n\t}\n\n\t/**\n\t * `join(base, snapshot, fold(log - terminally rejected, provisional effects))`, or\n\t * null when none exists. Base and snapshot are adapted to the current fold plan\n\t * (RT-63): a field whose kind changed is rebuilt from its materialized value.\n\t */\n\tasync foldFromLog(\n\t\ttx: Transaction,\n\t\tcollection: string,\n\t\trecordId: string,\n\t): Promise<FoldState | null> {\n\t\tconst ops = [\n\t\t\t...(await this.loadRecordOperations(tx, collection, recordId)),\n\t\t\t...(await this.loadProvisional(tx, collection, recordId)),\n\t\t]\n\t\tconst rejected = await this.loadTerminalRejections(\n\t\t\ttx,\n\t\t\tops.map((op) => op.id),\n\t\t)\n\t\tconst base = await this.loadBase(tx, collection, recordId)\n\t\tconst snapshot = await this.loadSnapshot(tx, collection, recordId)\n\t\tlet state =\n\t\t\tbase !== null && snapshot !== null\n\t\t\t\t? joinStates(base, snapshot, this.schema)\n\t\t\t\t: (base ?? snapshot)\n\t\tfor (const op of ops) {\n\t\t\tif (rejected.has(op.id)) continue\n\t\t\tstate = mergeOp(\n\t\t\t\tstate ?? createFoldState(collection, recordId),\n\t\t\t\top,\n\t\t\t\tthis.schema,\n\t\t\t\tthis.options(),\n\t\t\t).state\n\t\t}\n\t\treturn state\n\t}\n\n\t/** The record's operations (log + retained sequence-conflict rows). */\n\tasync loadRecordOperations(\n\t\ttx: Transaction,\n\t\tcollection: string,\n\t\trecordId: string,\n\t): Promise<Operation[]> {\n\t\tconst rows = [\n\t\t\t...(await tx.query<OperationRow>(\n\t\t\t\t`SELECT * FROM ${quoteIdent(`_kora_ops_${collection}`)} WHERE record_id = ?`,\n\t\t\t\t[recordId],\n\t\t\t)),\n\t\t\t...(await loadRetainedConflictRows(\n\t\t\t\t(sql, params) => tx.query(sql, params),\n\t\t\t\tcollection,\n\t\t\t\trecordId,\n\t\t\t)),\n\t\t]\n\t\treturn rows.map((row) => deserializeOperationWithCollection(row, collection))\n\t}\n\n\t/**\n\t * Which of `ids` the fold leaves out: operations with a terminal-rejection marker\n\t * from the server (or quarantined by a scope retraction, which the server never\n\t * receives). Writes the user chose to discard from a held node are NOT left out:\n\t * discarding stops the upload, it is not a rollback.\n\t */\n\tasync loadTerminalRejections(tx: Transaction, ids: readonly string[]): Promise<Set<string>> {\n\t\tconst found = new Set<string>()\n\t\tconst CHUNK = 500\n\t\tfor (let i = 0; i < ids.length; i += CHUNK) {\n\t\t\tconst chunk = ids.slice(i, i + CHUNK)\n\t\t\tconst rows = await tx.query<{ operation_id: string }>(\n\t\t\t\t`SELECT operation_id FROM ${TERMINAL_REJECTIONS_TABLE} WHERE code NOT IN (${KEPT_REJECTION_CODES.map(() => '?').join(', ')}) AND operation_id IN (${chunk.map(() => '?').join(', ')})`,\n\t\t\t\t[...KEPT_REJECTION_CODES, ...chunk],\n\t\t\t)\n\t\t\tfor (const row of rows) found.add(row.operation_id)\n\t\t}\n\t\treturn found\n\t}\n\n\t/**\n\t * The record's stored state, or null (none, another format version, or a field\n\t * whose fold kind the schema has changed since: the caller re-folds, RT-63).\n\t */\n\tasync loadState(\n\t\ttx: Transaction,\n\t\tcollection: string,\n\t\trecordId: string,\n\t): Promise<FoldState | null> {\n\t\tconst state = await this.readStateRow(tx, FOLD_STATE_TABLE, collection, recordId)\n\t\tif (state === null || mismatchedFoldFields(state, this.schema).length > 0) return null\n\t\treturn state\n\t}\n\n\t/** The stored state as it is, even when the plan changed (a snapshot seed). */\n\tasync loadStoredState(\n\t\ttx: Transaction,\n\t\tcollection: string,\n\t\trecordId: string,\n\t): Promise<FoldState | null> {\n\t\treturn this.readStateRow(tx, FOLD_STATE_TABLE, collection, recordId)\n\t}\n\n\t/** The record's compacted base, adapted to the current fold plan (RT-63). */\n\tasync loadBase(tx: Transaction, collection: string, recordId: string): Promise<FoldState | null> {\n\t\tconst base = await this.readStateRow(tx, FOLD_BASE_TABLE, collection, recordId)\n\t\treturn base === null ? null : adaptFoldState(base, this.schema, this.options()).state\n\t}\n\n\t/** The record's row snapshot (RT-68), adapted to the current fold plan. */\n\tasync loadSnapshot(\n\t\ttx: Transaction,\n\t\tcollection: string,\n\t\trecordId: string,\n\t): Promise<FoldState | null> {\n\t\tconst snapshot = await this.readStateRow(tx, FOLD_SNAPSHOT_TABLE, collection, recordId)\n\t\treturn snapshot === null ? null : adaptFoldState(snapshot, this.schema, this.options()).state\n\t}\n\n\t/** Store `snapshot` as the record's row snapshot (joined with an existing one). */\n\tasync saveSnapshot(tx: Transaction, snapshot: FoldState): Promise<void> {\n\t\tconst existing = await this.loadSnapshot(tx, snapshot.c, snapshot.r)\n\t\tconst state = existing === null ? snapshot : joinStates(existing, snapshot, this.schema)\n\t\tawait tx.execute(\n\t\t\t`INSERT OR REPLACE INTO ${FOLD_SNAPSHOT_TABLE} (collection, record_id, state) VALUES (?, ?, ?)`,\n\t\t\t[state.c, state.r, persistedForm(state)],\n\t\t)\n\t}\n\n\t/**\n\t * A scope entry carrying the server's fold state (RT-29) replaces the record's row\n\t * snapshot (RT-68): the server's state is built from every operation of the record\n\t * the device was missing, so with the device's own log it is the exact state.\n\t * Only a carried state this schema can read and join counts (otherwise the entry\n\t * merges by its data and the snapshot stays).\n\t *\n\t * @returns Whether a snapshot was dropped\n\t */\n\tprivate async dropSnapshotForCarriedState(tx: Transaction, op: Operation): Promise<boolean> {\n\t\tif (op.type !== 'insert' || op.foldState === undefined) return false\n\t\tconst rows = await tx.query<{ n: number }>(\n\t\t\t`SELECT COUNT(*) AS n FROM ${FOLD_SNAPSHOT_TABLE} WHERE collection = ? AND record_id = ?`,\n\t\t\t[op.collection, op.recordId],\n\t\t)\n\t\tif ((rows[0]?.n ?? 0) === 0) return false\n\t\tlet carried: FoldState\n\t\ttry {\n\t\t\tcarried = deserializeFoldState(op.foldState)\n\t\t} catch (error) {\n\t\t\tif (error instanceof FoldStateError) return false\n\t\t\tthrow error\n\t\t}\n\t\tif (carried.c !== op.collection || carried.r !== op.recordId) return false\n\t\tif (mismatchedFoldFields(carried, this.schema).length > 0) return false\n\t\tawait tx.execute(`DELETE FROM ${FOLD_SNAPSHOT_TABLE} WHERE collection = ? AND record_id = ?`, [\n\t\t\top.collection,\n\t\t\top.recordId,\n\t\t])\n\t\treturn true\n\t}\n\n\t/** Records that still fold against a row snapshot (approximate, RT-68). */\n\tasync listSnapshotRecords(\n\t\ttx: Transaction,\n\t): Promise<Array<{ collection: string; recordId: string }>> {\n\t\tconst rows = await tx.query<{ collection: string; record_id: string }>(\n\t\t\t`SELECT collection, record_id FROM ${FOLD_SNAPSHOT_TABLE} ORDER BY collection, record_id`,\n\t\t)\n\t\treturn rows.map((row) => ({ collection: row.collection, recordId: row.record_id }))\n\t}\n\n\t/**\n\t * After a full resync, a record whose log holds its insert again no longer needs\n\t * its row snapshot: drop it and re-fold the record from base and log (RT-68).\n\t *\n\t * @returns Whether the snapshot was dropped\n\t */\n\tasync settleSnapshotInTx(\n\t\ttx: Transaction,\n\t\tcollection: string,\n\t\trecordId: string,\n\t): Promise<boolean> {\n\t\tconst ops = await this.loadRecordOperations(tx, collection, recordId)\n\t\tconst rejected = await this.loadTerminalRejections(\n\t\t\ttx,\n\t\t\tops.map((op) => op.id),\n\t\t)\n\t\tconst hasInsert = ops.some((op) => op.type === 'insert' && !rejected.has(op.id))\n\t\tconst base = await this.loadBase(tx, collection, recordId)\n\t\tif (!hasInsert && (base?.cr ?? null) === null) return false\n\t\tawait tx.execute(`DELETE FROM ${FOLD_SNAPSHOT_TABLE} WHERE collection = ? AND record_id = ?`, [\n\t\t\tcollection,\n\t\t\trecordId,\n\t\t])\n\t\tawait this.refoldInTx(tx, collection, recordId)\n\t\treturn true\n\t}\n\n\t/**\n\t * Fold a local-only provisional side effect (RT-69) into its record: stored apart\n\t * from the log (never sequenced, never uploaded) and kept until the real copy of\n\t * the effect arrives or the delivery stream catches up.\n\t *\n\t * @param parentId - The remote operation that caused it (the parent delete)\n\t */\n\tasync applyProvisionalInTx(tx: Transaction, op: Operation, parentId: string): Promise<void> {\n\t\tconst existing = await tx.query<{ id: string }>(\n\t\t\t`SELECT id FROM ${PROVISIONAL_OPS_TABLE} WHERE id = ?`,\n\t\t\t[op.id],\n\t\t)\n\t\tif (existing.length > 0) return\n\t\tawait tx.execute(\n\t\t\t`INSERT INTO ${PROVISIONAL_OPS_TABLE} (id, collection, record_id, parent_id, operation) VALUES (?, ?, ?, ?, ?)`,\n\t\t\t[op.id, op.collection, op.recordId, parentId, JSON.stringify(op)],\n\t\t)\n\t\tconst prior = await this.loadOrRebuild(tx, op.collection, op.recordId, op.id)\n\t\tconst result = mergeOp(prior.state, op, this.schema, this.options())\n\t\tif (!result.changed && !prior.rebuilt) return\n\t\tawait this.saveState(tx, result.state)\n\t\tawait this.materializeRow(tx, result.state, prior.rebuilt ? 'all' : this.touchedFields(op), {\n\t\t\tclearRetraction: false,\n\t\t})\n\t}\n\n\t/**\n\t * Remove provisional effects of a record (those caused by one of `parentIds`, or\n\t * all of them when null). The caller re-folds the record.\n\t *\n\t * @returns How many were removed\n\t */\n\tasync deleteProvisional(\n\t\ttx: Transaction,\n\t\tcollection: string,\n\t\trecordId: string,\n\t\tparentIds: readonly string[] | null,\n\t): Promise<number> {\n\t\tif (parentIds !== null && parentIds.length === 0) return 0\n\t\tconst filter =\n\t\t\tparentIds === null ? '' : ` AND parent_id IN (${parentIds.map(() => '?').join(', ')})`\n\t\tconst rows = await tx.query<{ id: string }>(\n\t\t\t`SELECT id FROM ${PROVISIONAL_OPS_TABLE} WHERE collection = ? AND record_id = ?${filter}`,\n\t\t\t[collection, recordId, ...(parentIds ?? [])],\n\t\t)\n\t\tif (rows.length === 0) return 0\n\t\tawait tx.execute(\n\t\t\t`DELETE FROM ${PROVISIONAL_OPS_TABLE} WHERE id IN (${rows.map(() => '?').join(', ')})`,\n\t\t\trows.map((row) => row.id),\n\t\t)\n\t\treturn rows.length\n\t}\n\n\t/** Records with provisional effects. */\n\tasync listProvisionalRecords(\n\t\ttx: Transaction,\n\t): Promise<Array<{ collection: string; recordId: string }>> {\n\t\tconst rows = await tx.query<{ collection: string; record_id: string }>(\n\t\t\t`SELECT DISTINCT collection, record_id FROM ${PROVISIONAL_OPS_TABLE} ORDER BY collection, record_id`,\n\t\t)\n\t\treturn rows.map((row) => ({ collection: row.collection, recordId: row.record_id }))\n\t}\n\n\tprivate async loadProvisional(\n\t\ttx: Transaction,\n\t\tcollection: string,\n\t\trecordId: string,\n\t): Promise<Operation[]> {\n\t\tconst rows = await tx.query<{ operation: string }>(\n\t\t\t`SELECT operation FROM ${PROVISIONAL_OPS_TABLE} WHERE collection = ? AND record_id = ?`,\n\t\t\t[collection, recordId],\n\t\t)\n\t\treturn rows.map((row) => JSON.parse(row.operation) as Operation)\n\t}\n\n\tasync saveState(tx: Transaction, state: FoldState): Promise<void> {\n\t\tawait tx.execute(\n\t\t\t`INSERT OR REPLACE INTO ${FOLD_STATE_TABLE} (collection, record_id, state) VALUES (?, ?, ?)`,\n\t\t\t[state.c, state.r, persistedForm(state)],\n\t\t)\n\t}\n\n\tasync saveBase(tx: Transaction, state: FoldState): Promise<void> {\n\t\tawait tx.execute(\n\t\t\t`INSERT OR REPLACE INTO ${FOLD_BASE_TABLE} (collection, record_id, state) VALUES (?, ?, ?)`,\n\t\t\t[state.c, state.r, persistedForm(state)],\n\t\t)\n\t}\n\n\t/** Join `addition` into the record's base state. */\n\tasync joinIntoBase(tx: Transaction, addition: FoldState): Promise<void> {\n\t\tconst base = await this.loadBase(tx, addition.c, addition.r)\n\t\tawait this.saveBase(tx, base === null ? addition : joinStates(base, addition, this.schema))\n\t}\n\n\t/**\n\t * Write the row of a record from its fold state.\n\t *\n\t * - No insert merged: no row (an existing one is hidden).\n\t * - Otherwise the row holds the fold's values (also while deleted: a tombstone\n\t * keeps its last values), `_deleted` from the record's liveness, and versions\n\t * from the state: `_version` / `_updated_at` = newest operation, `_created_at` =\n\t * creation, `_field_versions` = each field's newest write.\n\t * - Only `fields` are written to an existing row; columns the fold never wrote\n\t * (a column a schema migration added with a default, a local-only backfill)\n\t * keep their stored value.\n\t * - A row hidden by a scope retraction stays hidden unless `clearRetraction`\n\t * (a scope-entry insert) is set.\n\t */\n\tasync materializeRow(\n\t\ttx: Transaction,\n\t\tstate: FoldState,\n\t\tfields: MaterializeFields,\n\t\toptions: { clearRetraction: boolean; absent?: boolean },\n\t): Promise<void> {\n\t\tconst collection = state.c\n\t\tconst definition = this.schema.collections[collection]\n\t\tif (!definition) return\n\t\tconst table = quoteIdent(collection)\n\t\tconst rows = options.absent\n\t\t\t? []\n\t\t\t: await tx.query<RawCollectionRow>(`SELECT id, _deleted FROM ${table} WHERE id = ?`, [\n\t\t\t\t\tstate.r,\n\t\t\t\t])\n\t\tconst existing = rows[0]\n\t\tif (state.cr === null || state.u === null) {\n\t\t\tif (existing && existing._deleted !== 1) {\n\t\t\t\tawait tx.execute(`UPDATE ${table} SET _deleted = 1 WHERE id = ?`, [state.r])\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t\tconst asLive: FoldState = { ...state, d: null }\n\t\tconst values = materialize(asLive, { richtext: mergeYjsUpdates }) ?? {}\n\t\tconst latest = HybridLogicalClock.deserialize(state.u.t)\n\t\tconst created = HybridLogicalClock.deserialize(state.cr.t)\n\t\t// Sorted keys: replicas holding the same state write byte-identical columns.\n\t\tconst fieldVersions = getFoldFieldVersionStrings(state)\n\t\tlet deleted = isDeadState(state) ? 1 : 0\n\t\tif (existing && deleted === 0) {\n\t\t\tconst retracted = await tx.query<{ record_id: string }>(\n\t\t\t\t'SELECT record_id FROM _kora_scope_retractions WHERE collection = ? AND record_id = ?',\n\t\t\t\t[collection, state.r],\n\t\t\t)\n\t\t\tif (retracted.length > 0) {\n\t\t\t\tif (options.clearRetraction) {\n\t\t\t\t\tawait tx.execute(\n\t\t\t\t\t\t'DELETE FROM _kora_scope_retractions WHERE collection = ? AND record_id = ?',\n\t\t\t\t\t\t[collection, state.r],\n\t\t\t\t\t)\n\t\t\t\t} else {\n\t\t\t\t\tdeleted = 1\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tconst known = Object.keys(definition.fields)\n\t\t// A tombstone keeps the values it had when it was deleted: a write that lost to\n\t\t// the delete never shows, not even in the hidden row. A revival rewrites them all.\n\t\tconst writable =\n\t\t\texisting && deleted === 1\n\t\t\t\t? []\n\t\t\t\t: known.filter((field) => field in state.f && (fields === 'all' || fields.has(field)))\n\t\tconst fieldValues: Record<string, unknown> = {}\n\t\tfor (const field of writable) {\n\t\t\tconst value = values[field] ?? null\n\t\t\t// A richtext field with a single live update materializes as that update's\n\t\t\t// own bytes; re-encode it so every replica stores the same canonical bytes,\n\t\t\t// however its state happens to be split into updates.\n\t\t\tfieldValues[field] =\n\t\t\t\tdefinition.fields[field]?.kind === 'richtext' &&\n\t\t\t\tvalue !== null &&\n\t\t\t\ttypeof value === 'object' &&\n\t\t\t\t'$koraBytes' in value\n\t\t\t\t\t? mergeYjsUpdates([base64ToBytes(String((value as { $koraBytes: string }).$koraBytes))])\n\t\t\t\t\t: value\n\t\t}\n\t\tconst serialized = serializeRecord(fieldValues, definition.fields)\n\t\tconst meta: Record<string, unknown> = {\n\t\t\t_updated_at: latest.wallTime,\n\t\t\t_version: state.u.t,\n\t\t\t_field_versions: JSON.stringify(fieldVersions),\n\t\t\t_deleted: deleted,\n\t\t}\n\t\tif (!existing) {\n\t\t\tconst insert = buildInsertQuery(collection, {\n\t\t\t\tid: state.r,\n\t\t\t\t...serialized,\n\t\t\t\t...meta,\n\t\t\t\t_created_at: created.wallTime,\n\t\t\t})\n\t\t\tawait tx.execute(insert.sql, insert.params)\n\t\t\treturn\n\t\t}\n\t\tconst changes: Record<string, unknown> = {\n\t\t\t...serialized,\n\t\t\t...meta,\n\t\t\t_created_at: created.wallTime,\n\t\t}\n\t\tconst columns = Object.keys(changes)\n\t\tawait tx.execute(\n\t\t\t`UPDATE ${table} SET ${columns.map((c) => `${quoteIdent(c)} = ?`).join(', ')} WHERE id = ?`,\n\t\t\t[...columns.map((c) => changes[c]), state.r],\n\t\t)\n\t}\n\n\t/**\n\t * Load the record's state; rebuild it from base + log when it is missing or in\n\t * another format version. `rebuilt` tells the caller to rewrite the whole row.\n\t */\n\tprivate async loadOrRebuild(\n\t\ttx: Transaction,\n\t\tcollection: string,\n\t\trecordId: string,\n\t\tappendedId: string,\n\t): Promise<{ state: FoldState; rebuilt: boolean }> {\n\t\tconst stored = await this.loadState(tx, collection, recordId)\n\t\tif (stored !== null) return { state: stored, rebuilt: false }\n\t\tconst hasRow = await this.hasStateRow(tx, collection, recordId)\n\t\tconst others = await tx.query<{ n: number }>(\n\t\t\t`SELECT COUNT(*) AS n FROM ${quoteIdent(`_kora_ops_${collection}`)} WHERE record_id = ? AND id != ?`,\n\t\t\t[recordId, appendedId],\n\t\t)\n\t\tconst retained = await loadRetainedConflictRows(\n\t\t\t(sql, params) => tx.query(sql, params),\n\t\t\tcollection,\n\t\t\trecordId,\n\t\t)\n\t\tconst hasBase =\n\t\t\t(await this.loadBase(tx, collection, recordId)) !== null ||\n\t\t\t(await this.loadSnapshot(tx, collection, recordId)) !== null ||\n\t\t\t(await this.loadProvisional(tx, collection, recordId)).some((p) => p.id !== appendedId)\n\t\tif (\n\t\t\t!hasRow &&\n\t\t\t!hasBase &&\n\t\t\t(others[0]?.n ?? 0) === 0 &&\n\t\t\tretained.every((row) => row.id === appendedId)\n\t\t) {\n\t\t\t// A new record: nothing to rebuild.\n\t\t\treturn { state: createFoldState(collection, recordId), rebuilt: false }\n\t\t}\n\t\tconst rebuilt = await this.foldFromLog(tx, collection, recordId)\n\t\treturn { state: rebuilt ?? createFoldState(collection, recordId), rebuilt: true }\n\t}\n\n\tprivate async hasStateRow(\n\t\ttx: Transaction,\n\t\tcollection: string,\n\t\trecordId: string,\n\t): Promise<boolean> {\n\t\tconst rows = await tx.query<{ n: number }>(\n\t\t\t`SELECT COUNT(*) AS n FROM ${FOLD_STATE_TABLE} WHERE collection = ? AND record_id = ?`,\n\t\t\t[collection, recordId],\n\t\t)\n\t\treturn (rows[0]?.n ?? 0) > 0\n\t}\n\n\tprivate async readStateRow(\n\t\ttx: Transaction,\n\t\ttable: string,\n\t\tcollection: string,\n\t\trecordId: string,\n\t): Promise<FoldState | null> {\n\t\tconst rows = await tx.query<{ state: string }>(\n\t\t\t`SELECT state FROM ${table} WHERE collection = ? AND record_id = ?`,\n\t\t\t[collection, recordId],\n\t\t)\n\t\tconst raw = rows[0]?.state\n\t\tif (raw === undefined) return null\n\t\ttry {\n\t\t\treturn deserializeFoldState(raw)\n\t\t} catch (error) {\n\t\t\t// Another format version: the caller re-folds the record.\n\t\t\tif (error instanceof FoldStateError) return null\n\t\t\tthrow error\n\t\t}\n\t}\n\n\tprivate async toMergeTraces(tx: Transaction, traces: FoldTrace[]): Promise<MergeTrace[]> {\n\t\tconst out: MergeTrace[] = []\n\t\tfor (const trace of traces) {\n\t\t\tlet prior: Operation | null = null\n\t\t\tif (trace.priorOperationId !== null) {\n\t\t\t\tconst rows = await tx.query<OperationRow>(\n\t\t\t\t\t`SELECT * FROM ${quoteIdent(`_kora_ops_${trace.operation.collection}`)} WHERE id = ?`,\n\t\t\t\t\t[trace.priorOperationId],\n\t\t\t\t)\n\t\t\t\tconst row = rows[0]\n\t\t\t\tif (row) prior = deserializeOperationWithCollection(row, trace.operation.collection)\n\t\t\t}\n\t\t\tout.push(toMergeTrace(trace, prior))\n\t\t}\n\t\treturn out\n\t}\n}\n\n/** No insert merged yet, or the newest delete is later than the newest write. */\n/**\n * The stored form of a fold state: plain JSON, read back by `deserializeFoldState`.\n * The canonical form (`serializeFoldState`, sorted keys) is for comparing and\n * exchanging states; a local row only needs to round-trip, and plain JSON is several\n * times cheaper on the write path.\n */\nfunction persistedForm(state: FoldState): string {\n\treturn JSON.stringify(state)\n}\n\nfunction isDeadState(state: FoldState): boolean {\n\treturn !isFoldStateLive(state)\n}\n"],"mappings":"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","names":["quoteIdent","quoteIdent","quoteIdent","quoteIdent"]}
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
} from "./chunk-MYSJN3DF.js";
|
|
6
6
|
import {
|
|
7
7
|
deserializeOperationWithCollection
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-J5AGXF3D.js";
|
|
9
9
|
|
|
10
10
|
// src/audit/export-audit.ts
|
|
11
11
|
import { quoteIdent } from "@korajs/core";
|
|
@@ -186,4 +186,4 @@ export {
|
|
|
186
186
|
readAuditExportManifest,
|
|
187
187
|
verifyAuditExportChecksum
|
|
188
188
|
};
|
|
189
|
-
//# sourceMappingURL=chunk-
|
|
189
|
+
//# sourceMappingURL=chunk-5ZRRF6R2.js.map
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// src/migrations/schema-ceiling.ts
|
|
2
|
+
var DIRECTIVE = /^--kora:schema-ceiling (\d+)$/;
|
|
3
|
+
var AHEAD = /KORA_SCHEMA_VERSION_AHEAD stored=(\d+) code=(\d+)/;
|
|
4
|
+
function parseSchemaCeiling(sql) {
|
|
5
|
+
const match = DIRECTIVE.exec(sql.trim());
|
|
6
|
+
return match ? Number(match[1]) : null;
|
|
7
|
+
}
|
|
8
|
+
function storedSchemaVersion(rows) {
|
|
9
|
+
const value = Number(rows[0]?.value ?? 0);
|
|
10
|
+
return Number.isFinite(value) ? value : 0;
|
|
11
|
+
}
|
|
12
|
+
function schemaAheadMessage(stored, code) {
|
|
13
|
+
return `KORA_SCHEMA_VERSION_AHEAD stored=${stored} code=${code}: the database was migrated by a newer build (schema version ${stored}); this build's schema version is ${code}.`;
|
|
14
|
+
}
|
|
15
|
+
function parseSchemaAhead(error) {
|
|
16
|
+
const seen = /* @__PURE__ */ new Set();
|
|
17
|
+
let current = error;
|
|
18
|
+
while (current !== null && current !== void 0 && !seen.has(current)) {
|
|
19
|
+
seen.add(current);
|
|
20
|
+
const text = current instanceof Error ? current.message : typeof current === "string" ? current : "";
|
|
21
|
+
const match = AHEAD.exec(text);
|
|
22
|
+
if (match) return { stored: Number(match[1]), code: Number(match[2]) };
|
|
23
|
+
current = current instanceof Error ? current.cause : null;
|
|
24
|
+
}
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
var STORED_SCHEMA_VERSION_SQL = "SELECT value FROM _kora_meta WHERE key = 'schema_version'";
|
|
28
|
+
|
|
29
|
+
export {
|
|
30
|
+
parseSchemaCeiling,
|
|
31
|
+
storedSchemaVersion,
|
|
32
|
+
schemaAheadMessage,
|
|
33
|
+
parseSchemaAhead,
|
|
34
|
+
STORED_SCHEMA_VERSION_SQL
|
|
35
|
+
};
|
|
36
|
+
//# sourceMappingURL=chunk-A6GFH5IG.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/migrations/schema-ceiling.ts"],"sourcesContent":["/**\n * The schema-version ceiling (RT-109): a build never runs against a database a newer\n * build already migrated.\n *\n * `generateFullDDL` emits `--kora:schema-ceiling <version>` right after `_kora_meta`, before\n * any other DDL. It is a SQL comment; Kora's DDL executors (the native adapter, the SQLite\n * WASM worker, the test bridge) stop there with {@link schemaAheadMessage} when the\n * database's stored schema version is newer, so not even this build's additive DDL touches\n * it. The store then maps the failure to `SchemaVersionAheadError` and checks again after\n * every open (adapters that restore data after their DDL, such as the IndexedDB fallback).\n *\n * No imports: the SQLite WASM worker bundles this file.\n */\n\nconst DIRECTIVE = /^--kora:schema-ceiling (\\d+)$/\nconst AHEAD = /KORA_SCHEMA_VERSION_AHEAD stored=(\\d+) code=(\\d+)/\n\n/** The version a `--kora:schema-ceiling <version>` DDL statement names, or null. */\nexport function parseSchemaCeiling(sql: string): number | null {\n\tconst match = DIRECTIVE.exec(sql.trim())\n\treturn match ? Number(match[1]) : null\n}\n\n/** The stored version from a `_kora_meta` row read, or 0 when none is stored. */\nexport function storedSchemaVersion(rows: ReadonlyArray<{ value: unknown }>): number {\n\tconst value = Number(rows[0]?.value ?? 0)\n\treturn Number.isFinite(value) ? value : 0\n}\n\n/** The message a DDL executor throws when the database is ahead (parsed back by the store). */\nexport function schemaAheadMessage(stored: number, code: number): string {\n\treturn `KORA_SCHEMA_VERSION_AHEAD stored=${stored} code=${code}: the database was migrated by a newer build (schema version ${stored}); this build's schema version is ${code}.`\n}\n\n/** The versions in an error raised by {@link schemaAheadMessage}, wherever it was wrapped. */\nexport function parseSchemaAhead(error: unknown): { stored: number; code: number } | null {\n\tconst seen = new Set<unknown>()\n\tlet current: unknown = error\n\twhile (current !== null && current !== undefined && !seen.has(current)) {\n\t\tseen.add(current)\n\t\tconst text =\n\t\t\tcurrent instanceof Error ? current.message : typeof current === 'string' ? current : ''\n\t\tconst match = AHEAD.exec(text)\n\t\tif (match) return { stored: Number(match[1]), code: Number(match[2]) }\n\t\tcurrent = current instanceof Error ? (current as { cause?: unknown }).cause : null\n\t}\n\treturn null\n}\n\n/** Query the stored schema version through a synchronous runner (DDL executors). */\nexport const STORED_SCHEMA_VERSION_SQL = \"SELECT value FROM _kora_meta WHERE key = 'schema_version'\"\n"],"mappings":";AAcA,IAAM,YAAY;AAClB,IAAM,QAAQ;AAGP,SAAS,mBAAmB,KAA4B;AAC9D,QAAM,QAAQ,UAAU,KAAK,IAAI,KAAK,CAAC;AACvC,SAAO,QAAQ,OAAO,MAAM,CAAC,CAAC,IAAI;AACnC;AAGO,SAAS,oBAAoB,MAAiD;AACpF,QAAM,QAAQ,OAAO,KAAK,CAAC,GAAG,SAAS,CAAC;AACxC,SAAO,OAAO,SAAS,KAAK,IAAI,QAAQ;AACzC;AAGO,SAAS,mBAAmB,QAAgB,MAAsB;AACxE,SAAO,oCAAoC,MAAM,SAAS,IAAI,gEAAgE,MAAM,qCAAqC,IAAI;AAC9K;AAGO,SAAS,iBAAiB,OAAyD;AACzF,QAAM,OAAO,oBAAI,IAAa;AAC9B,MAAI,UAAmB;AACvB,SAAO,YAAY,QAAQ,YAAY,UAAa,CAAC,KAAK,IAAI,OAAO,GAAG;AACvE,SAAK,IAAI,OAAO;AAChB,UAAM,OACL,mBAAmB,QAAQ,QAAQ,UAAU,OAAO,YAAY,WAAW,UAAU;AACtF,UAAM,QAAQ,MAAM,KAAK,IAAI;AAC7B,QAAI,MAAO,QAAO,EAAE,QAAQ,OAAO,MAAM,CAAC,CAAC,GAAG,MAAM,OAAO,MAAM,CAAC,CAAC,EAAE;AACrE,cAAU,mBAAmB,QAAS,QAAgC,QAAQ;AAAA,EAC/E;AACA,SAAO;AACR;AAGO,IAAM,4BAA4B;","names":[]}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
// src/errors.ts
|
|
2
|
+
import { KoraError } from "@korajs/core";
|
|
3
|
+
var QueryError = class extends KoraError {
|
|
4
|
+
constructor(message, context) {
|
|
5
|
+
super(message, "QUERY_ERROR", context);
|
|
6
|
+
this.name = "QueryError";
|
|
7
|
+
}
|
|
8
|
+
};
|
|
9
|
+
var RecordNotFoundError = class extends KoraError {
|
|
10
|
+
constructor(collection, recordId) {
|
|
11
|
+
super(`Record "${recordId}" not found in collection "${collection}"`, "RECORD_NOT_FOUND", {
|
|
12
|
+
collection,
|
|
13
|
+
recordId
|
|
14
|
+
});
|
|
15
|
+
this.name = "RecordNotFoundError";
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
var OptimisticLockError = class extends KoraError {
|
|
19
|
+
constructor(collection, recordId) {
|
|
20
|
+
super(
|
|
21
|
+
`Row version changed while merging record "${recordId}" in "${collection}"; retry with fresh state`,
|
|
22
|
+
"OPTIMISTIC_LOCK",
|
|
23
|
+
{ collection, recordId }
|
|
24
|
+
);
|
|
25
|
+
this.name = "OptimisticLockError";
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
var AdapterError = class extends KoraError {
|
|
29
|
+
constructor(message, context) {
|
|
30
|
+
super(message, "ADAPTER_ERROR", context);
|
|
31
|
+
this.name = "AdapterError";
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
var StorageDurabilityError = class extends KoraError {
|
|
35
|
+
constructor(dbName, phase, reason) {
|
|
36
|
+
super(
|
|
37
|
+
`Database "${dbName}" has no durable storage (${reason} during ${phase}); writes are refused so they are not silently lost on reload. Close other tabs or apps using this origin's storage and reload, or set allowNonDurable: true to accept in-memory storage.`,
|
|
38
|
+
"STORAGE_DURABILITY_LOST",
|
|
39
|
+
{ dbName, phase, reason }
|
|
40
|
+
);
|
|
41
|
+
this.name = "StorageDurabilityError";
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
var SchemaVersionAheadError = class extends KoraError {
|
|
45
|
+
constructor(dbName, storedVersion, codeVersion) {
|
|
46
|
+
super(
|
|
47
|
+
`Database "${dbName}" is at schema version ${storedVersion}, newer than this build's schema version ${codeVersion}: a newer build of the app already migrated it. It was not opened and nothing in it changed. Run the newer build (reload while online, or accept the update); never lower schema.version in a deployed app.`,
|
|
48
|
+
"SCHEMA_VERSION_AHEAD",
|
|
49
|
+
{ dbName, storedVersion, codeVersion }
|
|
50
|
+
);
|
|
51
|
+
this.dbName = dbName;
|
|
52
|
+
this.storedVersion = storedVersion;
|
|
53
|
+
this.codeVersion = codeVersion;
|
|
54
|
+
this.name = "SchemaVersionAheadError";
|
|
55
|
+
}
|
|
56
|
+
dbName;
|
|
57
|
+
storedVersion;
|
|
58
|
+
codeVersion;
|
|
59
|
+
};
|
|
60
|
+
var StoreNotOpenError = class extends KoraError {
|
|
61
|
+
constructor() {
|
|
62
|
+
super("Store is not open. Call store.open() before performing operations.", "STORE_NOT_OPEN");
|
|
63
|
+
this.name = "StoreNotOpenError";
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
var WorkerInitError = class extends KoraError {
|
|
67
|
+
constructor(message, context) {
|
|
68
|
+
super(`Worker initialization failed: ${message}`, "WORKER_INIT_ERROR", context);
|
|
69
|
+
this.name = "WorkerInitError";
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
var WorkerTimeoutError = class extends KoraError {
|
|
73
|
+
constructor(operation, timeoutMs) {
|
|
74
|
+
super(
|
|
75
|
+
`Worker did not respond within ${timeoutMs}ms for operation "${operation}"`,
|
|
76
|
+
"WORKER_TIMEOUT",
|
|
77
|
+
{ operation, timeoutMs }
|
|
78
|
+
);
|
|
79
|
+
this.name = "WorkerTimeoutError";
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
var NoLeaderError = class extends KoraError {
|
|
83
|
+
constructor(operation, message = `No live leader tab is answering multi-tab storage RPC for operation "${operation}"`, code = "NO_LEADER", context = {}) {
|
|
84
|
+
super(message, code, { operation, ...context });
|
|
85
|
+
this.name = "NoLeaderError";
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
var LeaderUnresponsiveError = class extends NoLeaderError {
|
|
89
|
+
constructor(operation, silentMs, requestId) {
|
|
90
|
+
super(
|
|
91
|
+
operation,
|
|
92
|
+
`The leader tab stopped responding (no heartbeat for ${silentMs}ms) during "${operation}". The request may or may not have been applied; retry it with the same requestId and the leader de-duplicates it.`,
|
|
93
|
+
"LEADER_UNRESPONSIVE",
|
|
94
|
+
{ silentMs, requestId, retriable: true }
|
|
95
|
+
);
|
|
96
|
+
this.name = "LeaderUnresponsiveError";
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
var BridgeTerminatedError = class extends KoraError {
|
|
100
|
+
constructor(operation, reason) {
|
|
101
|
+
super(
|
|
102
|
+
`Storage request "${operation}" was interrupted (${reason}); retry it against the new storage leader.`,
|
|
103
|
+
"BRIDGE_TERMINATED",
|
|
104
|
+
{ operation, reason, retriable: true }
|
|
105
|
+
);
|
|
106
|
+
this.name = "BridgeTerminatedError";
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
var RequestAbortedError = class extends KoraError {
|
|
110
|
+
constructor(operation, requestId) {
|
|
111
|
+
super(
|
|
112
|
+
`Storage request "${operation}" was aborted by the caller. A write may already have reached the leader; retry with the same requestId to stay idempotent.`,
|
|
113
|
+
"REQUEST_ABORTED",
|
|
114
|
+
{ operation, requestId }
|
|
115
|
+
);
|
|
116
|
+
this.name = "RequestAbortedError";
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
var StorageInUseError = class extends KoraError {
|
|
120
|
+
constructor(dbName) {
|
|
121
|
+
super(
|
|
122
|
+
`Database "${dbName}" is open in a tab on this origin; close it before deleting it.`,
|
|
123
|
+
"STORAGE_IN_USE",
|
|
124
|
+
{ dbName }
|
|
125
|
+
);
|
|
126
|
+
this.name = "StorageInUseError";
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
var UnsyncedDataError = class extends KoraError {
|
|
130
|
+
constructor(dbName) {
|
|
131
|
+
super(
|
|
132
|
+
`Database "${dbName}" has unsynced operations; deleting it would lose them. Sync first, or pass { force: true } to discard them deliberately.`,
|
|
133
|
+
"UNSYNCED_DATA",
|
|
134
|
+
{ dbName }
|
|
135
|
+
);
|
|
136
|
+
this.name = "UnsyncedDataError";
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
var StorageBackendMismatchError = class extends KoraError {
|
|
140
|
+
constructor(dbName, recorded, requested, reason) {
|
|
141
|
+
super(
|
|
142
|
+
`Database "${dbName}" is stored in ${recorded}, but this session can only use ${requested} (${reason}). Kora will not start a separate empty copy; reload in a browser profile where ${recorded} is available.`,
|
|
143
|
+
"STORAGE_BACKEND_MISMATCH",
|
|
144
|
+
{ dbName, recorded, requested, reason }
|
|
145
|
+
);
|
|
146
|
+
this.name = "StorageBackendMismatchError";
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
var PersistenceError = class extends KoraError {
|
|
150
|
+
constructor(message, context) {
|
|
151
|
+
super(`Persistence error: ${message}`, "PERSISTENCE_ERROR", context);
|
|
152
|
+
this.name = "PersistenceError";
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
export {
|
|
157
|
+
QueryError,
|
|
158
|
+
RecordNotFoundError,
|
|
159
|
+
OptimisticLockError,
|
|
160
|
+
AdapterError,
|
|
161
|
+
StorageDurabilityError,
|
|
162
|
+
SchemaVersionAheadError,
|
|
163
|
+
StoreNotOpenError,
|
|
164
|
+
WorkerInitError,
|
|
165
|
+
WorkerTimeoutError,
|
|
166
|
+
NoLeaderError,
|
|
167
|
+
LeaderUnresponsiveError,
|
|
168
|
+
BridgeTerminatedError,
|
|
169
|
+
RequestAbortedError,
|
|
170
|
+
StorageInUseError,
|
|
171
|
+
UnsyncedDataError,
|
|
172
|
+
StorageBackendMismatchError,
|
|
173
|
+
PersistenceError
|
|
174
|
+
};
|
|
175
|
+
//# sourceMappingURL=chunk-DUKTWVZW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts"],"sourcesContent":["import { KoraError } from '@korajs/core'\n\n/**\n * Thrown when a query is invalid (bad field names, invalid operators, etc.).\n */\nexport class QueryError extends KoraError {\n\tconstructor(message: string, context?: Record<string, unknown>) {\n\t\tsuper(message, 'QUERY_ERROR', context)\n\t\tthis.name = 'QueryError'\n\t}\n}\n\n/**\n * Thrown when a record is not found by ID (findById, update, delete on missing record).\n */\nexport class RecordNotFoundError extends KoraError {\n\tconstructor(collection: string, recordId: string) {\n\t\tsuper(`Record \"${recordId}\" not found in collection \"${collection}\"`, 'RECORD_NOT_FOUND', {\n\t\t\tcollection,\n\t\t\trecordId,\n\t\t})\n\t\tthis.name = 'RecordNotFoundError'\n\t}\n}\n\n/**\n * Thrown inside `applyRemoteOperation` when the row's version state changed\n * between the caller's snapshot read and the guarded write (a concurrent local\n * mutation landed in the window). The transaction is rolled back with nothing\n * written; the caller re-reads fresh state, recomputes its merge, and retries.\n * This is the optimistic-concurrency guard that keeps merge-engine results\n * (richtext, add-wins arrays, constraint resolutions) from clobbering newer\n * local edits they never saw.\n */\nexport class OptimisticLockError extends KoraError {\n\tconstructor(collection: string, recordId: string) {\n\t\tsuper(\n\t\t\t`Row version changed while merging record \"${recordId}\" in \"${collection}\"; retry with fresh state`,\n\t\t\t'OPTIMISTIC_LOCK',\n\t\t\t{ collection, recordId },\n\t\t)\n\t\tthis.name = 'OptimisticLockError'\n\t}\n}\n\n/**\n * Thrown when a storage adapter operation fails.\n */\nexport class AdapterError extends KoraError {\n\tconstructor(message: string, context?: Record<string, unknown>) {\n\t\tsuper(message, 'ADAPTER_ERROR', context)\n\t\tthis.name = 'AdapterError'\n\t}\n}\n\n/**\n * Thrown when a write reaches a storage adapter that could not obtain durable\n * storage (it opened, or was promoted to leader, on a non-persistent in-memory\n * database). Kora refuses such writes instead of accepting data that would be\n * lost on reload. Reads still work.\n *\n * Fix: close other tabs or apps using the same origin's OPFS storage and reopen,\n * or opt in explicitly with `allowNonDurable: true` if in-memory storage is\n * acceptable for this app.\n */\nexport class StorageDurabilityError extends KoraError {\n\tconstructor(dbName: string, phase: 'open' | 'promotion', reason: string) {\n\t\tsuper(\n\t\t\t`Database \"${dbName}\" has no durable storage (${reason} during ${phase}); writes are refused so they are not silently lost on reload. Close other tabs or apps using this origin's storage and reload, or set allowNonDurable: true to accept in-memory storage.`,\n\t\t\t'STORAGE_DURABILITY_LOST',\n\t\t\t{ dbName, phase, reason },\n\t\t)\n\t\tthis.name = 'StorageDurabilityError'\n\t}\n}\n\n/**\n * Thrown when the store opens a database a NEWER build of the app already migrated: its\n * stored schema version is above this code's `schema.version` (RT-109). Running older\n * code against it would write operations of the old schema into the new one, or fail\n * part-way, so the store refuses before changing anything and emits `store:schema-ahead`.\n *\n * Fix: run the newer build (reload while online, or accept the app's update prompt).\n * Never lower `schema.version` in a deployed app.\n */\nexport class SchemaVersionAheadError extends KoraError {\n\tconstructor(\n\t\tpublic readonly dbName: string,\n\t\tpublic readonly storedVersion: number,\n\t\tpublic readonly codeVersion: number,\n\t) {\n\t\tsuper(\n\t\t\t`Database \"${dbName}\" is at schema version ${storedVersion}, newer than this build's schema version ${codeVersion}: a newer build of the app already migrated it. It was not opened and nothing in it changed. Run the newer build (reload while online, or accept the update); never lower schema.version in a deployed app.`,\n\t\t\t'SCHEMA_VERSION_AHEAD',\n\t\t\t{ dbName, storedVersion, codeVersion },\n\t\t)\n\t\tthis.name = 'SchemaVersionAheadError'\n\t}\n}\n\n/**\n * Thrown when an operation is attempted on a store that has not been opened.\n */\nexport class StoreNotOpenError extends KoraError {\n\tconstructor() {\n\t\tsuper('Store is not open. Call store.open() before performing operations.', 'STORE_NOT_OPEN')\n\t\tthis.name = 'StoreNotOpenError'\n\t}\n}\n\n/**\n * Thrown when the Web Worker fails to initialize (WASM load failure, OPFS unavailable, etc.).\n */\nexport class WorkerInitError extends KoraError {\n\tconstructor(message: string, context?: Record<string, unknown>) {\n\t\tsuper(`Worker initialization failed: ${message}`, 'WORKER_INIT_ERROR', context)\n\t\tthis.name = 'WorkerInitError'\n\t}\n}\n\n/**\n * Thrown when the Web Worker does not respond within the configured timeout.\n */\nexport class WorkerTimeoutError extends KoraError {\n\tconstructor(operation: string, timeoutMs: number) {\n\t\tsuper(\n\t\t\t`Worker did not respond within ${timeoutMs}ms for operation \"${operation}\"`,\n\t\t\t'WORKER_TIMEOUT',\n\t\t\t{ operation, timeoutMs },\n\t\t)\n\t\tthis.name = 'WorkerTimeoutError'\n\t}\n}\n\n/**\n * Thrown when a follower tab cannot reach a live leader tab over the multi-tab\n * broadcast channel (the leader tab was closed, crashed, or is unresponsive).\n * Distinct from {@link WorkerTimeoutError}: this fails fast on a confirmed-absent\n * leader instead of waiting out the full RPC timeout.\n */\nexport class NoLeaderError extends KoraError {\n\tconstructor(\n\t\toperation: string,\n\t\tmessage = `No live leader tab is answering multi-tab storage RPC for operation \"${operation}\"`,\n\t\tcode = 'NO_LEADER',\n\t\tcontext: Record<string, unknown> = {},\n\t) {\n\t\tsuper(message, code, { operation, ...context })\n\t\tthis.name = 'NoLeaderError'\n\t}\n}\n\n/**\n * Thrown to a follower tab's pending storage requests when the leader tab that\n * was answering stopped sending heartbeats (hung, frozen, or suspended). The\n * request may or may not have been applied: retry it with the same `requestId`\n * (in the error context) and the leader de-duplicates it. Retriable.\n */\nexport class LeaderUnresponsiveError extends NoLeaderError {\n\tconstructor(operation: string, silentMs: number, requestId: string) {\n\t\tsuper(\n\t\t\toperation,\n\t\t\t`The leader tab stopped responding (no heartbeat for ${silentMs}ms) during \"${operation}\". The request may or may not have been applied; retry it with the same requestId and the leader de-duplicates it.`,\n\t\t\t'LEADER_UNRESPONSIVE',\n\t\t\t{ silentMs, requestId, retriable: true },\n\t\t)\n\t\tthis.name = 'LeaderUnresponsiveError'\n\t}\n}\n\n/**\n * Thrown to pending storage requests when their bridge was torn down, typically\n * because this tab was just promoted to leader or the leader handed over.\n * Retriable: the next attempt goes to the new leader.\n */\nexport class BridgeTerminatedError extends KoraError {\n\tconstructor(operation: string, reason: string) {\n\t\tsuper(\n\t\t\t`Storage request \"${operation}\" was interrupted (${reason}); retry it against the new storage leader.`,\n\t\t\t'BRIDGE_TERMINATED',\n\t\t\t{ operation, reason, retriable: true },\n\t\t)\n\t\tthis.name = 'BridgeTerminatedError'\n\t}\n}\n\n/** Thrown when a storage request is cancelled through its `AbortSignal`. */\nexport class RequestAbortedError extends KoraError {\n\tconstructor(operation: string, requestId: string) {\n\t\tsuper(\n\t\t\t`Storage request \"${operation}\" was aborted by the caller. A write may already have reached the leader; retry with the same requestId to stay idempotent.`,\n\t\t\t'REQUEST_ABORTED',\n\t\t\t{ operation, requestId },\n\t\t)\n\t\tthis.name = 'RequestAbortedError'\n\t}\n}\n\n/**\n * Thrown by `deleteDatabase()` when the database is open in some tab or worker\n * on this origin. Close it everywhere (or call `app.close()`) and retry.\n */\nexport class StorageInUseError extends KoraError {\n\tconstructor(dbName: string) {\n\t\tsuper(\n\t\t\t`Database \"${dbName}\" is open in a tab on this origin; close it before deleting it.`,\n\t\t\t'STORAGE_IN_USE',\n\t\t\t{ dbName },\n\t\t)\n\t\tthis.name = 'StorageInUseError'\n\t}\n}\n\n/**\n * Thrown by `deleteDatabase()` when the database still holds operations that\n * never reached the server. Sync first, or pass `{ force: true }` to discard them.\n */\nexport class UnsyncedDataError extends KoraError {\n\tconstructor(dbName: string) {\n\t\tsuper(\n\t\t\t`Database \"${dbName}\" has unsynced operations; deleting it would lose them. Sync first, or pass { force: true } to discard them deliberately.`,\n\t\t\t'UNSYNCED_DATA',\n\t\t\t{ dbName },\n\t\t)\n\t\tthis.name = 'UnsyncedDataError'\n\t}\n}\n\n/**\n * Thrown when a database's data lives in a storage backend this runtime cannot\n * read (for example it was written to OPFS, and OPFS is unavailable now). Kora\n * refuses to start an empty, disjoint copy rather than hide the existing data.\n */\nexport class StorageBackendMismatchError extends KoraError {\n\tconstructor(dbName: string, recorded: string, requested: string, reason: string) {\n\t\tsuper(\n\t\t\t`Database \"${dbName}\" is stored in ${recorded}, but this session can only use ${requested} (${reason}). Kora will not start a separate empty copy; reload in a browser profile where ${recorded} is available.`,\n\t\t\t'STORAGE_BACKEND_MISMATCH',\n\t\t\t{ dbName, recorded, requested, reason },\n\t\t)\n\t\tthis.name = 'StorageBackendMismatchError'\n\t}\n}\n\n/**\n * Thrown when IndexedDB persistence operations fail (serialize/deserialize).\n */\nexport class PersistenceError extends KoraError {\n\tconstructor(message: string, context?: Record<string, unknown>) {\n\t\tsuper(`Persistence error: ${message}`, 'PERSISTENCE_ERROR', context)\n\t\tthis.name = 'PersistenceError'\n\t}\n}\n"],"mappings":"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","names":[]}
|