@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.
Files changed (92) hide show
  1. package/README.md +29 -37
  2. package/dist/adapters/better-sqlite3.cjs +90 -4
  3. package/dist/adapters/better-sqlite3.cjs.map +1 -1
  4. package/dist/adapters/better-sqlite3.d.cts +21 -12
  5. package/dist/adapters/better-sqlite3.d.ts +21 -12
  6. package/dist/adapters/better-sqlite3.js +69 -5
  7. package/dist/adapters/better-sqlite3.js.map +1 -1
  8. package/dist/adapters/indexeddb.cjs +1316 -610
  9. package/dist/adapters/indexeddb.cjs.map +1 -1
  10. package/dist/adapters/indexeddb.d.cts +29 -3
  11. package/dist/adapters/indexeddb.d.ts +29 -3
  12. package/dist/adapters/indexeddb.js +247 -221
  13. package/dist/adapters/indexeddb.js.map +1 -1
  14. package/dist/adapters/sqlite-wasm-worker.cjs +803 -62
  15. package/dist/adapters/sqlite-wasm-worker.cjs.map +1 -1
  16. package/dist/adapters/sqlite-wasm-worker.js +480 -62
  17. package/dist/adapters/sqlite-wasm-worker.js.map +1 -1
  18. package/dist/adapters/sqlite-wasm.cjs +1032 -344
  19. package/dist/adapters/sqlite-wasm.cjs.map +1 -1
  20. package/dist/adapters/sqlite-wasm.d.cts +239 -18
  21. package/dist/adapters/sqlite-wasm.d.ts +239 -18
  22. package/dist/adapters/sqlite-wasm.js +111 -5
  23. package/dist/adapters/sqlite-wasm.js.map +1 -1
  24. package/dist/backup-4NUPDEMB.js +25 -0
  25. package/dist/chunk-32EDKWMI.js +876 -0
  26. package/dist/chunk-32EDKWMI.js.map +1 -0
  27. package/dist/{chunk-CYO3YKFL.js → chunk-5ZRRF6R2.js} +2 -2
  28. package/dist/chunk-A6GFH5IG.js +36 -0
  29. package/dist/chunk-A6GFH5IG.js.map +1 -0
  30. package/dist/chunk-DUKTWVZW.js +175 -0
  31. package/dist/chunk-DUKTWVZW.js.map +1 -0
  32. package/dist/chunk-HZTDBLDB.js +607 -0
  33. package/dist/chunk-HZTDBLDB.js.map +1 -0
  34. package/dist/{chunk-GSJ7EEUC.js → chunk-J5AGXF3D.js} +58 -9
  35. package/dist/chunk-J5AGXF3D.js.map +1 -0
  36. package/dist/chunk-MCQKEHOD.js +112 -0
  37. package/dist/chunk-MCQKEHOD.js.map +1 -0
  38. package/dist/chunk-P4V375FY.js +810 -0
  39. package/dist/chunk-P4V375FY.js.map +1 -0
  40. package/dist/chunk-QDUSJMFV.js +1095 -0
  41. package/dist/chunk-QDUSJMFV.js.map +1 -0
  42. package/dist/chunk-SJP2HTYZ.js +1003 -0
  43. package/dist/chunk-SJP2HTYZ.js.map +1 -0
  44. package/dist/chunk-W5F2LWG6.js +591 -0
  45. package/dist/chunk-W5F2LWG6.js.map +1 -0
  46. package/dist/chunk-Y5LRH7KI.js +5341 -0
  47. package/dist/chunk-Y5LRH7KI.js.map +1 -0
  48. package/dist/{export-audit-ODGQTQIK.js → export-audit-J2QXRHD2.js} +3 -3
  49. package/dist/index.cjs +9354 -4157
  50. package/dist/index.cjs.map +1 -1
  51. package/dist/index.d.cts +1064 -108
  52. package/dist/index.d.ts +1064 -108
  53. package/dist/index.js +249 -3092
  54. package/dist/index.js.map +1 -1
  55. package/dist/internal.cjs +580 -264
  56. package/dist/internal.cjs.map +1 -1
  57. package/dist/internal.d.cts +15 -85
  58. package/dist/internal.d.ts +15 -85
  59. package/dist/internal.js +10 -8
  60. package/dist/restore-FR7XIKT2.js +299 -0
  61. package/dist/restore-FR7XIKT2.js.map +1 -0
  62. package/dist/sql-builder-C4u55jKW.d.cts +608 -0
  63. package/dist/sql-builder-CGckdBDL.d.ts +608 -0
  64. package/dist/sqlite-wasm-channel-DVX93Uiq.d.cts +141 -0
  65. package/dist/sqlite-wasm-channel-DVX93Uiq.d.ts +141 -0
  66. package/dist/sqlite-wasm-channel-MLHLKEED.js +12 -0
  67. package/dist/store-IMWKZLWB.js +16 -0
  68. package/dist/store-IMWKZLWB.js.map +1 -0
  69. package/dist/{types-BslDOTk0.d.ts → types-Dh-xyUjP.d.cts} +99 -26
  70. package/dist/{types-BslDOTk0.d.cts → types-Dh-xyUjP.d.ts} +99 -26
  71. package/package.json +3 -2
  72. package/dist/backup-5S7K2Z35.js +0 -14
  73. package/dist/chunk-GSJ7EEUC.js.map +0 -1
  74. package/dist/chunk-HS6DBMST.js +0 -383
  75. package/dist/chunk-HS6DBMST.js.map +0 -1
  76. package/dist/chunk-RJIEKEN4.js +0 -751
  77. package/dist/chunk-RJIEKEN4.js.map +0 -1
  78. package/dist/chunk-TUR7RGEP.js +0 -84
  79. package/dist/chunk-TUR7RGEP.js.map +0 -1
  80. package/dist/chunk-VDBJQ75K.js +0 -78
  81. package/dist/chunk-VDBJQ75K.js.map +0 -1
  82. package/dist/chunk-YT7MRFCP.js +0 -687
  83. package/dist/chunk-YT7MRFCP.js.map +0 -1
  84. package/dist/sqlite-wasm-channel-GGHA2BXU.js +0 -12
  85. package/dist/sqlite-wasm-channel-L6o3bWQK.d.cts +0 -92
  86. package/dist/sqlite-wasm-channel-L6o3bWQK.d.ts +0 -92
  87. package/dist/types-BOO9EPt1.d.ts +0 -170
  88. package/dist/types-C_GDavG-.d.cts +0 -170
  89. /package/dist/{backup-5S7K2Z35.js.map → backup-4NUPDEMB.js.map} +0 -0
  90. /package/dist/{chunk-CYO3YKFL.js.map → chunk-5ZRRF6R2.js.map} +0 -0
  91. /package/dist/{export-audit-ODGQTQIK.js.map → export-audit-J2QXRHD2.js.map} +0 -0
  92. /package/dist/{sqlite-wasm-channel-GGHA2BXU.js.map → sqlite-wasm-channel-MLHLKEED.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lww/row-version.ts","../src/query/sql-builder.ts","../src/sync/sync-state.ts","../src/sync/sync-durability.ts","../src/sync/local-sync-records.ts"],"sourcesContent":["import { type HLCTimestamp, HybridLogicalClock } from '@korajs/core'\nimport type { RawCollectionRow } from '../types'\n\n/** Empty _version means legacy rows (compare by wallTime only via fallback). */\nexport const EMPTY_ROW_VERSION = ''\n\n/**\n * Serialize an HLC timestamp for storage in the `_version` column.\n * Lexicographic order matches {@link HybridLogicalClock.compare}.\n */\nexport function serializeRowVersion(timestamp: HLCTimestamp): string {\n\treturn HybridLogicalClock.serialize(timestamp)\n}\n\n/**\n * Read the version stamp stored on a materialized row.\n * Legacy rows without `_version` fall back to wallTime with logical 0.\n */\nexport function rowVersionFromRecord(\n\trow: Pick<RawCollectionRow, '_updated_at' | '_version'>,\n): HLCTimestamp {\n\tconst version = row._version\n\tif (typeof version === 'string' && version.length > 0) {\n\t\treturn HybridLogicalClock.deserialize(version)\n\t}\n\treturn { wallTime: row._updated_at, logical: 0, nodeId: '' }\n}\n\n/**\n * Returns true when `incoming` is strictly newer than the version on `row`.\n */\nexport function isIncomingNewerThanRow(\n\tincoming: HLCTimestamp,\n\trow: Pick<RawCollectionRow, '_updated_at' | '_version'>,\n): boolean {\n\treturn HybridLogicalClock.compare(incoming, rowVersionFromRecord(row)) > 0\n}\n\n/**\n * SQL fragment and params for LWW guards: apply only when row is missing or older.\n * Uses serialized `_version` for total order (matches HLC compare).\n */\nexport function lwwVersionWhereClause(remoteVersion: string): { sql: string; params: string[] } {\n\treturn {\n\t\tsql: '(_version = ? OR _version < ?)',\n\t\tparams: [EMPTY_ROW_VERSION, remoteVersion],\n\t}\n}\n","import type { CollectionDefinition, FieldDescriptor } from '@korajs/core'\nimport { quoteIdent } from '@korajs/core'\nimport { QueryError } from '../errors'\nimport { lwwVersionWhereClause } from '../lww/row-version'\nimport { encodeStoredFilterValue } from '../serialization/serializer'\nimport type { QueryDescriptor, WhereOperators } from '../types'\n\n/**\n * Result of building a SQL query: the parameterized SQL string and its bound values.\n */\nexport interface SqlQuery {\n\tsql: string\n\tparams: unknown[]\n}\n\n/**\n * Build a SELECT query from a QueryDescriptor.\n * Automatically adds `WHERE _deleted = 0` to exclude soft-deleted records.\n *\n * @param descriptor - The query descriptor\n * @param fields - The field descriptors from the collection schema\n * @returns A parameterized SQL query\n */\nexport function buildSelectQuery(\n\tdescriptor: QueryDescriptor,\n\tfields: Record<string, FieldDescriptor>,\n): SqlQuery {\n\tconst params: unknown[] = []\n\tconst parts = [`SELECT * FROM ${quoteIdent(descriptor.collection)}`]\n\n\tconst whereClause = buildWhereClauseParts(descriptor.where, fields, params)\n\t// Always filter out soft-deleted records\n\tconst deletedFilter = '_deleted = 0'\n\tif (whereClause) {\n\t\tparts.push(`WHERE ${deletedFilter} AND ${whereClause}`)\n\t} else {\n\t\tparts.push(`WHERE ${deletedFilter}`)\n\t}\n\n\tif (descriptor.orderBy.length > 0) {\n\t\tconst orderParts = descriptor.orderBy.map((o) => {\n\t\t\tvalidateFieldName(o.field, fields)\n\t\t\t// SEC-7: the direction is whitelisted to a fixed keyword, never spliced from\n\t\t\t// the caller's string (a runtime value cast to the type is untrusted input).\n\t\t\treturn `${quoteIdent(resolveColumnName(o.field, fields))} ${sqlSortDirection(o.direction, o.field)}`\n\t\t})\n\t\tparts.push(`ORDER BY ${orderParts.join(', ')}`)\n\t}\n\n\t// SEC-7: LIMIT / OFFSET are bound as parameters after a safe-integer check, so a\n\t// value that only claims to be a number can never become SQL text.\n\tconst limit = descriptor.limit !== undefined ? assertQueryCount(descriptor.limit, 'limit') : null\n\tconst offset =\n\t\tdescriptor.offset !== undefined ? assertQueryCount(descriptor.offset, 'offset') : null\n\tif (limit !== null) {\n\t\tparts.push('LIMIT ?')\n\t\tparams.push(limit)\n\t}\n\tif (offset !== null) {\n\t\t// SQLite accepts OFFSET only after LIMIT; LIMIT -1 means \"no limit\".\n\t\tif (limit === null) parts.push('LIMIT -1')\n\t\tparts.push('OFFSET ?')\n\t\tparams.push(offset)\n\t}\n\n\treturn { sql: parts.join(' '), params }\n}\n\n/**\n * Build a COUNT query from a QueryDescriptor.\n * Automatically adds `WHERE _deleted = 0`.\n *\n * @param descriptor - The query descriptor\n * @param fields - The field descriptors from the collection schema\n * @returns A parameterized SQL query that returns { count: number }\n */\nexport function buildCountQuery(\n\tdescriptor: QueryDescriptor,\n\tfields: Record<string, FieldDescriptor>,\n): SqlQuery {\n\tconst params: unknown[] = []\n\tconst parts = [`SELECT COUNT(*) as count FROM ${quoteIdent(descriptor.collection)}`]\n\n\tconst whereClause = buildWhereClauseParts(descriptor.where, fields, params)\n\tconst deletedFilter = '_deleted = 0'\n\tif (whereClause) {\n\t\tparts.push(`WHERE ${deletedFilter} AND ${whereClause}`)\n\t} else {\n\t\tparts.push(`WHERE ${deletedFilter}`)\n\t}\n\n\treturn { sql: parts.join(' '), params }\n}\n\n/**\n * Build an INSERT query for a collection record.\n *\n * @param collection - The collection name\n * @param record - The record data (already serialized with id, _created_at, _updated_at)\n * @returns A parameterized SQL query\n */\nexport function buildInsertQuery(collection: string, record: Record<string, unknown>): SqlQuery {\n\tconst columns = Object.keys(record)\n\tconst placeholders = columns.map(() => '?')\n\tconst params = Object.values(record)\n\n\tconst quotedColumns = columns.map((col) => quoteIdent(col))\n\tconst sql = `INSERT INTO ${quoteIdent(collection)} (${quotedColumns.join(', ')}) VALUES (${placeholders.join(', ')})`\n\treturn { sql, params }\n}\n\n/**\n * Build an UPDATE query for a collection record.\n *\n * @param collection - The collection name\n * @param id - The record ID\n * @param changes - The fields to update (already serialized)\n * @returns A parameterized SQL query\n */\nexport function buildUpdateQuery(\n\tcollection: string,\n\tid: string,\n\tchanges: Record<string, unknown>,\n): SqlQuery {\n\tconst setClauses = Object.keys(changes).map((col) => `${quoteIdent(col)} = ?`)\n\tconst params = [...Object.values(changes), id]\n\n\tconst sql = `UPDATE ${quoteIdent(collection)} SET ${setClauses.join(', ')} WHERE id = ?`\n\treturn { sql, params }\n}\n\n/**\n * Build a field-level fast-forward UPDATE: writes the changed field values\n * unconditionally (the caller has already proven per-field that the local value\n * still equals the base the remote wrote from, so the remote is the newest known\n * writer of those fields), while advancing the row's `_version` / `_updated_at`\n * watermark MONOTONICALLY — never regressing it below its current value.\n *\n * This is what makes per-field LWW correct on a per-row `_version` column: a\n * concurrent edit to a different field may have pushed `_version` past this\n * operation's timestamp, but that must not cause this operation's own field\n * change to be dropped, nor may materializing it move the watermark backward\n * (which would let a genuinely stale later operation win).\n *\n * @param collection - The collection name\n * @param id - The record ID\n * @param fieldChanges - Serialized field values to write unconditionally (must NOT include _version / _updated_at)\n * @param remoteVersion - The operation's serialized row version (lexicographically comparable)\n * @param wallTime - The operation's wall-clock time in ms\n * @param options - Optional extras. `maxCreatedAt` advances `_created_at` to the\n * greater of its current value and the given wall time — used for insert\n * collisions so every node converges on the max insert wall time regardless\n * of arrival order.\n */\nexport function buildFieldFastForwardUpdateQuery(\n\tcollection: string,\n\tid: string,\n\tfieldChanges: Record<string, unknown>,\n\tremoteVersion: string,\n\twallTime: number,\n\toptions?: { maxCreatedAt?: number },\n): SqlQuery {\n\tconst fieldClauses = Object.keys(fieldChanges).map((col) => `${quoteIdent(col)} = ?`)\n\t// _version is a lexicographically-sortable string; _updated_at is a number.\n\t// Keep the greater of the current and incoming value for each (monotonic).\n\tconst setClauses = [\n\t\t...fieldClauses,\n\t\t'_version = CASE WHEN _version >= ? THEN _version ELSE ? END',\n\t\t'_updated_at = CASE WHEN _updated_at >= ? THEN _updated_at ELSE ? END',\n\t]\n\tconst params: unknown[] = [\n\t\t...Object.values(fieldChanges),\n\t\tremoteVersion,\n\t\tremoteVersion,\n\t\twallTime,\n\t\twallTime,\n\t]\n\tif (options?.maxCreatedAt !== undefined) {\n\t\tsetClauses.push('_created_at = CASE WHEN _created_at >= ? THEN _created_at ELSE ? END')\n\t\tparams.push(options.maxCreatedAt, options.maxCreatedAt)\n\t}\n\tparams.push(id)\n\tconst sql = `UPDATE ${quoteIdent(collection)} SET ${setClauses.join(', ')} WHERE id = ?`\n\treturn { sql, params }\n}\n\n/**\n * Build a soft-delete query (SET _deleted = 1).\n *\n * @param collection - The collection name\n * @param id - The record ID\n * @param updatedAt - The timestamp to set on _updated_at\n * @returns A parameterized SQL query\n */\nexport function buildSoftDeleteQuery(\n\tcollection: string,\n\tid: string,\n\tupdatedAt: number,\n\tversion?: string,\n): SqlQuery {\n\tif (version !== undefined) {\n\t\treturn {\n\t\t\tsql: `UPDATE ${quoteIdent(collection)} SET _deleted = 1, _updated_at = ?, _version = ? WHERE id = ?`,\n\t\t\tparams: [updatedAt, version, id],\n\t\t}\n\t}\n\treturn {\n\t\tsql: `UPDATE ${quoteIdent(collection)} SET _deleted = 1, _updated_at = ? WHERE id = ?`,\n\t\tparams: [updatedAt, id],\n\t}\n}\n\n/**\n * Build an UPDATE that applies only when the row is missing or older than `remoteVersion`\n * (serialized HLC). Prevents stale remote sync from overwriting newer local materialized state.\n */\nexport function buildLwwUpdateQuery(\n\tcollection: string,\n\tid: string,\n\tchanges: Record<string, unknown>,\n\tremoteVersion: string,\n): SqlQuery {\n\tconst setClauses = Object.keys(changes).map((col) => `${quoteIdent(col)} = ?`)\n\tconst lww = lwwVersionWhereClause(remoteVersion)\n\tconst sql = `UPDATE ${quoteIdent(collection)} SET ${setClauses.join(', ')} WHERE id = ? AND ${lww.sql}`\n\tconst params = [...Object.values(changes), id, ...lww.params]\n\treturn { sql, params }\n}\n\n/**\n * Build a soft-delete that applies only when the row is older than `remoteVersion`.\n */\nexport function buildLwwSoftDeleteQuery(\n\tcollection: string,\n\tid: string,\n\tupdatedAt: number,\n\tversion: string,\n): SqlQuery {\n\tconst lww = lwwVersionWhereClause(version)\n\treturn {\n\t\tsql: `UPDATE ${quoteIdent(collection)} SET _deleted = 1, _updated_at = ?, _version = ? WHERE id = ? AND ${lww.sql}`,\n\t\tparams: [updatedAt, version, id, ...lww.params],\n\t}\n}\n\n/**\n * Build a WHERE clause from conditions, validating field names against the schema.\n *\n * @param where - The where conditions\n * @param fields - The field descriptors from the collection schema\n * @returns The SQL WHERE clause string and params, or null if no conditions\n */\nexport function buildWhereClause(\n\twhere: Record<string, unknown>,\n\tfields: Record<string, FieldDescriptor>,\n): SqlQuery | null {\n\tconst params: unknown[] = []\n\tconst result = buildWhereClauseParts(where, fields, params)\n\tif (!result) return null\n\treturn { sql: result, params }\n}\n\n// --- Internal helpers ---\n\nconst VALID_OPERATORS = new Set(['$eq', '$ne', '$gt', '$gte', '$lt', '$lte', '$in'])\n\nfunction buildWhereClauseParts(\n\twhere: Record<string, unknown>,\n\tfields: Record<string, FieldDescriptor>,\n\tparams: unknown[],\n): string | null {\n\tconst conditions: string[] = []\n\n\tfor (const [fieldName, value] of Object.entries(where)) {\n\t\tvalidateFieldName(fieldName, fields)\n\t\tconst descriptor = fields[fieldName]\n\t\tconst column = resolveColumnName(fieldName, fields)\n\n\t\tif (value !== null && typeof value === 'object' && !Array.isArray(value)) {\n\t\t\t// Operator object: { $gt: 5, $lt: 10 }\n\t\t\tconst ops = value as WhereOperators\n\t\t\tfor (const [op, opValue] of Object.entries(ops)) {\n\t\t\t\tif (!VALID_OPERATORS.has(op)) {\n\t\t\t\t\tthrow new QueryError(`Unknown operator \"${op}\" on field \"${fieldName}\"`, {\n\t\t\t\t\t\tfield: fieldName,\n\t\t\t\t\t\toperator: op,\n\t\t\t\t\t\tvalidOperators: [...VALID_OPERATORS],\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\tconditions.push(buildOperatorCondition(fieldName, column, op, opValue, descriptor, params))\n\t\t\t}\n\t\t} else {\n\t\t\t// Shorthand: { completed: false } means { completed: { $eq: false } }\n\t\t\tconditions.push(buildOperatorCondition(fieldName, column, '$eq', value, descriptor, params))\n\t\t}\n\t}\n\n\tif (conditions.length === 0) return null\n\treturn conditions.join(' AND ')\n}\n\nfunction buildOperatorCondition(\n\tfieldName: string,\n\tcolumnName: string,\n\toperator: string,\n\tvalue: unknown,\n\tdescriptor: FieldDescriptor | undefined,\n\tparams: unknown[],\n): string {\n\t// Serialize boolean values to 0/1 and raw strings to their stored form (RT-65)\n\tconst sqlValue = toSqlFilterValue(value, descriptor)\n\n\tconst column = quoteIdent(columnName)\n\n\tswitch (operator) {\n\t\tcase '$eq':\n\t\t\tif (sqlValue === null) {\n\t\t\t\treturn `${column} IS NULL`\n\t\t\t}\n\t\t\tparams.push(sqlValue)\n\t\t\treturn `${column} = ?`\n\t\tcase '$ne':\n\t\t\tif (sqlValue === null) {\n\t\t\t\treturn `${column} IS NOT NULL`\n\t\t\t}\n\t\t\tparams.push(sqlValue)\n\t\t\treturn `${column} != ?`\n\t\tcase '$gt':\n\t\t\tparams.push(sqlValue)\n\t\t\treturn `${column} > ?`\n\t\tcase '$gte':\n\t\t\tparams.push(sqlValue)\n\t\t\treturn `${column} >= ?`\n\t\tcase '$lt':\n\t\t\tparams.push(sqlValue)\n\t\t\treturn `${column} < ?`\n\t\tcase '$lte':\n\t\t\tparams.push(sqlValue)\n\t\t\treturn `${column} <= ?`\n\t\tcase '$in': {\n\t\t\tif (!Array.isArray(sqlValue)) {\n\t\t\t\tthrow new QueryError(`$in operator requires an array value for field \"${fieldName}\"`, {\n\t\t\t\t\tfield: fieldName,\n\t\t\t\t\treceived: typeof sqlValue,\n\t\t\t\t})\n\t\t\t}\n\t\t\tconst placeholders = sqlValue.map(() => '?')\n\t\t\tfor (const item of sqlValue) {\n\t\t\t\tparams.push(toSqlFilterValue(item, descriptor))\n\t\t\t}\n\t\t\treturn `${column} IN (${placeholders.join(', ')})`\n\t\t}\n\t\tdefault:\n\t\t\tthrow new QueryError(`Unknown operator \"${operator}\"`, { operator })\n\t}\n}\n\nfunction toSqlFilterValue(value: unknown, descriptor: FieldDescriptor | undefined): unknown {\n\tif (descriptor?.kind === 'boolean' && typeof value === 'boolean') return value ? 1 : 0\n\treturn encodeStoredFilterValue(value, descriptor)\n}\n\n/**\n * Record metadata exposed on every record under a camelCase name and backed by a\n * system column (STORE-11): `where({ updatedAt: { $gt: t } })` and\n * `orderBy('createdAt', 'desc')` filter and sort on these columns. A schema field\n * declared with the same name wins and its own column is used instead.\n */\nexport const VIRTUAL_TIMESTAMP_FIELDS = Object.freeze({\n\tcreatedAt: '_created_at',\n\tupdatedAt: '_updated_at',\n} as const)\n\n/** Name of a virtual record-metadata field usable in `where` and `orderBy`. */\nexport type VirtualTimestampField = keyof typeof VIRTUAL_TIMESTAMP_FIELDS\n\n/** Every virtual record-metadata field name, for typing `where` / `orderBy` keys. */\nexport const VIRTUAL_TIMESTAMP_FIELD_NAMES: readonly VirtualTimestampField[] = Object.freeze([\n\t'createdAt',\n\t'updatedAt',\n] as const)\n\nconst SORT_DIRECTIONS: Readonly<Record<string, 'ASC' | 'DESC'>> = Object.freeze({\n\tasc: 'ASC',\n\tdesc: 'DESC',\n})\n\n/** Map a query field name to the column it reads (STORE-11 virtual fields). */\nfunction resolveColumnName(fieldName: string, fields: Record<string, FieldDescriptor>): string {\n\tif (Object.hasOwn(fields, fieldName)) return fieldName\n\tif (fieldName === 'createdAt' || fieldName === 'updatedAt') {\n\t\treturn VIRTUAL_TIMESTAMP_FIELDS[fieldName]\n\t}\n\treturn fieldName\n}\n\nfunction sqlSortDirection(direction: unknown, field: string): 'ASC' | 'DESC' {\n\tconst key = typeof direction === 'string' ? direction.toLowerCase() : ''\n\tconst keyword = Object.hasOwn(SORT_DIRECTIONS, key) ? SORT_DIRECTIONS[key] : undefined\n\tif (keyword === undefined) {\n\t\tthrow new QueryError(`Invalid sort direction for field \"${field}\". Use 'asc' or 'desc'.`, {\n\t\t\tfield,\n\t\t\tdirection: typeof direction === 'string' ? direction.slice(0, 64) : typeof direction,\n\t\t})\n\t}\n\treturn keyword\n}\n\nfunction assertQueryCount(value: unknown, clause: 'limit' | 'offset'): number {\n\tif (typeof value !== 'number' || !Number.isSafeInteger(value) || value < 0) {\n\t\tthrow new QueryError(\n\t\t\t`Invalid ${clause}: expected a non-negative safe integer. Pass a whole number, for example .${clause}(10).`,\n\t\t\t{ clause, received: typeof value === 'number' ? value : typeof value },\n\t\t)\n\t}\n\treturn value\n}\n\nfunction validateFieldName(fieldName: string, fields: Record<string, FieldDescriptor>): void {\n\t// Allow schema fields plus metadata fields that map to query-able columns\n\tconst allowedFields = new Set([\n\t\t...Object.keys(fields),\n\t\t'id',\n\t\t...VIRTUAL_TIMESTAMP_FIELD_NAMES,\n\t\t'_created_at',\n\t\t'_updated_at',\n\t])\n\tif (!allowedFields.has(fieldName)) {\n\t\tthrow new QueryError(\n\t\t\t`Unknown field \"${fieldName}\" in query. Available fields: ${[...allowedFields].join(', ')}`,\n\t\t\t{ field: fieldName },\n\t\t)\n\t}\n}\n","import type { Operation, VersionVector } from '@korajs/core'\nimport { createVersionVector } from '@korajs/core'\nimport type { MetaRow, StorageAdapter } from '../types'\n\nexport const LAST_ACKED_SERVER_VECTOR_META_KEY = 'last_acked_server_vector'\nexport const DELTA_CURSOR_META_KEY = 'delta_cursor'\nexport const DELIVERY_WATERMARK_META_KEY = 'delivery_watermark'\nexport const NODE_TOKEN_META_KEY = 'sync_node_token'\nexport const AUTHORITATIVE_NODE_IDS_META_KEY = 'sync_authoritative_node_ids'\n\n/**\n * Serialize a version vector for `_kora_meta` storage.\n */\nexport function serializeVersionVectorToMeta(vector: VersionVector): string {\n\tconst record: Record<string, number> = {}\n\tfor (const [nodeId, seq] of vector) {\n\t\trecord[nodeId] = seq\n\t}\n\treturn JSON.stringify(record)\n}\n\n/**\n * Deserialize a version vector from `_kora_meta`.\n */\nexport function deserializeVersionVectorFromMeta(value: string): VersionVector {\n\tconst parsed = JSON.parse(value) as Record<string, number>\n\tconst vector = createVersionVector()\n\tfor (const [nodeId, seq] of Object.entries(parsed)) {\n\t\tif (typeof seq === 'number' && seq >= 0) {\n\t\t\tvector.set(nodeId, seq)\n\t\t}\n\t}\n\treturn vector\n}\n\n/**\n * Merge two version vectors, keeping the maximum sequence per node.\n */\nexport function mergeVersionVectors(a: VersionVector, b: VersionVector): VersionVector {\n\tconst merged = new Map(a)\n\tfor (const [nodeId, seq] of b) {\n\t\tmerged.set(nodeId, Math.max(merged.get(nodeId) ?? 0, seq))\n\t}\n\treturn merged\n}\n\n/**\n * Operations present locally but not yet on the server (per server version vector).\n */\nexport async function collectOperationsAheadOfServer(\n\tlocalVector: VersionVector,\n\tserverVector: VersionVector,\n\tfetchRange: (nodeId: string, fromSeq: number, toSeq: number) => Promise<Operation[]>,\n): Promise<Operation[]> {\n\tconst missing: Operation[] = []\n\tfor (const [nodeId, localSeq] of localVector) {\n\t\tconst serverSeq = serverVector.get(nodeId) ?? 0\n\t\tif (localSeq > serverSeq) {\n\t\t\tconst ops = await fetchRange(nodeId, serverSeq + 1, localSeq)\n\t\t\tmissing.push(...ops)\n\t\t}\n\t}\n\tmissing.sort((a, b) => a.sequenceNumber - b.sequenceNumber)\n\treturn missing\n}\n\n/**\n * Load persisted last-acked server vector from `_kora_meta`.\n */\nexport async function loadLastAckedServerVector(adapter: StorageAdapter): Promise<VersionVector> {\n\tconst rows = await adapter.query<MetaRow>('SELECT value FROM _kora_meta WHERE key = ?', [\n\t\tLAST_ACKED_SERVER_VECTOR_META_KEY,\n\t])\n\tconst row = rows[0]\n\tif (!row?.value) {\n\t\treturn createVersionVector()\n\t}\n\ttry {\n\t\treturn deserializeVersionVectorFromMeta(row.value)\n\t} catch {\n\t\treturn createVersionVector()\n\t}\n}\n\n/**\n * Persist the last-acked server version vector to `_kora_meta`.\n */\nexport async function saveLastAckedServerVector(\n\tadapter: StorageAdapter,\n\tvector: VersionVector,\n): Promise<void> {\n\tawait adapter.execute('INSERT OR REPLACE INTO _kora_meta (key, value) VALUES (?, ?)', [\n\t\tLAST_ACKED_SERVER_VECTOR_META_KEY,\n\t\tserializeVersionVectorToMeta(vector),\n\t])\n}\n\n/**\n * Load the per-device node token the sync server issued for this node id (RT-12).\n */\nexport async function loadNodeToken(\n\tadapter: StorageAdapter,\n\tnodeId?: string,\n): Promise<string | null> {\n\tif (nodeId !== undefined) {\n\t\tconst own = await adapter.query<MetaRow>('SELECT value FROM _kora_meta WHERE key = ?', [\n\t\t\tnodeTokenKey(nodeId),\n\t\t])\n\t\tif (own[0]) return own[0].value\n\t\t// The legacy single key belongs to the database's node id (`_kora_meta.node_id`).\n\t\tconst meta = await adapter.query<MetaRow>(\"SELECT value FROM _kora_meta WHERE key = 'node_id'\")\n\t\tif (meta[0]?.value !== nodeId) return null\n\t}\n\tconst rows = await adapter.query<MetaRow>('SELECT value FROM _kora_meta WHERE key = ?', [\n\t\tNODE_TOKEN_META_KEY,\n\t])\n\treturn rows[0]?.value ?? null\n}\n\n/** `_kora_meta` key of one node id's token (RT-38/RT-40: a database may use several). */\nexport function nodeTokenKey(nodeId: string): string {\n\treturn `${NODE_TOKEN_META_KEY}:${nodeId}`\n}\n\n/**\n * Persist the per-device node token next to the node id in `_kora_meta`. With a node\n * id, the token is stored under that node's own key: a database that uses several node\n * ids (a rotated identity, per-tab isolation) keeps each node's token.\n */\nexport async function saveNodeToken(\n\tadapter: StorageAdapter,\n\ttoken: string,\n\tnodeId?: string,\n): Promise<void> {\n\tawait adapter.execute('INSERT OR REPLACE INTO _kora_meta (key, value) VALUES (?, ?)', [\n\t\tnodeId === undefined ? NODE_TOKEN_META_KEY : nodeTokenKey(nodeId),\n\t\ttoken,\n\t])\n}\n\n/**\n * Load a persisted delta cursor for resuming paginated initial sync.\n */\nexport async function loadDeltaCursor(adapter: StorageAdapter): Promise<string | null> {\n\tconst rows = await adapter.query<MetaRow>('SELECT value FROM _kora_meta WHERE key = ?', [\n\t\tDELTA_CURSOR_META_KEY,\n\t])\n\treturn rows[0]?.value ?? null\n}\n\n/**\n * Persist or clear the delta cursor in `_kora_meta`.\n */\nexport async function saveDeltaCursor(\n\tadapter: StorageAdapter,\n\tcursor: string | null,\n): Promise<void> {\n\tif (cursor === null) {\n\t\tawait adapter.execute('DELETE FROM _kora_meta WHERE key = ?', [DELTA_CURSOR_META_KEY])\n\t\treturn\n\t}\n\n\tawait adapter.execute('INSERT OR REPLACE INTO _kora_meta (key, value) VALUES (?, ?)', [\n\t\tDELTA_CURSOR_META_KEY,\n\t\tcursor,\n\t])\n}\n\n/**\n * The `_kora_meta` key for a view's delivery watermark. The default (empty) signature\n * uses the bare key for backward compatibility; other views suffix the signature.\n */\nexport function deliveryWatermarkKey(signature: string): string {\n\treturn signature === ''\n\t\t? DELIVERY_WATERMARK_META_KEY\n\t\t: `${DELIVERY_WATERMARK_META_KEY}:${signature}`\n}\n\n/**\n * Load the persisted delivery watermark for a view signature (0 when none recorded).\n */\nexport async function loadDeliveryWatermark(\n\tadapter: StorageAdapter,\n\tsignature: string,\n): Promise<number> {\n\tconst rows = await adapter.query<MetaRow>('SELECT value FROM _kora_meta WHERE key = ?', [\n\t\tdeliveryWatermarkKey(signature),\n\t])\n\tconst value = rows[0]?.value\n\tif (value === undefined || value === null) {\n\t\treturn 0\n\t}\n\tconst parsed = Number(value)\n\treturn Number.isFinite(parsed) && parsed >= 0 ? parsed : 0\n}\n\n/**\n * Persist the delivery watermark for a view signature in `_kora_meta`.\n */\nexport async function saveDeliveryWatermark(\n\tadapter: StorageAdapter,\n\tsignature: string,\n\twatermark: number,\n): Promise<void> {\n\tawait adapter.execute('INSERT OR REPLACE INTO _kora_meta (key, value) VALUES (?, ?)', [\n\t\tdeliveryWatermarkKey(signature),\n\t\tString(watermark),\n\t])\n}\n\n/**\n * Delete a persisted view watermark. Dropping a watermark is always safe: the view simply\n * back-fills from 0 (deduplicated) the next time it is visited. This bounds the number of\n * `_kora_meta` rows an app that churns through many distinct views can accumulate.\n */\nexport async function deleteDeliveryWatermark(\n\tadapter: StorageAdapter,\n\tsignature: string,\n): Promise<void> {\n\tawait adapter.execute('DELETE FROM _kora_meta WHERE key = ?', [deliveryWatermarkKey(signature)])\n}\n\n/**\n * Load every persisted view watermark, keyed by signature (the default view is '').\n */\nexport async function loadAllDeliveryWatermarks(\n\tadapter: StorageAdapter,\n): Promise<Record<string, number>> {\n\tconst rows = await adapter.query<MetaRow & { key: string }>(\n\t\t'SELECT key, value FROM _kora_meta WHERE key = ? OR key LIKE ?',\n\t\t[DELIVERY_WATERMARK_META_KEY, `${DELIVERY_WATERMARK_META_KEY}:%`],\n\t)\n\tconst result: Record<string, number> = {}\n\tconst prefix = `${DELIVERY_WATERMARK_META_KEY}:`\n\tfor (const row of rows) {\n\t\tconst signature = row.key === DELIVERY_WATERMARK_META_KEY ? '' : row.key.slice(prefix.length)\n\t\tconst parsed = Number(row.value)\n\t\tif (Number.isFinite(parsed) && parsed >= 0) {\n\t\t\tresult[signature] = parsed\n\t\t}\n\t}\n\treturn result\n}\n\n/**\n * Persist the node ids the sync server named authoritative (protocol v2): their\n * operations are server-authored. Stored as a JSON array in `_kora_meta`.\n */\nexport async function saveAuthoritativeNodeIds(\n\tadapter: StorageAdapter,\n\tnodeIds: string[],\n): Promise<void> {\n\tawait adapter.execute('INSERT OR REPLACE INTO _kora_meta (key, value) VALUES (?, ?)', [\n\t\tAUTHORITATIVE_NODE_IDS_META_KEY,\n\t\tJSON.stringify(nodeIds),\n\t])\n}\n\n/** `_kora_meta` key of the explicit authoritative ids a server revoked (RT-81). */\nconst REVOKED_AUTHORITATIVE_NODE_IDS_META_KEY = 'sync_revoked_authoritative_node_ids'\n\n/**\n * Persist the explicit authoritative node ids a sync server revoked (RT-81). A revoked\n * id is never authoritative again on this device, whatever a later handshake lists.\n */\nexport async function saveRevokedAuthoritativeNodeIds(\n\tadapter: StorageAdapter,\n\tnodeIds: string[],\n): Promise<void> {\n\tawait adapter.execute('INSERT OR REPLACE INTO _kora_meta (key, value) VALUES (?, ?)', [\n\t\tREVOKED_AUTHORITATIVE_NODE_IDS_META_KEY,\n\t\tJSON.stringify(nodeIds),\n\t])\n}\n\n/** Load the persisted revoked authoritative node ids (empty when none, or unreadable). */\nexport async function loadRevokedAuthoritativeNodeIds(adapter: StorageAdapter): Promise<string[]> {\n\tconst rows = await adapter.query<MetaRow>('SELECT value FROM _kora_meta WHERE key = ?', [\n\t\tREVOKED_AUTHORITATIVE_NODE_IDS_META_KEY,\n\t])\n\tconst raw = rows[0]?.value\n\tif (raw === undefined) return []\n\ttry {\n\t\tconst parsed: unknown = JSON.parse(raw)\n\t\tif (Array.isArray(parsed)) return parsed.filter((id): id is string => typeof id === 'string')\n\t} catch {\n\t\t// Unreadable: no revocation known; the next handshake that carries one rewrites it.\n\t}\n\treturn []\n}\n\n/**\n * Load the persisted authoritative node ids, or null when no protocol-2 server ever\n * answered (or the stored value is unreadable).\n */\nexport async function loadAuthoritativeNodeIds(adapter: StorageAdapter): Promise<string[] | null> {\n\tconst rows = await adapter.query<MetaRow>('SELECT value FROM _kora_meta WHERE key = ?', [\n\t\tAUTHORITATIVE_NODE_IDS_META_KEY,\n\t])\n\tconst raw = rows[0]?.value\n\tif (raw === undefined) return null\n\ttry {\n\t\tconst parsed: unknown = JSON.parse(raw)\n\t\tif (Array.isArray(parsed) && parsed.every((id) => typeof id === 'string')) {\n\t\t\treturn parsed as string[]\n\t\t}\n\t} catch {\n\t\t// Unreadable: treated as never received; the next handshake rewrites it.\n\t}\n\treturn null\n}\n","import type { Operation } from '@korajs/core'\nimport type { MetaRow, StorageAdapter } from '../types'\nimport { deliveryWatermarkKey } from './sync-state'\n\n/** `_kora_meta` key of this device's contiguous acknowledged own-operation prefix (W3). */\nexport const OWN_ACKED_THROUGH_META_KEY = 'own_acked_through'\n/** `_kora_meta` key of the downlink scope the sync server last accepted (SYNC-11). */\nexport const ACCEPTED_DOWNLINK_SCOPE_META_KEY = 'accepted_downlink_scope'\n\n/**\n * Durable inbound quarantine (W4): delivered operations the client deliberately did not\n * apply, kept so they are never silently lost and can be replayed. Created on first use\n * so existing databases need no migration.\n */\nconst UNAPPLIED_OPS_DDL =\n\t'CREATE TABLE IF NOT EXISTS _kora_unapplied_ops (\\n' +\n\t' op_id TEXT PRIMARY KEY NOT NULL,\\n' +\n\t' collection TEXT NOT NULL,\\n' +\n\t' delivery_seq INTEGER,\\n' +\n\t' code TEXT NOT NULL,\\n' +\n\t' message TEXT NOT NULL,\\n' +\n\t' payload TEXT NOT NULL,\\n' +\n\t' quarantined_at INTEGER NOT NULL\\n' +\n\t')'\n\n/** A delivered operation the client did not apply, as stored in `_kora_unapplied_ops`. */\nexport interface UnappliedOperation {\n\t/** The operation as delivered (still encrypted when decryption failed). */\n\toperation: Operation\n\t/** Delivery sequence of the batch that carried it, or null for a legacy batch. */\n\tdeliverySequence: number | null\n\t/** Machine-readable reason. */\n\tcode: string\n\t/** Human-readable explanation. */\n\tmessage: string\n\t/** Wall-clock time (ms) it was quarantined. Display only. */\n\tquarantinedAt: number\n}\n\ninterface UnappliedRow {\n\top_id: string\n\tdelivery_seq: number | null\n\tcode: string\n\tmessage: string\n\tpayload: string\n\tquarantined_at: number\n}\n\nconst ensuredAdapters = new WeakSet<StorageAdapter>()\n\nasync function ensureUnappliedTable(adapter: StorageAdapter): Promise<void> {\n\tif (ensuredAdapters.has(adapter)) return\n\tawait adapter.execute(UNAPPLIED_OPS_DDL)\n\tensuredAdapters.add(adapter)\n}\n\n/**\n * Record quarantined operations and, when given, advance a view's delivery watermark in\n * the SAME transaction, so the watermark can never pass an operation that is neither\n * applied nor recorded here (the W4 invariant).\n */\nexport async function saveUnappliedOperations(\n\tadapter: StorageAdapter,\n\tentries: UnappliedOperation[],\n\twatermark?: { signature: string; watermark: number },\n): Promise<void> {\n\tawait ensureUnappliedTable(adapter)\n\tawait adapter.transaction(async (tx) => {\n\t\tfor (const entry of entries) {\n\t\t\tawait tx.execute(\n\t\t\t\t'INSERT OR REPLACE INTO _kora_unapplied_ops (op_id, collection, delivery_seq, code, message, payload, quarantined_at) VALUES (?, ?, ?, ?, ?, ?, ?)',\n\t\t\t\t[\n\t\t\t\t\tentry.operation.id,\n\t\t\t\t\tentry.operation.collection,\n\t\t\t\t\tentry.deliverySequence,\n\t\t\t\t\tentry.code,\n\t\t\t\t\tentry.message,\n\t\t\t\t\tJSON.stringify(entry.operation),\n\t\t\t\t\tentry.quarantinedAt,\n\t\t\t\t],\n\t\t\t)\n\t\t}\n\t\tif (watermark) {\n\t\t\tawait tx.execute('INSERT OR REPLACE INTO _kora_meta (key, value) VALUES (?, ?)', [\n\t\t\t\tdeliveryWatermarkKey(watermark.signature),\n\t\t\t\tString(watermark.watermark),\n\t\t\t])\n\t\t}\n\t})\n}\n\n/** Every quarantined operation, oldest delivery first. */\nexport async function loadUnappliedOperations(\n\tadapter: StorageAdapter,\n): Promise<UnappliedOperation[]> {\n\tawait ensureUnappliedTable(adapter)\n\tconst rows = await adapter.query<UnappliedRow>(\n\t\t'SELECT op_id, delivery_seq, code, message, payload, quarantined_at FROM _kora_unapplied_ops ORDER BY delivery_seq ASC, quarantined_at ASC',\n\t)\n\treturn rows.map((row) => ({\n\t\toperation: JSON.parse(row.payload) as Operation,\n\t\tdeliverySequence: row.delivery_seq === null ? null : Number(row.delivery_seq),\n\t\tcode: row.code,\n\t\tmessage: row.message,\n\t\tquarantinedAt: Number(row.quarantined_at),\n\t}))\n}\n\n/** Remove quarantined operations by operation id (applied on replay, or reconciled). */\nexport async function removeUnappliedOperations(\n\tadapter: StorageAdapter,\n\toperationIds: string[],\n): Promise<void> {\n\tif (operationIds.length === 0) return\n\tawait ensureUnappliedTable(adapter)\n\tconst placeholders = operationIds.map(() => '?').join(', ')\n\tawait adapter.execute(\n\t\t`DELETE FROM _kora_unapplied_ops WHERE op_id IN (${placeholders})`,\n\t\toperationIds,\n\t)\n}\n\n/** `_kora_meta` key of a node's prefix when the legacy single key holds another node's. */\nexport function ownAckedThroughKey(nodeId: string): string {\n\treturn `${OWN_ACKED_THROUGH_META_KEY}:${nodeId}`\n}\n\nfunction parseLegacyPrefix(value: string | undefined): { nodeId: string; sequence: number } | null {\n\tif (value === undefined || value === null) return null\n\ttry {\n\t\tconst parsed = JSON.parse(value) as { nodeId?: unknown; sequence?: unknown }\n\t\tif (typeof parsed.nodeId !== 'string') return null\n\t\tconst sequence =\n\t\t\ttypeof parsed.sequence === 'number' && parsed.sequence >= 0 ? parsed.sequence : null\n\t\treturn sequence === null ? null : { nodeId: parsed.nodeId, sequence }\n\t} catch {\n\t\treturn null\n\t}\n}\n\n/**\n * Load the acknowledged own-operation prefix for a node id. Null when none was ever\n * recorded for this node (an upgrade from a release that persisted a max instead).\n *\n * The first node a database tracks keeps the single legacy key (`own_acked_through`, as\n * earlier releases wrote it); any other local node (a rotated node, another tab's node\n * under per-tab isolation, RT-40) has its own key, so tracking one node never erases\n * another node's prefix.\n */\nexport async function loadOwnAckedThrough(\n\tadapter: StorageAdapter,\n\tnodeId: string,\n): Promise<number | null> {\n\tconst rows = await adapter.query<MetaRow>('SELECT value FROM _kora_meta WHERE key = ?', [\n\t\tOWN_ACKED_THROUGH_META_KEY,\n\t])\n\tconst legacy = parseLegacyPrefix(rows[0]?.value)\n\tif (legacy && legacy.nodeId === nodeId) return legacy.sequence\n\tconst own = await adapter.query<MetaRow>('SELECT value FROM _kora_meta WHERE key = ?', [\n\t\townAckedThroughKey(nodeId),\n\t])\n\tconst value = own[0]?.value\n\tif (value === undefined || value === null) return null\n\tconst sequence = Number(value)\n\treturn Number.isInteger(sequence) && sequence >= 0 ? sequence : null\n}\n\n/** Persist the acknowledged own-operation prefix for a node id. */\nexport async function saveOwnAckedThrough(\n\tadapter: StorageAdapter,\n\tnodeId: string,\n\tsequence: number,\n): Promise<void> {\n\tawait adapter.transaction(async (tx) => {\n\t\tconst rows = await tx.query<MetaRow>('SELECT value FROM _kora_meta WHERE key = ?', [\n\t\t\tOWN_ACKED_THROUGH_META_KEY,\n\t\t])\n\t\tconst legacy = parseLegacyPrefix(rows[0]?.value)\n\t\tif (legacy === null || legacy.nodeId === nodeId) {\n\t\t\tawait tx.execute('INSERT OR REPLACE INTO _kora_meta (key, value) VALUES (?, ?)', [\n\t\t\t\tOWN_ACKED_THROUGH_META_KEY,\n\t\t\t\tJSON.stringify({ nodeId, sequence }),\n\t\t\t])\n\t\t\treturn\n\t\t}\n\t\tawait tx.execute('INSERT OR REPLACE INTO _kora_meta (key, value) VALUES (?, ?)', [\n\t\t\townAckedThroughKey(nodeId),\n\t\t\tString(sequence),\n\t\t])\n\t})\n}\n\n/** Load the downlink scope the sync server last accepted (null when none). */\nexport async function loadAcceptedDownlinkScope(\n\tadapter: StorageAdapter,\n): Promise<Record<string, Record<string, unknown>> | null> {\n\tconst rows = await adapter.query<MetaRow>('SELECT value FROM _kora_meta WHERE key = ?', [\n\t\tACCEPTED_DOWNLINK_SCOPE_META_KEY,\n\t])\n\tconst value = rows[0]?.value\n\tif (value === undefined || value === null) return null\n\ttry {\n\t\tconst parsed = JSON.parse(value) as unknown\n\t\treturn parsed !== null && typeof parsed === 'object'\n\t\t\t? (parsed as Record<string, Record<string, unknown>>)\n\t\t\t: null\n\t} catch {\n\t\treturn null\n\t}\n}\n\n/** Persist (or clear) the downlink scope the sync server last accepted. */\nexport async function saveAcceptedDownlinkScope(\n\tadapter: StorageAdapter,\n\tscope: Record<string, Record<string, unknown>> | null,\n): Promise<void> {\n\tif (scope === null) {\n\t\tawait adapter.execute('DELETE FROM _kora_meta WHERE key = ?', [\n\t\t\tACCEPTED_DOWNLINK_SCOPE_META_KEY,\n\t\t])\n\t\treturn\n\t}\n\tawait adapter.execute('INSERT OR REPLACE INTO _kora_meta (key, value) VALUES (?, ?)', [\n\t\tACCEPTED_DOWNLINK_SCOPE_META_KEY,\n\t\tJSON.stringify(scope),\n\t])\n}\n","import type { MetaRow, StorageAdapter, Transaction } from '../types'\nimport { OWN_ACKED_THROUGH_META_KEY } from './sync-durability'\nimport { NODE_TOKEN_META_KEY, nodeTokenKey } from './sync-state'\n\n/**\n * Durable sync bookkeeping that belongs to the device, not to the app (Phase 2 RT-36,\n * RT-38, RT-40): the operations the server refused for good, and the node ids this\n * database authored operations under.\n *\n * Both tables are created on first use, so existing databases need no migration.\n */\n\n/**\n * Operations the server refused with a non-retriable rejection (RT-36). Unlike\n * `_kora_sync_rejected` (the app's reconciliation list, which `clearRejectedOperations`\n * empties), a row here is never removed: a refused operation stays refused, so a later\n * rescan of the device's own history never submits it again.\n */\nexport const TERMINAL_REJECTIONS_TABLE = '_kora_terminal_rejections'\n\n/**\n * Node ids this database authored operations under (RT-38, RT-40): the node in use,\n * nodes it rotated away from, and other tabs' nodes under per-tab isolation.\n */\nexport const LOCAL_NODES_TABLE = '_kora_local_nodes'\n\n/** Meta key: count of accepted sync handshakes on this database (refusal cycles, RT-38). */\nexport const ACCEPTED_CYCLE_META_KEY = 'sync_accepted_cycle'\n\n/** Meta key: terminal rejections were seeded from the pre-Phase-2 rejected list once. */\nconst TERMINAL_SEED_META_KEY = 'terminal_rejections_seeded_v1'\n\n/**\n * Rejection codes that never become a terminal marker: the operation was not judged on\n * its content, so a later upload of it may be accepted.\n *\n * - `SEQUENCE_CONFLICT`: the device's sequence number collided with an operation the\n * server holds (a lost local tail, RT-35, or a beta.12 duplicate pair, RT-37); the\n * operation is renumbered and uploaded again.\n * - `NODE_ID_MISMATCH`: uploaded on another node's session.\n * - `OUT_OF_UPLINK_SCOPE`: judged by the client against the scope it had then.\n */\nexport const NON_TERMINAL_REJECTION_CODES: ReadonlySet<string> = new Set([\n\t'SEQUENCE_CONFLICT',\n\t'NODE_ID_MISMATCH',\n\t'OUT_OF_UPLINK_SCOPE',\n])\n\nconst TERMINAL_REJECTIONS_DDL = `CREATE TABLE IF NOT EXISTS ${TERMINAL_REJECTIONS_TABLE} (\n operation_id TEXT PRIMARY KEY NOT NULL,\n node_id TEXT,\n sequence_number INTEGER,\n code TEXT NOT NULL,\n rejected_at INTEGER NOT NULL\n)`\n\nconst LOCAL_NODES_DDL = `CREATE TABLE IF NOT EXISTS ${LOCAL_NODES_TABLE} (\n node_id TEXT PRIMARY KEY NOT NULL,\n created_at INTEGER NOT NULL,\n accepted INTEGER NOT NULL DEFAULT 0,\n held INTEGER NOT NULL DEFAULT 0,\n refused_cycle INTEGER,\n principal TEXT,\n binding TEXT,\n refused_principals TEXT\n)`\n\n/**\n * How a local node's {@link LocalNodeRecord.principal} was learned (RT-50):\n *\n * - `fresh`: the node had no writes when it was bound to the signed-in user, so every\n * write under it was made by that user.\n * - `server`: a sync handshake as the node was accepted for that user (the server's node\n * claims are authoritative).\n * - `app`: the app assigned a held node to the signed-in user\n * (`app.sync.assignHeld`). A guess: cleared if the server refuses the node for them.\n */\nexport type LocalNodeBinding = 'fresh' | 'server' | 'app'\n\nconst LOCAL_NODE_BINDINGS: readonly LocalNodeBinding[] = ['fresh', 'server', 'app']\n\n/** At most this many principals are remembered as refused for one node (RT-50). */\nconst MAX_REFUSED_PRINCIPALS = 32\n\n/** Meta key: per-node adoption schedule (parked adoptions, upload progress; RT-46). */\nexport const ADOPTION_SCHEDULE_META_KEY = 'sync_adoption_schedule_v1'\n\n/** Adapters whose `_kora_local_nodes` table is known to have every column (this process). */\nconst migratedAdapters = new WeakSet<StorageAdapter>()\n\n/** A terminal rejection to record (RT-36). */\nexport interface TerminalRejection {\n\toperationId: string\n\t/** Authoring node and sequence, when known (null for rows seeded from the old list). */\n\tnodeId: string | null\n\tsequenceNumber: number | null\n\tcode: string\n\trejectedAt: number\n}\n\n/** A node id this database authored operations under (RT-38, RT-40). */\nexport interface LocalNodeRecord {\n\tnodeId: string\n\t/** Wall-clock time (ms) the node was registered. Display only. */\n\tcreatedAt: number\n\t/** A sync handshake as this node was accepted at least once. */\n\taccepted: boolean\n\t/**\n\t * The server refused this node (`NODE_ID_CLAIMED`) after it had been accepted: it\n\t * belongs to a principal that is not signed in. Its unsynced operations are held for\n\t * that principal, never uploaded under another one.\n\t */\n\theld: boolean\n\t/** {@link ACCEPTED_CYCLE_META_KEY} value when the server last refused it, or null. */\n\trefusedCycle: number | null\n\t/**\n\t * The signed-in user the node's writes belong to (RT-42), or null when the app never\n\t * told the store who was signed in while it was in use. A node bound to one user is\n\t * never used for, uploaded under, or adopted by another user's session.\n\t */\n\tprincipal: string | null\n\t/**\n\t * How {@link principal} was learned (RT-50), or null when unbound, or bound by a release\n\t * that did not record it (treated as a guess).\n\t */\n\tbinding: LocalNodeBinding | null\n\t/**\n\t * Users the server refused this UNBOUND node for (`NODE_ID_CLAIMED`, RT-50): it is\n\t * not theirs, so it is never tried again on their sessions. An unbound node that was\n\t * accepted before belongs to whichever user the server accepts it for.\n\t */\n\trefusedPrincipals: string[]\n}\n\ninterface LocalNodeRow {\n\tnode_id: string\n\tcreated_at: number\n\taccepted: number\n\theld: number\n\trefused_cycle: number | null\n\tprincipal: string | null\n\tbinding: string | null\n\trefused_principals: string | null\n}\n\n/** A parked adoption (RT-46): the node made no upload progress in its last session. */\nexport interface ParkedAdoption {\n\t/** {@link AdoptionSchedule.progress} when it was parked: retried once it moves. */\n\tprogressMark: number\n\t/** Wall-clock time (ms) after which it is retried anyway. Scheduling only. */\n\tuntilMs: number\n\t/** Consecutive parks (backoff exponent). */\n\tcount: number\n\t/** Wall-clock time (ms) it was parked. Scheduling only. */\n\tparkedAtMs: number\n}\n\n/**\n * Which local nodes' adoptions are parked (RT-46), and a counter of upload progress on\n * this database: a parked node is retried once anything else uploaded (its deferral may\n * have depended on it) or after its backoff.\n */\nexport interface AdoptionSchedule {\n\tprogress: number\n\tparked: Record<string, ParkedAdoption>\n}\n\n/**\n * Create both tables. `Store.open` runs it (through {@link registerLocalNode}), so the\n * read paths, which run often, assume the tables exist and never issue DDL (on the\n * IndexedDB adapter every statement schedules a snapshot).\n */\nexport async function ensureLocalSyncRecordTables(adapter: StorageAdapter): Promise<void> {\n\tawait adapter.execute(TERMINAL_REJECTIONS_DDL)\n\tawait adapter.execute(LOCAL_NODES_DDL)\n\tif (migratedAdapters.has(adapter)) return\n\t// A table created by an earlier release lacks the principal column (RT-42).\n\t// ... and the binding columns (RT-50).\n\tconst columns = await adapter.query<{ name: string }>(`PRAGMA table_info(${LOCAL_NODES_TABLE})`)\n\tfor (const column of ['principal', 'binding', 'refused_principals']) {\n\t\tif (!columns.some((existing) => existing.name === column)) {\n\t\t\tawait adapter.execute(`ALTER TABLE ${LOCAL_NODES_TABLE} ADD COLUMN ${column} TEXT`)\n\t\t}\n\t}\n\tmigratedAdapters.add(adapter)\n}\n\n/** Record terminal rejections (idempotent by operation id; the first record wins). */\nexport async function recordTerminalRejections(\n\tadapter: StorageAdapter,\n\tentries: TerminalRejection[],\n): Promise<void> {\n\tconst recordable = entries.filter((entry) => !NON_TERMINAL_REJECTION_CODES.has(entry.code))\n\tif (recordable.length === 0) return\n\tawait ensureLocalSyncRecordTables(adapter)\n\tawait adapter.transaction(async (tx) => {\n\t\tfor (const entry of recordable) {\n\t\t\tawait tx.execute(\n\t\t\t\t`INSERT OR IGNORE INTO ${TERMINAL_REJECTIONS_TABLE} (operation_id, node_id, sequence_number, code, rejected_at) VALUES (?, ?, ?, ?, ?)`,\n\t\t\t\t[entry.operationId, entry.nodeId, entry.sequenceNumber, entry.code, entry.rejectedAt],\n\t\t\t)\n\t\t}\n\t})\n}\n\n/** Which of `operationIds` carry a terminal rejection marker. */\nexport async function findTerminalRejections(\n\tadapter: StorageAdapter,\n\toperationIds: string[],\n): Promise<Set<string>> {\n\tconst found = new Set<string>()\n\tif (operationIds.length === 0) return found\n\tconst CHUNK = 500\n\tfor (let i = 0; i < operationIds.length; i += CHUNK) {\n\t\tconst chunk = operationIds.slice(i, i + CHUNK)\n\t\tconst rows = await adapter.query<{ operation_id: string }>(\n\t\t\t`SELECT operation_id FROM ${TERMINAL_REJECTIONS_TABLE} WHERE operation_id IN (${chunk.map(() => '?').join(', ')})`,\n\t\t\tchunk,\n\t\t)\n\t\tfor (const row of rows) found.add(row.operation_id)\n\t}\n\treturn found\n}\n\n/**\n * Seed terminal markers once from `_kora_sync_rejected`, the list earlier releases kept\n * (and the app may have cleared since). Rows whose code is not terminal are skipped:\n * in particular a pre-release device's `SEQUENCE_CONFLICT` rejections (RT-37) stay eligible\n * for the one-time re-upload, which is how those writes reach the server.\n */\nexport async function seedTerminalRejectionsOnce(adapter: StorageAdapter): Promise<void> {\n\tawait ensureLocalSyncRecordTables(adapter)\n\tconst done = await adapter.query<MetaRow>('SELECT value FROM _kora_meta WHERE key = ?', [\n\t\tTERMINAL_SEED_META_KEY,\n\t])\n\tif (done.length > 0) return\n\tconst tables = await adapter.query<{ name: string }>(\n\t\t\"SELECT name FROM sqlite_master WHERE type = 'table' AND name = '_kora_sync_rejected'\",\n\t)\n\tawait adapter.transaction(async (tx) => {\n\t\tif (tables.length > 0) {\n\t\t\tconst placeholders = [...NON_TERMINAL_REJECTION_CODES].map(() => '?').join(', ')\n\t\t\tawait tx.execute(\n\t\t\t\t`INSERT OR IGNORE INTO ${TERMINAL_REJECTIONS_TABLE} (operation_id, node_id, sequence_number, code, rejected_at)\n SELECT operation_id, NULL, NULL, code, rejected_at FROM _kora_sync_rejected\n WHERE retriable = 0 AND code NOT IN (${placeholders})`,\n\t\t\t\t[...NON_TERMINAL_REJECTION_CODES],\n\t\t\t)\n\t\t}\n\t\tawait tx.execute('INSERT OR REPLACE INTO _kora_meta (key, value) VALUES (?, ?)', [\n\t\t\tTERMINAL_SEED_META_KEY,\n\t\t\tString(Date.now()),\n\t\t])\n\t})\n}\n\nfunction rowToRecord(row: LocalNodeRow): LocalNodeRecord {\n\treturn {\n\t\tnodeId: row.node_id,\n\t\tcreatedAt: Number(row.created_at),\n\t\taccepted: Number(row.accepted) === 1,\n\t\theld: Number(row.held) === 1,\n\t\trefusedCycle: row.refused_cycle === null ? null : Number(row.refused_cycle),\n\t\tprincipal: typeof row.principal === 'string' ? row.principal : null,\n\t\tbinding:\n\t\t\ttypeof row.principal === 'string' &&\n\t\t\tLOCAL_NODE_BINDINGS.includes(row.binding as LocalNodeBinding)\n\t\t\t\t? (row.binding as LocalNodeBinding)\n\t\t\t\t: null,\n\t\trefusedPrincipals: parsePrincipalList(row.refused_principals),\n\t}\n}\n\nfunction parsePrincipalList(value: string | null): string[] {\n\tif (typeof value !== 'string' || value.length === 0) return []\n\ttry {\n\t\tconst parsed: unknown = JSON.parse(value)\n\t\treturn Array.isArray(parsed)\n\t\t\t? parsed.filter((entry): entry is string => typeof entry === 'string')\n\t\t\t: []\n\t} catch {\n\t\treturn []\n\t}\n}\n\n/**\n * Register a node id this database authors operations under. A node registered for the\n * first time that a claims-aware server already accepted here (a database from a build\n * with node claims) is recorded as accepted, so a later refusal holds its writes\n * instead of re-authoring them under another principal (RT-38).\n *\n * Sync history alone is not that evidence (RT-92): beta.12 and older servers recorded\n * no node claims, so a node only they accepted belongs to nobody on an upgraded server.\n * It registers as not accepted, and a refusal re-authors its never-sent writes under a\n * fresh node (RT-21) instead of holding them for an owner that does not exist.\n */\nexport async function registerLocalNode(adapter: StorageAdapter, nodeId: string): Promise<void> {\n\tawait ensureLocalSyncRecordTables(adapter)\n\tconst existing = await adapter.query<{ node_id: string }>(\n\t\t`SELECT node_id FROM ${LOCAL_NODES_TABLE} WHERE node_id = ?`,\n\t\t[nodeId],\n\t)\n\tif (existing.length > 0) return\n\tconst accepted = await hasSyncHistory(adapter, nodeId)\n\tawait adapter.execute(\n\t\t`INSERT OR IGNORE INTO ${LOCAL_NODES_TABLE} (node_id, created_at, accepted, held, refused_cycle) VALUES (?, ?, ?, 0, NULL)`,\n\t\t[nodeId, Date.now(), accepted ? 1 : 0],\n\t)\n}\n\n/**\n * Whether a claims-aware server accepted `nodeId` on this database before the registry\n * existed: a node token it issued (anonymous claims), or the acknowledged-prefix record\n * builds with node claims keep. beta.12's `last_acked_server_vector` does not count: its\n * server recorded no claims (RT-92).\n */\nasync function hasSyncHistory(adapter: StorageAdapter, nodeId: string): Promise<boolean> {\n\tconst rows = await adapter.query<MetaRow & { key: string }>(\n\t\t'SELECT key, value FROM _kora_meta WHERE key IN (?, ?, ?)',\n\t\t[NODE_TOKEN_META_KEY, nodeTokenKey(nodeId), OWN_ACKED_THROUGH_META_KEY],\n\t)\n\tconst nodeIdRows = await adapter.query<MetaRow>(\n\t\t\"SELECT value FROM _kora_meta WHERE key = 'node_id'\",\n\t)\n\tconst isMetaNode = nodeIdRows[0]?.value === nodeId\n\tfor (const row of rows) {\n\t\tif (row.key === nodeTokenKey(nodeId)) return true\n\t\tif (row.key === NODE_TOKEN_META_KEY) {\n\t\t\tif (isMetaNode) return true\n\t\t\tcontinue\n\t\t}\n\t\ttry {\n\t\t\tconst parsed = JSON.parse(row.value) as Record<string, unknown>\n\t\t\tif (row.key === OWN_ACKED_THROUGH_META_KEY) {\n\t\t\t\tif (parsed.nodeId === nodeId && typeof parsed.sequence === 'number' && parsed.sequence > 0)\n\t\t\t\t\treturn true\n\t\t\t}\n\t\t} catch {\n\t\t\t// An unreadable row is no evidence either way.\n\t\t}\n\t}\n\treturn false\n}\n\n/** Every registered local node, oldest first. */\nexport async function listLocalNodes(adapter: StorageAdapter): Promise<LocalNodeRecord[]> {\n\tconst rows = await adapter.query<LocalNodeRow>(\n\t\t`SELECT node_id, created_at, accepted, held, refused_cycle, principal, binding, refused_principals FROM ${LOCAL_NODES_TABLE} ORDER BY created_at ASC, node_id ASC`,\n\t)\n\treturn rows.map(rowToRecord)\n}\n\nasync function readAcceptedCycle(tx: Transaction): Promise<number> {\n\tconst rows = await tx.query<MetaRow>('SELECT value FROM _kora_meta WHERE key = ?', [\n\t\tACCEPTED_CYCLE_META_KEY,\n\t])\n\tconst value = Number(rows[0]?.value ?? 0)\n\treturn Number.isFinite(value) ? value : 0\n}\n\n/**\n * Record an accepted handshake as `nodeId`: the node is accepted and no longer held,\n * and a new refusal cycle starts (every node may be tried again after a refusal).\n */\nexport async function markLocalNodeAccepted(\n\tadapter: StorageAdapter,\n\tnodeId: string,\n): Promise<void> {\n\tawait ensureLocalSyncRecordTables(adapter)\n\tawait adapter.transaction(async (tx) => {\n\t\tconst cycle = await readAcceptedCycle(tx)\n\t\tawait tx.execute(\n\t\t\t`INSERT INTO ${LOCAL_NODES_TABLE} (node_id, created_at, accepted, held, refused_cycle) VALUES (?, ?, 1, 0, NULL)\n ON CONFLICT(node_id) DO UPDATE SET accepted = 1, held = 0, refused_cycle = NULL`,\n\t\t\t[nodeId, Date.now()],\n\t\t)\n\t\tawait tx.execute('INSERT OR REPLACE INTO _kora_meta (key, value) VALUES (?, ?)', [\n\t\t\tACCEPTED_CYCLE_META_KEY,\n\t\t\tString(cycle + 1),\n\t\t])\n\t})\n}\n\n/**\n * Record that the server refused `nodeId` (`NODE_ID_CLAIMED`) in the current refusal\n * cycle. `held` marks its unsynced operations as held for the principal owning it.\n */\nexport async function markLocalNodeRefused(\n\tadapter: StorageAdapter,\n\tnodeId: string,\n\theld: boolean,\n): Promise<void> {\n\tawait ensureLocalSyncRecordTables(adapter)\n\tawait adapter.transaction(async (tx) => {\n\t\tconst cycle = await readAcceptedCycle(tx)\n\t\tawait tx.execute(\n\t\t\t`INSERT INTO ${LOCAL_NODES_TABLE} (node_id, created_at, accepted, held, refused_cycle) VALUES (?, ?, 0, ?, ?)\n ON CONFLICT(node_id) DO UPDATE SET held = MAX(held, excluded.held), refused_cycle = excluded.refused_cycle`,\n\t\t\t[nodeId, Date.now(), held ? 1 : 0, cycle],\n\t\t)\n\t})\n}\n\n/**\n * Forget a local node that has nothing left to upload (bounds the registry under per-tab\n * isolation, where every tab adds a node). A node that writes again is registered again\n * when its store opens. Never the database's own node id.\n */\nexport async function forgetLocalNode(adapter: StorageAdapter, nodeId: string): Promise<void> {\n\tawait ensureLocalSyncRecordTables(adapter)\n\tawait adapter.execute(\n\t\t`DELETE FROM ${LOCAL_NODES_TABLE} WHERE node_id = ? AND held = 0 AND node_id NOT IN (SELECT value FROM _kora_meta WHERE key = 'node_id')`,\n\t\t[nodeId],\n\t)\n}\n\n/**\n * Bind a local node to the signed-in user whose writes it carries (RT-42), recording how\n * that was learned (RT-50). The node is registered if it is not yet.\n */\nexport async function setLocalNodePrincipal(\n\tadapter: StorageAdapter,\n\tnodeId: string,\n\tprincipal: string,\n\tbinding: LocalNodeBinding,\n): Promise<void> {\n\tawait ensureLocalSyncRecordTables(adapter)\n\tawait adapter.execute(\n\t\t`INSERT INTO ${LOCAL_NODES_TABLE} (node_id, created_at, accepted, held, refused_cycle, principal, binding) VALUES (?, ?, 0, 0, NULL, ?, ?)\n ON CONFLICT(node_id) DO UPDATE SET principal = excluded.principal, binding = excluded.binding`,\n\t\t[nodeId, Date.now(), principal, binding],\n\t)\n}\n\n/** A binding that is only a guess: cleared when the server refuses the node (RT-50). */\nfunction isGuessedBinding(node: LocalNodeRecord): boolean {\n\treturn node.principal !== null && (node.binding === null || node.binding === 'app')\n}\n\nasync function findLocalNode(\n\tadapter: StorageAdapter | Transaction,\n\tnodeId: string,\n): Promise<LocalNodeRecord | null> {\n\tconst rows = await adapter.query<LocalNodeRow>(\n\t\t`SELECT node_id, created_at, accepted, held, refused_cycle, principal, binding, refused_principals FROM ${LOCAL_NODES_TABLE} WHERE node_id = ?`,\n\t\t[nodeId],\n\t)\n\tconst row = rows[0]\n\treturn row ? rowToRecord(row) : null\n}\n\n/**\n * A sync handshake as `nodeId` was accepted for `principal` (RT-50): the server's node\n * claims say the node is theirs. Binds an unbound node, or replaces a guessed binding,\n * as `server`. A node bound from evidence (`fresh` or `server`) to another user keeps\n * its binding: the engine never runs such a session.\n */\nexport async function confirmLocalNodePrincipal(\n\tadapter: StorageAdapter,\n\tnodeId: string,\n\tprincipal: string,\n): Promise<void> {\n\tawait ensureLocalSyncRecordTables(adapter)\n\tawait adapter.transaction(async (tx) => {\n\t\tconst node = await findLocalNode(tx, nodeId)\n\t\tif (node && node.principal !== null && node.principal !== principal && !isGuessedBinding(node))\n\t\t\treturn\n\t\tawait tx.execute(\n\t\t\t`INSERT INTO ${LOCAL_NODES_TABLE} (node_id, created_at, accepted, held, refused_cycle, principal, binding) VALUES (?, ?, 0, 0, NULL, ?, 'server')\n ON CONFLICT(node_id) DO UPDATE SET principal = excluded.principal, binding = 'server', refused_principals = NULL`,\n\t\t\t[nodeId, Date.now(), principal],\n\t\t)\n\t})\n}\n\n/**\n * The server refused `nodeId` for `principal` (`NODE_ID_CLAIMED`, RT-50): another user\n * owns it. A guessed binding is cleared (it was wrong), and an unbound node remembers\n * that it is not `principal`'s, so it is tried on another user's session instead.\n */\nexport async function recordLocalNodeRefusedFor(\n\tadapter: StorageAdapter,\n\tnodeId: string,\n\tprincipal: string,\n): Promise<void> {\n\tawait ensureLocalSyncRecordTables(adapter)\n\tawait adapter.transaction(async (tx) => {\n\t\tconst node = await findLocalNode(tx, nodeId)\n\t\tif (!node) return\n\t\tif (node.principal !== null && !isGuessedBinding(node)) return\n\t\tconst refused = node.refusedPrincipals.filter((entry) => entry !== principal)\n\t\trefused.push(principal)\n\t\tawait tx.execute(\n\t\t\t`UPDATE ${LOCAL_NODES_TABLE} SET principal = NULL, binding = NULL, refused_principals = ? WHERE node_id = ?`,\n\t\t\t[JSON.stringify(refused.slice(-MAX_REFUSED_PRINCIPALS)), nodeId],\n\t\t)\n\t})\n}\n\n/**\n * The app assigned a held, unbound local node to `principal` (RT-50,\n * `app.sync.assignHeld`): its writes upload on their sessions from now on. A guess, so\n * a later refusal by the server clears it again.\n *\n * @returns false when the node is unknown, already bound, or was refused for `principal`\n */\nexport async function assignLocalNodePrincipal(\n\tadapter: StorageAdapter,\n\tnodeId: string,\n\tprincipal: string,\n): Promise<boolean> {\n\tawait ensureLocalSyncRecordTables(adapter)\n\tlet assigned = false\n\tawait adapter.transaction(async (tx) => {\n\t\tconst node = await findLocalNode(tx, nodeId)\n\t\tif (!node || node.principal !== null || node.refusedPrincipals.includes(principal)) return\n\t\tawait tx.execute(\n\t\t\t`UPDATE ${LOCAL_NODES_TABLE} SET principal = ?, binding = 'app', held = 0, refused_cycle = NULL WHERE node_id = ?`,\n\t\t\t[principal, nodeId],\n\t\t)\n\t\tassigned = true\n\t})\n\treturn assigned\n}\n\n/** Forget a local node whatever its state (its writes were discarded by the app, RT-50). */\nexport async function dropLocalNode(adapter: StorageAdapter, nodeId: string): Promise<void> {\n\tawait ensureLocalSyncRecordTables(adapter)\n\tawait adapter.execute(\n\t\t`DELETE FROM ${LOCAL_NODES_TABLE} WHERE node_id = ? AND node_id NOT IN (SELECT value FROM _kora_meta WHERE key = 'node_id')`,\n\t\t[nodeId],\n\t)\n}\n\n/** The adoption schedule (RT-46); empty when none was saved. */\nexport async function loadAdoptionSchedule(adapter: StorageAdapter): Promise<AdoptionSchedule> {\n\tconst rows = await adapter.query<MetaRow>('SELECT value FROM _kora_meta WHERE key = ?', [\n\t\tADOPTION_SCHEDULE_META_KEY,\n\t])\n\tconst empty: AdoptionSchedule = { progress: 0, parked: {} }\n\tconst raw = rows[0]?.value\n\tif (!raw) return empty\n\ttry {\n\t\tconst parsed = JSON.parse(raw) as Partial<AdoptionSchedule>\n\t\treturn {\n\t\t\tprogress: typeof parsed.progress === 'number' ? parsed.progress : 0,\n\t\t\tparked: parsed.parked && typeof parsed.parked === 'object' ? parsed.parked : {},\n\t\t}\n\t} catch {\n\t\t// An unreadable schedule only costs an earlier retry of a parked adoption.\n\t\treturn empty\n\t}\n}\n\n/** Persist the adoption schedule (RT-46). */\nexport async function saveAdoptionSchedule(\n\tadapter: StorageAdapter,\n\tschedule: AdoptionSchedule,\n): Promise<void> {\n\tawait adapter.execute('INSERT OR REPLACE INTO _kora_meta (key, value) VALUES (?, ?)', [\n\t\tADOPTION_SCHEDULE_META_KEY,\n\t\tJSON.stringify(schedule),\n\t])\n}\n\n/** The current refusal cycle (count of accepted handshakes on this database). */\nexport async function loadAcceptedCycle(adapter: StorageAdapter): Promise<number> {\n\tconst rows = await adapter.query<MetaRow>('SELECT value FROM _kora_meta WHERE key = ?', [\n\t\tACCEPTED_CYCLE_META_KEY,\n\t])\n\tconst value = Number(rows[0]?.value ?? 0)\n\treturn Number.isFinite(value) ? value : 0\n}\n\n/** Read access to a database (an open adapter, or a reader handed to a delete check). */\nexport interface DatabaseQuery {\n\tquery<T>(sql: string, params?: unknown[]): Promise<T[]>\n}\n\n/**\n * Whether any local node has operations above its contiguous acknowledged prefix that\n * the server did not refuse for good (RT-41): the authoritative \"unsynced\" (W3), which\n * the outbound queue only approximates. A local node is one in the registry, the\n * database's node id, or the node of the legacy prefix key; a node with no recorded\n * prefix counts from 0. Works on a database no store has opened in this release.\n */\nexport async function hasUnsyncedOwnOperations(db: DatabaseQuery): Promise<boolean> {\n\tconst tables = new Set(\n\t\t(await db.query<{ name: string }>(\"SELECT name FROM sqlite_master WHERE type = 'table'\")).map(\n\t\t\t(row) => row.name,\n\t\t),\n\t)\n\tconst opsTables = [...tables].filter((name) => name.startsWith('_kora_ops_'))\n\tif (opsTables.length === 0 || !tables.has('_kora_meta')) return false\n\n\tconst nodes = new Set<string>()\n\tif (tables.has(LOCAL_NODES_TABLE)) {\n\t\tfor (const row of await db.query<{ node_id: string }>(\n\t\t\t`SELECT node_id FROM ${LOCAL_NODES_TABLE}`,\n\t\t)) {\n\t\t\tnodes.add(row.node_id)\n\t\t}\n\t}\n\tconst meta = await db.query<{ key: string; value: string }>(\n\t\t\"SELECT key, value FROM _kora_meta WHERE key = 'node_id' OR key = ? OR key LIKE ?\",\n\t\t[OWN_ACKED_THROUGH_META_KEY, `${OWN_ACKED_THROUGH_META_KEY}:%`],\n\t)\n\tconst prefixes = new Map<string, number>()\n\tfor (const row of meta) {\n\t\tif (row.key === 'node_id') {\n\t\t\tnodes.add(row.value)\n\t\t} else if (row.key === OWN_ACKED_THROUGH_META_KEY) {\n\t\t\ttry {\n\t\t\t\tconst parsed = JSON.parse(row.value) as { nodeId?: unknown; sequence?: unknown }\n\t\t\t\tif (typeof parsed.nodeId === 'string') {\n\t\t\t\t\tnodes.add(parsed.nodeId)\n\t\t\t\t\tif (typeof parsed.sequence === 'number') prefixes.set(parsed.nodeId, parsed.sequence)\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// Unreadable: the node (if known otherwise) counts from 0.\n\t\t\t}\n\t\t} else {\n\t\t\tconst nodeId = row.key.slice(OWN_ACKED_THROUGH_META_KEY.length + 1)\n\t\t\t// The legacy key wins for its node (loadOwnAckedThrough reads it first).\n\t\t\tconst sequence = Number(row.value)\n\t\t\tif (!prefixes.has(nodeId) && Number.isInteger(sequence)) prefixes.set(nodeId, sequence)\n\t\t}\n\t}\n\tconst exclude = tables.has(TERMINAL_REJECTIONS_TABLE)\n\t\t? ` AND id NOT IN (SELECT operation_id FROM ${TERMINAL_REJECTIONS_TABLE})`\n\t\t: ''\n\tfor (const nodeId of nodes) {\n\t\tconst prefix = prefixes.get(nodeId) ?? 0\n\t\tfor (const table of opsTables) {\n\t\t\tconst rows = await db.query<{ n: number }>(\n\t\t\t\t`SELECT COUNT(*) AS n FROM \"${table.replace(/\"/g, '\"\"')}\" WHERE node_id = ? AND sequence_number > ?${exclude}`,\n\t\t\t\t[nodeId, prefix],\n\t\t\t)\n\t\t\tif (Number(rows[0]?.n ?? 0) > 0) return true\n\t\t}\n\t}\n\treturn false\n}\n"],"mappings":"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","names":[]}