korajs 1.0.0-beta.13 → 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.
@@ -930,6 +930,14 @@ var MergeAwareSyncStore = class {
930
930
  async rotateNodeId(ids) {
931
931
  return this.store.rotateNodeId(ids);
932
932
  }
933
+ /** Delegates the pinned-node write guard to the store (F9). */
934
+ setPinnedNodeOwnedElsewhere(owned) {
935
+ this.store.setPinnedNodeOwnedElsewhere(owned);
936
+ }
937
+ /** Delegates re-authoring a refused adopted node's writes to the store. */
938
+ async reauthorLocalNode(fromNodeId, ids, principal) {
939
+ return this.store.reauthorLocalNode(fromNodeId, ids, principal);
940
+ }
933
941
  /** Move back to a node id this database used before (RT-38). */
934
942
  bindPrincipal(principal) {
935
943
  return this.store.bindPrincipal(principal);
@@ -1179,4 +1187,4 @@ export {
1179
1187
  StoreQueueStorage,
1180
1188
  StoreSyncStatePersistence
1181
1189
  };
1182
- //# sourceMappingURL=chunk-JLKS237Z.js.map
1190
+ //# sourceMappingURL=chunk-A3YX2SBD.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/apply-pipeline.ts","../src/legacy-apply-pipeline.ts","../src/audit-bridge.ts","../src/blob/blob-upload-coordinator.ts","../src/blob/sync-chunk-port.ts","../src/merge-aware-sync-store.ts","../src/store-queue-storage.ts","../src/store-sync-state.ts"],"sourcesContent":["import type { KoraEventEmitter, MergeTrace, Operation, SchemaDefinition } from '@korajs/core'\nimport { KoraError, quoteIdent } from '@korajs/core'\nimport type { MergeEngine, ReferentialMergeContext } from '@korajs/merge'\nimport {\n\tbuildMergeRelationLookup,\n\tcheckConstraints,\n\tcheckReferentialIntegrityOnDelete,\n} from '@korajs/merge'\nimport type { CollectionRecord, LocalMutationHandler, Store, Transaction } from '@korajs/store'\nimport {\n\tdeserializeRecord,\n\texecuteDelete,\n\texecuteInsert,\n\texecuteUpdate,\n} from '@korajs/store/internal'\nimport type { RawCollectionRow } from '@korajs/store/internal'\nimport type { ApplyResult } from '@korajs/sync'\nimport { LegacyApplyPipeline } from './legacy-apply-pipeline'\n\n/**\n * Whether the operation originated locally or arrived from sync.\n */\nexport type ApplyMode = 'local' | 'remote'\n\n/**\n * Context passed into each apply invocation.\n */\nexport interface ApplyContext {\n\treadonly mode: ApplyMode\n\treadonly schema: SchemaDefinition\n}\n\n/**\n * Dependencies for the apply pipeline.\n */\nexport interface ApplyPipelineDeps {\n\treadonly store: Store\n\treadonly emitter: KoraEventEmitter | null\n\t/** Called when a merge had a conflicting field decision (sync conflict counter). */\n\treadonly onMergeConflict?: () => void\n\t/**\n\t * The beta.12 pairwise merge engine. Used only when the store runs the legacy\n\t * materialization (`experimental.legacyMerge`, one beta).\n\t */\n\treadonly mergeEngine?: MergeEngine\n}\n\n/**\n * Applies operations to the local store (W7): \"append, then merge\". The store\n * appends each operation to the log and merges it into its record's per-field\n * CRDT fold state, which re-materializes the row, in one write transaction; the\n * result is independent of arrival order. Local writes go through the same fold\n * (the single local write path stays the sequencing authority).\n *\n * The pipeline adds what involves OTHER records:\n * - referential integrity for deletes (restrict / cascade / set-null);\n * - an optimistic check of cross-record (tier 2) constraints after a remote\n * operation, reported as `constraint:violated`; the server is the authority and\n * its corrections arrive as ordinary operations.\n */\nexport class ApplyPipeline implements LocalMutationHandler {\n\tprivate readonly relationLookupMap: ReturnType<typeof buildMergeRelationLookup>\n\tprivate legacy: LegacyApplyPipeline | null = null\n\n\tconstructor(private readonly deps: ApplyPipelineDeps) {\n\t\tthis.relationLookupMap = buildMergeRelationLookup(deps.store.getSchema())\n\t}\n\n\t/** Local insert — the single local write path. */\n\tasync insert(collection: string, data: Record<string, unknown>): Promise<CollectionRecord> {\n\t\treturn executeInsert(this.deps.store.createMutationContext(collection), data)\n\t}\n\n\t/** Local update. */\n\tasync update(\n\t\tcollection: string,\n\t\tid: string,\n\t\tdata: Record<string, unknown>,\n\t): Promise<CollectionRecord> {\n\t\treturn executeUpdate(this.deps.store.createMutationContext(collection), id, data)\n\t}\n\n\t/**\n\t * Local delete. The store builds and persists the delete, its referential\n\t * side effects (cascade / set-null, recursively) and their sequence numbers in\n\t * one write transaction; {@link beforeLocalDelete} adds the merge-package\n\t * referential checks and their DevTools traces inside that transaction.\n\t */\n\tasync delete(collection: string, id: string): Promise<void> {\n\t\tawait executeDelete(this.deps.store.createMutationContext(collection), id)\n\t}\n\n\t/**\n\t * Referential integrity for a local delete, run inside the delete's write\n\t * transaction: emits the referential merge traces and refuses a delete a\n\t * `restrict` relation forbids.\n\t */\n\tasync beforeLocalDelete(operation: Operation, tx: Transaction): Promise<void> {\n\t\tconst schema = this.deps.store.getSchema()\n\t\tconst check = await checkReferentialIntegrityOnDelete(\n\t\t\toperation,\n\t\t\tschema,\n\t\t\tcreateTransactionalReferentialContext(schema, tx),\n\t\t\tthis.relationLookupMap,\n\t\t)\n\n\t\tfor (const trace of check.traces) {\n\t\t\tthis.deps.emitter?.emit({ type: 'merge:conflict', trace })\n\t\t}\n\n\t\tif (!check.allowed) {\n\t\t\tthrow new KoraError(\n\t\t\t\t`Cannot delete record \"${operation.recordId}\" from \"${operation.collection}\": referential restrict policy violated`,\n\t\t\t\t'REFERENTIAL_INTEGRITY',\n\t\t\t\t{ collection: operation.collection, recordId: operation.recordId },\n\t\t\t)\n\t\t}\n\t}\n\n\tasync applyRemote(op: Operation): Promise<ApplyResult> {\n\t\treturn this.apply(op, { mode: 'remote', schema: this.deps.store.getSchema() })\n\t}\n\n\tasync apply(op: Operation, context: ApplyContext): Promise<ApplyResult> {\n\t\tif (!this.deps.store.isFoldMaterialized()) {\n\t\t\treturn this.legacyPipeline().apply(op, context)\n\t\t}\n\t\tif (context.mode === 'local') {\n\t\t\treturn this.deps.store.applyRemoteOperation(op)\n\t\t}\n\t\tif (op.type === 'delete') {\n\t\t\treturn this.applyRemoteDelete(op)\n\t\t}\n\t\tconst result = await this.applyFolded(op)\n\t\tif (result === 'applied') await this.checkConstraintsOptimistically(op)\n\t\treturn result\n\t}\n\n\tprivate applyFolded(op: Operation): Promise<ApplyResult> {\n\t\treturn this.deps.store.applyRemoteOperation(op, {\n\t\t\tonMergeTraces: (traces: MergeTrace[]) => {\n\t\t\t\tif (traces.length > 0) this.deps.onMergeConflict?.()\n\t\t\t},\n\t\t})\n\t}\n\n\t/**\n\t * A remote delete: refused when a `restrict` relation forbids it; otherwise\n\t * merged (record-level last-write-wins against the record's newest write), and\n\t * its cascades / set-nulls run only when the record is actually deleted.\n\t */\n\tprivate async applyRemoteDelete(op: Operation): Promise<ApplyResult> {\n\t\tconst check = await checkReferentialIntegrityOnDelete(\n\t\t\top,\n\t\t\tthis.deps.store.getSchema(),\n\t\t\tcreateReferentialMergeContext(this.deps.store),\n\t\t\tthis.relationLookupMap,\n\t\t)\n\t\tfor (const trace of check.traces) {\n\t\t\tthis.deps.emitter?.emit({ type: 'merge:conflict', trace })\n\t\t}\n\t\tif (!check.allowed) {\n\t\t\treturn 'rejected'\n\t\t}\n\t\tconst result = await this.applyFolded(op)\n\t\tif (result !== 'applied' || check.sideEffectOps.length === 0) {\n\t\t\treturn result\n\t\t}\n\t\t// A newer local write keeps the record alive: then nothing cascades.\n\t\tconst row = await this.deps.store.findMaterializedRow(op.collection, op.recordId)\n\t\tif (row && !row.deleted) {\n\t\t\treturn result\n\t\t}\n\t\t// RT-69: the cascades of a REMOTE delete stay local. The author uploaded its own\n\t\t// copies and the server derives its own; a copy authored here would be stored and\n\t\t// relayed once per receiving device. They are folded as provisional effects (never\n\t\t// logged, sequenced or queued) until the server's copy arrives.\n\t\tawait this.deps.store.applyProvisionalSideEffects(\n\t\t\top,\n\t\t\tcheck.sideEffectOps.map((effect) => ({\n\t\t\t\ttype: effect.type,\n\t\t\t\tcollection: effect.collection,\n\t\t\t\trecordId: effect.recordId,\n\t\t\t\tdata: effect.data,\n\t\t\t\tpreviousData: effect.previousData,\n\t\t\t\truleId: `relation:${effect.relationName}:${effect.type === 'delete' ? 'cascade' : 'set-null'}`,\n\t\t\t})),\n\t\t)\n\t\treturn result\n\t}\n\n\t/**\n\t * Tier 2 constraints that span records (unique, capacity, referential) are\n\t * evaluated optimistically here and authoritatively on the server: a violation\n\t * is reported (`constraint:violated`) but not resolved locally, so every\n\t * replica keeps folding the same operations and the server's correction, an\n\t * ordinary operation, converges them.\n\t */\n\tprivate async checkConstraintsOptimistically(op: Operation): Promise<void> {\n\t\tconst emitter = this.deps.emitter\n\t\tconst definition = this.deps.store.getSchema().collections[op.collection]\n\t\tif (!emitter || !definition || definition.constraints.length === 0) return\n\t\tconst record = await this.deps.store.collection(op.collection).findById(op.recordId)\n\t\tif (!record) return\n\t\tconst violations = await checkConstraints(\n\t\t\trecord as Record<string, unknown>,\n\t\t\top.recordId,\n\t\t\top.collection,\n\t\t\tdefinition,\n\t\t\t{\n\t\t\t\tqueryRecords: async (collection, where) =>\n\t\t\t\t\t(await this.deps.store.collection(collection).where(where).exec()) as Record<\n\t\t\t\t\t\tstring,\n\t\t\t\t\t\tunknown\n\t\t\t\t\t>[],\n\t\t\t\tcountRecords: (collection, where) =>\n\t\t\t\t\tthis.deps.store.collection(collection).where(where).count(),\n\t\t\t},\n\t\t)\n\t\tfor (const violation of violations) {\n\t\t\tconst field = violation.fields.join(',')\n\t\t\temitter.emit({\n\t\t\t\ttype: 'constraint:violated',\n\t\t\t\tconstraint: violation.message,\n\t\t\t\ttrace: {\n\t\t\t\t\toperationA: op,\n\t\t\t\t\toperationB: op,\n\t\t\t\t\tfield,\n\t\t\t\t\tstrategy: `optimistic-${violation.constraint.type}`,\n\t\t\t\t\tinputA: record[violation.fields[0] ?? ''] ?? null,\n\t\t\t\t\tinputB: record[violation.fields[0] ?? ''] ?? null,\n\t\t\t\t\tbase: null,\n\t\t\t\t\toutput: record[violation.fields[0] ?? ''] ?? null,\n\t\t\t\t\ttier: 2,\n\t\t\t\t\tconstraintViolated: violation.message,\n\t\t\t\t\tduration: 0,\n\t\t\t\t},\n\t\t\t})\n\t\t}\n\t}\n\n\tprivate legacyPipeline(): LegacyApplyPipeline {\n\t\tif (this.legacy === null) {\n\t\t\tif (!this.deps.mergeEngine) {\n\t\t\t\tthrow new KoraError(\n\t\t\t\t\t'The store uses the legacy materialization but no merge engine was given to the apply pipeline.',\n\t\t\t\t\t'LEGACY_MERGE_ENGINE_MISSING',\n\t\t\t\t\t{ fix: 'Pass mergeEngine (experimental.legacyMerge) or use the default fold.' },\n\t\t\t\t)\n\t\t\t}\n\t\t\tthis.legacy = new LegacyApplyPipeline({\n\t\t\t\tstore: this.deps.store,\n\t\t\t\tmergeEngine: this.deps.mergeEngine,\n\t\t\t\temitter: this.deps.emitter,\n\t\t\t\t...(this.deps.onMergeConflict ? { onMergeConflict: this.deps.onMergeConflict } : {}),\n\t\t\t})\n\t\t}\n\t\treturn this.legacy\n\t}\n}\n\n/**\n * Referential lookups for a local delete, read through the delete's own write\n * transaction so they see exactly the rows the transaction commits against.\n */\nfunction createTransactionalReferentialContext(\n\tschema: SchemaDefinition,\n\ttx: Transaction,\n): ReferentialMergeContext {\n\treturn {\n\t\tasync queryRecords(collection: string, where: Record<string, unknown>) {\n\t\t\tconst definition = schema.collections[collection]\n\t\t\tif (!definition) return []\n\t\t\tconst fields = Object.keys(where)\n\t\t\tconst clause = fields.map((field) => `${quoteIdent(field)} = ?`).join(' AND ')\n\t\t\tconst rows = await tx.query<RawCollectionRow>(\n\t\t\t\t`SELECT * FROM ${quoteIdent(collection)} WHERE _deleted = 0${clause ? ` AND ${clause}` : ''}`,\n\t\t\t\tfields.map((field) => where[field]),\n\t\t\t)\n\t\t\treturn rows.map((row) => deserializeRecord(row, definition.fields) as Record<string, unknown>)\n\t\t},\n\t\tasync recordExists(collection: string, recordId: string) {\n\t\t\tconst rows = await tx.query<{ id: string }>(\n\t\t\t\t`SELECT id FROM ${quoteIdent(collection)} WHERE id = ? AND _deleted = 0`,\n\t\t\t\t[recordId],\n\t\t\t)\n\t\t\treturn rows.length > 0\n\t\t},\n\t}\n}\n\nfunction createReferentialMergeContext(store: Store): ReferentialMergeContext {\n\treturn {\n\t\tasync queryRecords(collection: string, where: Record<string, unknown>) {\n\t\t\tconst rows = await store.collection(collection).where(where).exec()\n\t\t\treturn rows as Record<string, unknown>[]\n\t\t},\n\t\tasync recordExists(collection: string, recordId: string) {\n\t\t\tconst row = await store.collection(collection).findById(recordId)\n\t\t\treturn row !== null\n\t\t},\n\t}\n}\n","import type {\n\tCollectionDefinition,\n\tHLCTimestamp,\n\tKoraEventEmitter,\n\tOperation,\n\tSchemaDefinition,\n} from '@korajs/core'\nimport {\n\tHybridLogicalClock,\n\tKoraError,\n\texpandFieldVersionedOperations,\n\tquoteIdent,\n\treplayOperationsForRecord,\n} from '@korajs/core'\nimport { topologicalSort } from '@korajs/core/internal'\nimport type { MergeEngine, MergeResult, ReferentialMergeContext, SideEffectOp } from '@korajs/merge'\nimport { buildMergeRelationLookup, checkReferentialIntegrityOnDelete } from '@korajs/merge'\nimport type { ConstraintContext } from '@korajs/merge'\nimport type {\n\tApplyRemoteOptions,\n\tCollectionRecord,\n\tLocalMutationHandler,\n\tRowVersionState,\n\tStore,\n\tTransaction,\n} from '@korajs/store'\nimport { OptimisticLockError, richtextStatesEqual } from '@korajs/store'\nimport {\n\tdeserializeRecord,\n\texecuteDelete,\n\texecuteInsert,\n\texecuteUpdate,\n} from '@korajs/store/internal'\nimport type { RawCollectionRow } from '@korajs/store/internal'\nimport type { ApplyResult } from '@korajs/sync'\nimport type { ApplyContext } from './apply-pipeline'\n\n/*\n * The beta.12 pairwise apply pipeline, kept for ONE beta behind\n * `experimental.legacyMerge` so CI can compare it with the W7 fold\n * (apply-pipeline.ts). Do not extend it: a later beta removes it.\n */\n\n/**\n * How many times a merge-engine apply retries when the row changed underneath\n * it (OptimisticLockError). Each retry recomputes the merge from fresh state;\n * since JavaScript is single-threaded, invalidation requires an actual new\n * local write landing at an `await` point, so contention is self-limiting.\n * Exhaustion rethrows: the operation stays unacknowledged and sync retries it\n * later — data is never dropped.\n */\nconst MERGE_APPLY_RETRY_LIMIT = 8\n\n/**\n * Dependencies for the unified apply pipeline.\n */\nexport interface LegacyApplyPipelineDeps {\n\treadonly store: Store\n\treadonly mergeEngine: MergeEngine\n\treadonly emitter: KoraEventEmitter | null\n\t/** Called when a field-level merge runs (updates sync conflict counter). */\n\treadonly onMergeConflict?: () => void\n}\n\n/**\n * The beta.12 pairwise apply pipeline (`experimental.legacyMerge`, one beta only).\n */\nexport class LegacyApplyPipeline implements LocalMutationHandler {\n\tprivate readonly relationLookupMap: ReturnType<typeof buildMergeRelationLookup>\n\n\tconstructor(private readonly deps: LegacyApplyPipelineDeps) {\n\t\tthis.relationLookupMap = buildMergeRelationLookup(deps.store.getSchema())\n\t}\n\n\t/** Local insert — same persistence path as remote apply side effects. */\n\tasync insert(collection: string, data: Record<string, unknown>): Promise<CollectionRecord> {\n\t\treturn executeInsert(this.deps.store.createMutationContext(collection), data)\n\t}\n\n\t/** Local update. */\n\tasync update(\n\t\tcollection: string,\n\t\tid: string,\n\t\tdata: Record<string, unknown>,\n\t): Promise<CollectionRecord> {\n\t\treturn executeUpdate(this.deps.store.createMutationContext(collection), id, data)\n\t}\n\n\t/**\n\t * Local delete. The store builds and persists the delete, its referential\n\t * side effects (cascade / set-null, recursively) and their sequence numbers in\n\t * one write transaction; {@link beforeLocalDelete} adds the merge-package\n\t * referential checks and their DevTools traces inside that transaction.\n\t */\n\tasync delete(collection: string, id: string): Promise<void> {\n\t\tawait executeDelete(this.deps.store.createMutationContext(collection), id)\n\t}\n\n\t/**\n\t * Referential integrity for a local delete, run inside the delete's write\n\t * transaction (single-record, `app.transaction` entries and cascades alike):\n\t * emits the referential merge traces and refuses a delete a `restrict` relation\n\t * forbids. The side effects themselves are written by the store's relation\n\t * enforcer through the single local write path, so they share the commit's\n\t * sequence block (STORE-2).\n\t */\n\tasync beforeLocalDelete(operation: Operation, tx: Transaction): Promise<void> {\n\t\tconst schema = this.deps.store.getSchema()\n\t\tconst check = await checkReferentialIntegrityOnDelete(\n\t\t\toperation,\n\t\t\tschema,\n\t\t\tcreateTransactionalReferentialContext(schema, tx),\n\t\t\tthis.relationLookupMap,\n\t\t)\n\n\t\tfor (const trace of check.traces) {\n\t\t\tthis.deps.emitter?.emit({ type: 'merge:conflict', trace })\n\t\t}\n\n\t\tif (!check.allowed) {\n\t\t\tthrow new KoraError(\n\t\t\t\t`Cannot delete record \"${operation.recordId}\" from \"${operation.collection}\": referential restrict policy violated`,\n\t\t\t\t'REFERENTIAL_INTEGRITY',\n\t\t\t\t{ collection: operation.collection, recordId: operation.recordId },\n\t\t\t)\n\t\t}\n\t}\n\n\tasync applyRemote(op: Operation): Promise<ApplyResult> {\n\t\treturn this.apply(op, { mode: 'remote', schema: this.deps.store.getSchema() })\n\t}\n\n\tasync apply(op: Operation, context: ApplyContext): Promise<ApplyResult> {\n\t\tif (context.mode === 'local') {\n\t\t\treturn this.deps.store.applyRemoteOperation(op)\n\t\t}\n\n\t\tif (op.type === 'delete') {\n\t\t\treturn this.applyRemoteDelete(op)\n\t\t}\n\n\t\tif (op.type === 'insert' && op.data) {\n\t\t\treturn this.applyRemoteInsert(op)\n\t\t}\n\n\t\tif (op.type === 'update' && op.data && op.previousData) {\n\t\t\treturn this.applyRemoteUpdate(op)\n\t\t}\n\n\t\treturn this.deps.store.applyRemoteOperation(op)\n\t}\n\n\tprivate async applyRemoteDelete(op: Operation): Promise<ApplyResult> {\n\t\tconst blocked = await this.resolveRemoteDeleteVsLocalUpdate(op)\n\t\tif (blocked) {\n\t\t\treturn 'skipped'\n\t\t}\n\n\t\tconst refCtx = createReferentialMergeContext(this.deps.store)\n\t\tconst check = await checkReferentialIntegrityOnDelete(\n\t\t\top,\n\t\t\tthis.deps.store.getSchema(),\n\t\t\trefCtx,\n\t\t\tthis.relationLookupMap,\n\t\t)\n\n\t\tfor (const trace of check.traces) {\n\t\t\tthis.deps.emitter?.emit({ type: 'merge:conflict', trace })\n\t\t}\n\n\t\tif (!check.allowed) {\n\t\t\treturn 'rejected'\n\t\t}\n\n\t\tconst result = await this.deps.store.applyRemoteOperation(op)\n\t\tif (result !== 'applied') {\n\t\t\treturn result\n\t\t}\n\n\t\tif (check.sideEffectOps.length > 0) {\n\t\t\tawait applySideEffectOps(this.deps.store, check.sideEffectOps, op.id)\n\t\t}\n\n\t\treturn 'applied'\n\t}\n\n\t/**\n\t * When a local update is newer than a remote delete, keep the record alive.\n\t */\n\tprivate async resolveRemoteDeleteVsLocalUpdate(op: Operation): Promise<boolean> {\n\t\tconst collectionDef = this.deps.store.getSchema().collections[op.collection]\n\t\tif (!collectionDef) {\n\t\t\treturn false\n\t\t}\n\n\t\tconst localOp = await this.deps.store.getLatestLocalOperationForRecord(\n\t\t\top.collection,\n\t\t\top.recordId,\n\t\t)\n\t\tif (!localOp || localOp.type !== 'update') {\n\t\t\treturn false\n\t\t}\n\n\t\tconst baseState = localOp.previousData ?? {}\n\t\tconst mergeResult = await this.deps.mergeEngine.merge({\n\t\t\tlocal: localOp,\n\t\t\tremote: op,\n\t\t\tbaseState,\n\t\t\tcollectionDef,\n\t\t})\n\n\t\tthis.emitMergeLifecycle(op, localOp, mergeResult)\n\n\t\treturn mergeResult.appliedOperation === 'local'\n\t}\n\n\tprivate async applyRemoteUpdate(op: Operation): Promise<ApplyResult> {\n\t\tconst schema = this.deps.store.getSchema()\n\t\tconst collectionDef = schema.collections[op.collection]\n\t\tif (!collectionDef) {\n\t\t\treturn this.deps.store.applyRemoteOperation(op)\n\t\t}\n\n\t\t// Merge-engine paths read state, compute a merge, then write. A concurrent\n\t\t// local mutation landing between read and write invalidates the merge; the\n\t\t// guarded apply detects this (OptimisticLockError) and we recompute from\n\t\t// fresh state. Bounded so a pathological writer can't spin forever —\n\t\t// exhaustion rethrows, leaving the op unacknowledged for a later sync\n\t\t// retry (never silently dropped).\n\t\tlet lockError: OptimisticLockError | null = null\n\t\tfor (let attempt = 0; attempt < MERGE_APPLY_RETRY_LIMIT; attempt++) {\n\t\t\ttry {\n\t\t\t\treturn await this.applyRemoteUpdateAttempt(op, collectionDef)\n\t\t\t} catch (error) {\n\t\t\t\tif (!(error instanceof OptimisticLockError)) {\n\t\t\t\t\tthrow error\n\t\t\t\t}\n\t\t\t\tlockError = error\n\t\t\t}\n\t\t}\n\t\tthrow lockError ?? new OptimisticLockError(op.collection, op.recordId)\n\t}\n\n\tprivate async applyRemoteUpdateAttempt(\n\t\top: Operation,\n\t\tcollectionDef: CollectionDefinition,\n\t): Promise<ApplyResult> {\n\t\t// Snapshot the row's version state BEFORE reading the record: if a local\n\t\t// write lands between these two reads, the guard is older than the record\n\t\t// and the guarded apply fails safe (retry). The reverse order would let a\n\t\t// merge computed from a stale record pass a fresh guard and clobber the\n\t\t// local write.\n\t\tconst guard: RowVersionState = (await this.deps.store.getRowVersionState(\n\t\t\top.collection,\n\t\t\top.recordId,\n\t\t)) ?? { version: null, fieldVersions: null }\n\n\t\tconst accessor = this.deps.store.collection(op.collection)\n\t\tconst currentRecord = await accessor.findById(op.recordId)\n\n\t\tif (!currentRecord) {\n\t\t\tconst tombstoneResult = await this.applyRemoteUpdateOnDeletedRow(op, collectionDef, guard)\n\t\t\tif (tombstoneResult !== null) {\n\t\t\t\treturn tombstoneResult\n\t\t\t}\n\t\t\t// No materialized row at all: the store's atomic path appends the op\n\t\t\t// (nothing to guard — materialization is a no-op until the insert lands).\n\t\t\treturn this.deps.store.applyRemoteOperation(op)\n\t\t}\n\n\t\t// Pure scalar last-write-wins is resolved deterministically and atomically\n\t\t// inside the store using per-field HLC versions. Routing it there (instead\n\t\t// of pre-reading the row here to guess a conflict) both removes the\n\t\t// read-decide-write race — a concurrent local edit can no longer slip\n\t\t// between the check and the write — and guarantees every node converges to\n\t\t// the max-timestamp writer regardless of the order operations arrive. Only\n\t\t// CRDT fields (richtext, add-wins-set arrays), declared constraints, or\n\t\t// custom resolvers still need the three-tier merge engine.\n\t\tif (!updateNeedsMergeEngine(op, collectionDef)) {\n\t\t\t// The store resolves the write deterministically, but a same-field\n\t\t\t// concurrent edit is still a merge decision the developer/DevTools must\n\t\t\t// see. Emit the trace from the immutable local op in the log (race-free),\n\t\t\t// then let the store perform the authoritative atomic write.\n\t\t\tawait this.observeScalarMerge(op, collectionDef)\n\t\t\treturn this.deps.store.applyRemoteOperation(op)\n\t\t}\n\n\t\tlet hasConflict = false\n\t\tfor (const field of Object.keys(op.data ?? {})) {\n\t\t\tconst fieldDef = collectionDef.fields[field]\n\t\t\tconst expectedBase = op.previousData?.[field]\n\t\t\tconst currentLocal = currentRecord[field]\n\n\t\t\tif (fieldDef?.kind === 'richtext') {\n\t\t\t\tif (!richtextStatesEqual(currentLocal, expectedBase)) {\n\t\t\t\t\thasConflict = true\n\t\t\t\t}\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif (!deepEqual(expectedBase, currentLocal)) {\n\t\t\t\thasConflict = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tif (!hasConflict) {\n\t\t\t// No CRDT/constraint field the remote op touches has diverged locally\n\t\t\t// from the base it wrote from: a clean fast-forward. Guarded, because\n\t\t\t// the divergence check above read the row outside the write transaction.\n\t\t\treturn this.deps.store.applyRemoteOperation(op, {\n\t\t\t\tforceMaterialize: true,\n\t\t\t\tguardRowState: guard,\n\t\t\t})\n\t\t}\n\n\t\treturn this.applyMergedUpdate(op, collectionDef, currentRecord, op.previousData ?? {}, guard)\n\t}\n\n\t/**\n\t * Remote update vs local soft-delete: merge before materializing to avoid zombie rows.\n\t */\n\t/**\n\t * Emit merge observability (trace + conflict counter) for a scalar update that\n\t * concurrently touches a field a local operation also changed.\n\t *\n\t * The store resolves the actual value by deterministic per-field LWW; this\n\t * method exists only so the decision is loggable (CLAUDE.md: every merge\n\t * decision must be traceable). It reads the local operation from the append-\n\t * only log — which is immutable — rather than the materialized row, so it is\n\t * not subject to the read-then-write race the store write path was hardened\n\t * against. The merge engine is invoked purely to build an accurate trace; its\n\t * timestamps match the store's LWW comparison, so the trace never lies.\n\t */\n\tprivate async observeScalarMerge(\n\t\top: Operation,\n\t\tcollectionDef: CollectionDefinition,\n\t): Promise<void> {\n\t\tconst localOp = await this.deps.store.getLatestLocalOperationForRecord(\n\t\t\top.collection,\n\t\t\top.recordId,\n\t\t)\n\t\tif (!localOp || !localOp.data) {\n\t\t\treturn\n\t\t}\n\t\tconst remoteFields = Object.keys(op.data ?? {})\n\t\tconst sharesField = remoteFields.some((field) => localOp.data?.[field] !== undefined)\n\t\tif (!sharesField) {\n\t\t\treturn\n\t\t}\n\n\t\tconst mergeResult = await this.deps.mergeEngine.merge({\n\t\t\tlocal: localOp,\n\t\t\tremote: op,\n\t\t\tbaseState: op.previousData ?? {},\n\t\t\tcollectionDef,\n\t\t})\n\t\tthis.emitMergeLifecycle(op, localOp, mergeResult)\n\t}\n\n\tprivate async applyRemoteUpdateOnDeletedRow(\n\t\top: Operation,\n\t\tcollectionDef: CollectionDefinition,\n\t\tguard: RowVersionState,\n\t): Promise<ApplyResult | null> {\n\t\tconst snapshot = await this.deps.store.findMaterializedRow(op.collection, op.recordId)\n\t\tif (!snapshot?.deleted) {\n\t\t\t// Not a tombstone (never inserted): let the caller append the orphan.\n\t\t\treturn null\n\t\t}\n\n\t\t// A remote update landing on a tombstone must be resolved authoritatively by\n\t\t// folding the record's whole operation log in HLC order — the same fold the\n\t\t// server uses — so every device agrees on whether the update resurrects the\n\t\t// record and on the resulting field values. The previous path only handled a\n\t\t// LOCAL delete (via the pairwise merge engine) and left a remote-created\n\t\t// tombstone hidden on any passive observer that received delete-then-update,\n\t\t// and it materialized the resurrecting op's raw value rather than the composed\n\t\t// atomic chain. Folding fixes both: delete-vs-newer-update convergence and\n\t\t// atomic resurrection (increments before and after the delete compose correctly).\n\t\tconst priorOps = await this.deps.store.getOperationsForRecord(op.collection, op.recordId)\n\t\t// Scope-entry inserts expand into their per-field writes (RT-27); HLC order.\n\t\tconst ops = expandFieldVersionedOperations([...priorOps, op])\n\t\tconst folded = replayOperationsForRecord(ops)\n\n\t\tif (!folded) {\n\t\t\t// The delete still wins: append the op to the log (so a later fold — e.g. an\n\t\t\t// atomic resurrection composing this op's delta — is complete) but leave the\n\t\t\t// row a clean tombstone: no zombie fields, no version regression.\n\t\t\treturn this.deps.store.applyRemoteOperation(op, { logOnly: true })\n\t\t}\n\n\t\t// Resurrected: materialize the authoritative folded state and clear the\n\t\t// tombstone. The log keeps the canonical op; the row takes the folded data at\n\t\t// the newest operation's timestamp. Guarded so a concurrent local write retries.\n\t\tconst newestTimestamp = (ops[ops.length - 1] as Operation).timestamp\n\t\treturn this.deps.store.applyRemoteOperation(op, {\n\t\t\treactivateIfDeleted: true,\n\t\t\tforceMaterialize: true,\n\t\t\tmaterializeData: folded,\n\t\t\tmaterializeTimestamp: maxTimestamp(op.timestamp, newestTimestamp),\n\t\t\tguardRowState: guard,\n\t\t})\n\t}\n\n\tprivate async applyMergedUpdate(\n\t\top: Operation,\n\t\tcollectionDef: CollectionDefinition,\n\t\tcurrentRecord: CollectionRecord,\n\t\tbaseState: Record<string, unknown>,\n\t\tguard: RowVersionState,\n\t\tapplyOptions?: ApplyRemoteOptions,\n\t): Promise<ApplyResult> {\n\t\tconst latestLocal = await this.deps.store.getLatestLocalOperationForRecord(\n\t\t\top.collection,\n\t\t\top.recordId,\n\t\t)\n\t\tconst localTimestamp = resolveLocalTimestamp(\n\t\t\tlatestLocal,\n\t\t\tcurrentRecord,\n\t\t\tthis.deps.store.getNodeId(),\n\t\t)\n\t\t// The spread of `op` would copy the REMOTE op's atomicOps onto the local\n\t\t// side, making atomic composition double the remote delta instead of\n\t\t// summing both intents. The local side's intent metadata must come from\n\t\t// the actual local operation — or be absent entirely.\n\t\tconst { atomicOps: _remoteAtomicOps, ...opWithoutAtomic } = op\n\t\tconst localOp: Operation = {\n\t\t\t...opWithoutAtomic,\n\t\t\tdata: buildLocalDiff(baseState, currentRecord, Object.keys(op.data ?? {}), collectionDef),\n\t\t\tpreviousData: op.previousData,\n\t\t\tnodeId: this.deps.store.getNodeId(),\n\t\t\ttimestamp: localTimestamp,\n\t\t\t...(latestLocal?.atomicOps !== undefined ? { atomicOps: latestLocal.atomicOps } : {}),\n\t\t}\n\n\t\tconst constraintContext = createConstraintContext(this.deps.store)\n\t\tconst mergeResult = await this.deps.mergeEngine.merge(\n\t\t\t{\n\t\t\t\tlocal: localOp,\n\t\t\t\tremote: op,\n\t\t\t\tbaseState,\n\t\t\t\tcollectionDef,\n\t\t\t},\n\t\t\tconstraintContext,\n\t\t)\n\n\t\t// Atomic-op fields are materialized by folding the record's operation log in\n\t\t// HLC order (the same fold the server uses), not through the merge engine's\n\t\t// pairwise `base + localDelta + remoteDelta`. The pairwise form is correct only\n\t\t// for two concurrent writes from a shared base; with a third concurrent writer\n\t\t// the current row already folds in an earlier remote delta, and re-deriving from\n\t\t// base + the local device's own delta silently drops it (a lost update). The\n\t\t// fold composes a same-type atomic chain and last-write-wins for anything else\n\t\t// (including a plain set breaking the chain), so every device — author or passive\n\t\t// observer — converges to the same value the server materializes.\n\t\tconst mergedData = await this.materializeAtomicFieldsFromLog(op, mergeResult.mergedData)\n\n\t\t// The merged data is authoritative (it already folds in the current local\n\t\t// row), so it must materialize even when its timestamp ties the current\n\t\t// row version — otherwise the device that authored the newer of two\n\t\t// concurrent edits silently drops the merge result and never converges.\n\t\t// The LOG stores the canonical op (ops are immutable, content-addressed);\n\t\t// only the row write uses the merged data and max(local, remote) stamp.\n\t\t// Guarded: a local write since our snapshot invalidates the merge.\n\t\tconst applyResult = await this.deps.store.applyRemoteOperation(op, {\n\t\t\t...applyOptions,\n\t\t\tforceMaterialize: true,\n\t\t\tmaterializeData: mergedData,\n\t\t\tmaterializeTimestamp: maxTimestamp(op.timestamp, localTimestamp),\n\t\t\tguardRowState: guard,\n\t\t})\n\n\t\t// Emit AFTER the guarded apply so a retried attempt doesn't double-report\n\t\t// a merge decision that never materialized.\n\t\tthis.emitMergeLifecycle(op, localOp, mergeResult)\n\n\t\tif (applyResult === 'applied' && mergeResult.sideEffects.length > 0) {\n\t\t\tawait applySideEffectOps(this.deps.store, mergeResult.sideEffects, op.id)\n\t\t}\n\n\t\treturn applyResult\n\t}\n\n\t/**\n\t * Materialize the operation's atomic-op fields by folding the record's full\n\t * operation log (in HLC order, including this not-yet-appended op) through the\n\t * shared atomic-aware replay — the same fold the server uses. Non-atomic fields\n\t * keep their merge-engine result. This composes a same-type atomic chain and\n\t * last-write-wins for anything else, so all replicas converge regardless of how\n\t * many concurrent atomic writers there were or which device authored them.\n\t */\n\tprivate async materializeAtomicFieldsFromLog(\n\t\top: Operation,\n\t\tmergedData: Record<string, unknown>,\n\t): Promise<Record<string, unknown>> {\n\t\tif (!op.atomicOps || Object.keys(op.atomicOps).length === 0) {\n\t\t\treturn mergedData\n\t\t}\n\t\tconst priorOps = await this.deps.store.getOperationsForRecord(op.collection, op.recordId)\n\t\t// The op being applied is not in the log yet; fold it in at its HLC position\n\t\t// (scope-entry inserts expand into their per-field writes, RT-27).\n\t\tconst ops = expandFieldVersionedOperations([...priorOps, op])\n\t\tconst folded = replayOperationsForRecord(ops)\n\t\tif (!folded) {\n\t\t\treturn mergedData\n\t\t}\n\t\tconst result = { ...mergedData }\n\t\tfor (const field of Object.keys(op.atomicOps)) {\n\t\t\tif (field in folded) {\n\t\t\t\tresult[field] = folded[field]\n\t\t\t}\n\t\t}\n\t\treturn result\n\t}\n\n\tprivate async applyRemoteInsert(op: Operation): Promise<ApplyResult> {\n\t\tconst collectionDef = this.deps.store.getSchema().collections[op.collection]\n\t\tif (!collectionDef || !op.data) {\n\t\t\treturn this.deps.store.applyRemoteOperation(op)\n\t\t}\n\n\t\tlet lockError: OptimisticLockError | null = null\n\t\tfor (let attempt = 0; attempt < MERGE_APPLY_RETRY_LIMIT; attempt++) {\n\t\t\ttry {\n\t\t\t\treturn await this.applyRemoteInsertAttempt(op, collectionDef)\n\t\t\t} catch (error) {\n\t\t\t\tif (!(error instanceof OptimisticLockError)) {\n\t\t\t\t\tthrow error\n\t\t\t\t}\n\t\t\t\tlockError = error\n\t\t\t}\n\t\t}\n\t\tthrow lockError ?? new OptimisticLockError(op.collection, op.recordId)\n\t}\n\n\tprivate async applyRemoteInsertAttempt(\n\t\top: Operation,\n\t\tcollectionDef: CollectionDefinition,\n\t): Promise<ApplyResult> {\n\t\t// Guard snapshot BEFORE the record read (see applyRemoteUpdateAttempt).\n\t\tconst guard: RowVersionState = (await this.deps.store.getRowVersionState(\n\t\t\top.collection,\n\t\t\top.recordId,\n\t\t)) ?? { version: null, fieldVersions: null }\n\n\t\tconst snapshot = await this.deps.store.findMaterializedRow(op.collection, op.recordId)\n\t\tif (!snapshot || snapshot.deleted || op.fieldVersions) {\n\t\t\t// Absent row and insert-vs-tombstone are resolved atomically inside the\n\t\t\t// store; guard against a local write racing this decision. A server\n\t\t\t// scope-entry insert (per-field versions, RT-27) is resolved there too, field\n\t\t\t// by field against `_field_versions`: never as one whole-op merge, whose\n\t\t\t// single timestamp would override a newer local edit of an older field.\n\t\t\treturn this.deps.store.applyRemoteOperation(op, { guardRowState: guard })\n\t\t}\n\n\t\tconst localOp = await resolveLocalOpForRecord(\n\t\t\tthis.deps.store,\n\t\t\top.collection,\n\t\t\top.recordId,\n\t\t\tsnapshot.record,\n\t\t)\n\n\t\tconst mergeResult = await this.deps.mergeEngine.merge({\n\t\t\tlocal: localOp,\n\t\t\tremote: op,\n\t\t\tbaseState: {},\n\t\t\tcollectionDef,\n\t\t})\n\n\t\t// Canonical op in the log; merged data + max(local, remote) stamp on the\n\t\t// row. Force, because the merged result folds in the current local row and\n\t\t// must win even on a version tie with it.\n\t\tconst applyResult = await this.deps.store.applyRemoteOperation(op, {\n\t\t\tforceMaterialize: true,\n\t\t\tmaterializeData: mergeResult.mergedData,\n\t\t\tmaterializeTimestamp: maxTimestamp(op.timestamp, localOp.timestamp),\n\t\t\tguardRowState: guard,\n\t\t})\n\n\t\tthis.emitMergeLifecycle(op, localOp, mergeResult)\n\n\t\treturn applyResult\n\t}\n\n\tprivate emitMergeLifecycle(remote: Operation, local: Operation, mergeResult: MergeResult): void {\n\t\tthis.deps.emitter?.emit({\n\t\t\ttype: 'merge:started',\n\t\t\toperationA: remote,\n\t\t\toperationB: local,\n\t\t})\n\n\t\tconst hadMergeConflict = mergeResult.traces.some(\n\t\t\t(t) =>\n\t\t\t\tt.strategy !== 'no-conflict-local' &&\n\t\t\t\tt.strategy !== 'no-conflict-remote' &&\n\t\t\t\tt.strategy !== 'no-conflict-unchanged',\n\t\t)\n\t\tif (hadMergeConflict) {\n\t\t\tthis.deps.onMergeConflict?.()\n\t\t}\n\n\t\tfor (const trace of mergeResult.traces) {\n\t\t\tif (\n\t\t\t\ttrace.strategy !== 'no-conflict-local' &&\n\t\t\t\ttrace.strategy !== 'no-conflict-remote' &&\n\t\t\t\ttrace.strategy !== 'no-conflict-unchanged'\n\t\t\t) {\n\t\t\t\tthis.deps.emitter?.emit({ type: 'merge:conflict', trace })\n\t\t\t}\n\t\t}\n\t\tconst firstTrace = mergeResult.traces[0]\n\t\tif (firstTrace) {\n\t\t\tthis.deps.emitter?.emit({ type: 'merge:completed', trace: firstTrace })\n\t\t}\n\t}\n}\n\n/**\n * Prefer the latest local op, then any op in the log for this record, then a snapshot-derived insert.\n */\nasync function resolveLocalOpForRecord(\n\tstore: Store,\n\tcollection: string,\n\trecordId: string,\n\trecord: CollectionRecord,\n): Promise<Operation> {\n\tconst localLatest = await store.getLatestLocalOperationForRecord(collection, recordId)\n\tif (localLatest) {\n\t\treturn localLatest\n\t}\n\n\tconst anyLatest = await store.getLatestOperationForRecord(collection, recordId)\n\tif (anyLatest) {\n\t\treturn anyLatest\n\t}\n\n\treturn syntheticInsertFromSnapshot(\n\t\trecord,\n\t\tcollection,\n\t\tstore.getNodeId(),\n\t\tstore.getSchema().version,\n\t)\n}\n\nfunction syntheticInsertFromSnapshot(\n\trecord: CollectionRecord,\n\tcollection: string,\n\tnodeId: string,\n\tschemaVersion: number,\n): Operation {\n\tconst { id, createdAt, updatedAt, ...fields } = record\n\treturn {\n\t\tid: `synthetic-local-${id}`,\n\t\tnodeId,\n\t\ttype: 'insert',\n\t\tcollection,\n\t\trecordId: id,\n\t\tdata: fields,\n\t\tpreviousData: null,\n\t\ttimestamp: { wallTime: updatedAt, logical: 0, nodeId },\n\t\tsequenceNumber: 0,\n\t\tcausalDeps: [],\n\t\tschemaVersion,\n\t}\n}\n\nfunction createConstraintContext(store: Store): ConstraintContext {\n\treturn {\n\t\tasync queryRecords(collection: string, where: Record<string, unknown>) {\n\t\t\tconst rows = await store.collection(collection).where(where).exec()\n\t\t\treturn rows as Record<string, unknown>[]\n\t\t},\n\t\tasync countRecords(collection: string, where: Record<string, unknown>) {\n\t\t\treturn store.collection(collection).where(where).count()\n\t\t},\n\t}\n}\n\n/**\n * Referential lookups for a local delete, read through the delete's own write\n * transaction so they see exactly the rows the transaction commits against.\n */\nfunction createTransactionalReferentialContext(\n\tschema: SchemaDefinition,\n\ttx: Transaction,\n): ReferentialMergeContext {\n\treturn {\n\t\tasync queryRecords(collection: string, where: Record<string, unknown>) {\n\t\t\tconst definition = schema.collections[collection]\n\t\t\tif (!definition) return []\n\t\t\tconst fields = Object.keys(where)\n\t\t\tconst clause = fields.map((field) => `${quoteIdent(field)} = ?`).join(' AND ')\n\t\t\tconst rows = await tx.query<RawCollectionRow>(\n\t\t\t\t`SELECT * FROM ${quoteIdent(collection)} WHERE _deleted = 0${clause ? ` AND ${clause}` : ''}`,\n\t\t\t\tfields.map((field) => where[field]),\n\t\t\t)\n\t\t\treturn rows.map((row) => deserializeRecord(row, definition.fields) as Record<string, unknown>)\n\t\t},\n\t\tasync recordExists(collection: string, recordId: string) {\n\t\t\tconst rows = await tx.query<{ id: string }>(\n\t\t\t\t`SELECT id FROM ${quoteIdent(collection)} WHERE id = ? AND _deleted = 0`,\n\t\t\t\t[recordId],\n\t\t\t)\n\t\t\treturn rows.length > 0\n\t\t},\n\t}\n}\n\nfunction createReferentialMergeContext(store: Store): ReferentialMergeContext {\n\treturn {\n\t\tasync queryRecords(collection: string, where: Record<string, unknown>) {\n\t\t\tconst rows = await store.collection(collection).where(where).exec()\n\t\t\treturn rows as Record<string, unknown>[]\n\t\t},\n\t\tasync recordExists(collection: string, recordId: string) {\n\t\t\tconst row = await store.collection(collection).findById(recordId)\n\t\t\treturn row !== null\n\t\t},\n\t}\n}\n\nasync function applySideEffectOps(\n\tstore: Store,\n\tsideEffects: SideEffectOp[],\n\tparentOpId: string,\n): Promise<void> {\n\tfor (const effect of sideEffects) {\n\t\tconst ctx = store.createMutationContext(effect.collection, {\n\t\t\textraCausalDeps: [parentOpId],\n\t\t})\n\t\tif (effect.type === 'delete') {\n\t\t\tawait executeDelete(ctx, effect.recordId, { skipReferentialEnforcement: true })\n\t\t} else if (effect.type === 'update' && effect.data) {\n\t\t\tawait executeUpdate(ctx, effect.recordId, effect.data)\n\t\t}\n\t}\n}\n\n/**\n * Whether applying this remote update requires the three-tier merge engine.\n *\n * Scalar fields converge under deterministic per-field LWW handled entirely in\n * the store. The merge engine is only needed when a changed field is a CRDT\n * (richtext or add-wins-set array), when the collection declares constraints, or\n * when a changed field has a custom resolver.\n */\nfunction updateNeedsMergeEngine(op: Operation, collectionDef: CollectionDefinition): boolean {\n\tif (collectionDef.constraints.length > 0) {\n\t\treturn true\n\t}\n\t// Intent-preserving atomic ops (increment/max/min) COMPOSE with a concurrent\n\t// local atomic op instead of last-write-wins — plain per-field LWW would\n\t// silently drop one side's delta (a lost update).\n\tif (op.atomicOps && Object.keys(op.atomicOps).length > 0) {\n\t\treturn true\n\t}\n\tfor (const field of Object.keys(op.data ?? {})) {\n\t\tconst kind = collectionDef.fields[field]?.kind\n\t\t// CRDT kinds converge key/element-wise via the merge engine, not by\n\t\t// whole-value LWW: richtext (Yjs), arrays (add-wins set), and structured\n\t\t// object/json (recursive LWW-map). Plain per-field LWW would clobber a\n\t\t// concurrent edit to a different key of the same object.\n\t\tif (kind === 'richtext' || kind === 'array' || kind === 'object' || kind === 'json') {\n\t\t\treturn true\n\t\t}\n\t\tif (collectionDef.resolvers[field]) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n/**\n * The local side of a pairwise merge: only the fields the remote op touches\n * whose LOCAL value actually differs from the base the remote op wrote from.\n *\n * A field the local device left unchanged is not a concurrent edit. Treating it\n * as one let the local copy of the base value compete with the remote change:\n * for arrays it resurrected elements the remote side removed, and for scalars a\n * newer local timestamp could restore the old value (NEW-MERGE-1). Interim (S1);\n * W7 replaces the pairwise merge with a per-field fold.\n */\nfunction buildLocalDiff(\n\tbaseState: Record<string, unknown>,\n\tcurrentRecord: Record<string, unknown>,\n\tfields: string[],\n\tcollectionDef: CollectionDefinition,\n): Record<string, unknown> {\n\tconst diff: Record<string, unknown> = {}\n\tfor (const field of fields) {\n\t\tconst local = currentRecord[field]\n\t\tconst base = baseState[field]\n\t\tconst unchanged =\n\t\t\tcollectionDef.fields[field]?.kind === 'richtext'\n\t\t\t\t? richtextStatesEqual(local, base)\n\t\t\t\t: deepEqual(local, base)\n\t\tif (!unchanged) {\n\t\t\tdiff[field] = local\n\t\t}\n\t}\n\treturn diff\n}\n\nfunction resolveLocalTimestamp(\n\tlatestLocal: Operation | null,\n\tcurrentRecord: CollectionRecord,\n\tnodeId: string,\n): HLCTimestamp {\n\tif (latestLocal) {\n\t\treturn latestLocal.timestamp\n\t}\n\tconst updatedAt = currentRecord.updatedAt\n\tif (typeof updatedAt === 'number') {\n\t\treturn { wallTime: updatedAt, logical: 0, nodeId }\n\t}\n\treturn { wallTime: Date.now(), logical: 0, nodeId }\n}\n\nfunction maxTimestamp(a: HLCTimestamp, b: HLCTimestamp): HLCTimestamp {\n\treturn HybridLogicalClock.compare(a, b) >= 0 ? a : b\n}\n\nfunction deepEqual(a: unknown, b: unknown): boolean {\n\tif (a === b) return true\n\tif (a === null || b === null) return false\n\tif (a === undefined || b === undefined) return false\n\tif (typeof a !== typeof b) return false\n\n\tif (Array.isArray(a) && Array.isArray(b)) {\n\t\tif (a.length !== b.length) return false\n\t\treturn a.every((val, i) => deepEqual(val, b[i]))\n\t}\n\n\tif (typeof a === 'object' && typeof b === 'object') {\n\t\tconst keysA = Object.keys(a as Record<string, unknown>)\n\t\tconst keysB = Object.keys(b as Record<string, unknown>)\n\t\tif (keysA.length !== keysB.length) return false\n\t\treturn keysA.every((key) =>\n\t\t\tdeepEqual((a as Record<string, unknown>)[key], (b as Record<string, unknown>)[key]),\n\t\t)\n\t}\n\n\treturn false\n}\n","import type { KoraEvent, KoraEventEmitter } from '@korajs/core'\nimport type { Store } from '@korajs/store'\nimport { persistedAuditTraceFromEvent } from '@korajs/store'\n\nconst AUDIT_EVENT_TYPES = ['merge:completed', 'merge:conflict', 'constraint:violated'] as const\n\ntype AuditEventType = (typeof AUDIT_EVENT_TYPES)[number]\n\nfunction isAuditEvent(event: KoraEvent): event is Extract<KoraEvent, { type: AuditEventType }> {\n\treturn (AUDIT_EVENT_TYPES as readonly string[]).includes(event.type)\n}\n\n/**\n * Persist merge and constraint traces from the event bus to `_kora_audit_traces`.\n */\nexport function wireAuditPersistence(store: Store, emitter: KoraEventEmitter): () => void {\n\tconst unsubscribers = AUDIT_EVENT_TYPES.map((eventType) =>\n\t\temitter.on(eventType, (event) => {\n\t\t\tif (!isAuditEvent(event)) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst trace = persistedAuditTraceFromEvent(event)\n\t\t\tvoid store.appendAuditTrace(trace).catch(() => {\n\t\t\t\t// Audit persistence must not break mutations or sync.\n\t\t\t})\n\t\t}),\n\t)\n\n\treturn () => {\n\t\tfor (const unsub of unsubscribers) {\n\t\t\tunsub()\n\t\t}\n\t}\n}\n","import { type BlobRef, type KoraEventEmitter, isBlobRef } from '@korajs/core'\nimport { type ContentAddressedBlobStore, parseBlobManifest } from '@korajs/store'\nimport type { SyncEngine } from '@korajs/sync'\n\n/** Collect the blob references (with a manifest) carried by an operation's data. */\nfunction blobRefsInData(data: Record<string, unknown> | null): BlobRef[] {\n\tif (!data) {\n\t\treturn []\n\t}\n\tconst refs: BlobRef[] = []\n\tfor (const value of Object.values(data)) {\n\t\tif (isBlobRef(value) && value.manifestHash !== undefined) {\n\t\t\trefs.push(value)\n\t\t}\n\t}\n\treturn refs\n}\n\n/**\n * Upload a single blob (its manifest and every chunk) to the server so the bytes\n * remain available after this device disconnects. Reads the already-staged bytes\n * from the local blob store; skips anything the store does not hold.\n */\nasync function uploadBlob(\n\tref: BlobRef,\n\tsyncEngine: SyncEngine,\n\tblobStore: ContentAddressedBlobStore,\n): Promise<void> {\n\tconst manifestHash = ref.manifestHash\n\tif (manifestHash === undefined) {\n\t\treturn\n\t}\n\tconst manifestBytes = await blobStore.get(manifestHash)\n\tif (manifestBytes === null) {\n\t\treturn\n\t}\n\t// Upload chunks first so the manifest a peer resolves is never dangling.\n\tconst manifest = parseBlobManifest(manifestBytes)\n\tconst seen = new Set<string>()\n\tfor (const chunkHash of manifest.chunkHashes) {\n\t\tif (seen.has(chunkHash)) {\n\t\t\tcontinue\n\t\t}\n\t\tseen.add(chunkHash)\n\t\tconst bytes = await blobStore.get(chunkHash)\n\t\tif (bytes !== null) {\n\t\t\tsyncEngine.uploadBlobChunk(chunkHash, bytes)\n\t\t}\n\t}\n\tsyncEngine.uploadBlobChunk(manifestHash, manifestBytes)\n}\n\n/**\n * Automatically upload the bytes behind `blob` fields to the server as their\n * operations are synced. The bytes (every chunk, then the manifest) are pushed\n * BEFORE the batch carrying the reference, on the same connection: the server only\n * accepts a reference to content the writer can already read or has uploaded, so\n * pushing first is the writer's proof of possession (RT-11). A blob authored offline\n * is uploaded when its operation is finally pushed on reconnect. Each blob is\n * uploaded once per sync engine (deduplicated by manifest hash).\n *\n * A no-op unless the connected server advertised central blob storage or asked for\n * proofs of possession (peer-relay mode, RT-23).\n *\n * @returns An unsubscribe function.\n */\nexport function wireBlobUpload(\n\t_emitter: KoraEventEmitter,\n\tsyncEngine: SyncEngine,\n\tblobStore: ContentAddressedBlobStore,\n): () => void {\n\tconst uploaded = new Set<string>()\n\treturn syncEngine.setOutboundPreparer(async (operations) => {\n\t\t// Central storage keeps the bytes; a peer-relay server only verifies them as\n\t\t// proof of possession before it accepts the reference (RT-23).\n\t\tif (!syncEngine.isBlobStorageEnabled() && !syncEngine.isBlobPossessionProofRequested()) {\n\t\t\treturn\n\t\t}\n\t\tfor (const op of operations) {\n\t\t\tfor (const ref of blobRefsInData(op.data)) {\n\t\t\t\tconst manifestHash = ref.manifestHash\n\t\t\t\tif (manifestHash === undefined || uploaded.has(manifestHash)) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tawait uploadBlob(ref, syncEngine, blobStore)\n\t\t\t\t\tuploaded.add(manifestHash)\n\t\t\t\t} catch {\n\t\t\t\t\t// Upload is best-effort; a failure leaves the blob to be served\n\t\t\t\t\t// peer-to-peer, and the next batch carrying it retries the upload.\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t})\n}\n","import type { ChunkMessage, ChunkMessagePort } from '@korajs/store'\nimport type { SyncEngine } from '@korajs/sync'\n\n/**\n * Bind the store's transport-agnostic {@link ChunkMessagePort} to a live sync\n * connection. The returned port carries blob chunk requests and responses over\n * the same WebSocket the sync engine already owns, so blob bytes transfer out of\n * band from the operation stream without a second connection.\n *\n * Pair it with `@korajs/store`'s `createRemoteChunkProvider(port)` to pull a\n * blob's chunks from peers (or the server), and `serveBlobChunks(port, store)`\n * to answer requests for chunks this device holds. The sync engine's blob-chunk\n * channel handles the base64 wire encoding; this adapter only maps message\n * shapes, which are identical on both sides.\n *\n * @param syncEngine - The client's sync engine (from `app.getSyncEngine()`)\n * @returns A `ChunkMessagePort` over the sync connection\n *\n * @example\n * ```typescript\n * const port = createSyncEngineChunkPort(app.getSyncEngine())\n * const provider = createRemoteChunkProvider(port)\n * const result = await receiveBlob(manifest, provider, { chunkStore, blobStore })\n * ```\n */\nexport function createSyncEngineChunkPort(syncEngine: SyncEngine): ChunkMessagePort {\n\tconst channel = syncEngine.getBlobChunkChannel()\n\treturn {\n\t\tsend(message: ChunkMessage): void {\n\t\t\t// ChunkMessage and the channel's decoded message shape are identical\n\t\t\t// (request: {requestId, hash}; response: {requestId, bytes}).\n\t\t\tchannel.send(message)\n\t\t},\n\t\tonMessage(handler: (message: ChunkMessage) => void): void {\n\t\t\tchannel.onMessage((decoded) => {\n\t\t\t\t// The store's ChunkMessagePort speaks only request/response. Uploads\n\t\t\t\t// (blob-chunk-push) are a separate server-ingest concern, not routed here.\n\t\t\t\tif (decoded.type === 'blob-chunk-request' || decoded.type === 'blob-chunk-response') {\n\t\t\t\t\thandler(decoded)\n\t\t\t\t}\n\t\t\t})\n\t\t},\n\t}\n}\n","import type { KoraEventEmitter, Operation, VersionVector } from '@korajs/core'\nimport type { MergeEngine } from '@korajs/merge'\nimport type { ResequenceResult, Store } from '@korajs/store'\nimport type { ApplyResult, SyncStore } from '@korajs/sync'\nimport { ApplyPipeline } from './apply-pipeline'\n\nexport interface MergeAwareSyncStoreOptions {\n\t/** Increments SyncEngine conflict counter when merge runs on a conflicting update. */\n\tonMergeConflict?: () => void\n}\n\n/**\n * Wraps a Store to route remote sync operations through {@link ApplyPipeline}.\n *\n * Ensures remote deletes honor referential integrity (cascade, set-null, restrict)\n * and remote updates use the full three-tier merge engine with constraint context.\n */\nexport class MergeAwareSyncStore implements SyncStore {\n\tprivate readonly pipeline: ApplyPipeline\n\n\tconstructor(\n\t\tprivate readonly store: Store,\n\t\tmergeEngine: MergeEngine,\n\t\temitter: KoraEventEmitter | null,\n\t\toptions?: MergeAwareSyncStoreOptions,\n\t) {\n\t\tthis.pipeline = new ApplyPipeline({\n\t\t\tstore,\n\t\t\tmergeEngine,\n\t\t\temitter,\n\t\t\tonMergeConflict: options?.onMergeConflict,\n\t\t})\n\t}\n\n\tgetVersionVector(): VersionVector {\n\t\treturn this.store.getVersionVector()\n\t}\n\n\tgetNodeId(): string {\n\t\treturn this.store.getNodeId()\n\t}\n\n\tasync getOperationRange(nodeId: string, fromSeq: number, toSeq: number): Promise<Operation[]> {\n\t\treturn this.store.getOperationRange(nodeId, fromSeq, toSeq)\n\t}\n\n\t/**\n\t * Read a record's current field values (including a soft-deleted row) so the sync\n\t * engine can backfill scope / query-subset fields a partial update or delete does\n\t * not restate, and thus never wrongly drop an in-scope edit from sync.\n\t */\n\tasync readRecordFields(\n\t\tcollection: string,\n\t\trecordId: string,\n\t): Promise<Record<string, unknown> | null> {\n\t\tconst snapshot = await this.store.findMaterializedRow(collection, recordId)\n\t\treturn snapshot ? snapshot.record : null\n\t}\n\n\t/** Whether the local schema defines this collection (unknown ones are quarantined). */\n\thasCollection(collection: string): boolean {\n\t\treturn this.store.getSchema().collections[collection] !== undefined\n\t}\n\n\tasync applyRemoteOperation(op: Operation): Promise<ApplyResult> {\n\t\treturn this.pipeline.applyRemote(op)\n\t}\n\n\t/** W7: the server's authoritative node ids (handshake), persisted by the store. */\n\tasync settleAfterCatchUp(options?: { provisionalOnly?: boolean }): Promise<number> {\n\t\treturn this.store.settleAfterCatchUp(options)\n\t}\n\n\tasync setAuthoritativeNodeIds(\n\t\tnodeIds: readonly string[],\n\t\trevokedNodeIds: readonly string[] = [],\n\t): Promise<void> {\n\t\tawait this.store.setAuthoritativeNodeIds(nodeIds, revokedNodeIds)\n\t}\n\n\tasync applyScopeRetraction(collection: string, recordId: string): Promise<void> {\n\t\treturn this.store.applyScopeRetraction(collection, recordId)\n\t}\n\n\tasync applyScopeNarrowing(\n\t\tscopes: Record<string, Record<string, unknown>>,\n\t): Promise<Array<{ collection: string; recordId: string }>> {\n\t\treturn this.store.applyScopeNarrowing(scopes)\n\t}\n\n\t/**\n\t * Delegates node-id rotation to the store (RT-21): the server refused this\n\t * device's node id, so unsynced writes move to a fresh one.\n\t */\n\tasync rotateNodeId(ids: string[]): Promise<{ nodeId: string; operations: Operation[] }> {\n\t\treturn this.store.rotateNodeId(ids)\n\t}\n\n\t/** Delegates the pinned-node write guard to the store (F9). */\n\tsetPinnedNodeOwnedElsewhere(owned: boolean): void {\n\t\tthis.store.setPinnedNodeOwnedElsewhere(owned)\n\t}\n\n\t/** Delegates re-authoring a refused adopted node's writes to the store. */\n\tasync reauthorLocalNode(\n\t\tfromNodeId: string,\n\t\tids: string[],\n\t\tprincipal: string,\n\t): Promise<{ nodeId: string; operations: Operation[] }> {\n\t\treturn this.store.reauthorLocalNode(fromNodeId, ids, principal)\n\t}\n\n\t/** Move back to a node id this database used before (RT-38). */\n\tbindPrincipal(principal: string): ReturnType<Store['bindPrincipal']> {\n\t\treturn this.store.bindPrincipal(principal)\n\t}\n\n\tasync switchNodeId(nodeId: string): Promise<void> {\n\t\tawait this.store.switchNodeId(nodeId)\n\t}\n\n\t/** Durability barrier before an upload (RT-35). */\n\tasync ensureDurable(): Promise<void> {\n\t\tawait this.store.ensureDurable()\n\t}\n\n\t/** Raise a local node's sequence counter past numbers the server holds (RT-35). */\n\traiseSequenceFloor(nodeId: string, floor: number): Promise<boolean> {\n\t\treturn this.store.raiseSequenceFloor(nodeId, floor)\n\t}\n\n\t/** Renumber an operation refused with SEQUENCE_CONFLICT (RT-35); a version-2 op is re-hashed. */\n\tresequenceOperation(\n\t\toperationId: string,\n\t\tnodeId: string,\n\t\tfloor: number,\n\t\trewritableDependents?: readonly string[],\n\t): Promise<ResequenceResult | null> {\n\t\treturn this.store.resequenceOperation(operationId, nodeId, floor, rewritableDependents)\n\t}\n\n\t/** Take over a closed tab's node id (RT-40). */\n\tclaimLocalNode(nodeId: string): Promise<(() => void) | null> {\n\t\treturn this.store.claimLocalNode(nodeId)\n\t}\n\n\t/**\n\t * Delegates timestamp rebase to the store so the sync engine can re-stamp\n\t * never-acknowledged operations after a fast device clock is corrected.\n\t */\n\tasync rebaseUnsyncedOperations(\n\t\tids: string[],\n\t\tcorrectedNowMs: number,\n\t): Promise<{ operations: Operation[]; idMapping: Record<string, string>; rebasedCount: number }> {\n\t\treturn this.store.rebaseUnsyncedOperations(ids, correctedNowMs)\n\t}\n}\n","import type { Operation } from '@korajs/core'\nimport type { StorageAdapter } from '@korajs/store'\nimport { deserializeOperation, serializeOperation } from '@korajs/store/internal'\nimport type { OperationRow } from '@korajs/store/internal'\nimport type { QueueStorage } from '@korajs/sync'\n\ninterface SyncQueueRow {\n\tid: string\n\tpayload: string\n}\n\ntype QueuePayload = OperationRow & { _collection: string; _sent?: 1 }\n\n/**\n * Persists the outbound sync queue in `_kora_sync_queue` via the local StorageAdapter.\n */\nexport class StoreQueueStorage implements QueueStorage {\n\tconstructor(private readonly adapter: StorageAdapter) {}\n\n\tasync load(): Promise<Operation[]> {\n\t\tconst rows = await this.adapter.query<SyncQueueRow>(\n\t\t\t'SELECT id, payload FROM _kora_sync_queue ORDER BY rowid ASC',\n\t\t)\n\t\treturn rows.map((row) => operationFromQueuePayload(row.payload))\n\t}\n\n\tasync enqueue(op: Operation): Promise<void> {\n\t\tconst row = serializeOperation(op)\n\t\tconst payload: QueuePayload = { ...row, _collection: op.collection }\n\t\tawait this.adapter.execute(\n\t\t\t'INSERT OR REPLACE INTO _kora_sync_queue (id, payload) VALUES (?, ?)',\n\t\t\t[op.id, JSON.stringify(payload)],\n\t\t)\n\t}\n\n\t/**\n\t * Flag queued operations as sent (W3 step 4: a sent op is never re-stamped by a clock\n\t * rebase). An UPDATE, never an insert: an op acknowledged meanwhile stays dequeued.\n\t */\n\tasync markSent(ops: Operation[]): Promise<void> {\n\t\tfor (const op of ops) {\n\t\t\tconst payload: QueuePayload = {\n\t\t\t\t...serializeOperation(op),\n\t\t\t\t_collection: op.collection,\n\t\t\t\t_sent: 1,\n\t\t\t}\n\t\t\tawait this.adapter.execute('UPDATE _kora_sync_queue SET payload = ? WHERE id = ?', [\n\t\t\t\tJSON.stringify(payload),\n\t\t\t\top.id,\n\t\t\t])\n\t\t}\n\t}\n\n\tasync loadSentIds(): Promise<string[]> {\n\t\tconst rows = await this.adapter.query<SyncQueueRow>('SELECT id, payload FROM _kora_sync_queue')\n\t\tconst ids: string[] = []\n\t\tfor (const row of rows) {\n\t\t\ttry {\n\t\t\t\tif ((JSON.parse(row.payload) as QueuePayload)._sent === 1) ids.push(row.id)\n\t\t\t} catch {\n\t\t\t\t// An unreadable row is not reported as sent; load() surfaces the error.\n\t\t\t}\n\t\t}\n\t\treturn ids\n\t}\n\n\tasync dequeue(ids: string[]): Promise<void> {\n\t\tif (ids.length === 0) return\n\t\tconst placeholders = ids.map(() => '?').join(', ')\n\t\tawait this.adapter.execute(`DELETE FROM _kora_sync_queue WHERE id IN (${placeholders})`, ids)\n\t}\n\n\tasync count(): Promise<number> {\n\t\tconst rows = await this.adapter.query<{ cnt: number }>(\n\t\t\t'SELECT COUNT(*) as cnt FROM _kora_sync_queue',\n\t\t)\n\t\treturn rows[0]?.cnt ?? 0\n\t}\n}\n\nfunction operationFromQueuePayload(payload: string): Operation {\n\tconst parsed = JSON.parse(payload) as QueuePayload\n\tconst op = deserializeOperation(parsed)\n\treturn {\n\t\t...op,\n\t\tcollection: parsed._collection,\n\t}\n}\n","import type { Operation, VersionVector } from '@korajs/core'\nimport { mergeVersionVectors } from '@korajs/store'\nimport type { Store } from '@korajs/store'\nimport { decodeDeltaCursor, encodeDeltaCursor, operationMatchesScope } from '@korajs/sync'\nimport type {\n\tAdoptionScheduleInfo,\n\tDeltaCursor,\n\tLocalNodeInfo,\n\tQuarantinedOperation,\n\tSyncScopeMap,\n\tSyncStatePersistence,\n\tTerminalRejectionRecord,\n} from '@korajs/sync'\n\n/**\n * Persists and queries sync acknowledgment state via the local Store.\n */\nexport class StoreSyncStatePersistence implements SyncStatePersistence {\n\tconstructor(\n\t\tprivate readonly store: Store,\n\t\tprivate readonly scope?: SyncScopeMap,\n\t) {}\n\n\tloadLastAckedServerVector(): Promise<VersionVector> {\n\t\treturn this.store.loadLastAckedServerVector()\n\t}\n\n\tsaveLastAckedServerVector(vector: VersionVector): Promise<void> {\n\t\treturn this.store.saveLastAckedServerVector(vector)\n\t}\n\n\tmergeServerVectors(a: VersionVector, b: VersionVector): VersionVector {\n\t\treturn this.store.mergeServerVectors(a, b)\n\t}\n\n\tasync countUnsyncedOperations(serverVector: VersionVector): Promise<number> {\n\t\tconst ops = await this.getUnsyncedOperations(serverVector)\n\t\treturn ops.length\n\t}\n\n\tasync getUnsyncedOperations(serverVector: VersionVector): Promise<Operation[]> {\n\t\tconst ops = await this.store.getUnsyncedOperations(serverVector)\n\t\treturn ops.filter((op) => operationMatchesScope(op, this.scope))\n\t}\n\n\tloadDeltaCursor(): Promise<DeltaCursor | null> {\n\t\treturn this.store.loadDeltaCursor().then((encoded) => decodeDeltaCursor(encoded))\n\t}\n\n\tasync saveDeltaCursor(cursor: DeltaCursor | null): Promise<void> {\n\t\tawait this.store.saveDeltaCursor(cursor ? encodeDeltaCursor(cursor) : null)\n\t}\n\n\tloadDeliveryWatermark(signature: string): Promise<number> {\n\t\treturn this.store.loadDeliveryWatermark(signature)\n\t}\n\n\tasync saveDeliveryWatermark(signature: string, watermark: number): Promise<void> {\n\t\tawait this.store.saveDeliveryWatermark(signature, watermark)\n\t}\n\n\tloadAllDeliveryWatermarks(): Promise<Record<string, number>> {\n\t\treturn this.store.loadAllDeliveryWatermarks()\n\t}\n\n\tasync deleteDeliveryWatermark(signature: string): Promise<void> {\n\t\tawait this.store.deleteDeliveryWatermark(signature)\n\t}\n\n\tloadNodeToken(nodeId?: string): Promise<string | null> {\n\t\treturn this.store.loadNodeToken(nodeId)\n\t}\n\n\tasync saveNodeToken(token: string, nodeId?: string): Promise<void> {\n\t\tawait this.store.saveNodeToken(token, nodeId)\n\t}\n\n\tloadAuthoritativeNodeIds(): Promise<string[] | null> {\n\t\treturn this.store.loadAuthoritativeNodeIds()\n\t}\n\n\tasync saveAuthoritativeNodeIds(nodeIds: string[]): Promise<void> {\n\t\tawait this.store.saveAuthoritativeNodeIds(nodeIds)\n\t}\n\n\tloadOwnAckedThrough(nodeId: string): Promise<number | null> {\n\t\treturn this.store.loadOwnAckedThrough(nodeId)\n\t}\n\n\tasync saveOwnAckedThrough(nodeId: string, sequence: number): Promise<void> {\n\t\tawait this.store.saveOwnAckedThrough(nodeId, sequence)\n\t}\n\n\t/** Quarantine rows and the watermark advance commit in one store transaction (W4). */\n\tasync saveQuarantine(\n\t\tentries: QuarantinedOperation[],\n\t\twatermark?: { signature: string; watermark: number },\n\t): Promise<void> {\n\t\tawait this.store.saveInboundQuarantine(entries, watermark)\n\t}\n\n\tloadQuarantine(): Promise<QuarantinedOperation[]> {\n\t\treturn this.store.loadInboundQuarantine()\n\t}\n\n\tasync removeQuarantine(operationIds: string[]): Promise<void> {\n\t\tawait this.store.removeInboundQuarantine(operationIds)\n\t}\n\n\tloadAcceptedDownlinkScope(): Promise<SyncScopeMap | null> {\n\t\treturn this.store.loadAcceptedDownlinkScope()\n\t}\n\n\tasync saveAcceptedDownlinkScope(scope: SyncScopeMap | null): Promise<void> {\n\t\tawait this.store.saveAcceptedDownlinkScope(scope)\n\t}\n\n\t/** Durable terminal-rejection markers (RT-36); the app cannot clear them. */\n\tasync recordTerminalRejections(entries: TerminalRejectionRecord[]): Promise<void> {\n\t\tawait this.store.recordTerminalRejections(entries)\n\t}\n\n\tfindTerminalRejections(operationIds: string[]): Promise<Set<string>> {\n\t\treturn this.store.findTerminalRejections(operationIds)\n\t}\n\n\t/** The node ids this database authored under (RT-38, RT-40). */\n\tasync listLocalNodes(): Promise<LocalNodeInfo[]> {\n\t\tconst nodes = await this.store.listLocalNodes()\n\t\treturn nodes.map(\n\t\t\t({ nodeId, accepted, held, refusedCycle, principal, binding, refusedPrincipals }) => ({\n\t\t\t\tnodeId,\n\t\t\t\taccepted,\n\t\t\t\theld,\n\t\t\t\trefusedCycle,\n\t\t\t\tprincipal,\n\t\t\t\tbinding,\n\t\t\t\trefusedPrincipals,\n\t\t\t}),\n\t\t)\n\t}\n\n\t/** An accepted handshake binds the node to the session's user (RT-50). */\n\tasync confirmLocalNodePrincipal(nodeId: string, principal: string): Promise<void> {\n\t\tawait this.store.confirmNodePrincipal(nodeId, principal)\n\t}\n\n\t/** The server refused the node for this user (RT-50). */\n\tasync recordLocalNodeRefusedFor(nodeId: string, principal: string): Promise<void> {\n\t\tawait this.store.recordNodeRefusedFor(nodeId, principal)\n\t}\n\n\t/** The app assigned a held node's writes to this user (RT-50). */\n\tassignLocalNodePrincipal(nodeId: string, principal: string): Promise<boolean> {\n\t\treturn this.store.assignNodePrincipal(nodeId, principal)\n\t}\n\n\t/** Forget a local node whose held writes were discarded (RT-50). */\n\tasync dropLocalNode(nodeId: string): Promise<void> {\n\t\tawait this.store.dropLocalNode(nodeId)\n\t}\n\n\t/** Parked adoptions and the upload-progress counter (RT-46). */\n\tloadAdoptionSchedule(): Promise<AdoptionScheduleInfo> {\n\t\treturn this.store.loadAdoptionSchedule()\n\t}\n\n\tasync saveAdoptionSchedule(schedule: AdoptionScheduleInfo): Promise<void> {\n\t\tawait this.store.saveAdoptionSchedule(schedule)\n\t}\n\n\tasync markLocalNodeAccepted(nodeId: string): Promise<void> {\n\t\tawait this.store.markLocalNodeAccepted(nodeId)\n\t}\n\n\tasync markLocalNodeRefused(nodeId: string, held: boolean): Promise<void> {\n\t\tawait this.store.markLocalNodeRefused(nodeId, held)\n\t}\n\n\tloadAcceptedCycle(): Promise<number> {\n\t\treturn this.store.loadAcceptedCycle()\n\t}\n\n\tasync forgetLocalNode(nodeId: string): Promise<void> {\n\t\tawait this.store.forgetLocalNode(nodeId)\n\t}\n}\n"],"mappings":"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","names":["KoraError","quoteIdent","buildMergeRelationLookup","checkReferentialIntegrityOnDelete","deserializeRecord","executeDelete","executeInsert","executeUpdate","buildMergeRelationLookup","executeInsert","executeUpdate","executeDelete","checkReferentialIntegrityOnDelete","createTransactionalReferentialContext","KoraError","createReferentialMergeContext","quoteIdent","deserializeRecord"]}
package/dist/index.cjs CHANGED
@@ -1556,6 +1556,14 @@ var MergeAwareSyncStore = class {
1556
1556
  async rotateNodeId(ids) {
1557
1557
  return this.store.rotateNodeId(ids);
1558
1558
  }
1559
+ /** Delegates the pinned-node write guard to the store (F9). */
1560
+ setPinnedNodeOwnedElsewhere(owned) {
1561
+ this.store.setPinnedNodeOwnedElsewhere(owned);
1562
+ }
1563
+ /** Delegates re-authoring a refused adopted node's writes to the store. */
1564
+ async reauthorLocalNode(fromNodeId, ids, principal) {
1565
+ return this.store.reauthorLocalNode(fromNodeId, ids, principal);
1566
+ }
1559
1567
  /** Move back to a node id this database used before (RT-38). */
1560
1568
  bindPrincipal(principal) {
1561
1569
  return this.store.bindPrincipal(principal);