@korajs/store 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.
- 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 +856 -63
- package/dist/adapters/sqlite-wasm-worker.cjs.map +1 -1
- package/dist/adapters/sqlite-wasm-worker.js +529 -63
- 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-IHKVMUAM.js +25 -0
- package/dist/chunk-5AQSGMJV.js +5471 -0
- package/dist/chunk-5AQSGMJV.js.map +1 -0
- package/dist/chunk-5JMGMPUE.js +591 -0
- package/dist/chunk-5JMGMPUE.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-BILSA6XZ.js +608 -0
- package/dist/chunk-BILSA6XZ.js.map +1 -0
- package/dist/chunk-BQSIL6TT.js +1095 -0
- package/dist/chunk-BQSIL6TT.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-KK3GBONL.js +112 -0
- package/dist/chunk-KK3GBONL.js.map +1 -0
- package/dist/chunk-KTVNANUH.js +876 -0
- package/dist/chunk-KTVNANUH.js.map +1 -0
- package/dist/chunk-QW4UU7NG.js +1003 -0
- package/dist/chunk-QW4UU7NG.js.map +1 -0
- package/dist/chunk-SRHDJF5B.js +186 -0
- package/dist/chunk-SRHDJF5B.js.map +1 -0
- package/dist/chunk-UC2LGFPV.js +810 -0
- package/dist/chunk-UC2LGFPV.js.map +1 -0
- package/dist/{export-audit-ODGQTQIK.js → export-audit-J2QXRHD2.js} +3 -3
- package/dist/index.cjs +9533 -4246
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1143 -110
- package/dist/index.d.ts +1143 -110
- package/dist/index.js +298 -3191
- package/dist/index.js.map +1 -1
- package/dist/internal.cjs +581 -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-MNDPR557.js +299 -0
- package/dist/restore-MNDPR557.js.map +1 -0
- package/dist/sql-builder-D0tC3sv9.d.cts +615 -0
- package/dist/sql-builder-D5UMzHEo.d.ts +615 -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-QCCNBYCU.js +12 -0
- package/dist/store-HNGX4KTT.js +16 -0
- package/dist/store-HNGX4KTT.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-IHKVMUAM.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-QCCNBYCU.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/backup/backup.ts","../src/compaction/types.ts","../src/log-integrity/log-integrity.ts"],"sourcesContent":["import { HybridLogicalClock, KoraError, quoteIdent } from '@korajs/core'\nimport type { Operation, SchemaDefinition } from '@korajs/core'\nimport { COMPACTION_BASELINE_META_KEY } from '../compaction/types'\nimport {\n\tCOMPACTED_THROUGH_TABLE,\n\tFOLD_BASE_TABLE,\n\tFOLD_SNAPSHOT_TABLE,\n} from '../fold/record-folder'\nimport { checkOperationRow, recoverTimestamp } from '../log-integrity/log-integrity'\nimport { deserializeOperationWithCollection, serializeOperation } from '../serialization/serializer'\nimport { SEQ_CONFLICTS_TABLE } from '../store/sequence-repair'\nimport { TERMINAL_REJECTIONS_TABLE, type TerminalRejection } from '../sync/local-sync-records'\nimport type { OperationRow, StorageAdapter, Transaction } from '../types'\nimport type { BackupManifest, BackupOptions, RestoreOptions, RestoreResult } from './types'\n\n// ── Format ──────────────────────────────────────────────────────────────────\n//\n// A backup is a sequence of sections `[u32 nameLen][u32 contentLen][name][content]`:\n//\n// manifest JSON BackupManifest (first section)\n// version_vector JSON { nodeId: maxSequence } of the exporting database\n// operations NDJSON, one canonical Operation per line (collection, data,\n// previousData, HLC timestamp object, atomicOps, transactionId,\n// mutationName, fieldVersions), in HLC order. Includes\n// operations kept only in the sequence-conflicts table.\n// terminal_rejections JSON TerminalRejection[] (operations the server refused for good)\n// fold_base NDJSON { collection, recordId, state }: per-record fold states of\n// compacted operations (W7, RT-66); a restore keeps them\n// fold_snapshot NDJSON { collection, recordId, state }: per-record row snapshots\n// (approximate bases, RT-68)\n// compacted_through JSON { nodeId: sequence }: per-node prefix folded into the bases\n// records:<name> NDJSON raw rows of the collection, tombstones included, bytes\n// tagged as { \"$bytes\": \"<base64>\" }\n// checksum SHA-256 hex over every section between manifest and checksum\n//\n// Version 2 (STORE-5) carries no `_kora_meta`: a device's identity (node id, node\n// tokens) and sync state never travel in a backup. Version 1 files are refused with\n// BACKUP_FORMAT_OUTDATED; {@link convertBackupV1} converts them.\n\n/** Current backup format version. */\nexport const BACKUP_VERSION = 2\n\n/** A backup file this release cannot restore as-is. */\nexport class BackupFormatError extends KoraError {\n\tconstructor(message: string, code: string, context?: Record<string, unknown>) {\n\t\tsuper(message, code, context)\n\t\tthis.name = 'BackupFormatError'\n\t}\n}\n\nfunction encodeSection(name: string, content: Uint8Array): Uint8Array {\n\tconst nameBytes = new TextEncoder().encode(name)\n\tconst result = new Uint8Array(8 + nameBytes.length + content.length)\n\tconst dv = new DataView(result.buffer)\n\tdv.setUint32(0, nameBytes.length, true)\n\tdv.setUint32(4, content.length, true)\n\tresult.set(nameBytes, 8)\n\tresult.set(content, 8 + nameBytes.length)\n\treturn result\n}\n\nfunction encodeJsonSection(name: string, data: unknown): Uint8Array {\n\treturn encodeSection(name, new TextEncoder().encode(JSON.stringify(data, bytesReplacer)))\n}\n\nfunction encodeNdjsonSection(name: string, items: unknown[]): Uint8Array {\n\tconst lines = items.map((item) => JSON.stringify(item, bytesReplacer)).join('\\n')\n\treturn encodeSection(name, new TextEncoder().encode(items.length > 0 ? `${lines}\\n` : ''))\n}\n\ninterface Section {\n\tname: string\n\tcontent: Uint8Array\n}\n\nfunction parseSections(data: Uint8Array): Section[] {\n\tconst sections: Section[] = []\n\tconst dv = new DataView(data.buffer, data.byteOffset, data.byteLength)\n\tlet offset = 0\n\twhile (offset + 8 <= data.byteLength) {\n\t\tconst nameLen = dv.getUint32(offset, true)\n\t\tconst contentLen = dv.getUint32(offset + 4, true)\n\t\toffset += 8\n\t\tif (offset + nameLen + contentLen > data.byteLength) break\n\t\tconst name = new TextDecoder().decode(data.slice(offset, offset + nameLen))\n\t\toffset += nameLen\n\t\tsections.push({ name, content: data.slice(offset, offset + contentLen) })\n\t\toffset += contentLen\n\t}\n\treturn sections\n}\n\nfunction findSection(sections: Section[], name: string): Uint8Array | null {\n\treturn sections.find((section) => section.name === name)?.content ?? null\n}\n\nfunction parseJsonSection<T>(sections: Section[], name: string): T | null {\n\tconst content = findSection(sections, name)\n\tif (!content) return null\n\treturn JSON.parse(new TextDecoder().decode(content), bytesReviver) as T\n}\n\nfunction parseNdjson<T>(content: Uint8Array | null): T[] {\n\tif (!content) return []\n\treturn new TextDecoder()\n\t\t.decode(content)\n\t\t.split('\\n')\n\t\t.filter((line) => line.trim().length > 0)\n\t\t.map((line) => JSON.parse(line, bytesReviver) as T)\n}\n\nfunction concat(parts: Uint8Array[]): Uint8Array {\n\tconst total = parts.reduce((sum, part) => sum + part.length, 0)\n\tconst result = new Uint8Array(total)\n\tlet pos = 0\n\tfor (const part of parts) {\n\t\tresult.set(part, pos)\n\t\tpos += part.length\n\t}\n\treturn result\n}\n\n// ── Export ──────────────────────────────────────────────────────────────────\n\n/**\n * Export a backup (format version 2) from an opened database.\n *\n * Everything is read inside one transaction, so the backup is a consistent snapshot.\n * Operations are exported in canonical form (exactly what `deserializeOperation` reads\n * back), including tombstones, so a restore rebuilds the same log.\n *\n * @param adapter - The storage adapter\n * @param schema - The schema definition\n * @param nodeId - Node id of the exporting device (informational only; never imported)\n * @param schemaVersion - Schema version\n * @param options - Backup options\n * @returns Backup as a Uint8Array\n */\nexport async function exportBackup(\n\tadapter: StorageAdapter,\n\tschema: SchemaDefinition,\n\tnodeId: string,\n\tschemaVersion: number,\n\toptions?: BackupOptions,\n): Promise<Uint8Array> {\n\tconst onProgress = options?.onProgress ?? (() => {})\n\tconst includeRecords = options?.includeRecords ?? true\n\tconst filter = options?.collections\n\tconst collections = Object.keys(schema.collections).filter(\n\t\t(name) => !filter || filter.includes(name),\n\t)\n\n\tconst snapshot: {\n\t\tvector: Record<string, number>\n\t\toperations: Operation[]\n\t\tterminal: TerminalRejection[]\n\t\trecords: Map<string, Array<Record<string, unknown>>>\n\t\tbases: FoldStateRow[]\n\t\tsnapshots: FoldStateRow[]\n\t\tcompactedThrough: Record<string, number>\n\t\tcompacted: boolean\n\t} = {\n\t\tvector: {},\n\t\toperations: [],\n\t\tterminal: [],\n\t\trecords: new Map(),\n\t\tbases: [],\n\t\tsnapshots: [],\n\t\tcompactedThrough: {},\n\t\tcompacted: false,\n\t}\n\n\tonProgress({ phase: 'reading', progress: 0, message: 'Reading the local database' })\n\tawait adapter.transaction(async (tx) => {\n\t\tconst vector = await tx.query<{ node_id: string; sequence_number: number }>(\n\t\t\t'SELECT node_id, sequence_number FROM _kora_version_vector',\n\t\t)\n\t\tfor (const row of vector) snapshot.vector[row.node_id] = row.sequence_number\n\t\tsnapshot.operations = await readOperations(tx, collections)\n\t\tsnapshot.terminal = await readTerminalRejections(tx)\n\t\t// W7 (RT-66): compacted history lives only in the base states; without them a\n\t\t// restore on another device would rebuild records from an incomplete log.\n\t\tsnapshot.bases = await readFoldStateRows(tx, FOLD_BASE_TABLE, collections)\n\t\tsnapshot.snapshots = await readFoldStateRows(tx, FOLD_SNAPSHOT_TABLE, collections)\n\t\tif (await hasTable(tx, COMPACTED_THROUGH_TABLE)) {\n\t\t\tfor (const row of await tx.query<{ node_id: string; sequence_number: number }>(\n\t\t\t\t`SELECT node_id, sequence_number FROM ${COMPACTED_THROUGH_TABLE}`,\n\t\t\t)) {\n\t\t\t\tsnapshot.compactedThrough[row.node_id] = row.sequence_number\n\t\t\t}\n\t\t}\n\t\tsnapshot.compacted =\n\t\t\tsnapshot.bases.length > 0 ||\n\t\t\tObject.keys(snapshot.compactedThrough).length > 0 ||\n\t\t\t(\n\t\t\t\tawait tx.query<{ value: string }>('SELECT value FROM _kora_meta WHERE key = ?', [\n\t\t\t\t\tCOMPACTION_BASELINE_META_KEY,\n\t\t\t\t])\n\t\t\t).length > 0\n\t\tif (includeRecords) {\n\t\t\tfor (const collection of collections) {\n\t\t\t\tsnapshot.records.set(\n\t\t\t\t\tcollection,\n\t\t\t\t\tawait tx.query<Record<string, unknown>>(`SELECT * FROM ${quoteIdent(collection)}`),\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t})\n\tonProgress({ phase: 'reading', progress: 0.7, message: 'Encoding' })\n\n\tconst content: Uint8Array[] = [\n\t\tencodeJsonSection('version_vector', snapshot.vector),\n\t\tencodeNdjsonSection('operations', snapshot.operations),\n\t\tencodeJsonSection('terminal_rejections', snapshot.terminal),\n\t\tencodeNdjsonSection('fold_base', snapshot.bases),\n\t\tencodeNdjsonSection('fold_snapshot', snapshot.snapshots),\n\t\tencodeJsonSection('compacted_through', snapshot.compactedThrough),\n\t]\n\tfor (const [collection, rows] of snapshot.records) {\n\t\tif (rows.length > 0) content.push(encodeNdjsonSection(`records:${collection}`, rows))\n\t}\n\tconst body = concat(content)\n\tconst checksum = await computeSha256(body)\n\tonProgress({ phase: 'writing', progress: 1, message: 'Finalizing' })\n\n\tconst manifest: BackupManifest = {\n\t\tversion: BACKUP_VERSION,\n\t\tcreatedAt: Date.now(),\n\t\tnodeId,\n\t\tschemaVersion,\n\t\toperationCount: snapshot.operations.length,\n\t\tcollections,\n\t\tincludesRecords: includeRecords,\n\t\tincludesTombstones: true,\n\t\tincludesFoldState: true,\n\t\tcompacted: snapshot.compacted,\n\t\tchecksum,\n\t}\n\treturn concat([\n\t\tencodeJsonSection('manifest', manifest),\n\t\tbody,\n\t\tencodeSection('checksum', new TextEncoder().encode(checksum)),\n\t])\n}\n\n/** Operations of `collections` in canonical form and HLC order (causal order). */\nasync function readOperations(tx: Transaction, collections: string[]): Promise<Operation[]> {\n\tconst operations: Operation[] = []\n\tconst seen = new Set<string>()\n\tconst retained = await hasTable(tx, SEQ_CONFLICTS_TABLE)\n\tfor (const collection of collections) {\n\t\tconst rows = await tx.query<OperationRow>(\n\t\t\t`SELECT * FROM ${quoteIdent(`_kora_ops_${collection}`)} ORDER BY sequence_number ASC`,\n\t\t)\n\t\t// Other nodes' operations kept only in the sequence-conflicts table still belong\n\t\t// to the log (record folds and dedup use them).\n\t\tif (retained) {\n\t\t\trows.push(\n\t\t\t\t...(await tx.query<OperationRow>(\n\t\t\t\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 reemitted_as IS NULL`,\n\t\t\t\t\t[collection],\n\t\t\t\t)),\n\t\t\t)\n\t\t}\n\t\tfor (const row of rows) {\n\t\t\tif (seen.has(row.id)) continue\n\t\t\tseen.add(row.id)\n\t\t\toperations.push(deserializeOperationWithCollection(row, collection))\n\t\t}\n\t}\n\toperations.sort((a, b) => HybridLogicalClock.compare(a.timestamp, b.timestamp))\n\treturn operations\n}\n\n/** One per-record fold state row (`_kora_fold_base` / `_kora_fold_snapshot`) in a backup. */\nexport interface FoldStateRow {\n\tcollection: string\n\trecordId: string\n\t/** The serialized `FoldState`, as stored. */\n\tstate: string\n}\n\nasync function readFoldStateRows(\n\ttx: Transaction,\n\ttable: string,\n\tcollections: string[],\n): Promise<FoldStateRow[]> {\n\tif (!(await hasTable(tx, table))) return []\n\tconst out: FoldStateRow[] = []\n\tfor (const collection of collections) {\n\t\tconst rows = await tx.query<{ record_id: string; state: string }>(\n\t\t\t`SELECT record_id, state FROM ${table} WHERE collection = ? ORDER BY record_id`,\n\t\t\t[collection],\n\t\t)\n\t\tfor (const row of rows) out.push({ collection, recordId: row.record_id, state: row.state })\n\t}\n\treturn out\n}\n\nasync function readTerminalRejections(tx: Transaction): Promise<TerminalRejection[]> {\n\tif (!(await hasTable(tx, TERMINAL_REJECTIONS_TABLE))) return []\n\tconst rows = await tx.query<{\n\t\toperation_id: string\n\t\tnode_id: string | null\n\t\tsequence_number: number | null\n\t\tcode: string\n\t\trejected_at: number\n\t}>(\n\t\t`SELECT operation_id, node_id, sequence_number, code, rejected_at FROM ${TERMINAL_REJECTIONS_TABLE} ORDER BY operation_id`,\n\t)\n\treturn rows.map((row) => ({\n\t\toperationId: row.operation_id,\n\t\tnodeId: row.node_id,\n\t\tsequenceNumber: row.sequence_number,\n\t\tcode: row.code,\n\t\trejectedAt: row.rejected_at,\n\t}))\n}\n\nasync function hasTable(tx: Transaction, name: string): Promise<boolean> {\n\tconst rows = await tx.query<{ name: string }>(\n\t\t\"SELECT name FROM sqlite_master WHERE type = 'table' AND name = ?\",\n\t\t[name],\n\t)\n\treturn rows.length > 0\n}\n\n// ── Parse ───────────────────────────────────────────────────────────────────\n\n/** A verified, parsed version-2 backup. */\nexport interface ParsedBackup {\n\tmanifest: BackupManifest\n\t/** Canonical operations of the requested collections, in HLC order. */\n\toperations: Operation[]\n\t/** Version vector of the exporting database. */\n\tversionVector: Map<string, number>\n\tterminalRejections: TerminalRejection[]\n\t/** Raw rows per collection (present only when the manifest includes records). */\n\trecords: Map<string, Array<Record<string, unknown>>>\n\t/** Per-record compacted base states of the requested collections (RT-66). */\n\tfoldBases: FoldStateRow[]\n\t/** Per-record row snapshots of the requested collections (RT-68). */\n\tfoldSnapshots: FoldStateRow[]\n\t/** Per node, the sequence prefix compacted into the bases. */\n\tcompactedThrough: Map<string, number>\n}\n\n/**\n * Read backup manifest without loading the entire backup.\n *\n * @param data - The raw backup data\n * @returns The backup manifest\n */\nexport function readBackupManifest(data: Uint8Array): BackupManifest {\n\tconst manifest = parseJsonSection<BackupManifest>(parseSections(data), 'manifest')\n\tif (!manifest) {\n\t\tthrow new BackupFormatError('Invalid backup: manifest section not found', 'BACKUP_INVALID')\n\t}\n\treturn manifest\n}\n\n/**\n * Validate the backup checksum.\n *\n * @param data - The raw backup data\n * @returns True if the checksum is valid\n */\nexport async function verifyBackupChecksum(data: Uint8Array): Promise<boolean> {\n\tconst sections = parseSections(data)\n\tconst manifest = parseJsonSection<BackupManifest>(sections, 'manifest')\n\tif (!manifest?.checksum) return false\n\tconst body = concat(\n\t\tsections\n\t\t\t.filter((s) => s.name !== 'manifest' && s.name !== 'checksum')\n\t\t\t.map((s) => encodeSection(s.name, s.content)),\n\t)\n\treturn (await computeSha256(body)) === manifest.checksum\n}\n\n/**\n * Parse and verify a backup: format version, checksum, and every operation must be\n * canonical (it round-trips through the operation serializer). Throws\n * {@link BackupFormatError}; nothing is written.\n *\n * @param data - The raw backup data\n * @param options - `collections` keeps only those collections\n */\nexport async function parseBackup(\n\tdata: Uint8Array,\n\toptions?: { collections?: string[] },\n): Promise<ParsedBackup> {\n\tconst sections = parseSections(data)\n\tconst manifest = parseJsonSection<BackupManifest>(sections, 'manifest')\n\tif (!manifest) {\n\t\tthrow new BackupFormatError('Invalid backup: manifest section not found', 'BACKUP_INVALID')\n\t}\n\tif (manifest.version === 1) {\n\t\tthrow new BackupFormatError(\n\t\t\t'This backup was written by Kora 1.0.0-beta.12 or earlier (format version 1), whose restore corrupted operation timestamps and copied the exporting device identity. Convert it first: `restoreBackup`/`importBackup(await convertBackupV1(data))`.',\n\t\t\t'BACKUP_FORMAT_OUTDATED',\n\t\t\t{ version: 1, fix: 'Call convertBackupV1(data) and import the result.' },\n\t\t)\n\t}\n\tif (manifest.version !== BACKUP_VERSION) {\n\t\tthrow new BackupFormatError(\n\t\t\t`Unsupported backup version: ${String(manifest.version)} (this release reads version ${BACKUP_VERSION}).`,\n\t\t\t'BACKUP_VERSION_UNSUPPORTED',\n\t\t\t{ version: manifest.version },\n\t\t)\n\t}\n\tif (!(await verifyBackupChecksum(data))) {\n\t\tthrow new BackupFormatError(\n\t\t\t'Backup checksum mismatch: data may be corrupted',\n\t\t\t'BACKUP_CHECKSUM_MISMATCH',\n\t\t)\n\t}\n\n\tconst keep = (collection: string): boolean =>\n\t\t!options?.collections || options.collections.includes(collection)\n\tconst operations: Operation[] = []\n\tfor (const raw of parseNdjson<Operation>(findSection(sections, 'operations'))) {\n\t\tif (!keep(raw.collection)) continue\n\t\toperations.push(canonicalOperation(raw))\n\t}\n\toperations.sort((a, b) => HybridLogicalClock.compare(a.timestamp, b.timestamp))\n\n\tconst vector = new Map<string, number>()\n\tfor (const [nodeId, seq] of Object.entries(\n\t\tparseJsonSection<Record<string, number>>(sections, 'version_vector') ?? {},\n\t)) {\n\t\tif (Number.isInteger(seq) && seq > 0) vector.set(nodeId, seq)\n\t}\n\n\tconst records = new Map<string, Array<Record<string, unknown>>>()\n\tif (manifest.includesRecords) {\n\t\tfor (const collection of manifest.collections) {\n\t\t\tif (!keep(collection)) continue\n\t\t\trecords.set(\n\t\t\t\tcollection,\n\t\t\t\tparseNdjson<Record<string, unknown>>(findSection(sections, `records:${collection}`)),\n\t\t\t)\n\t\t}\n\t}\n\n\tconst foldRows = (name: string): FoldStateRow[] =>\n\t\tparseNdjson<FoldStateRow>(findSection(sections, name)).filter(\n\t\t\t(row) =>\n\t\t\t\ttypeof row?.collection === 'string' &&\n\t\t\t\ttypeof row.recordId === 'string' &&\n\t\t\t\ttypeof row.state === 'string' &&\n\t\t\t\tkeep(row.collection),\n\t\t)\n\tconst compactedThrough = new Map<string, number>()\n\tfor (const [nodeId, seq] of Object.entries(\n\t\tparseJsonSection<Record<string, number>>(sections, 'compacted_through') ?? {},\n\t)) {\n\t\tif (Number.isInteger(seq) && seq > 0) compactedThrough.set(nodeId, seq)\n\t}\n\n\treturn {\n\t\tmanifest,\n\t\toperations,\n\t\tversionVector: vector,\n\t\tterminalRejections:\n\t\t\tparseJsonSection<TerminalRejection[]>(sections, 'terminal_rejections') ?? [],\n\t\trecords,\n\t\tfoldBases: foldRows('fold_base'),\n\t\tfoldSnapshots: foldRows('fold_snapshot'),\n\t\tcompactedThrough,\n\t}\n}\n\n/** Re-read an exported operation through the log serializer; refuse a damaged one. */\nfunction canonicalOperation(raw: Operation): Operation {\n\tlet row: OperationRow\n\ttry {\n\t\trow = serializeOperation(raw)\n\t} catch (error) {\n\t\tthrow new BackupFormatError(\n\t\t\t`Backup operation ${String(raw?.id)} is not a valid operation: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t'BACKUP_OPERATION_INVALID',\n\t\t\t{ operationId: raw?.id },\n\t\t)\n\t}\n\tconst verdict = checkOperationRow(row)\n\tif (verdict.kind !== 'ok' || typeof raw.collection !== 'string' || raw.collection === '') {\n\t\tthrow new BackupFormatError(\n\t\t\t`Backup operation ${String(raw.id)} is not canonical (${verdict.kind === 'ok' ? 'no collection' : verdict.problem}).`,\n\t\t\t'BACKUP_OPERATION_INVALID',\n\t\t\t{ operationId: raw.id },\n\t\t)\n\t}\n\treturn deserializeOperationWithCollection(row, raw.collection)\n}\n\n// ── Version 1 conversion ────────────────────────────────────────────────────\n\n/** Options for {@link convertBackupV1}. */\nexport interface ConvertBackupV1Options {\n\t/**\n\t * Drop operations whose timestamp cannot be recovered instead of refusing the file.\n\t * Default false.\n\t */\n\tdropUnrecoverable?: boolean\n}\n\n/**\n * Convert a version-1 backup (Kora 1.0.0-beta.12 and earlier) to version 2.\n *\n * - Operations: a v1 file exported from a database that a v1 restore had damaged holds\n * misread timestamps (`wallTime: null`); they are recovered from the misread values\n * (the same rule as the log-integrity scan). An unrecoverable one refuses the file\n * unless `dropUnrecoverable` is set.\n * - The `meta` section (the exporting device's node id, node tokens, sync state) is\n * dropped: it must never be imported into another database.\n * - Record rows are kept; v1 exported live rows only, so the manifest records\n * `includesTombstones: false`. Bytes that v1 serialized as `{\"0\":..,\"1\":..}` objects\n * are decoded on restore.\n *\n * @throws {BackupFormatError} When the input is not a valid version-1 backup\n */\nexport async function convertBackupV1(\n\tdata: Uint8Array,\n\toptions?: ConvertBackupV1Options,\n): Promise<Uint8Array> {\n\tconst sections = parseSections(data)\n\tconst manifest = parseJsonSection<BackupManifest>(sections, 'manifest')\n\tif (!manifest || manifest.version !== 1) {\n\t\tthrow new BackupFormatError('convertBackupV1 expects a version-1 backup.', 'BACKUP_INVALID', {\n\t\t\tversion: manifest?.version,\n\t\t})\n\t}\n\tif (!(await verifyBackupChecksum(data))) {\n\t\tthrow new BackupFormatError(\n\t\t\t'Backup checksum mismatch: data may be corrupted',\n\t\t\t'BACKUP_CHECKSUM_MISMATCH',\n\t\t)\n\t}\n\tconst operations: Operation[] = []\n\tconst dropped: string[] = []\n\tfor (const raw of parseNdjson<Operation>(findSection(sections, 'operations'))) {\n\t\tconst fixed = recoverV1Operation(raw)\n\t\tif (fixed) operations.push(fixed)\n\t\telse dropped.push(String(raw?.id))\n\t}\n\tif (dropped.length > 0 && !options?.dropUnrecoverable) {\n\t\tthrow new BackupFormatError(\n\t\t\t`${dropped.length} operation(s) in this version-1 backup have unrecoverable timestamps (first: ${dropped[0]}). Pass { dropUnrecoverable: true } to convert without them.`,\n\t\t\t'BACKUP_OPERATION_INVALID',\n\t\t\t{ operationIds: dropped.slice(0, 20) },\n\t\t)\n\t}\n\toperations.sort((a, b) => HybridLogicalClock.compare(a.timestamp, b.timestamp))\n\n\tconst content: Uint8Array[] = [\n\t\tencodeJsonSection(\n\t\t\t'version_vector',\n\t\t\tparseJsonSection<Record<string, number>>(sections, 'version_vector') ?? {},\n\t\t),\n\t\tencodeNdjsonSection('operations', operations),\n\t\tencodeJsonSection('terminal_rejections', []),\n\t]\n\tfor (const section of sections) {\n\t\tif (section.name.startsWith('records:')) {\n\t\t\tconst rows = parseNdjson<Record<string, unknown>>(section.content).map(decodeV1Bytes)\n\t\t\tcontent.push(encodeNdjsonSection(section.name, rows))\n\t\t}\n\t}\n\tconst body = concat(content)\n\tconst checksum = await computeSha256(body)\n\tconst converted: BackupManifest = {\n\t\tversion: BACKUP_VERSION,\n\t\tcreatedAt: manifest.createdAt,\n\t\tnodeId: manifest.nodeId,\n\t\tschemaVersion: manifest.schemaVersion,\n\t\toperationCount: operations.length,\n\t\tcollections: manifest.collections,\n\t\tincludesRecords: manifest.includesRecords,\n\t\tincludesTombstones: false,\n\t\tchecksum,\n\t\tconvertedFrom: 1,\n\t}\n\treturn concat([\n\t\tencodeJsonSection('manifest', converted),\n\t\tbody,\n\t\tencodeSection('checksum', new TextEncoder().encode(checksum)),\n\t])\n}\n\nfunction recoverV1Operation(raw: Operation): Operation | null {\n\tif (!raw || typeof raw !== 'object' || typeof raw.id !== 'string') return null\n\tconst ts = raw.timestamp as unknown\n\tlet timestamp = ts as Operation['timestamp']\n\tconst valid =\n\t\tts !== null &&\n\t\ttypeof ts === 'object' &&\n\t\tNumber.isInteger((ts as { wallTime: unknown }).wallTime) &&\n\t\tNumber.isInteger((ts as { logical: unknown }).logical)\n\tif (!valid) {\n\t\tconst recovered = recoverTimestamp(JSON.stringify(ts))\n\t\tif (!recovered) return null\n\t\ttimestamp = HybridLogicalClock.deserialize(recovered)\n\t}\n\ttry {\n\t\treturn canonicalOperation({ ...raw, timestamp })\n\t} catch {\n\t\treturn null\n\t}\n}\n\n/** v1 wrote Uint8Array columns through JSON.stringify: `{\"0\":1,\"1\":2}`. */\nfunction decodeV1Bytes(row: Record<string, unknown>): Record<string, unknown> {\n\tconst out: Record<string, unknown> = {}\n\tfor (const [key, value] of Object.entries(row)) {\n\t\tout[key] = looksLikeSerializedBytes(value) ? toBytes(value as Record<string, number>) : value\n\t}\n\treturn out\n}\n\nfunction looksLikeSerializedBytes(value: unknown): boolean {\n\tif (value === null || typeof value !== 'object' || Array.isArray(value)) return false\n\tconst entries = Object.entries(value as Record<string, unknown>)\n\tif (entries.length === 0) return false\n\treturn entries.every(\n\t\t([key, byte], index) =>\n\t\t\tkey === String(index) &&\n\t\t\tNumber.isInteger(byte) &&\n\t\t\t(byte as number) >= 0 &&\n\t\t\t(byte as number) < 256,\n\t)\n}\n\nfunction toBytes(value: Record<string, number>): Uint8Array {\n\tconst length = Object.keys(value).length\n\tconst bytes = new Uint8Array(length)\n\tfor (let i = 0; i < length; i++) bytes[i] = value[String(i)] ?? 0\n\treturn bytes\n}\n\n// ── Low-level restore (deprecated entry point) ─────────────────────────────\n\n/**\n * Restore a backup into the database behind `adapter`.\n *\n * @deprecated Use `store.importBackup()` / `app.importBackup()`: restoring needs the\n * store (the device's identity, version vector, clock and live queries). This entry\n * point opens a temporary `Store` on `adapter`, imports, and CLOSES the adapter.\n *\n * @param adapter - A storage adapter no store is using\n * @param schema - The schema definition\n * @param data - The backup data\n * @param options - Restore options\n */\nexport async function restoreBackup(\n\tadapter: StorageAdapter,\n\tschema: SchemaDefinition,\n\tdata: Uint8Array,\n\toptions?: RestoreOptions,\n): Promise<RestoreResult> {\n\tconst { Store } = await import('../store/store')\n\tconst store = new Store({ schema, adapter })\n\tawait store.open()\n\ttry {\n\t\treturn await store.importBackup(data, options)\n\t} finally {\n\t\tawait store.close()\n\t}\n}\n\n// ── Helpers ─────────────────────────────────────────────────────────────────\n\nfunction bytesReplacer(_key: string, value: unknown): unknown {\n\tif (value instanceof Uint8Array) return { $bytes: toBase64(value) }\n\treturn value\n}\n\nfunction bytesReviver(_key: string, value: unknown): unknown {\n\tif (\n\t\tvalue !== null &&\n\t\ttypeof value === 'object' &&\n\t\t!Array.isArray(value) &&\n\t\tObject.keys(value).length === 1 &&\n\t\ttypeof (value as { $bytes?: unknown }).$bytes === 'string'\n\t) {\n\t\treturn fromBase64((value as { $bytes: string }).$bytes)\n\t}\n\treturn value\n}\n\nfunction toBase64(bytes: Uint8Array): string {\n\tlet binary = ''\n\tconst CHUNK = 0x8000\n\tfor (let i = 0; i < bytes.length; i += CHUNK) {\n\t\tbinary += String.fromCharCode(...bytes.subarray(i, i + CHUNK))\n\t}\n\treturn btoa(binary)\n}\n\nfunction fromBase64(text: string): Uint8Array {\n\tconst binary = atob(text)\n\tconst bytes = new Uint8Array(binary.length)\n\tfor (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i)\n\treturn bytes\n}\n\nasync function computeSha256(data: Uint8Array): Promise<string> {\n\tconst hashBuffer = await crypto.subtle.digest('SHA-256', new Uint8Array(data))\n\treturn Array.from(new Uint8Array(hashBuffer))\n\t\t.map((b) => b.toString(16).padStart(2, '0'))\n\t\t.join('')\n}\n","import type { VersionVector } from '@korajs/core'\n\n/**\n * How the local operation log may be compacted.\n * Materialized collection rows are always kept as the convergence baseline.\n */\nexport type CompactionStrategy =\n\t| { mode: 'never' }\n\t| {\n\t\t\tmode: 'after-ack'\n\t\t\t/** Server version vector; defaults to persisted last-acked vector on the store. */\n\t\t\tserverVector?: VersionVector\n\t }\n\t| {\n\t\t\tmode: 'after-days'\n\t\t\t/** Delete only ops older than this many days (still requires ack watermark). */\n\t\t\tdays: number\n\t\t\tserverVector?: VersionVector\n\t }\n\n/**\n * Result of a compaction run.\n */\nexport interface CompactionResult {\n\t/** Number of operation log rows removed. */\n\tdeletedCount: number\n\t/** Per-node sequence ceiling used for deletion (from server ack vector). */\n\twatermark: VersionVector\n}\n\nexport const COMPACTION_BASELINE_META_KEY = 'compaction_baseline_at'\n","import { HybridLogicalClock, quoteIdent } from '@korajs/core'\nimport type { SchemaDefinition } from '@korajs/core'\nimport { COMPACTION_BASELINE_META_KEY } from '../compaction/types'\nimport { deserializeOperation, serializeOperation } from '../serialization/serializer'\nimport type { MetaRow, OperationRow, StorageAdapter, Transaction } from '../types'\n\n/**\n * Log-integrity scan (W8 step 0).\n *\n * Every later fold of the operation log (W7 re-materialization, replay, compaction)\n * trusts that each stored row is a canonical operation. Two earlier releases could\n * break that:\n *\n * - beta.12's backup restore wrote `JSON.stringify(timestamp)` into the timestamp\n * column, which `HybridLogicalClock.deserialize` reads as `wallTime: NaN` (a `null`\n * once re-exported), and a second restore of such a backup nested the damage;\n * - compaction deletes acknowledged operations, leaving holes in a node's sequence.\n *\n * The scan detects rows that do not round-trip through `deserializeOperation` /\n * `serializeOperation`, repairs the ones whose original value is recoverable from the\n * row itself (the JSON-encoded timestamp), and moves the rest to\n * {@link LOG_QUARANTINE_TABLE} (never deleted), so no fold ever reads them. It also\n * reports sequence gaps in this database's own nodes. Remote nodes' gaps are normal\n * (scoped sync only delivers part of another device's log) and are not reported.\n */\n\n/** Rows that could not be repaired, kept verbatim. Never cleared automatically. */\nexport const LOG_QUARANTINE_TABLE = '_kora_log_quarantine'\n\nconst QUARANTINE_DDL = `CREATE TABLE IF NOT EXISTS ${LOG_QUARANTINE_TABLE} (\n collection TEXT NOT NULL,\n operation_id TEXT NOT NULL,\n node_id TEXT,\n sequence_number INTEGER,\n problem TEXT NOT NULL,\n detail TEXT NOT NULL,\n row_json TEXT NOT NULL,\n quarantined_at INTEGER NOT NULL,\n PRIMARY KEY (collection, operation_id)\n)`\n\n/** What is wrong with an operation row. */\nexport type LogRowProblem =\n\t/** The timestamp is a JSON-encoded HLC (beta.12 backup restore). Repairable. */\n\t| 'timestamp-json'\n\t/** The timestamp cannot be read as an HLC and is not recoverable. */\n\t| 'timestamp-malformed'\n\t/** `id`, `node_id` or `record_id` is missing. */\n\t| 'identity-malformed'\n\t/** `type` is not insert, update or delete. */\n\t| 'type-invalid'\n\t/** `sequence_number` is not a positive integer. */\n\t| 'sequence-invalid'\n\t/** `data` or `previous_data` is not a JSON object. */\n\t| 'data-malformed'\n\t/** `causal_deps` is not a JSON array of operation ids. */\n\t| 'causal-deps-malformed'\n\t/** The row cannot be turned into an operation and back. */\n\t| 'round-trip-failed'\n\n/** One operation row the scan repaired or quarantined. */\nexport interface LogIntegrityRow {\n\tcollection: string\n\toperationId: string\n\tnodeId: string | null\n\tsequenceNumber: number | null\n\tproblem: LogRowProblem\n\t/** Human-readable detail: the bad value, or how it was repaired. */\n\tdetail: string\n}\n\n/** Sequence numbers missing from one of this database's own nodes. */\nexport interface LogSequenceGap {\n\tnodeId: string\n\t/** First missing sequence number (inclusive). */\n\tfrom: number\n\t/** Last missing sequence number (inclusive). */\n\tto: number\n}\n\n/**\n * Result of {@link scanLogIntegrity} / `Store.verifyLogIntegrity()`.\n *\n * `clean` is the precondition for rebuilding state from the log (W7): every row is\n * canonical, nothing is quarantined, and this database's own nodes have no holes\n * below their highest stored sequence number.\n */\nexport interface LogIntegrityReport {\n\t/** True when the log can be folded as-is (no quarantined rows, no own-node gaps). */\n\tclean: boolean\n\t/** `full`: every row was checked in JS. `quick`: SQL prefilter, suspects checked in JS. */\n\tmode: 'full' | 'quick'\n\t/** Rows checked in JS (all rows in full mode, suspects in quick mode). */\n\tcheckedRows: number\n\t/** Rows this scan repaired in place. */\n\trepaired: LogIntegrityRow[]\n\t/** Rows this scan moved to the quarantine table. */\n\tnewlyQuarantined: LogIntegrityRow[]\n\t/** Every row in the quarantine table (this scan's and earlier ones'). */\n\tquarantined: LogIntegrityRow[]\n\t/** Holes in this database's own nodes' sequences (compaction, a lost tail). */\n\tgaps: LogSequenceGap[]\n\t/** When the log was last compacted (epoch ms), or null when never. */\n\tcompactedAt: number | null\n\t/** False when the scan only reported (`repair: false`). */\n\trepairApplied: boolean\n}\n\n/** Options for {@link scanLogIntegrity}. */\nexport interface LogIntegrityScanOptions {\n\t/** Check every row in JS (default) or only the rows a SQL prefilter flags. */\n\tmode?: 'full' | 'quick'\n\t/** Repair and quarantine (default true). False only reports. */\n\trepair?: boolean\n\t/** Node ids this database authors under (gaps are reported for these only). */\n\tlocalNodeIds: readonly string[]\n}\n\nconst OPERATION_TYPES = new Set(['insert', 'update', 'delete'])\nconst CANONICAL_TIMESTAMP = /^\\d{15}:\\d{5}:.+$/\nconst PAGE_SIZE = 500\n\n/**\n * SQL prefilter: rows that cannot be canonical. Cheap enough to run on every open; the\n * JS check then confirms each suspect. `CASE` keeps `json_type` from seeing invalid JSON.\n */\nconst SUSPECT_WHERE = `id IS NULL OR node_id IS NULL OR record_id IS NULL\n OR type NOT IN ('insert', 'update', 'delete')\n OR typeof(sequence_number) != 'integer' OR sequence_number < 1\n OR typeof(timestamp) != 'text' OR length(timestamp) < 23\n OR substr(timestamp, 16, 1) != ':' OR substr(timestamp, 22, 1) != ':'\n OR substr(timestamp, 1, 15) GLOB '*[^0-9]*' OR substr(timestamp, 17, 5) GLOB '*[^0-9]*'\n OR causal_deps IS NULL\n OR (CASE WHEN json_valid(causal_deps) THEN json_type(causal_deps) != 'array' ELSE 1 END)\n OR (data IS NOT NULL AND (CASE WHEN json_valid(data) THEN json_type(data) != 'object' ELSE 1 END))\n OR (previous_data IS NOT NULL AND (CASE WHEN json_valid(previous_data) THEN json_type(previous_data) != 'object' ELSE 1 END))`\n\ntype RowWithRowid = OperationRow & { __rowid: number }\n\n/** Outcome of {@link checkOperationRow}. */\nexport type LogRowVerdict =\n\t| { kind: 'ok' }\n\t| { kind: 'repair'; problem: LogRowProblem; detail: string; timestamp: string }\n\t| { kind: 'quarantine'; problem: LogRowProblem; detail: string }\n\n/**\n * Scan the operation log of every schema collection; repair and quarantine (unless\n * `repair: false`), then report. Repairs and quarantine moves run in one transaction.\n *\n * @param adapter - An opened storage adapter\n * @param schema - The schema whose operation tables are scanned\n * @param options - Scan mode, repair switch and this database's own node ids\n */\nexport async function scanLogIntegrity(\n\tadapter: StorageAdapter,\n\tschema: SchemaDefinition,\n\toptions: LogIntegrityScanOptions,\n): Promise<LogIntegrityReport> {\n\tconst repair = options.repair ?? true\n\tlet mode = options.mode ?? 'full'\n\tawait adapter.execute(QUARANTINE_DDL)\n\n\tconst actions: Array<{ collection: string; row: RowWithRowid; verdict: LogRowVerdict }> = []\n\tlet checkedRows = 0\n\tfor (const collection of Object.keys(schema.collections)) {\n\t\tconst table = quoteIdent(`_kora_ops_${collection}`)\n\t\tlet rows: RowWithRowid[] | null = null\n\t\tif (mode === 'quick') {\n\t\t\ttry {\n\t\t\t\trows = await adapter.query<RowWithRowid>(\n\t\t\t\t\t`SELECT rowid AS __rowid, * FROM ${table} WHERE ${SUSPECT_WHERE}`,\n\t\t\t\t)\n\t\t\t} catch {\n\t\t\t\t// No JSON functions in this SQLite build: check every row instead.\n\t\t\t\tmode = 'full'\n\t\t\t}\n\t\t}\n\t\tif (rows !== null) {\n\t\t\tfor (const row of rows) {\n\t\t\t\tcheckedRows++\n\t\t\t\tconst verdict = checkOperationRow(row)\n\t\t\t\tif (verdict.kind !== 'ok') actions.push({ collection, row, verdict })\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t\tlet after = 0\n\t\tfor (;;) {\n\t\t\tconst page = await adapter.query<RowWithRowid>(\n\t\t\t\t`SELECT rowid AS __rowid, * FROM ${table} WHERE rowid > ? ORDER BY rowid LIMIT ${PAGE_SIZE}`,\n\t\t\t\t[after],\n\t\t\t)\n\t\t\tfor (const row of page) {\n\t\t\t\tcheckedRows++\n\t\t\t\tconst verdict = checkOperationRow(row)\n\t\t\t\tif (verdict.kind !== 'ok') actions.push({ collection, row, verdict })\n\t\t\t}\n\t\t\tif (page.length < PAGE_SIZE) break\n\t\t\tafter = page[page.length - 1]?.__rowid ?? after\n\t\t}\n\t}\n\n\tconst repaired: LogIntegrityRow[] = []\n\tconst newlyQuarantined: LogIntegrityRow[] = []\n\tfor (const { collection, row, verdict } of actions) {\n\t\tif (verdict.kind === 'ok') continue\n\t\tconst entry = describeRow(collection, row, verdict.problem, verdict.detail)\n\t\tif (verdict.kind === 'repair') repaired.push(entry)\n\t\telse newlyQuarantined.push(entry)\n\t}\n\n\tif (repair && actions.length > 0) {\n\t\tconst now = Date.now()\n\t\tawait adapter.transaction(async (tx) => {\n\t\t\tfor (const { collection, row, verdict } of actions) {\n\t\t\t\tconst table = quoteIdent(`_kora_ops_${collection}`)\n\t\t\t\tif (verdict.kind === 'repair') {\n\t\t\t\t\tawait tx.execute(`UPDATE ${table} SET timestamp = ? WHERE rowid = ?`, [\n\t\t\t\t\t\tverdict.timestamp,\n\t\t\t\t\t\trow.__rowid,\n\t\t\t\t\t])\n\t\t\t\t} else if (verdict.kind === 'quarantine') {\n\t\t\t\t\tawait quarantineRow(tx, collection, row, verdict.problem, verdict.detail, now)\n\t\t\t\t\tawait tx.execute(`DELETE FROM ${table} WHERE rowid = ?`, [row.__rowid])\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n\n\tconst quarantined = await loadQuarantine(adapter)\n\tconst gaps = await findOwnSequenceGaps(adapter, schema, options.localNodeIds)\n\tconst compactedAt = await loadCompactedAt(adapter)\n\tconst pendingQuarantine = repair ? 0 : newlyQuarantined.length\n\treturn {\n\t\tclean: quarantined.length === 0 && pendingQuarantine === 0 && gaps.length === 0,\n\t\tmode,\n\t\tcheckedRows,\n\t\trepaired,\n\t\tnewlyQuarantined,\n\t\tquarantined,\n\t\tgaps,\n\t\tcompactedAt,\n\t\trepairApplied: repair,\n\t}\n}\n\n/**\n * Judge one operation row: canonical, repairable (with the repaired timestamp), or\n * to be quarantined.\n */\nexport function checkOperationRow(row: OperationRow): LogRowVerdict {\n\tif (\n\t\t!isNonEmptyString(row.id) ||\n\t\t!isNonEmptyString(row.node_id) ||\n\t\t!isNonEmptyString(row.record_id)\n\t) {\n\t\treturn {\n\t\t\tkind: 'quarantine',\n\t\t\tproblem: 'identity-malformed',\n\t\t\tdetail: 'id, node_id or record_id is missing',\n\t\t}\n\t}\n\tif (!OPERATION_TYPES.has(row.type)) {\n\t\treturn {\n\t\t\tkind: 'quarantine',\n\t\t\tproblem: 'type-invalid',\n\t\t\tdetail: `type ${JSON.stringify(row.type)}`,\n\t\t}\n\t}\n\tif (!Number.isInteger(row.sequence_number) || row.sequence_number < 1) {\n\t\treturn {\n\t\t\tkind: 'quarantine',\n\t\t\tproblem: 'sequence-invalid',\n\t\t\tdetail: `sequence_number ${JSON.stringify(row.sequence_number)}`,\n\t\t}\n\t}\n\tif (!isJsonObjectOrNull(row.data) || !isJsonObjectOrNull(row.previous_data)) {\n\t\treturn {\n\t\t\tkind: 'quarantine',\n\t\t\tproblem: 'data-malformed',\n\t\t\tdetail: 'data or previous_data is not a JSON object',\n\t\t}\n\t}\n\tif (!isJsonStringArray(row.causal_deps)) {\n\t\treturn {\n\t\t\tkind: 'quarantine',\n\t\t\tproblem: 'causal-deps-malformed',\n\t\t\tdetail: `causal_deps ${truncate(String(row.causal_deps))}`,\n\t\t}\n\t}\n\n\tlet timestamp = row.timestamp\n\tlet repairedFrom: string | null = null\n\tif (!isCanonicalTimestamp(timestamp)) {\n\t\tconst recovered = recoverTimestamp(timestamp)\n\t\tif (recovered === null) {\n\t\t\treturn {\n\t\t\t\tkind: 'quarantine',\n\t\t\t\tproblem: 'timestamp-malformed',\n\t\t\t\tdetail: `timestamp ${truncate(String(timestamp))}`,\n\t\t\t}\n\t\t}\n\t\trepairedFrom = String(timestamp)\n\t\ttimestamp = recovered\n\t}\n\n\ttry {\n\t\tconst op = deserializeOperation({ ...row, timestamp })\n\t\tconst again = serializeOperation({ ...op, collection: '' })\n\t\tif (again.timestamp !== timestamp) {\n\t\t\tthrow new Error(`timestamp ${again.timestamp} != ${timestamp}`)\n\t\t}\n\t} catch (error) {\n\t\treturn {\n\t\t\tkind: 'quarantine',\n\t\t\tproblem: 'round-trip-failed',\n\t\t\tdetail: error instanceof Error ? error.message : String(error),\n\t\t}\n\t}\n\n\tif (repairedFrom !== null) {\n\t\treturn {\n\t\t\tkind: 'repair',\n\t\t\tproblem: 'timestamp-json',\n\t\t\tdetail: `timestamp ${truncate(repairedFrom)} -> ${timestamp}`,\n\t\t\ttimestamp,\n\t\t}\n\t}\n\treturn { kind: 'ok' }\n}\n\n/** Whether `value` is the zero-padded `wall:logical:node` form that sorts like HLC order. */\nfunction isCanonicalTimestamp(value: unknown): value is string {\n\tif (typeof value !== 'string' || !CANONICAL_TIMESTAMP.test(value)) return false\n\ttry {\n\t\treturn HybridLogicalClock.serialize(HybridLogicalClock.deserialize(value)) === value\n\t} catch {\n\t\treturn false\n\t}\n}\n\ninterface LooseTimestamp {\n\twallTime: unknown\n\tlogical: unknown\n\tnodeId: unknown\n}\n\n/**\n * Recover the canonical timestamp from a JSON-encoded HLC (beta.12 restore wrote\n * `JSON.stringify(timestamp)`). A backup exported from such a database and restored\n * again nests the damage: `deserialize` read the JSON as `wallTime: NaN` (exported as\n * `null`), `logical: <wallTime>` and `nodeId: '<logical>,\"nodeId\":\"<nodeId>\"}'`, which\n * is undone level by level.\n */\nexport function recoverTimestamp(value: unknown): string | null {\n\tif (typeof value !== 'string' || !value.startsWith('{')) return null\n\tlet parsed: unknown\n\ttry {\n\t\tparsed = JSON.parse(value)\n\t} catch {\n\t\treturn null\n\t}\n\tlet candidate = parsed as LooseTimestamp\n\tfor (let depth = 0; depth < 8; depth++) {\n\t\tif (candidate === null || typeof candidate !== 'object') return null\n\t\tconst { wallTime, logical, nodeId } = candidate\n\t\tif (Number.isInteger(wallTime) && Number.isInteger(logical) && isNonEmptyString(nodeId)) {\n\t\t\ttry {\n\t\t\t\treturn HybridLogicalClock.serialize({\n\t\t\t\t\twallTime: wallTime as number,\n\t\t\t\t\tlogical: logical as number,\n\t\t\t\t\tnodeId,\n\t\t\t\t})\n\t\t\t} catch {\n\t\t\t\treturn null\n\t\t\t}\n\t\t}\n\t\t// One level of nesting: wallTime lost, logical holds the wall time, and nodeId\n\t\t// holds the rest of the inner JSON object.\n\t\tif (wallTime !== null || !Number.isInteger(logical) || typeof nodeId !== 'string') return null\n\t\tconst match = /^(\\d+),\"nodeId\":(\".*\")\\}$/.exec(nodeId)\n\t\tif (!match?.[1] || !match[2]) return null\n\t\tlet innerNode: unknown\n\t\ttry {\n\t\t\tinnerNode = JSON.parse(match[2])\n\t\t} catch {\n\t\t\treturn null\n\t\t}\n\t\tcandidate = { wallTime: logical, logical: Number(match[1]), nodeId: innerNode }\n\t}\n\treturn null\n}\n\nasync function quarantineRow(\n\ttx: Transaction,\n\tcollection: string,\n\trow: RowWithRowid,\n\tproblem: LogRowProblem,\n\tdetail: string,\n\tnow: number,\n): Promise<void> {\n\tconst { __rowid: _rowid, ...original } = row\n\tawait tx.execute(\n\t\t`INSERT OR REPLACE INTO ${LOG_QUARANTINE_TABLE} (collection, operation_id, node_id, sequence_number, problem, detail, row_json, quarantined_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,\n\t\t[\n\t\t\tcollection,\n\t\t\ttypeof row.id === 'string' ? row.id : `rowid:${row.__rowid}`,\n\t\t\ttypeof row.node_id === 'string' ? row.node_id : null,\n\t\t\tNumber.isInteger(row.sequence_number) ? row.sequence_number : null,\n\t\t\tproblem,\n\t\t\tdetail,\n\t\t\tJSON.stringify(original, bytesReplacer),\n\t\t\tnow,\n\t\t],\n\t)\n}\n\ninterface QuarantineRow {\n\tcollection: string\n\toperation_id: string\n\tnode_id: string | null\n\tsequence_number: number | null\n\tproblem: string\n\tdetail: string\n}\n\nasync function loadQuarantine(adapter: StorageAdapter): Promise<LogIntegrityRow[]> {\n\tconst rows = await adapter.query<QuarantineRow>(\n\t\t`SELECT collection, operation_id, node_id, sequence_number, problem, detail FROM ${LOG_QUARANTINE_TABLE} ORDER BY quarantined_at ASC, collection ASC, operation_id ASC`,\n\t)\n\treturn rows.map((row) => ({\n\t\tcollection: row.collection,\n\t\toperationId: row.operation_id,\n\t\tnodeId: row.node_id,\n\t\tsequenceNumber: row.sequence_number,\n\t\tproblem: row.problem as LogRowProblem,\n\t\tdetail: row.detail,\n\t}))\n}\n\n/**\n * Holes in each own node's sequence below its highest stored number. Numbers held only\n * by `_kora_seq_conflicts` re-emissions are in the log under their new number, so the\n * log tables alone decide.\n */\nasync function findOwnSequenceGaps(\n\tadapter: StorageAdapter,\n\tschema: SchemaDefinition,\n\tnodeIds: readonly string[],\n): Promise<LogSequenceGap[]> {\n\tconst collections = Object.keys(schema.collections)\n\tif (collections.length === 0) return []\n\tconst gaps: LogSequenceGap[] = []\n\tconst union = collections\n\t\t.map((c) => `SELECT sequence_number FROM ${quoteIdent(`_kora_ops_${c}`)} WHERE node_id = ?`)\n\t\t.join(' UNION ALL ')\n\tfor (const nodeId of [...new Set(nodeIds)]) {\n\t\tconst params = collections.map(() => nodeId)\n\t\tconst summary = await adapter.query<{ n: number; m: number | null }>(\n\t\t\t`SELECT COUNT(DISTINCT sequence_number) AS n, MAX(sequence_number) AS m FROM (${union})`,\n\t\t\tparams,\n\t\t)\n\t\tconst count = summary[0]?.n ?? 0\n\t\tconst max = summary[0]?.m ?? 0\n\t\tif (max === null || max === 0 || count === max) continue\n\t\tconst present = await adapter.query<{ sequence_number: number }>(\n\t\t\t`SELECT DISTINCT sequence_number FROM (${union}) ORDER BY sequence_number ASC`,\n\t\t\tparams,\n\t\t)\n\t\tlet expected = 1\n\t\tfor (const { sequence_number: seq } of present) {\n\t\t\tif (seq > expected) gaps.push({ nodeId, from: expected, to: seq - 1 })\n\t\t\texpected = Math.max(expected, seq + 1)\n\t\t}\n\t}\n\treturn gaps\n}\n\nasync function loadCompactedAt(adapter: StorageAdapter): Promise<number | null> {\n\tconst rows = await adapter.query<MetaRow>('SELECT value FROM _kora_meta WHERE key = ?', [\n\t\tCOMPACTION_BASELINE_META_KEY,\n\t])\n\tconst value = Number(rows[0]?.value)\n\treturn rows[0] && Number.isFinite(value) ? value : null\n}\n\nfunction describeRow(\n\tcollection: string,\n\trow: OperationRow,\n\tproblem: LogRowProblem,\n\tdetail: string,\n): LogIntegrityRow {\n\treturn {\n\t\tcollection,\n\t\toperationId: typeof row.id === 'string' ? row.id : '',\n\t\tnodeId: typeof row.node_id === 'string' ? row.node_id : null,\n\t\tsequenceNumber: Number.isInteger(row.sequence_number) ? row.sequence_number : null,\n\t\tproblem,\n\t\tdetail,\n\t}\n}\n\nfunction isNonEmptyString(value: unknown): value is string {\n\treturn typeof value === 'string' && value.length > 0\n}\n\nfunction isJsonObjectOrNull(value: unknown): boolean {\n\tif (value === null || value === undefined) return true\n\tif (typeof value !== 'string') return false\n\ttry {\n\t\tconst parsed: unknown = JSON.parse(value)\n\t\treturn parsed !== null && typeof parsed === 'object' && !Array.isArray(parsed)\n\t} catch {\n\t\treturn false\n\t}\n}\n\nfunction isJsonStringArray(value: unknown): boolean {\n\tif (typeof value !== 'string') return false\n\ttry {\n\t\tconst parsed: unknown = JSON.parse(value)\n\t\treturn Array.isArray(parsed) && parsed.every((id) => typeof id === 'string')\n\t} catch {\n\t\treturn false\n\t}\n}\n\nfunction truncate(value: string): string {\n\treturn value.length > 120 ? `${value.slice(0, 117)}...` : value\n}\n\nfunction bytesReplacer(_key: string, value: unknown): unknown {\n\tif (value instanceof Uint8Array) return { $bytes: Array.from(value) }\n\treturn value\n}\n"],"mappings":"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","names":["HybridLogicalClock","quoteIdent","bytesReplacer","quoteIdent","HybridLogicalClock"]}
|
|
@@ -3,13 +3,13 @@ import {
|
|
|
3
3
|
exportAudit,
|
|
4
4
|
readAuditExportManifest,
|
|
5
5
|
verifyAuditExportChecksum
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-5ZRRF6R2.js";
|
|
7
7
|
import "./chunk-MYSJN3DF.js";
|
|
8
|
-
import "./chunk-
|
|
8
|
+
import "./chunk-J5AGXF3D.js";
|
|
9
9
|
export {
|
|
10
10
|
decodeAuditExport,
|
|
11
11
|
exportAudit,
|
|
12
12
|
readAuditExportManifest,
|
|
13
13
|
verifyAuditExportChecksum
|
|
14
14
|
};
|
|
15
|
-
//# sourceMappingURL=export-audit-
|
|
15
|
+
//# sourceMappingURL=export-audit-J2QXRHD2.js.map
|