korajs 1.0.0-beta.0 → 1.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-HPBI67CZ.js → chunk-5FWGKTEO.js} +80 -2
- package/dist/chunk-5FWGKTEO.js.map +1 -0
- package/dist/index.cjs +310 -50
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +67 -5
- package/dist/index.d.ts +67 -5
- package/dist/index.js +193 -5
- package/dist/index.js.map +1 -1
- package/dist/sync-chunk-port-DGfASNhC.d.cts +28 -0
- package/dist/sync-chunk-port-DGfASNhC.d.ts +28 -0
- package/dist/testing.cjs +83 -3
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.cts +17 -3
- package/dist/testing.d.ts +17 -3
- package/dist/testing.js +7 -3
- package/package.json +14 -13
- package/dist/chunk-HPBI67CZ.js.map +0 -1
|
@@ -621,7 +621,7 @@ function updateNeedsMergeEngine(op, collectionDef) {
|
|
|
621
621
|
}
|
|
622
622
|
for (const field of Object.keys(op.data ?? {})) {
|
|
623
623
|
const kind = collectionDef.fields[field]?.kind;
|
|
624
|
-
if (kind === "richtext" || kind === "array") {
|
|
624
|
+
if (kind === "richtext" || kind === "array" || kind === "object" || kind === "json") {
|
|
625
625
|
return true;
|
|
626
626
|
}
|
|
627
627
|
if (collectionDef.resolvers[field]) {
|
|
@@ -694,6 +694,82 @@ function wireAuditPersistence(store, emitter) {
|
|
|
694
694
|
};
|
|
695
695
|
}
|
|
696
696
|
|
|
697
|
+
// src/blob/blob-upload-coordinator.ts
|
|
698
|
+
import { isBlobRef } from "@korajs/core";
|
|
699
|
+
import { parseBlobManifest } from "@korajs/store";
|
|
700
|
+
function blobRefsInData(data) {
|
|
701
|
+
if (!data) {
|
|
702
|
+
return [];
|
|
703
|
+
}
|
|
704
|
+
const refs = [];
|
|
705
|
+
for (const value of Object.values(data)) {
|
|
706
|
+
if (isBlobRef(value) && value.manifestHash !== void 0) {
|
|
707
|
+
refs.push(value);
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
return refs;
|
|
711
|
+
}
|
|
712
|
+
async function uploadBlob(ref, syncEngine, blobStore) {
|
|
713
|
+
const manifestHash = ref.manifestHash;
|
|
714
|
+
if (manifestHash === void 0) {
|
|
715
|
+
return;
|
|
716
|
+
}
|
|
717
|
+
const manifestBytes = await blobStore.get(manifestHash);
|
|
718
|
+
if (manifestBytes === null) {
|
|
719
|
+
return;
|
|
720
|
+
}
|
|
721
|
+
const manifest = parseBlobManifest(manifestBytes);
|
|
722
|
+
const seen = /* @__PURE__ */ new Set();
|
|
723
|
+
for (const chunkHash of manifest.chunkHashes) {
|
|
724
|
+
if (seen.has(chunkHash)) {
|
|
725
|
+
continue;
|
|
726
|
+
}
|
|
727
|
+
seen.add(chunkHash);
|
|
728
|
+
const bytes = await blobStore.get(chunkHash);
|
|
729
|
+
if (bytes !== null) {
|
|
730
|
+
syncEngine.uploadBlobChunk(chunkHash, bytes);
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
syncEngine.uploadBlobChunk(manifestHash, manifestBytes);
|
|
734
|
+
}
|
|
735
|
+
function wireBlobUpload(emitter, syncEngine, blobStore) {
|
|
736
|
+
const uploaded = /* @__PURE__ */ new Set();
|
|
737
|
+
return emitter.on("sync:sent", (event) => {
|
|
738
|
+
if (!syncEngine.isBlobStorageEnabled()) {
|
|
739
|
+
return;
|
|
740
|
+
}
|
|
741
|
+
for (const op of event.operations) {
|
|
742
|
+
for (const ref of blobRefsInData(op.data)) {
|
|
743
|
+
const manifestHash = ref.manifestHash;
|
|
744
|
+
if (manifestHash === void 0 || uploaded.has(manifestHash)) {
|
|
745
|
+
continue;
|
|
746
|
+
}
|
|
747
|
+
uploaded.add(manifestHash);
|
|
748
|
+
void uploadBlob(ref, syncEngine, blobStore).catch(() => {
|
|
749
|
+
uploaded.delete(manifestHash);
|
|
750
|
+
});
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
});
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
// src/blob/sync-chunk-port.ts
|
|
757
|
+
function createSyncEngineChunkPort(syncEngine) {
|
|
758
|
+
const channel = syncEngine.getBlobChunkChannel();
|
|
759
|
+
return {
|
|
760
|
+
send(message) {
|
|
761
|
+
channel.send(message);
|
|
762
|
+
},
|
|
763
|
+
onMessage(handler) {
|
|
764
|
+
channel.onMessage((decoded) => {
|
|
765
|
+
if (decoded.type === "blob-chunk-request" || decoded.type === "blob-chunk-response") {
|
|
766
|
+
handler(decoded);
|
|
767
|
+
}
|
|
768
|
+
});
|
|
769
|
+
}
|
|
770
|
+
};
|
|
771
|
+
}
|
|
772
|
+
|
|
697
773
|
// src/merge-aware-sync-store.ts
|
|
698
774
|
var MergeAwareSyncStore = class {
|
|
699
775
|
constructor(store, mergeEngine, emitter, options) {
|
|
@@ -808,8 +884,10 @@ var StoreSyncStatePersistence = class {
|
|
|
808
884
|
export {
|
|
809
885
|
ApplyPipeline,
|
|
810
886
|
wireAuditPersistence,
|
|
887
|
+
wireBlobUpload,
|
|
888
|
+
createSyncEngineChunkPort,
|
|
811
889
|
MergeAwareSyncStore,
|
|
812
890
|
StoreQueueStorage,
|
|
813
891
|
StoreSyncStatePersistence
|
|
814
892
|
};
|
|
815
|
-
//# sourceMappingURL=chunk-
|
|
893
|
+
//# sourceMappingURL=chunk-5FWGKTEO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/apply-pipeline.ts","../src/build-side-effect-entry.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 {\n\tCollectionDefinition,\n\tHLCTimestamp,\n\tKoraEventEmitter,\n\tOperation,\n\tSchemaDefinition,\n} from '@korajs/core'\nimport { HybridLogicalClock, KoraError, createOperation } 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\tTransactionCommitBatch,\n\tTransactionCommitResult,\n} from '@korajs/store'\nimport { OptimisticLockError, richtextStatesEqual } from '@korajs/store'\nimport {\n\texecuteDelete,\n\texecuteInsert,\n\texecuteUpdate,\n\tresolveCausalDeps,\n} from '@korajs/store/internal'\nimport type { ApplyResult } from '@korajs/sync'\nimport { buildSideEffectEntry } from './build-side-effect-entry'\n\n/**\n * Whether the operation originated locally or arrived from sync.\n */\nexport type ApplyMode = 'local' | 'remote'\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 ApplyPipelineDeps {\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 * Context passed into each apply invocation.\n */\nexport interface ApplyContext {\n\treadonly mode: ApplyMode\n\treadonly schema: SchemaDefinition\n}\n\n/**\n * Single entry point for applying remote sync operations with merge + referential integrity.\n */\nexport class ApplyPipeline implements LocalMutationHandler {\n\tprivate readonly relationLookupMap: ReturnType<typeof buildMergeRelationLookup>\n\n\tconstructor(private readonly deps: ApplyPipelineDeps) {\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 with merge-package referential integrity (same rules as remote delete).\n\t */\n\tasync delete(collection: string, id: string): Promise<void> {\n\t\tconst ctx = this.deps.store.createMutationContext(collection)\n\t\tconst causalDeps = resolveCausalDeps(ctx)\n\t\tconst operation = await createOperation(\n\t\t\t{\n\t\t\t\tnodeId: ctx.nodeId,\n\t\t\t\ttype: 'delete',\n\t\t\t\tcollection,\n\t\t\t\trecordId: id,\n\t\t\t\tdata: null,\n\t\t\t\tpreviousData: null,\n\t\t\t\tsequenceNumber: await ctx.allocateSequenceNumber(),\n\t\t\t\tcausalDeps,\n\t\t\t\tschemaVersion: ctx.schema.version,\n\t\t\t},\n\t\t\tctx.clock,\n\t\t)\n\t\tctx.causalTracker?.afterOperation(collection, operation.id, ctx.inTransaction)\n\n\t\tconst refCtx = createReferentialMergeContext(this.deps.store)\n\t\tconst check = await checkReferentialIntegrityOnDelete(\n\t\t\toperation,\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\tthrow new KoraError(\n\t\t\t\t`Cannot delete record \"${id}\" from \"${collection}\": referential restrict policy violated`,\n\t\t\t\t'REFERENTIAL_INTEGRITY',\n\t\t\t\t{ collection, recordId: id },\n\t\t\t)\n\t\t}\n\n\t\tawait executeDelete(ctx, id, {\n\t\t\tskipReferentialEnforcement: true,\n\t\t\toperation,\n\t\t})\n\n\t\tif (check.sideEffectOps.length > 0) {\n\t\t\tawait applySideEffectOps(this.deps.store, check.sideEffectOps, operation.id)\n\t\t}\n\t}\n\n\t/**\n\t * Commit a buffered transaction: merge-package delete enforcement, causal ordering, single DB txn.\n\t */\n\tasync commitTransaction(batch: TransactionCommitBatch): Promise<TransactionCommitResult> {\n\t\tconst store = this.deps.store\n\t\tconst supplemental: TransactionCommitBatch['entries'] = []\n\n\t\tfor (const entry of batch.entries) {\n\t\t\tif (entry.operation.type !== 'delete') {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tconst refCtx = createReferentialMergeContext(store)\n\t\t\tconst check = await checkReferentialIntegrityOnDelete(\n\t\t\t\tentry.operation,\n\t\t\t\tstore.getSchema(),\n\t\t\t\trefCtx,\n\t\t\t\tthis.relationLookupMap,\n\t\t\t)\n\n\t\t\tfor (const trace of check.traces) {\n\t\t\t\tthis.deps.emitter?.emit({ type: 'merge:conflict', trace })\n\t\t\t}\n\n\t\t\tif (!check.allowed) {\n\t\t\t\tthrow new KoraError(\n\t\t\t\t\t`Cannot delete record \"${entry.operation.recordId}\" from \"${entry.collection}\": referential restrict policy violated`,\n\t\t\t\t\t'REFERENTIAL_INTEGRITY',\n\t\t\t\t\t{ collection: entry.collection, recordId: entry.operation.recordId },\n\t\t\t\t)\n\t\t\t}\n\n\t\t\tfor (const effect of check.sideEffectOps) {\n\t\t\t\tconst ctx = store.createMutationContext(effect.collection, { inTransaction: true })\n\t\t\t\tsupplemental.push(\n\t\t\t\t\tawait buildSideEffectEntry(\n\t\t\t\t\t\tctx,\n\t\t\t\t\t\teffect,\n\t\t\t\t\t\tentry.operation.id,\n\t\t\t\t\t\tbatch.transactionId,\n\t\t\t\t\t\tbatch.mutationName,\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\n\t\tconst allEntries = [...batch.entries, ...supplemental]\n\t\tconst sortedOps = topologicalSort(allEntries.map((e) => e.operation))\n\t\tconst commandsByOpId = new Map(allEntries.map((e) => [e.operation.id, e.commands] as const))\n\n\t\tconst ctx = store.createMutationContext(\n\t\t\tbatch.entries[0]?.collection ?? Object.keys(store.getSchema().collections)[0] ?? 'todos',\n\t\t\t{ inTransaction: true },\n\t\t)\n\n\t\tawait ctx.adapter.transaction(async (tx) => {\n\t\t\tfor (const op of sortedOps) {\n\t\t\t\tconst commands = commandsByOpId.get(op.id)\n\t\t\t\tif (!commands) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tfor (const cmd of commands) {\n\t\t\t\t\tawait tx.execute(cmd.sql, cmd.params)\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\n\t\tconst affectedCollections = new Set<string>()\n\t\tfor (const entry of allEntries) {\n\t\t\taffectedCollections.add(entry.collection)\n\t\t}\n\n\t\treturn { operations: sortedOps, affectedCollections }\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\treturn null\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 !== 'delete') {\n\t\t\treturn null\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\n\t\tif (mergeResult.appliedOperation === 'local') {\n\t\t\tthis.emitMergeLifecycle(op, localOp, mergeResult)\n\t\t\treturn 'skipped'\n\t\t}\n\n\t\t// The log keeps the canonical op; only the ROW materializes the merged\n\t\t// data at max(local, remote). Guarded: a local write between our snapshot\n\t\t// read and this apply invalidates the merge and triggers a retry.\n\t\tconst applyResult = await this.deps.store.applyRemoteOperation(op, {\n\t\t\treactivateIfDeleted: true,\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\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\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 ?? {})),\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// 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: mergeResult.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\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) {\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.\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\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\nfunction buildLocalDiff(\n\tbaseState: Record<string, unknown>,\n\tcurrentRecord: Record<string, unknown>,\n\tfields: string[],\n): Record<string, unknown> {\n\tconst diff: Record<string, unknown> = {}\n\tfor (const field of fields) {\n\t\tdiff[field] = currentRecord[field]\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 { createOperation } from '@korajs/core'\nimport type { SideEffectOp } from '@korajs/merge'\nimport type { TransactionBufferedEntry } from '@korajs/store'\nimport type { LocalMutationContext } from '@korajs/store/internal'\nimport {\n\tbuildInsertQuery,\n\tbuildSoftDeleteQuery,\n\tbuildUpdateQuery,\n\tserializeOperation,\n\tserializeRecord,\n\tserializeRowVersion,\n} from '@korajs/store/internal'\n\n/**\n * Materialize a merge-package referential side effect as an operation log entry + SQL commands.\n */\nexport async function buildSideEffectEntry(\n\tctx: LocalMutationContext,\n\teffect: SideEffectOp,\n\tparentOpId: string,\n\ttransactionId?: string,\n\tmutationName?: string,\n): Promise<TransactionBufferedEntry> {\n\tconst causalDeps = [parentOpId]\n\tconst baseInput = {\n\t\tnodeId: ctx.nodeId,\n\t\tcollection: effect.collection,\n\t\trecordId: effect.recordId,\n\t\tsequenceNumber: await ctx.allocateSequenceNumber(),\n\t\tcausalDeps,\n\t\tschemaVersion: ctx.schema.version,\n\t\t...(transactionId !== undefined ? { transactionId } : {}),\n\t\t...(mutationName !== undefined ? { mutationName } : {}),\n\t}\n\n\tif (effect.type === 'delete') {\n\t\tconst operation = await createOperation(\n\t\t\t{\n\t\t\t\t...baseInput,\n\t\t\t\ttype: 'delete',\n\t\t\t\tdata: null,\n\t\t\t\tpreviousData: effect.previousData,\n\t\t\t},\n\t\t\tctx.clock,\n\t\t)\n\t\tctx.causalTracker?.afterOperation(effect.collection, operation.id, ctx.inTransaction)\n\n\t\tconst version = serializeRowVersion(operation.timestamp)\n\t\tconst deleteQuery = buildSoftDeleteQuery(\n\t\t\teffect.collection,\n\t\t\teffect.recordId,\n\t\t\toperation.timestamp.wallTime,\n\t\t\tversion,\n\t\t)\n\t\tconst opInsert = buildInsertQuery(\n\t\t\t`_kora_ops_${effect.collection}`,\n\t\t\tserializeOperation(operation) as unknown as Record<string, unknown>,\n\t\t)\n\n\t\treturn {\n\t\t\toperation,\n\t\t\tcollection: effect.collection,\n\t\t\tcommands: [\n\t\t\t\t{ sql: deleteQuery.sql, params: deleteQuery.params },\n\t\t\t\t{ sql: opInsert.sql, params: opInsert.params },\n\t\t\t\t{\n\t\t\t\t\tsql: 'INSERT OR REPLACE INTO _kora_version_vector (node_id, sequence_number) VALUES (?, ?)',\n\t\t\t\t\tparams: [ctx.nodeId, operation.sequenceNumber],\n\t\t\t\t},\n\t\t\t],\n\t\t}\n\t}\n\n\tconst operation = await createOperation(\n\t\t{\n\t\t\t...baseInput,\n\t\t\ttype: 'update',\n\t\t\tdata: effect.data,\n\t\t\tpreviousData: effect.previousData,\n\t\t},\n\t\tctx.clock,\n\t)\n\tctx.causalTracker?.afterOperation(effect.collection, operation.id, ctx.inTransaction)\n\n\tconst definition = ctx.schema.collections[effect.collection]\n\tconst serializedChanges =\n\t\teffect.data && definition\n\t\t\t? serializeRecord(effect.data, definition.fields)\n\t\t\t: (effect.data ?? {})\n\tconst version = serializeRowVersion(operation.timestamp)\n\tconst updateQuery = buildUpdateQuery(effect.collection, effect.recordId, {\n\t\t...serializedChanges,\n\t\t_updated_at: operation.timestamp.wallTime,\n\t\t_version: version,\n\t})\n\tconst opInsert = buildInsertQuery(\n\t\t`_kora_ops_${effect.collection}`,\n\t\tserializeOperation(operation) as unknown as Record<string, unknown>,\n\t)\n\n\treturn {\n\t\toperation,\n\t\tcollection: effect.collection,\n\t\tcommands: [\n\t\t\t{ sql: updateQuery.sql, params: updateQuery.params },\n\t\t\t{ sql: opInsert.sql, params: opInsert.params },\n\t\t\t{\n\t\t\t\tsql: 'INSERT OR REPLACE INTO _kora_version_vector (node_id, sequence_number) VALUES (?, ?)',\n\t\t\t\tparams: [ctx.nodeId, operation.sequenceNumber],\n\t\t\t},\n\t\t],\n\t}\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. Triggered on `sync:sent`, so a blob authored offline is\n * uploaded when its operation is finally pushed on reconnect — the same event\n * that makes the reference visible to other devices. Each blob is uploaded once\n * per session (deduplicated by manifest hash).\n *\n * A no-op unless the connected server advertised central blob storage.\n *\n * @returns An unsubscribe function.\n */\nexport function wireBlobUpload(\n\temitter: KoraEventEmitter,\n\tsyncEngine: SyncEngine,\n\tblobStore: ContentAddressedBlobStore,\n): () => void {\n\tconst uploaded = new Set<string>()\n\treturn emitter.on('sync:sent', (event) => {\n\t\tif (!syncEngine.isBlobStorageEnabled()) {\n\t\t\treturn\n\t\t}\n\t\tfor (const op of event.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\tuploaded.add(manifestHash)\n\t\t\t\tvoid uploadBlob(ref, syncEngine, blobStore).catch(() => {\n\t\t\t\t\t// Upload is best-effort; a failure just means the blob is served\n\t\t\t\t\t// peer-to-peer until a later successful upload. Allow a retry.\n\t\t\t\t\tuploaded.delete(manifestHash)\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 { 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\tasync applyRemoteOperation(op: Operation): Promise<ApplyResult> {\n\t\treturn this.pipeline.applyRemote(op)\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 }\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\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 { DeltaCursor, SyncScopeMap, SyncStatePersistence } 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"],"mappings":"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","names":["createOperation","operation","version","opInsert","createOperation","ctx","serializeOperation"]}
|