@korajs/store 0.5.0 → 1.0.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/LICENSE +21 -0
  2. package/dist/adapters/better-sqlite3.cjs +94 -40
  3. package/dist/adapters/better-sqlite3.cjs.map +1 -1
  4. package/dist/adapters/better-sqlite3.d.cts +9 -1
  5. package/dist/adapters/better-sqlite3.d.ts +9 -1
  6. package/dist/adapters/better-sqlite3.js +62 -41
  7. package/dist/adapters/better-sqlite3.js.map +1 -1
  8. package/dist/adapters/indexeddb.cjs +24 -13
  9. package/dist/adapters/indexeddb.cjs.map +1 -1
  10. package/dist/adapters/indexeddb.d.cts +2 -2
  11. package/dist/adapters/indexeddb.d.ts +2 -2
  12. package/dist/adapters/indexeddb.js +4 -3
  13. package/dist/adapters/indexeddb.js.map +1 -1
  14. package/dist/adapters/sqlite-wasm.cjs +24 -13
  15. package/dist/adapters/sqlite-wasm.cjs.map +1 -1
  16. package/dist/adapters/sqlite-wasm.d.cts +27 -4
  17. package/dist/adapters/sqlite-wasm.d.ts +27 -4
  18. package/dist/adapters/sqlite-wasm.js +6 -4
  19. package/dist/{backup-JN3LB4YT.js → backup-5XZ7THNJ.js} +3 -3
  20. package/dist/{chunk-EZSTD2XC.js → chunk-5R4QMY3Z.js} +2 -2
  21. package/dist/{chunk-AGN3CIPB.js → chunk-EIVXWF4B.js} +2 -2
  22. package/dist/{chunk-56LL4XP6.js → chunk-ETDJEH2I.js} +42 -1
  23. package/dist/chunk-ETDJEH2I.js.map +1 -0
  24. package/dist/{chunk-XO4LMPAH.js → chunk-IOEFNHHP.js} +2 -35
  25. package/dist/chunk-IOEFNHHP.js.map +1 -0
  26. package/dist/{chunk-7BPETY5Y.js → chunk-OUQDC5Z6.js} +105 -8
  27. package/dist/chunk-OUQDC5Z6.js.map +1 -0
  28. package/dist/{chunk-LAWV6CFH.js → chunk-QL2XVZRN.js} +12 -1
  29. package/dist/chunk-QL2XVZRN.js.map +1 -0
  30. package/dist/{chunk-6AHYGQQT.js → chunk-RBPVEAVM.js} +4 -4
  31. package/dist/chunk-TVJEC5S2.js +40 -0
  32. package/dist/chunk-TVJEC5S2.js.map +1 -0
  33. package/dist/{export-audit-5GV6VRDZ.js → export-audit-VPGQWNR6.js} +3 -3
  34. package/dist/index.cjs +1102 -104
  35. package/dist/index.cjs.map +1 -1
  36. package/dist/index.d.cts +219 -7
  37. package/dist/index.d.ts +219 -7
  38. package/dist/index.js +905 -44
  39. package/dist/index.js.map +1 -1
  40. package/dist/internal.cjs +100 -30
  41. package/dist/internal.cjs.map +1 -1
  42. package/dist/internal.d.cts +3 -3
  43. package/dist/internal.d.ts +3 -3
  44. package/dist/internal.js +3 -3
  45. package/dist/{sqlite-wasm-channel-I9y_jObg.d.cts → sqlite-wasm-channel-DUDPclTE.d.cts} +2 -15
  46. package/dist/{sqlite-wasm-channel-I9y_jObg.d.ts → sqlite-wasm-channel-DUDPclTE.d.ts} +2 -15
  47. package/dist/sqlite-wasm-channel-H43KEZLM.js +12 -0
  48. package/dist/{types-DepnRDk_.d.cts → types-CJOVKxLw.d.cts} +43 -2
  49. package/dist/{types-DepnRDk_.d.ts → types-CJOVKxLw.d.ts} +43 -2
  50. package/dist/{types-CTr00g_d.d.cts → types-CyjXwrjW.d.cts} +1 -1
  51. package/dist/{types-BMyHmwvn.d.ts → types-DAxCladl.d.ts} +1 -1
  52. package/package.json +4 -2
  53. package/dist/chunk-56LL4XP6.js.map +0 -1
  54. package/dist/chunk-7BPETY5Y.js.map +0 -1
  55. package/dist/chunk-LAWV6CFH.js.map +0 -1
  56. package/dist/chunk-XO4LMPAH.js.map +0 -1
  57. package/dist/sqlite-wasm-channel-HDDW6UBH.js +0 -10
  58. /package/dist/{backup-JN3LB4YT.js.map → backup-5XZ7THNJ.js.map} +0 -0
  59. /package/dist/{chunk-EZSTD2XC.js.map → chunk-5R4QMY3Z.js.map} +0 -0
  60. /package/dist/{chunk-AGN3CIPB.js.map → chunk-EIVXWF4B.js.map} +0 -0
  61. /package/dist/{chunk-6AHYGQQT.js.map → chunk-RBPVEAVM.js.map} +0 -0
  62. /package/dist/{export-audit-5GV6VRDZ.js.map → export-audit-VPGQWNR6.js.map} +0 -0
  63. /package/dist/{sqlite-wasm-channel-HDDW6UBH.js.map → sqlite-wasm-channel-H43KEZLM.js.map} +0 -0
package/dist/internal.cjs CHANGED
@@ -54,10 +54,28 @@ __export(internal_exports, {
54
54
  module.exports = __toCommonJS(internal_exports);
55
55
 
56
56
  // src/serialization/serializer.ts
57
- var import_core = require("@korajs/core");
57
+ var import_core2 = require("@korajs/core");
58
58
 
59
59
  // src/serialization/richtext-serializer.ts
60
60
  var Y = __toESM(require("yjs"), 1);
61
+
62
+ // src/serialization/op-data-encoding.ts
63
+ var import_core = require("@korajs/core");
64
+ var decodeRichtextOpDataValue = import_core.decodeBytesFromOpData;
65
+ function encodeRichtextFieldsForOpData(data, fields) {
66
+ const result = { ...data };
67
+ for (const [key, value] of Object.entries(data)) {
68
+ if (fields[key]?.kind !== "richtext") {
69
+ continue;
70
+ }
71
+ if (typeof value === "string" || value instanceof Uint8Array || value instanceof ArrayBuffer) {
72
+ result[key] = (0, import_core.encodeBytesForOpData)(value);
73
+ }
74
+ }
75
+ return result;
76
+ }
77
+
78
+ // src/serialization/richtext-serializer.ts
61
79
  var TEXT_KEY = "content";
62
80
  function encodeRichtext(value) {
63
81
  if (value === null || value === void 0) {
@@ -74,6 +92,10 @@ function encodeRichtext(value) {
74
92
  if (value instanceof ArrayBuffer) {
75
93
  return new Uint8Array(value);
76
94
  }
95
+ if ((0, import_core.isKoraBytesValue)(value) || (0, import_core.isLegacyNumericByteObject)(value)) {
96
+ const decoded = decodeRichtextOpDataValue(value);
97
+ return decoded instanceof Uint8Array ? decoded : null;
98
+ }
77
99
  throw new Error("Richtext value must be a string, Uint8Array, ArrayBuffer, null, or undefined.");
78
100
  }
79
101
  function decodeRichtext(value) {
@@ -156,7 +178,7 @@ function serializeOperation(op) {
156
178
  record_id: op.recordId,
157
179
  data: dataPayload ? JSON.stringify(dataPayload) : null,
158
180
  previous_data: op.previousData ? JSON.stringify(op.previousData) : null,
159
- timestamp: import_core.HybridLogicalClock.serialize(op.timestamp),
181
+ timestamp: import_core2.HybridLogicalClock.serialize(op.timestamp),
160
182
  sequence_number: op.sequenceNumber,
161
183
  causal_deps: JSON.stringify(op.causalDeps),
162
184
  schema_version: op.schemaVersion
@@ -190,7 +212,7 @@ function deserializeOperation(row) {
190
212
  recordId: row.record_id,
191
213
  data,
192
214
  previousData: row.previous_data ? JSON.parse(row.previous_data) : null,
193
- timestamp: import_core.HybridLogicalClock.deserialize(row.timestamp),
215
+ timestamp: import_core2.HybridLogicalClock.deserialize(row.timestamp),
194
216
  sequenceNumber: row.sequence_number,
195
217
  causalDeps: JSON.parse(row.causal_deps),
196
218
  schemaVersion: row.schema_version,
@@ -235,14 +257,14 @@ function deserializeValue(value, descriptor) {
235
257
  }
236
258
 
237
259
  // src/errors.ts
238
- var import_core2 = require("@korajs/core");
239
- var QueryError = class extends import_core2.KoraError {
260
+ var import_core3 = require("@korajs/core");
261
+ var QueryError = class extends import_core3.KoraError {
240
262
  constructor(message, context) {
241
263
  super(message, "QUERY_ERROR", context);
242
264
  this.name = "QueryError";
243
265
  }
244
266
  };
245
- var RecordNotFoundError = class extends import_core2.KoraError {
267
+ var RecordNotFoundError = class extends import_core3.KoraError {
246
268
  constructor(collection, recordId) {
247
269
  super(`Record "${recordId}" not found in collection "${collection}"`, "RECORD_NOT_FOUND", {
248
270
  collection,
@@ -253,20 +275,20 @@ var RecordNotFoundError = class extends import_core2.KoraError {
253
275
  };
254
276
 
255
277
  // src/lww/row-version.ts
256
- var import_core3 = require("@korajs/core");
278
+ var import_core4 = require("@korajs/core");
257
279
  var EMPTY_ROW_VERSION = "";
258
280
  function serializeRowVersion(timestamp) {
259
- return import_core3.HybridLogicalClock.serialize(timestamp);
281
+ return import_core4.HybridLogicalClock.serialize(timestamp);
260
282
  }
261
283
  function rowVersionFromRecord(row) {
262
284
  const version = row._version;
263
285
  if (typeof version === "string" && version.length > 0) {
264
- return import_core3.HybridLogicalClock.deserialize(version);
286
+ return import_core4.HybridLogicalClock.deserialize(version);
265
287
  }
266
288
  return { wallTime: row._updated_at, logical: 0, nodeId: "" };
267
289
  }
268
290
  function isIncomingNewerThanRow(incoming, row) {
269
- return import_core3.HybridLogicalClock.compare(incoming, rowVersionFromRecord(row)) > 0;
291
+ return import_core4.HybridLogicalClock.compare(incoming, rowVersionFromRecord(row)) > 0;
270
292
  }
271
293
  function lwwVersionWhereClause(remoteVersion) {
272
294
  return {
@@ -447,7 +469,39 @@ function validateFieldName(fieldName, fields) {
447
469
  }
448
470
 
449
471
  // src/mutations/execute-insert.ts
450
- var import_core4 = require("@korajs/core");
472
+ var import_core5 = require("@korajs/core");
473
+
474
+ // src/lww/field-versions.ts
475
+ function parseFieldVersions(raw) {
476
+ if (typeof raw !== "string" || raw.length === 0) {
477
+ return {};
478
+ }
479
+ try {
480
+ const parsed = JSON.parse(raw);
481
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
482
+ return {};
483
+ }
484
+ const result = {};
485
+ for (const [key, value] of Object.entries(parsed)) {
486
+ if (typeof value === "string") {
487
+ result[key] = value;
488
+ }
489
+ }
490
+ return result;
491
+ } catch {
492
+ return {};
493
+ }
494
+ }
495
+ function serializeFieldVersions(versions) {
496
+ return JSON.stringify(versions);
497
+ }
498
+ function fieldVersionsForFields(fieldNames, version) {
499
+ const versions = {};
500
+ for (const field of fieldNames) {
501
+ versions[field] = version;
502
+ }
503
+ return versions;
504
+ }
451
505
 
452
506
  // src/store/sequence-allocator.ts
453
507
  async function allocateNextSequenceInTransaction(tx, nodeId) {
@@ -482,8 +536,8 @@ function resolveCausalDeps(ctx) {
482
536
 
483
537
  // src/mutations/execute-insert.ts
484
538
  async function executeInsert(ctx, data) {
485
- const validated = (0, import_core4.validateRecord)(ctx.collection, ctx.definition, data, "insert");
486
- const recordId = (0, import_core4.generateUUIDv7)();
539
+ const validated = (0, import_core5.validateRecord)(ctx.collection, ctx.definition, data, "insert");
540
+ const recordId = (0, import_core5.generateUUIDv7)();
487
541
  for (const [fieldName, descriptor] of Object.entries(ctx.definition.fields)) {
488
542
  if (descriptor.auto && descriptor.kind === "timestamp") {
489
543
  validated[fieldName] = Date.now();
@@ -494,13 +548,16 @@ async function executeInsert(ctx, data) {
494
548
  let record;
495
549
  await ctx.adapter.transaction(async (tx) => {
496
550
  const sequenceNumber = await allocateNextSequenceInTransaction(tx, ctx.nodeId);
497
- operation = await (0, import_core4.createOperation)(
551
+ operation = await (0, import_core5.createOperation)(
498
552
  {
499
553
  nodeId: ctx.nodeId,
500
554
  type: "insert",
501
555
  collection: ctx.collection,
502
556
  recordId,
503
- data: { ...validated },
557
+ // Binary richtext values are tagged as canonical JSON BEFORE the
558
+ // operation is content-hashed, so the hash input, persisted JSON,
559
+ // and wire payload are the identical value.
560
+ data: encodeRichtextFieldsForOpData(validated, ctx.definition.fields),
504
561
  previousData: null,
505
562
  sequenceNumber,
506
563
  causalDeps,
@@ -516,7 +573,12 @@ async function executeInsert(ctx, data) {
516
573
  ...serializedData,
517
574
  _created_at: operation.timestamp.wallTime,
518
575
  _updated_at: operation.timestamp.wallTime,
519
- _version: version
576
+ _version: version,
577
+ // Stamp every inserted field with this operation's version so later
578
+ // per-field LWW compares against a real writer, not the fallback.
579
+ _field_versions: serializeFieldVersions(
580
+ fieldVersionsForFields(Object.keys(serializedData), version)
581
+ )
520
582
  };
521
583
  const builtInsert = buildInsertQuery(ctx.collection, record);
522
584
  const opInsert = buildInsertQuery(
@@ -536,11 +598,11 @@ async function executeInsert(ctx, data) {
536
598
  }
537
599
 
538
600
  // src/mutations/execute-update.ts
539
- var import_core6 = require("@korajs/core");
601
+ var import_core7 = require("@korajs/core");
540
602
 
541
603
  // src/state-machine/state-validator.ts
542
- var import_core5 = require("@korajs/core");
543
- var InvalidStateTransitionError = class extends import_core5.KoraError {
604
+ var import_core6 = require("@korajs/core");
605
+ var InvalidStateTransitionError = class extends import_core6.KoraError {
544
606
  constructor(collection, recordId, field, fromState, toState, allowedStates) {
545
607
  super(
546
608
  `Invalid state transition in collection "${collection}": cannot transition field "${field}" from "${fromState}" to "${toState}". Allowed transitions from "${fromState}": ${allowedStates.length > 0 ? allowedStates.join(", ") : "(none -- terminal state)"}`,
@@ -574,7 +636,7 @@ function validateStateTransition(collectionName, recordId, stateMachine, current
574
636
  collection: collectionName,
575
637
  transitions: stateMachine.transitions
576
638
  };
577
- const transitionResult = (0, import_core5.validateTransition)(constraint, currentState, newState);
639
+ const transitionResult = (0, import_core6.validateTransition)(constraint, currentState, newState);
578
640
  if (transitionResult.valid) {
579
641
  return { valid: true, allowedStates: transitionResult.allowedTargets };
580
642
  }
@@ -630,7 +692,7 @@ async function executeUpdate(ctx, id, data) {
630
692
  if (!currentRow) {
631
693
  throw new RecordNotFoundError(ctx.collection, id);
632
694
  }
633
- let validated = (0, import_core6.validateRecord)(ctx.collection, ctx.definition, data, "update");
695
+ let validated = (0, import_core7.validateRecord)(ctx.collection, ctx.definition, data, "update");
634
696
  const currentRecord = deserializeRecord(currentRow, ctx.definition.fields);
635
697
  validated = validateUpdateStateMachine(
636
698
  ctx.collection,
@@ -648,9 +710,9 @@ async function executeUpdate(ctx, id, data) {
648
710
  for (const key of Object.keys(validated)) {
649
711
  const value = validated[key];
650
712
  previousData[key] = currentRecord[key];
651
- if ((0, import_core6.isAtomicOp)(value)) {
652
- resolvedData[key] = (0, import_core6.resolveAtomicOp)(currentRecord[key], value);
653
- atomicOps[key] = (0, import_core6.toAtomicOp)(value);
713
+ if ((0, import_core7.isAtomicOp)(value)) {
714
+ resolvedData[key] = (0, import_core7.resolveAtomicOp)(currentRecord[key], value);
715
+ atomicOps[key] = (0, import_core7.toAtomicOp)(value);
654
716
  } else {
655
717
  resolvedData[key] = value;
656
718
  }
@@ -660,14 +722,17 @@ async function executeUpdate(ctx, id, data) {
660
722
  let operation;
661
723
  await ctx.adapter.transaction(async (tx) => {
662
724
  const sequenceNumber = await allocateNextSequenceInTransaction(tx, ctx.nodeId);
663
- operation = await (0, import_core6.createOperation)(
725
+ operation = await (0, import_core7.createOperation)(
664
726
  {
665
727
  nodeId: ctx.nodeId,
666
728
  type: "update",
667
729
  collection: ctx.collection,
668
730
  recordId: id,
669
- data: { ...resolvedData },
670
- previousData,
731
+ // Binary richtext values (new and previous) are tagged as canonical
732
+ // JSON BEFORE the operation is content-hashed, so the hash input,
733
+ // persisted JSON, and wire payload are the identical value.
734
+ data: encodeRichtextFieldsForOpData(resolvedData, ctx.definition.fields),
735
+ previousData: encodeRichtextFieldsForOpData(previousData, ctx.definition.fields),
671
736
  sequenceNumber,
672
737
  causalDeps,
673
738
  schemaVersion: ctx.schema.version,
@@ -678,10 +743,15 @@ async function executeUpdate(ctx, id, data) {
678
743
  ctx.causalTracker?.afterOperation(ctx.collection, operation.id, ctx.inTransaction);
679
744
  const serializedChanges = serializeRecord(resolvedData, ctx.definition.fields);
680
745
  const version = serializeRowVersion(operation.timestamp);
746
+ const mergedFieldVersions = parseFieldVersions(currentRow._field_versions);
747
+ for (const changedField of Object.keys(serializedChanges)) {
748
+ mergedFieldVersions[changedField] = version;
749
+ }
681
750
  const updateQuery = buildUpdateQuery(ctx.collection, id, {
682
751
  ...serializedChanges,
683
752
  _updated_at: operation.timestamp.wallTime,
684
- _version: version
753
+ _version: version,
754
+ _field_versions: serializeFieldVersions(mergedFieldVersions)
685
755
  });
686
756
  const opInsert = buildInsertQuery(
687
757
  `_kora_ops_${ctx.collection}`,
@@ -703,7 +773,7 @@ async function executeUpdate(ctx, id, data) {
703
773
  }
704
774
 
705
775
  // src/mutations/execute-delete.ts
706
- var import_core7 = require("@korajs/core");
776
+ var import_core8 = require("@korajs/core");
707
777
  async function executeDelete(ctx, id, options) {
708
778
  const currentRows = await ctx.adapter.query(
709
779
  `SELECT * FROM ${ctx.collection} WHERE id = ? AND _deleted = 0`,
@@ -718,7 +788,7 @@ async function executeDelete(ctx, id, options) {
718
788
  await ctx.adapter.transaction(async (tx) => {
719
789
  if (!operation) {
720
790
  const sequenceNumber = await allocateNextSequenceInTransaction(tx, ctx.nodeId);
721
- operation = await (0, import_core7.createOperation)(
791
+ operation = await (0, import_core8.createOperation)(
722
792
  {
723
793
  nodeId: ctx.nodeId,
724
794
  type: "delete",
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/internal.ts","../src/serialization/serializer.ts","../src/serialization/richtext-serializer.ts","../src/errors.ts","../src/lww/row-version.ts","../src/query/sql-builder.ts","../src/mutations/execute-insert.ts","../src/store/sequence-allocator.ts","../src/mutations/resolve-causal-deps.ts","../src/mutations/execute-update.ts","../src/state-machine/state-validator.ts","../src/mutations/execute-delete.ts"],"sourcesContent":["// Internal exports — shared within @kora packages but NOT part of the public API.\n// Other @kora packages can import from '@korajs/store/internal' if needed.\n\nexport {\n\tserializeOperation,\n\tdeserializeOperation,\n\tdeserializeOperationWithCollection,\n\tserializeRecord,\n\tdeserializeRecord,\n} from './serialization/serializer'\n\nexport {\n\tbuildSelectQuery,\n\tbuildCountQuery,\n\tbuildInsertQuery,\n\tbuildUpdateQuery,\n\tbuildLwwUpdateQuery,\n\tbuildSoftDeleteQuery,\n\tbuildLwwSoftDeleteQuery,\n\tbuildWhereClause,\n} from './query/sql-builder'\nexport {\n\tserializeRowVersion,\n\trowVersionFromRecord,\n\tisIncomingNewerThanRow,\n} from './lww/row-version'\nexport type { SqlQuery } from './query/sql-builder'\n\nexport type {\n\tOperationRow,\n\tRawCollectionRow,\n\tMetaRow,\n\tVersionVectorRow,\n\tSubscription,\n} from './types'\n\nexport { executeInsert } from './mutations/execute-insert'\nexport { executeUpdate } from './mutations/execute-update'\nexport { executeDelete } from './mutations/execute-delete'\nexport { resolveCausalDeps } from './mutations/resolve-causal-deps'\nexport type { ExecuteDeleteOptions } from './mutations/execute-delete'\nexport type { LocalMutationContext } from './mutations/types'\n","import { HybridLogicalClock } from '@korajs/core'\nimport type { CollectionDefinition, FieldDescriptor, Operation } from '@korajs/core'\nimport type { CollectionRecord, OperationRow, RawCollectionRow } from '../types'\nimport { decodeRichtext, encodeRichtext } from './richtext-serializer'\n\n/**\n * Serialize a JS record to SQL-compatible values for INSERT/UPDATE.\n * Transforms: boolean → 0/1, array → JSON string, richtext → Yjs binary update.\n *\n * @param data - The record data with JS-native types\n * @param fields - The field descriptors from the schema\n * @returns An object with SQL-compatible values\n */\nexport function serializeRecord(\n\tdata: Record<string, unknown>,\n\tfields: Record<string, FieldDescriptor>,\n): Record<string, unknown> {\n\tconst result: Record<string, unknown> = {}\n\tfor (const [key, value] of Object.entries(data)) {\n\t\tconst descriptor = fields[key]\n\t\tif (!descriptor) {\n\t\t\tresult[key] = value\n\t\t\tcontinue\n\t\t}\n\t\tresult[key] = serializeValue(value, descriptor)\n\t}\n\treturn result\n}\n\n/**\n * Deserialize a SQL row to JS-native types for the application layer.\n * Transforms: 0/1 → boolean, JSON string → array, strips _deleted, maps _created_at/_updated_at.\n *\n * @param row - The raw SQL row\n * @param fields - The field descriptors from the schema\n * @returns A CollectionRecord with JS-native types\n */\nexport function deserializeRecord(\n\trow: RawCollectionRow,\n\tfields: Record<string, FieldDescriptor>,\n): CollectionRecord {\n\tconst result: CollectionRecord = {\n\t\tid: row.id,\n\t\tcreatedAt: row._created_at,\n\t\tupdatedAt: row._updated_at,\n\t}\n\n\tfor (const [key, descriptor] of Object.entries(fields)) {\n\t\tconst rawValue = row[key]\n\t\tif (rawValue === undefined || rawValue === null) {\n\t\t\tresult[key] = rawValue ?? null\n\t\t\tcontinue\n\t\t}\n\t\tresult[key] = deserializeValue(rawValue, descriptor)\n\t}\n\n\treturn result\n}\n\n/**\n * Internal key used to embed atomicOps metadata in the data JSON column.\n * This avoids adding a new column to the ops table (no migration needed).\n */\nconst ATOMIC_OPS_KEY = '__kora_atomic_ops__'\n\n/**\n * Internal key used to embed transactionId in the data JSON column.\n */\nconst TX_ID_KEY = '__kora_tx_id__'\n\n/**\n * Internal key used to embed mutationName in the data JSON column.\n */\nconst MUTATION_NAME_KEY = '__kora_mutation__'\n\n/**\n * Serialize an Operation to a row for the operations log table.\n *\n * @param op - The operation to serialize\n * @returns An OperationRow suitable for SQL INSERT\n */\nexport function serializeOperation(op: Operation): OperationRow {\n\tconst hasMetadata = op.transactionId !== undefined || op.mutationName !== undefined\n\tlet dataPayload: Record<string, unknown> | null = null\n\tif (op.data) {\n\t\t// Embed metadata in the data JSON when present\n\t\tdataPayload = { ...op.data }\n\t\tif (op.atomicOps !== undefined && Object.keys(op.atomicOps).length > 0) {\n\t\t\tdataPayload[ATOMIC_OPS_KEY] = op.atomicOps\n\t\t}\n\t\tif (op.transactionId !== undefined) {\n\t\t\tdataPayload[TX_ID_KEY] = op.transactionId\n\t\t}\n\t\tif (op.mutationName !== undefined) {\n\t\t\tdataPayload[MUTATION_NAME_KEY] = op.mutationName\n\t\t}\n\t} else if (hasMetadata) {\n\t\t// For delete operations (data is null), we still need to store metadata\n\t\tdataPayload = {}\n\t\tif (op.transactionId !== undefined) {\n\t\t\tdataPayload[TX_ID_KEY] = op.transactionId\n\t\t}\n\t\tif (op.mutationName !== undefined) {\n\t\t\tdataPayload[MUTATION_NAME_KEY] = op.mutationName\n\t\t}\n\t}\n\n\treturn {\n\t\tid: op.id,\n\t\tnode_id: op.nodeId,\n\t\ttype: op.type,\n\t\trecord_id: op.recordId,\n\t\tdata: dataPayload ? JSON.stringify(dataPayload) : null,\n\t\tprevious_data: op.previousData ? JSON.stringify(op.previousData) : null,\n\t\ttimestamp: HybridLogicalClock.serialize(op.timestamp),\n\t\tsequence_number: op.sequenceNumber,\n\t\tcausal_deps: JSON.stringify(op.causalDeps),\n\t\tschema_version: op.schemaVersion,\n\t}\n}\n\n/**\n * Deserialize a row from the operations log table back to an Operation.\n *\n * @param row - The raw operation row from SQL\n * @returns The deserialized Operation object\n */\nexport function deserializeOperation(row: OperationRow): Operation {\n\tlet data: Record<string, unknown> | null = null\n\tlet atomicOps: Record<string, unknown> | undefined\n\tlet transactionId: string | undefined\n\tlet mutationName: string | undefined\n\n\tif (row.data) {\n\t\tconst parsed = JSON.parse(row.data) as Record<string, unknown>\n\t\t// Extract embedded metadata keys\n\t\tif (ATOMIC_OPS_KEY in parsed) {\n\t\t\tatomicOps = parsed[ATOMIC_OPS_KEY] as Record<string, unknown>\n\t\t}\n\t\tif (TX_ID_KEY in parsed) {\n\t\t\ttransactionId = parsed[TX_ID_KEY] as string\n\t\t}\n\t\tif (MUTATION_NAME_KEY in parsed) {\n\t\t\tmutationName = parsed[MUTATION_NAME_KEY] as string\n\t\t}\n\t\t// Remove metadata keys from data\n\t\tconst { [ATOMIC_OPS_KEY]: _a, [TX_ID_KEY]: _t, [MUTATION_NAME_KEY]: _m, ...rest } = parsed\n\t\tdata = Object.keys(rest).length > 0 ? rest : null\n\t}\n\n\treturn {\n\t\tid: row.id,\n\t\tnodeId: row.node_id,\n\t\ttype: row.type as Operation['type'],\n\t\tcollection: '', // Collection name is derived from the table name by the caller\n\t\trecordId: row.record_id,\n\t\tdata,\n\t\tpreviousData: row.previous_data\n\t\t\t? (JSON.parse(row.previous_data) as Record<string, unknown>)\n\t\t\t: null,\n\t\ttimestamp: HybridLogicalClock.deserialize(row.timestamp),\n\t\tsequenceNumber: row.sequence_number,\n\t\tcausalDeps: JSON.parse(row.causal_deps) as string[],\n\t\tschemaVersion: row.schema_version,\n\t\t...(atomicOps !== undefined ? { atomicOps: atomicOps as Operation['atomicOps'] } : {}),\n\t\t...(transactionId !== undefined ? { transactionId } : {}),\n\t\t...(mutationName !== undefined ? { mutationName } : {}),\n\t}\n}\n\n/**\n * Deserialize an operation row with collection name already known.\n */\nexport function deserializeOperationWithCollection(\n\trow: OperationRow,\n\tcollection: string,\n): Operation {\n\tconst op = deserializeOperation(row)\n\treturn { ...op, collection }\n}\n\nfunction serializeValue(value: unknown, descriptor: FieldDescriptor): unknown {\n\tif (value === null || value === undefined) {\n\t\treturn null\n\t}\n\n\tswitch (descriptor.kind) {\n\t\tcase 'boolean':\n\t\t\treturn value ? 1 : 0\n\t\tcase 'array':\n\t\t\treturn JSON.stringify(value)\n\t\tcase 'richtext':\n\t\t\treturn encodeRichtext(value as string | Uint8Array | ArrayBuffer)\n\t\tdefault:\n\t\t\treturn value\n\t}\n}\n\nfunction deserializeValue(value: unknown, descriptor: FieldDescriptor): unknown {\n\tswitch (descriptor.kind) {\n\t\tcase 'boolean':\n\t\t\treturn value === 1 || value === true\n\t\tcase 'array':\n\t\t\tif (typeof value === 'string') {\n\t\t\t\treturn JSON.parse(value) as unknown[]\n\t\t\t}\n\t\t\treturn value\n\t\tcase 'richtext':\n\t\t\treturn decodeRichtext(value)\n\t\tdefault:\n\t\t\treturn value\n\t}\n}\n","import * as Y from 'yjs'\n\nconst TEXT_KEY = 'content'\n\nexport type RichtextInput = string | Uint8Array | ArrayBuffer | null | undefined\n\n/**\n * Encodes richtext values into Yjs document updates.\n */\nexport function encodeRichtext(value: RichtextInput): Uint8Array | null {\n\tif (value === null || value === undefined) {\n\t\treturn null\n\t}\n\n\tif (typeof value === 'string') {\n\t\tconst doc = new Y.Doc()\n\t\tdoc.getText(TEXT_KEY).insert(0, value)\n\t\treturn Y.encodeStateAsUpdate(doc)\n\t}\n\n\tif (value instanceof Uint8Array) {\n\t\treturn value\n\t}\n\n\tif (value instanceof ArrayBuffer) {\n\t\treturn new Uint8Array(value)\n\t}\n\n\tthrow new Error('Richtext value must be a string, Uint8Array, ArrayBuffer, null, or undefined.')\n}\n\n/**\n * Decodes driver-provided richtext values into Uint8Array.\n */\nexport function decodeRichtext(value: unknown): Uint8Array | null {\n\tif (value === null || value === undefined) {\n\t\treturn null\n\t}\n\n\tif (typeof Buffer !== 'undefined' && Buffer.isBuffer(value)) {\n\t\treturn new Uint8Array(value)\n\t}\n\n\tif (value instanceof Uint8Array) {\n\t\treturn value\n\t}\n\n\tif (value instanceof ArrayBuffer) {\n\t\treturn new Uint8Array(value)\n\t}\n\n\tthrow new Error(\n\t\t'Richtext storage value must be Uint8Array, ArrayBuffer, Buffer, null, or undefined.',\n\t)\n}\n\n/**\n * Reads plain text from a richtext Yjs state update.\n */\nexport function richtextToPlainText(value: RichtextInput): string {\n\tconst encoded = encodeRichtext(value)\n\tif (!encoded) return ''\n\n\tconst doc = new Y.Doc()\n\tY.applyUpdate(doc, encoded)\n\treturn doc.getText(TEXT_KEY).toString()\n}\n\n/**\n * Compares two richtext values by decoded plain text.\n * Yjs update bytes are not stable across separate encodes of the same string.\n */\nexport function richtextStatesEqual(a: unknown, b: unknown): boolean {\n\ttry {\n\t\treturn richtextToPlainText(a as RichtextInput) === richtextToPlainText(b as RichtextInput)\n\t} catch {\n\t\treturn false\n\t}\n}\n","import { KoraError } from '@korajs/core'\n\n/**\n * Thrown when a query is invalid (bad field names, invalid operators, etc.).\n */\nexport class QueryError extends KoraError {\n\tconstructor(message: string, context?: Record<string, unknown>) {\n\t\tsuper(message, 'QUERY_ERROR', context)\n\t\tthis.name = 'QueryError'\n\t}\n}\n\n/**\n * Thrown when a record is not found by ID (findById, update, delete on missing record).\n */\nexport class RecordNotFoundError extends KoraError {\n\tconstructor(collection: string, recordId: string) {\n\t\tsuper(`Record \"${recordId}\" not found in collection \"${collection}\"`, 'RECORD_NOT_FOUND', {\n\t\t\tcollection,\n\t\t\trecordId,\n\t\t})\n\t\tthis.name = 'RecordNotFoundError'\n\t}\n}\n\n/**\n * Thrown when a storage adapter operation fails.\n */\nexport class AdapterError extends KoraError {\n\tconstructor(message: string, context?: Record<string, unknown>) {\n\t\tsuper(message, 'ADAPTER_ERROR', context)\n\t\tthis.name = 'AdapterError'\n\t}\n}\n\n/**\n * Thrown when an operation is attempted on a store that has not been opened.\n */\nexport class StoreNotOpenError extends KoraError {\n\tconstructor() {\n\t\tsuper('Store is not open. Call store.open() before performing operations.', 'STORE_NOT_OPEN')\n\t\tthis.name = 'StoreNotOpenError'\n\t}\n}\n\n/**\n * Thrown when the Web Worker fails to initialize (WASM load failure, OPFS unavailable, etc.).\n */\nexport class WorkerInitError extends KoraError {\n\tconstructor(message: string, context?: Record<string, unknown>) {\n\t\tsuper(`Worker initialization failed: ${message}`, 'WORKER_INIT_ERROR', context)\n\t\tthis.name = 'WorkerInitError'\n\t}\n}\n\n/**\n * Thrown when the Web Worker does not respond within the configured timeout.\n */\nexport class WorkerTimeoutError extends KoraError {\n\tconstructor(operation: string, timeoutMs: number) {\n\t\tsuper(\n\t\t\t`Worker did not respond within ${timeoutMs}ms for operation \"${operation}\"`,\n\t\t\t'WORKER_TIMEOUT',\n\t\t\t{ operation, timeoutMs },\n\t\t)\n\t\tthis.name = 'WorkerTimeoutError'\n\t}\n}\n\n/**\n * Thrown when IndexedDB persistence operations fail (serialize/deserialize).\n */\nexport class PersistenceError extends KoraError {\n\tconstructor(message: string, context?: Record<string, unknown>) {\n\t\tsuper(`Persistence error: ${message}`, 'PERSISTENCE_ERROR', context)\n\t\tthis.name = 'PersistenceError'\n\t}\n}\n","import { type HLCTimestamp, HybridLogicalClock } from '@korajs/core'\nimport type { RawCollectionRow } from '../types'\n\n/** Empty _version means legacy rows (compare by wallTime only via fallback). */\nexport const EMPTY_ROW_VERSION = ''\n\n/**\n * Serialize an HLC timestamp for storage in the `_version` column.\n * Lexicographic order matches {@link HybridLogicalClock.compare}.\n */\nexport function serializeRowVersion(timestamp: HLCTimestamp): string {\n\treturn HybridLogicalClock.serialize(timestamp)\n}\n\n/**\n * Read the version stamp stored on a materialized row.\n * Legacy rows without `_version` fall back to wallTime with logical 0.\n */\nexport function rowVersionFromRecord(\n\trow: Pick<RawCollectionRow, '_updated_at' | '_version'>,\n): HLCTimestamp {\n\tconst version = row._version\n\tif (typeof version === 'string' && version.length > 0) {\n\t\treturn HybridLogicalClock.deserialize(version)\n\t}\n\treturn { wallTime: row._updated_at, logical: 0, nodeId: '' }\n}\n\n/**\n * Returns true when `incoming` is strictly newer than the version on `row`.\n */\nexport function isIncomingNewerThanRow(\n\tincoming: HLCTimestamp,\n\trow: Pick<RawCollectionRow, '_updated_at' | '_version'>,\n): boolean {\n\treturn HybridLogicalClock.compare(incoming, rowVersionFromRecord(row)) > 0\n}\n\n/**\n * SQL fragment and params for LWW guards: apply only when row is missing or older.\n * Uses serialized `_version` for total order (matches HLC compare).\n */\nexport function lwwVersionWhereClause(remoteVersion: string): { sql: string; params: string[] } {\n\treturn {\n\t\tsql: '(_version = ? OR _version < ?)',\n\t\tparams: [EMPTY_ROW_VERSION, remoteVersion],\n\t}\n}\n","import type { CollectionDefinition, FieldDescriptor } from '@korajs/core'\nimport { QueryError } from '../errors'\nimport { lwwVersionWhereClause } from '../lww/row-version'\nimport type { QueryDescriptor, WhereOperators } from '../types'\n\n/**\n * Result of building a SQL query: the parameterized SQL string and its bound values.\n */\nexport interface SqlQuery {\n\tsql: string\n\tparams: unknown[]\n}\n\n/**\n * Build a SELECT query from a QueryDescriptor.\n * Automatically adds `WHERE _deleted = 0` to exclude soft-deleted records.\n *\n * @param descriptor - The query descriptor\n * @param fields - The field descriptors from the collection schema\n * @returns A parameterized SQL query\n */\nexport function buildSelectQuery(\n\tdescriptor: QueryDescriptor,\n\tfields: Record<string, FieldDescriptor>,\n): SqlQuery {\n\tconst params: unknown[] = []\n\tconst parts = [`SELECT * FROM ${descriptor.collection}`]\n\n\tconst whereClause = buildWhereClauseParts(descriptor.where, fields, params)\n\t// Always filter out soft-deleted records\n\tconst deletedFilter = '_deleted = 0'\n\tif (whereClause) {\n\t\tparts.push(`WHERE ${deletedFilter} AND ${whereClause}`)\n\t} else {\n\t\tparts.push(`WHERE ${deletedFilter}`)\n\t}\n\n\tif (descriptor.orderBy.length > 0) {\n\t\tconst orderParts = descriptor.orderBy.map((o) => {\n\t\t\tvalidateFieldName(o.field, fields)\n\t\t\treturn `${o.field} ${o.direction.toUpperCase()}`\n\t\t})\n\t\tparts.push(`ORDER BY ${orderParts.join(', ')}`)\n\t}\n\n\tif (descriptor.limit !== undefined) {\n\t\tparts.push(`LIMIT ${descriptor.limit}`)\n\t}\n\n\tif (descriptor.offset !== undefined) {\n\t\tparts.push(`OFFSET ${descriptor.offset}`)\n\t}\n\n\treturn { sql: parts.join(' '), params }\n}\n\n/**\n * Build a COUNT query from a QueryDescriptor.\n * Automatically adds `WHERE _deleted = 0`.\n *\n * @param descriptor - The query descriptor\n * @param fields - The field descriptors from the collection schema\n * @returns A parameterized SQL query that returns { count: number }\n */\nexport function buildCountQuery(\n\tdescriptor: QueryDescriptor,\n\tfields: Record<string, FieldDescriptor>,\n): SqlQuery {\n\tconst params: unknown[] = []\n\tconst parts = [`SELECT COUNT(*) as count FROM ${descriptor.collection}`]\n\n\tconst whereClause = buildWhereClauseParts(descriptor.where, fields, params)\n\tconst deletedFilter = '_deleted = 0'\n\tif (whereClause) {\n\t\tparts.push(`WHERE ${deletedFilter} AND ${whereClause}`)\n\t} else {\n\t\tparts.push(`WHERE ${deletedFilter}`)\n\t}\n\n\treturn { sql: parts.join(' '), params }\n}\n\n/**\n * Build an INSERT query for a collection record.\n *\n * @param collection - The collection name\n * @param record - The record data (already serialized with id, _created_at, _updated_at)\n * @returns A parameterized SQL query\n */\nexport function buildInsertQuery(collection: string, record: Record<string, unknown>): SqlQuery {\n\tconst columns = Object.keys(record)\n\tconst placeholders = columns.map(() => '?')\n\tconst params = Object.values(record)\n\n\tconst sql = `INSERT INTO ${collection} (${columns.join(', ')}) VALUES (${placeholders.join(', ')})`\n\treturn { sql, params }\n}\n\n/**\n * Build an UPDATE query for a collection record.\n *\n * @param collection - The collection name\n * @param id - The record ID\n * @param changes - The fields to update (already serialized)\n * @returns A parameterized SQL query\n */\nexport function buildUpdateQuery(\n\tcollection: string,\n\tid: string,\n\tchanges: Record<string, unknown>,\n): SqlQuery {\n\tconst setClauses = Object.keys(changes).map((col) => `${col} = ?`)\n\tconst params = [...Object.values(changes), id]\n\n\tconst sql = `UPDATE ${collection} SET ${setClauses.join(', ')} WHERE id = ?`\n\treturn { sql, params }\n}\n\n/**\n * Build a soft-delete query (SET _deleted = 1).\n *\n * @param collection - The collection name\n * @param id - The record ID\n * @param updatedAt - The timestamp to set on _updated_at\n * @returns A parameterized SQL query\n */\nexport function buildSoftDeleteQuery(\n\tcollection: string,\n\tid: string,\n\tupdatedAt: number,\n\tversion?: string,\n): SqlQuery {\n\tif (version !== undefined) {\n\t\treturn {\n\t\t\tsql: `UPDATE ${collection} SET _deleted = 1, _updated_at = ?, _version = ? WHERE id = ?`,\n\t\t\tparams: [updatedAt, version, id],\n\t\t}\n\t}\n\treturn {\n\t\tsql: `UPDATE ${collection} SET _deleted = 1, _updated_at = ? WHERE id = ?`,\n\t\tparams: [updatedAt, id],\n\t}\n}\n\n/**\n * Build an UPDATE that applies only when the row is missing or older than `remoteVersion`\n * (serialized HLC). Prevents stale remote sync from overwriting newer local materialized state.\n */\nexport function buildLwwUpdateQuery(\n\tcollection: string,\n\tid: string,\n\tchanges: Record<string, unknown>,\n\tremoteVersion: string,\n): SqlQuery {\n\tconst setClauses = Object.keys(changes).map((col) => `${col} = ?`)\n\tconst lww = lwwVersionWhereClause(remoteVersion)\n\tconst sql = `UPDATE ${collection} SET ${setClauses.join(', ')} WHERE id = ? AND ${lww.sql}`\n\tconst params = [...Object.values(changes), id, ...lww.params]\n\treturn { sql, params }\n}\n\n/**\n * Build a soft-delete that applies only when the row is older than `remoteVersion`.\n */\nexport function buildLwwSoftDeleteQuery(\n\tcollection: string,\n\tid: string,\n\tupdatedAt: number,\n\tversion: string,\n): SqlQuery {\n\tconst lww = lwwVersionWhereClause(version)\n\treturn {\n\t\tsql: `UPDATE ${collection} SET _deleted = 1, _updated_at = ?, _version = ? WHERE id = ? AND ${lww.sql}`,\n\t\tparams: [updatedAt, version, id, ...lww.params],\n\t}\n}\n\n/**\n * Build a WHERE clause from conditions, validating field names against the schema.\n *\n * @param where - The where conditions\n * @param fields - The field descriptors from the collection schema\n * @returns The SQL WHERE clause string and params, or null if no conditions\n */\nexport function buildWhereClause(\n\twhere: Record<string, unknown>,\n\tfields: Record<string, FieldDescriptor>,\n): SqlQuery | null {\n\tconst params: unknown[] = []\n\tconst result = buildWhereClauseParts(where, fields, params)\n\tif (!result) return null\n\treturn { sql: result, params }\n}\n\n// --- Internal helpers ---\n\nconst VALID_OPERATORS = new Set(['$eq', '$ne', '$gt', '$gte', '$lt', '$lte', '$in'])\n\nfunction buildWhereClauseParts(\n\twhere: Record<string, unknown>,\n\tfields: Record<string, FieldDescriptor>,\n\tparams: unknown[],\n): string | null {\n\tconst conditions: string[] = []\n\n\tfor (const [fieldName, value] of Object.entries(where)) {\n\t\tvalidateFieldName(fieldName, fields)\n\t\tconst descriptor = fields[fieldName]\n\n\t\tif (value !== null && typeof value === 'object' && !Array.isArray(value)) {\n\t\t\t// Operator object: { $gt: 5, $lt: 10 }\n\t\t\tconst ops = value as WhereOperators\n\t\t\tfor (const [op, opValue] of Object.entries(ops)) {\n\t\t\t\tif (!VALID_OPERATORS.has(op)) {\n\t\t\t\t\tthrow new QueryError(`Unknown operator \"${op}\" on field \"${fieldName}\"`, {\n\t\t\t\t\t\tfield: fieldName,\n\t\t\t\t\t\toperator: op,\n\t\t\t\t\t\tvalidOperators: [...VALID_OPERATORS],\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\tconditions.push(buildOperatorCondition(fieldName, op, opValue, descriptor, params))\n\t\t\t}\n\t\t} else {\n\t\t\t// Shorthand: { completed: false } means { completed: { $eq: false } }\n\t\t\tconditions.push(buildOperatorCondition(fieldName, '$eq', value, descriptor, params))\n\t\t}\n\t}\n\n\tif (conditions.length === 0) return null\n\treturn conditions.join(' AND ')\n}\n\nfunction buildOperatorCondition(\n\tfieldName: string,\n\toperator: string,\n\tvalue: unknown,\n\tdescriptor: FieldDescriptor | undefined,\n\tparams: unknown[],\n): string {\n\t// Serialize boolean values to 0/1 for SQL comparison\n\tconst sqlValue =\n\t\tdescriptor?.kind === 'boolean' && typeof value === 'boolean' ? (value ? 1 : 0) : value\n\n\tswitch (operator) {\n\t\tcase '$eq':\n\t\t\tif (sqlValue === null) {\n\t\t\t\treturn `${fieldName} IS NULL`\n\t\t\t}\n\t\t\tparams.push(sqlValue)\n\t\t\treturn `${fieldName} = ?`\n\t\tcase '$ne':\n\t\t\tif (sqlValue === null) {\n\t\t\t\treturn `${fieldName} IS NOT NULL`\n\t\t\t}\n\t\t\tparams.push(sqlValue)\n\t\t\treturn `${fieldName} != ?`\n\t\tcase '$gt':\n\t\t\tparams.push(sqlValue)\n\t\t\treturn `${fieldName} > ?`\n\t\tcase '$gte':\n\t\t\tparams.push(sqlValue)\n\t\t\treturn `${fieldName} >= ?`\n\t\tcase '$lt':\n\t\t\tparams.push(sqlValue)\n\t\t\treturn `${fieldName} < ?`\n\t\tcase '$lte':\n\t\t\tparams.push(sqlValue)\n\t\t\treturn `${fieldName} <= ?`\n\t\tcase '$in': {\n\t\t\tif (!Array.isArray(sqlValue)) {\n\t\t\t\tthrow new QueryError(`$in operator requires an array value for field \"${fieldName}\"`, {\n\t\t\t\t\tfield: fieldName,\n\t\t\t\t\treceived: typeof sqlValue,\n\t\t\t\t})\n\t\t\t}\n\t\t\tconst placeholders = sqlValue.map(() => '?')\n\t\t\tfor (const item of sqlValue) {\n\t\t\t\tparams.push(\n\t\t\t\t\tdescriptor?.kind === 'boolean' && typeof item === 'boolean' ? (item ? 1 : 0) : item,\n\t\t\t\t)\n\t\t\t}\n\t\t\treturn `${fieldName} IN (${placeholders.join(', ')})`\n\t\t}\n\t\tdefault:\n\t\t\tthrow new QueryError(`Unknown operator \"${operator}\"`, { operator })\n\t}\n}\n\nfunction validateFieldName(fieldName: string, fields: Record<string, FieldDescriptor>): void {\n\t// Allow schema fields plus metadata fields that map to query-able columns\n\tconst allowedFields = new Set([\n\t\t...Object.keys(fields),\n\t\t'id',\n\t\t'createdAt',\n\t\t'updatedAt',\n\t\t'_created_at',\n\t\t'_updated_at',\n\t])\n\tif (!allowedFields.has(fieldName)) {\n\t\tthrow new QueryError(\n\t\t\t`Unknown field \"${fieldName}\" in query. Available fields: ${[...allowedFields].join(', ')}`,\n\t\t\t{ field: fieldName },\n\t\t)\n\t}\n}\n","import { createOperation, generateUUIDv7, validateRecord } from '@korajs/core'\nimport { serializeRowVersion } from '../lww/row-version'\nimport { buildInsertQuery } from '../query/sql-builder'\nimport { serializeOperation, serializeRecord } from '../serialization/serializer'\nimport { allocateNextSequenceInTransaction } from '../store/sequence-allocator'\nimport type { CollectionRecord } from '../types'\nimport { resolveCausalDeps } from './resolve-causal-deps'\nimport type { LocalMutationContext } from './types'\n\n/**\n * Insert a record and persist the operation log entry atomically.\n */\nexport async function executeInsert(\n\tctx: LocalMutationContext,\n\tdata: Record<string, unknown>,\n): Promise<CollectionRecord> {\n\tconst validated = validateRecord(ctx.collection, ctx.definition, data, 'insert')\n\tconst recordId = generateUUIDv7()\n\n\tfor (const [fieldName, descriptor] of Object.entries(ctx.definition.fields)) {\n\t\tif (descriptor.auto && descriptor.kind === 'timestamp') {\n\t\t\tvalidated[fieldName] = Date.now()\n\t\t}\n\t}\n\n\tconst causalDeps = resolveCausalDeps(ctx)\n\n\tlet operation!: Awaited<ReturnType<typeof createOperation>>\n\tlet record!: Record<string, unknown>\n\n\tawait ctx.adapter.transaction(async (tx) => {\n\t\tconst sequenceNumber = await allocateNextSequenceInTransaction(tx, ctx.nodeId)\n\t\toperation = await createOperation(\n\t\t\t{\n\t\t\t\tnodeId: ctx.nodeId,\n\t\t\t\ttype: 'insert',\n\t\t\t\tcollection: ctx.collection,\n\t\t\t\trecordId,\n\t\t\t\tdata: { ...validated },\n\t\t\t\tpreviousData: null,\n\t\t\t\tsequenceNumber,\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(ctx.collection, operation.id, ctx.inTransaction)\n\n\t\tconst serializedData = serializeRecord(validated, ctx.definition.fields)\n\t\tconst version = serializeRowVersion(operation.timestamp)\n\t\trecord = {\n\t\t\tid: recordId,\n\t\t\t...serializedData,\n\t\t\t_created_at: operation.timestamp.wallTime,\n\t\t\t_updated_at: operation.timestamp.wallTime,\n\t\t\t_version: version,\n\t\t}\n\n\t\tconst builtInsert = buildInsertQuery(ctx.collection, record)\n\t\tconst opInsert = buildInsertQuery(\n\t\t\t`_kora_ops_${ctx.collection}`,\n\t\t\tserializeOperation(operation) as unknown as Record<string, unknown>,\n\t\t)\n\n\t\tawait tx.execute(builtInsert.sql, builtInsert.params)\n\t\tawait tx.execute(opInsert.sql, opInsert.params)\n\t})\n\n\tctx.onMutation(ctx.collection, operation)\n\n\treturn {\n\t\tid: recordId,\n\t\t...validated,\n\t\tcreatedAt: operation.timestamp.wallTime,\n\t\tupdatedAt: operation.timestamp.wallTime,\n\t}\n}\n","import type { StorageAdapter, Transaction } from '../types'\n\ninterface SequenceRow {\n\tsequence_number: number\n}\n\n/**\n * Atomically increment and return the next sequence number for a node.\n * Uses SQLite UPSERT + RETURNING so concurrent tabs do not reuse sequence slots.\n */\nexport async function allocateNextSequenceNumber(\n\tadapter: StorageAdapter,\n\tnodeId: string,\n): Promise<number> {\n\tconst rows = await adapter.query<SequenceRow>(\n\t\t`INSERT INTO _kora_version_vector (node_id, sequence_number) VALUES (?, 1)\n ON CONFLICT(node_id) DO UPDATE SET sequence_number = sequence_number + 1\n RETURNING sequence_number`,\n\t\t[nodeId],\n\t)\n\tconst seq = rows[0]?.sequence_number\n\tif (seq === undefined) {\n\t\tthrow new Error(`Failed to allocate sequence number for node \"${nodeId}\"`)\n\t}\n\treturn seq\n}\n\n/**\n * Allocate the next sequence inside an existing storage transaction.\n */\nexport async function allocateNextSequenceInTransaction(\n\ttx: Transaction,\n\tnodeId: string,\n): Promise<number> {\n\tconst rows = await tx.query<SequenceRow>(\n\t\t`INSERT INTO _kora_version_vector (node_id, sequence_number) VALUES (?, 1)\n ON CONFLICT(node_id) DO UPDATE SET sequence_number = sequence_number + 1\n RETURNING sequence_number`,\n\t\t[nodeId],\n\t)\n\tconst seq = rows[0]?.sequence_number\n\tif (seq === undefined) {\n\t\tthrow new Error(`Failed to allocate sequence number for node \"${nodeId}\" in transaction`)\n\t}\n\treturn seq\n}\n\n/**\n * Read the current sequence for a node without incrementing.\n */\nexport async function readSequenceNumber(adapter: StorageAdapter, nodeId: string): Promise<number> {\n\tconst rows = await adapter.query<SequenceRow>(\n\t\t'SELECT sequence_number FROM _kora_version_vector WHERE node_id = ?',\n\t\t[nodeId],\n\t)\n\treturn rows[0]?.sequence_number ?? 0\n}\n","import type { LocalMutationContext } from './types'\n\n/**\n * Merge explicit parent deps (e.g. referential cascade) with tracker-derived deps.\n */\nexport function resolveCausalDeps(ctx: LocalMutationContext): string[] {\n\tconst merged: string[] = []\n\tfor (const id of ctx.extraCausalDeps ?? []) {\n\t\tif (!merged.includes(id)) {\n\t\t\tmerged.push(id)\n\t\t}\n\t}\n\tfor (const id of ctx.causalTracker?.nextCausalDeps(ctx.collection, ctx.inTransaction) ?? []) {\n\t\tif (!merged.includes(id)) {\n\t\t\tmerged.push(id)\n\t\t}\n\t}\n\treturn merged\n}\n","import type { AtomicOp } from '@korajs/core'\nimport {\n\tcreateOperation,\n\tisAtomicOp,\n\tresolveAtomicOp,\n\ttoAtomicOp,\n\tvalidateRecord,\n} from '@korajs/core'\nimport { RecordNotFoundError } from '../errors'\nimport { serializeRowVersion } from '../lww/row-version'\nimport { buildInsertQuery, buildUpdateQuery } from '../query/sql-builder'\nimport { deserializeRecord, serializeOperation, serializeRecord } from '../serialization/serializer'\nimport { validateUpdateStateMachine } from '../state-machine/state-validator'\nimport { allocateNextSequenceInTransaction } from '../store/sequence-allocator'\nimport type { CollectionRecord, RawCollectionRow } from '../types'\nimport { resolveCausalDeps } from './resolve-causal-deps'\nimport type { LocalMutationContext } from './types'\n\n/**\n * Update a record and persist the operation log entry atomically.\n */\nexport async function executeUpdate(\n\tctx: LocalMutationContext,\n\tid: string,\n\tdata: Record<string, unknown>,\n): Promise<CollectionRecord> {\n\tconst currentRows = await ctx.adapter.query<RawCollectionRow>(\n\t\t`SELECT * FROM ${ctx.collection} WHERE id = ? AND _deleted = 0`,\n\t\t[id],\n\t)\n\tconst currentRow = currentRows[0]\n\tif (!currentRow) {\n\t\tthrow new RecordNotFoundError(ctx.collection, id)\n\t}\n\n\tlet validated = validateRecord(ctx.collection, ctx.definition, data, 'update')\n\tconst currentRecord = deserializeRecord(currentRow, ctx.definition.fields)\n\tvalidated = validateUpdateStateMachine(\n\t\tctx.collection,\n\t\tid,\n\t\tctx.definition,\n\t\tcurrentRecord,\n\t\tvalidated,\n\t)\n\n\tif (Object.keys(validated).length === 0) {\n\t\treturn { ...currentRecord }\n\t}\n\n\tconst previousData: Record<string, unknown> = {}\n\tconst resolvedData: Record<string, unknown> = {}\n\tconst atomicOps: Record<string, AtomicOp> = {}\n\n\tfor (const key of Object.keys(validated)) {\n\t\tconst value = validated[key]\n\t\tpreviousData[key] = currentRecord[key]\n\n\t\tif (isAtomicOp(value)) {\n\t\t\tresolvedData[key] = resolveAtomicOp(currentRecord[key], value)\n\t\t\tatomicOps[key] = toAtomicOp(value)\n\t\t} else {\n\t\t\tresolvedData[key] = value\n\t\t}\n\t}\n\n\tconst hasAtomicOps = Object.keys(atomicOps).length > 0\n\tconst causalDeps = resolveCausalDeps(ctx)\n\tlet operation!: Awaited<ReturnType<typeof createOperation>>\n\n\tawait ctx.adapter.transaction(async (tx) => {\n\t\tconst sequenceNumber = await allocateNextSequenceInTransaction(tx, ctx.nodeId)\n\t\toperation = await createOperation(\n\t\t\t{\n\t\t\t\tnodeId: ctx.nodeId,\n\t\t\t\ttype: 'update',\n\t\t\t\tcollection: ctx.collection,\n\t\t\t\trecordId: id,\n\t\t\t\tdata: { ...resolvedData },\n\t\t\t\tpreviousData,\n\t\t\t\tsequenceNumber,\n\t\t\t\tcausalDeps,\n\t\t\t\tschemaVersion: ctx.schema.version,\n\t\t\t\t...(hasAtomicOps ? { atomicOps } : {}),\n\t\t\t},\n\t\t\tctx.clock,\n\t\t)\n\t\tctx.causalTracker?.afterOperation(ctx.collection, operation.id, ctx.inTransaction)\n\n\t\tconst serializedChanges = serializeRecord(resolvedData, ctx.definition.fields)\n\t\tconst version = serializeRowVersion(operation.timestamp)\n\t\tconst updateQuery = buildUpdateQuery(ctx.collection, id, {\n\t\t\t...serializedChanges,\n\t\t\t_updated_at: operation.timestamp.wallTime,\n\t\t\t_version: version,\n\t\t})\n\t\tconst opInsert = buildInsertQuery(\n\t\t\t`_kora_ops_${ctx.collection}`,\n\t\t\tserializeOperation(operation) as unknown as Record<string, unknown>,\n\t\t)\n\n\t\tawait tx.execute(updateQuery.sql, updateQuery.params)\n\t\tawait tx.execute(opInsert.sql, opInsert.params)\n\t})\n\n\tctx.onMutation(ctx.collection, operation)\n\n\tconst rows = await ctx.adapter.query<RawCollectionRow>(\n\t\t`SELECT * FROM ${ctx.collection} WHERE id = ? AND _deleted = 0`,\n\t\t[id],\n\t)\n\tconst row = rows[0]\n\tif (!row) {\n\t\tthrow new RecordNotFoundError(ctx.collection, id)\n\t}\n\treturn deserializeRecord(row, ctx.definition.fields)\n}\n","import { KoraError, validateTransition } from '@korajs/core'\nimport type {\n\tCollectionDefinition,\n\tStateMachineConstraint,\n\tStateMachineDefinition,\n} from '@korajs/core'\n\n/**\n * Error thrown when a local mutation attempts an invalid state transition.\n *\n * Contains enough context to debug without reproduction:\n * the collection, record, field, current state, attempted state, and allowed transitions.\n */\nexport class InvalidStateTransitionError extends KoraError {\n\tconstructor(\n\t\tpublic readonly collection: string,\n\t\tpublic readonly recordId: string,\n\t\tpublic readonly field: string,\n\t\tpublic readonly fromState: string,\n\t\tpublic readonly toState: string,\n\t\tpublic readonly allowedStates: string[],\n\t) {\n\t\tsuper(\n\t\t\t`Invalid state transition in collection \"${collection}\": ` +\n\t\t\t\t`cannot transition field \"${field}\" from \"${fromState}\" to \"${toState}\". ` +\n\t\t\t\t`Allowed transitions from \"${fromState}\": ${allowedStates.length > 0 ? allowedStates.join(', ') : '(none -- terminal state)'}`,\n\t\t\t'INVALID_STATE_TRANSITION',\n\t\t\t{ collection, recordId, field, fromState, toState, allowedStates },\n\t\t)\n\t\tthis.name = 'InvalidStateTransitionError'\n\t}\n}\n\n/**\n * Validates a state machine transition for a local mutation (insert or update).\n *\n * For inserts: validates that the initial state (from the data or the default value)\n * is a known state in the state machine.\n *\n * For updates: looks up the current state field value and checks whether\n * the transition to the new value is allowed.\n *\n * @param collectionName - Name of the collection\n * @param recordId - The record being mutated\n * @param stateMachine - The state machine definition\n * @param currentState - The current value of the state field (null for inserts)\n * @param newState - The new value being set for the state field\n * @returns An object indicating whether the transition is valid, and if not, the allowed states.\n * When `onInvalidTransition` is 'last-valid-state', callers should suppress the field update\n * rather than throwing.\n */\nexport function validateStateTransition(\n\tcollectionName: string,\n\trecordId: string,\n\tstateMachine: StateMachineDefinition,\n\tcurrentState: string | null,\n\tnewState: string,\n): { valid: boolean; allowedStates: string[] } {\n\t// For inserts, any valid enum value is acceptable as the initial state\n\t// (schema validation already ensures the value is a valid enum value)\n\tif (currentState === null) {\n\t\treturn { valid: true, allowedStates: [] }\n\t}\n\n\t// Same-state transitions are always valid (idempotent updates)\n\tif (currentState === newState) {\n\t\treturn { valid: true, allowedStates: stateMachine.transitions[currentState] ?? [] }\n\t}\n\n\tconst constraint: StateMachineConstraint = {\n\t\tfield: stateMachine.field,\n\t\tcollection: collectionName,\n\t\ttransitions: stateMachine.transitions,\n\t}\n\tconst transitionResult = validateTransition(constraint, currentState, newState)\n\tif (transitionResult.valid) {\n\t\treturn { valid: true, allowedStates: transitionResult.allowedTargets }\n\t}\n\n\tconst allowedStates = transitionResult.allowedTargets\n\n\tif (stateMachine.onInvalidTransition === 'reject') {\n\t\tthrow new InvalidStateTransitionError(\n\t\t\tcollectionName,\n\t\t\trecordId,\n\t\t\tstateMachine.field,\n\t\t\tcurrentState,\n\t\t\tnewState,\n\t\t\tallowedStates,\n\t\t)\n\t}\n\n\t// 'last-valid-state': return invalid so the caller can suppress the field update\n\treturn { valid: false, allowedStates }\n}\n\n/**\n * Checks whether a collection update data object contains a change to the state machine field,\n * and if so, validates the transition.\n *\n * If the state field is not in the update data, returns the data unchanged.\n * If the transition is invalid and mode is 'last-valid-state', removes the field from the data.\n * If the transition is invalid and mode is 'reject', throws InvalidStateTransitionError.\n *\n * @param collectionName - Name of the collection\n * @param recordId - The record being updated\n * @param collectionDef - The collection definition from the schema\n * @param currentRecord - The current record data (must include the state field)\n * @param updateData - The partial update data\n * @returns The update data, potentially with the state field removed if invalid and mode is 'last-valid-state'\n */\nexport function validateUpdateStateMachine(\n\tcollectionName: string,\n\trecordId: string,\n\tcollectionDef: CollectionDefinition,\n\tcurrentRecord: Record<string, unknown>,\n\tupdateData: Record<string, unknown>,\n): Record<string, unknown> {\n\tconst stateMachine = collectionDef.stateMachine\n\tif (stateMachine === undefined) {\n\t\treturn updateData\n\t}\n\n\tconst stateField = stateMachine.field\n\tif (!(stateField in updateData)) {\n\t\t// State field not being changed -- no validation needed\n\t\treturn updateData\n\t}\n\n\tconst currentState = currentRecord[stateField]\n\tconst newState = updateData[stateField]\n\n\t// Both values must be strings for state machine validation\n\tif (typeof currentState !== 'string' || typeof newState !== 'string') {\n\t\treturn updateData\n\t}\n\n\tconst result = validateStateTransition(\n\t\tcollectionName,\n\t\trecordId,\n\t\tstateMachine,\n\t\tcurrentState,\n\t\tnewState,\n\t)\n\n\tif (result.valid) {\n\t\treturn updateData\n\t}\n\n\t// Mode is 'last-valid-state': silently remove the state field from the update\n\tconst filtered = { ...updateData }\n\tdelete filtered[stateField]\n\n\t// If no fields remain after removing the state field, the update becomes a no-op.\n\t// Return the empty object -- the caller can decide whether to proceed.\n\treturn filtered\n}\n","import { createOperation } from '@korajs/core'\nimport type { Operation } from '@korajs/core'\nimport { RecordNotFoundError } from '../errors'\nimport { serializeRowVersion } from '../lww/row-version'\nimport { buildInsertQuery, buildSoftDeleteQuery } from '../query/sql-builder'\nimport { serializeOperation } from '../serialization/serializer'\nimport { allocateNextSequenceInTransaction } from '../store/sequence-allocator'\nimport type { RawCollectionRow } from '../types'\nimport { resolveCausalDeps } from './resolve-causal-deps'\nimport type { LocalMutationContext } from './types'\n\nexport interface ExecuteDeleteOptions {\n\t/** When true, skip RelationEnforcer (caller already enforced referential integrity). */\n\tskipReferentialEnforcement?: boolean\n\t/** Pre-built delete operation (avoids duplicate sequence allocation). */\n\toperation?: Operation\n}\n\n/**\n * Soft-delete a record and persist the operation log entry atomically.\n * Returns the primary delete operation and any cascaded side-effect operations.\n */\nexport async function executeDelete(\n\tctx: LocalMutationContext,\n\tid: string,\n\toptions?: ExecuteDeleteOptions,\n): Promise<Operation[]> {\n\tconst currentRows = await ctx.adapter.query<RawCollectionRow>(\n\t\t`SELECT * FROM ${ctx.collection} WHERE id = ? AND _deleted = 0`,\n\t\t[id],\n\t)\n\tif (!currentRows[0]) {\n\t\tthrow new RecordNotFoundError(ctx.collection, id)\n\t}\n\n\tconst causalDeps = resolveCausalDeps(ctx)\n\tlet operation = options?.operation\n\tconst cascadedOps: Operation[] = []\n\n\tawait ctx.adapter.transaction(async (tx) => {\n\t\tif (!operation) {\n\t\t\tconst sequenceNumber = await allocateNextSequenceInTransaction(tx, ctx.nodeId)\n\t\t\toperation = await createOperation(\n\t\t\t\t{\n\t\t\t\t\tnodeId: ctx.nodeId,\n\t\t\t\t\ttype: 'delete',\n\t\t\t\t\tcollection: ctx.collection,\n\t\t\t\t\trecordId: id,\n\t\t\t\t\tdata: null,\n\t\t\t\t\tpreviousData: null,\n\t\t\t\t\tsequenceNumber,\n\t\t\t\t\tcausalDeps,\n\t\t\t\t\tschemaVersion: ctx.schema.version,\n\t\t\t\t},\n\t\t\t\tctx.clock,\n\t\t\t)\n\t\t\tctx.causalTracker?.afterOperation(ctx.collection, operation.id, ctx.inTransaction)\n\t\t}\n\n\t\tif (ctx.relationEnforcer && !options?.skipReferentialEnforcement) {\n\t\t\tconst enforcementResult = await ctx.relationEnforcer.enforceDelete(ctx.collection, id, tx, [\n\t\t\t\toperation.id,\n\t\t\t])\n\t\t\tcascadedOps.push(...enforcementResult.operations)\n\t\t}\n\n\t\tconst version = serializeRowVersion(operation.timestamp)\n\t\tconst deleteQuery = buildSoftDeleteQuery(\n\t\t\tctx.collection,\n\t\t\tid,\n\t\t\toperation.timestamp.wallTime,\n\t\t\tversion,\n\t\t)\n\t\tconst opInsert = buildInsertQuery(\n\t\t\t`_kora_ops_${ctx.collection}`,\n\t\t\tserializeOperation(operation) as unknown as Record<string, unknown>,\n\t\t)\n\n\t\tawait tx.execute(deleteQuery.sql, deleteQuery.params)\n\t\tawait tx.execute(opInsert.sql, opInsert.params)\n\t})\n\n\tif (!operation) {\n\t\tthrow new Error('Delete operation was not created')\n\t}\n\n\tctx.onMutation(ctx.collection, operation)\n\tfor (const cascadedOp of cascadedOps) {\n\t\tctx.onMutation(cascadedOp.collection, cascadedOp)\n\t}\n\n\treturn [operation, ...cascadedOps]\n}\n"],"mappings":"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","names":["import_core","import_core","import_core","import_core","import_core","import_core"]}
1
+ {"version":3,"sources":["../src/internal.ts","../src/serialization/serializer.ts","../src/serialization/richtext-serializer.ts","../src/serialization/op-data-encoding.ts","../src/errors.ts","../src/lww/row-version.ts","../src/query/sql-builder.ts","../src/mutations/execute-insert.ts","../src/lww/field-versions.ts","../src/store/sequence-allocator.ts","../src/mutations/resolve-causal-deps.ts","../src/mutations/execute-update.ts","../src/state-machine/state-validator.ts","../src/mutations/execute-delete.ts"],"sourcesContent":["// Internal exports — shared within @kora packages but NOT part of the public API.\n// Other @kora packages can import from '@korajs/store/internal' if needed.\n\nexport {\n\tserializeOperation,\n\tdeserializeOperation,\n\tdeserializeOperationWithCollection,\n\tserializeRecord,\n\tdeserializeRecord,\n} from './serialization/serializer'\n\nexport {\n\tbuildSelectQuery,\n\tbuildCountQuery,\n\tbuildInsertQuery,\n\tbuildUpdateQuery,\n\tbuildLwwUpdateQuery,\n\tbuildSoftDeleteQuery,\n\tbuildLwwSoftDeleteQuery,\n\tbuildWhereClause,\n} from './query/sql-builder'\nexport {\n\tserializeRowVersion,\n\trowVersionFromRecord,\n\tisIncomingNewerThanRow,\n} from './lww/row-version'\nexport type { SqlQuery } from './query/sql-builder'\n\nexport type {\n\tOperationRow,\n\tRawCollectionRow,\n\tMetaRow,\n\tVersionVectorRow,\n\tSubscription,\n} from './types'\n\nexport { executeInsert } from './mutations/execute-insert'\nexport { executeUpdate } from './mutations/execute-update'\nexport { executeDelete } from './mutations/execute-delete'\nexport { resolveCausalDeps } from './mutations/resolve-causal-deps'\nexport type { ExecuteDeleteOptions } from './mutations/execute-delete'\nexport type { LocalMutationContext } from './mutations/types'\n","import { HybridLogicalClock } from '@korajs/core'\nimport type { CollectionDefinition, FieldDescriptor, Operation } from '@korajs/core'\nimport type { CollectionRecord, OperationRow, RawCollectionRow } from '../types'\nimport { decodeRichtext, encodeRichtext } from './richtext-serializer'\n\n/**\n * Serialize a JS record to SQL-compatible values for INSERT/UPDATE.\n * Transforms: boolean → 0/1, array → JSON string, richtext → Yjs binary update.\n *\n * @param data - The record data with JS-native types\n * @param fields - The field descriptors from the schema\n * @returns An object with SQL-compatible values\n */\nexport function serializeRecord(\n\tdata: Record<string, unknown>,\n\tfields: Record<string, FieldDescriptor>,\n): Record<string, unknown> {\n\tconst result: Record<string, unknown> = {}\n\tfor (const [key, value] of Object.entries(data)) {\n\t\tconst descriptor = fields[key]\n\t\tif (!descriptor) {\n\t\t\tresult[key] = value\n\t\t\tcontinue\n\t\t}\n\t\tresult[key] = serializeValue(value, descriptor)\n\t}\n\treturn result\n}\n\n/**\n * Deserialize a SQL row to JS-native types for the application layer.\n * Transforms: 0/1 → boolean, JSON string → array, strips _deleted, maps _created_at/_updated_at.\n *\n * @param row - The raw SQL row\n * @param fields - The field descriptors from the schema\n * @returns A CollectionRecord with JS-native types\n */\nexport function deserializeRecord(\n\trow: RawCollectionRow,\n\tfields: Record<string, FieldDescriptor>,\n): CollectionRecord {\n\tconst result: CollectionRecord = {\n\t\tid: row.id,\n\t\tcreatedAt: row._created_at,\n\t\tupdatedAt: row._updated_at,\n\t}\n\n\tfor (const [key, descriptor] of Object.entries(fields)) {\n\t\tconst rawValue = row[key]\n\t\tif (rawValue === undefined || rawValue === null) {\n\t\t\tresult[key] = rawValue ?? null\n\t\t\tcontinue\n\t\t}\n\t\tresult[key] = deserializeValue(rawValue, descriptor)\n\t}\n\n\treturn result\n}\n\n/**\n * Internal key used to embed atomicOps metadata in the data JSON column.\n * This avoids adding a new column to the ops table (no migration needed).\n */\nconst ATOMIC_OPS_KEY = '__kora_atomic_ops__'\n\n/**\n * Internal key used to embed transactionId in the data JSON column.\n */\nconst TX_ID_KEY = '__kora_tx_id__'\n\n/**\n * Internal key used to embed mutationName in the data JSON column.\n */\nconst MUTATION_NAME_KEY = '__kora_mutation__'\n\n/**\n * Serialize an Operation to a row for the operations log table.\n *\n * @param op - The operation to serialize\n * @returns An OperationRow suitable for SQL INSERT\n */\nexport function serializeOperation(op: Operation): OperationRow {\n\tconst hasMetadata = op.transactionId !== undefined || op.mutationName !== undefined\n\tlet dataPayload: Record<string, unknown> | null = null\n\tif (op.data) {\n\t\t// Embed metadata in the data JSON when present\n\t\tdataPayload = { ...op.data }\n\t\tif (op.atomicOps !== undefined && Object.keys(op.atomicOps).length > 0) {\n\t\t\tdataPayload[ATOMIC_OPS_KEY] = op.atomicOps\n\t\t}\n\t\tif (op.transactionId !== undefined) {\n\t\t\tdataPayload[TX_ID_KEY] = op.transactionId\n\t\t}\n\t\tif (op.mutationName !== undefined) {\n\t\t\tdataPayload[MUTATION_NAME_KEY] = op.mutationName\n\t\t}\n\t} else if (hasMetadata) {\n\t\t// For delete operations (data is null), we still need to store metadata\n\t\tdataPayload = {}\n\t\tif (op.transactionId !== undefined) {\n\t\t\tdataPayload[TX_ID_KEY] = op.transactionId\n\t\t}\n\t\tif (op.mutationName !== undefined) {\n\t\t\tdataPayload[MUTATION_NAME_KEY] = op.mutationName\n\t\t}\n\t}\n\n\treturn {\n\t\tid: op.id,\n\t\tnode_id: op.nodeId,\n\t\ttype: op.type,\n\t\trecord_id: op.recordId,\n\t\tdata: dataPayload ? JSON.stringify(dataPayload) : null,\n\t\tprevious_data: op.previousData ? JSON.stringify(op.previousData) : null,\n\t\ttimestamp: HybridLogicalClock.serialize(op.timestamp),\n\t\tsequence_number: op.sequenceNumber,\n\t\tcausal_deps: JSON.stringify(op.causalDeps),\n\t\tschema_version: op.schemaVersion,\n\t}\n}\n\n/**\n * Deserialize a row from the operations log table back to an Operation.\n *\n * @param row - The raw operation row from SQL\n * @returns The deserialized Operation object\n */\nexport function deserializeOperation(row: OperationRow): Operation {\n\tlet data: Record<string, unknown> | null = null\n\tlet atomicOps: Record<string, unknown> | undefined\n\tlet transactionId: string | undefined\n\tlet mutationName: string | undefined\n\n\tif (row.data) {\n\t\tconst parsed = JSON.parse(row.data) as Record<string, unknown>\n\t\t// Extract embedded metadata keys\n\t\tif (ATOMIC_OPS_KEY in parsed) {\n\t\t\tatomicOps = parsed[ATOMIC_OPS_KEY] as Record<string, unknown>\n\t\t}\n\t\tif (TX_ID_KEY in parsed) {\n\t\t\ttransactionId = parsed[TX_ID_KEY] as string\n\t\t}\n\t\tif (MUTATION_NAME_KEY in parsed) {\n\t\t\tmutationName = parsed[MUTATION_NAME_KEY] as string\n\t\t}\n\t\t// Remove metadata keys from data\n\t\tconst { [ATOMIC_OPS_KEY]: _a, [TX_ID_KEY]: _t, [MUTATION_NAME_KEY]: _m, ...rest } = parsed\n\t\tdata = Object.keys(rest).length > 0 ? rest : null\n\t}\n\n\treturn {\n\t\tid: row.id,\n\t\tnodeId: row.node_id,\n\t\ttype: row.type as Operation['type'],\n\t\tcollection: '', // Collection name is derived from the table name by the caller\n\t\trecordId: row.record_id,\n\t\tdata,\n\t\tpreviousData: row.previous_data\n\t\t\t? (JSON.parse(row.previous_data) as Record<string, unknown>)\n\t\t\t: null,\n\t\ttimestamp: HybridLogicalClock.deserialize(row.timestamp),\n\t\tsequenceNumber: row.sequence_number,\n\t\tcausalDeps: JSON.parse(row.causal_deps) as string[],\n\t\tschemaVersion: row.schema_version,\n\t\t...(atomicOps !== undefined ? { atomicOps: atomicOps as Operation['atomicOps'] } : {}),\n\t\t...(transactionId !== undefined ? { transactionId } : {}),\n\t\t...(mutationName !== undefined ? { mutationName } : {}),\n\t}\n}\n\n/**\n * Deserialize an operation row with collection name already known.\n */\nexport function deserializeOperationWithCollection(\n\trow: OperationRow,\n\tcollection: string,\n): Operation {\n\tconst op = deserializeOperation(row)\n\treturn { ...op, collection }\n}\n\nfunction serializeValue(value: unknown, descriptor: FieldDescriptor): unknown {\n\tif (value === null || value === undefined) {\n\t\treturn null\n\t}\n\n\tswitch (descriptor.kind) {\n\t\tcase 'boolean':\n\t\t\treturn value ? 1 : 0\n\t\tcase 'array':\n\t\t\treturn JSON.stringify(value)\n\t\tcase 'richtext':\n\t\t\t// May be a record-shaped value (string/bytes) or an op-data value\n\t\t\t// (tagged { $koraBytes }) — encodeRichtext accepts every form.\n\t\t\treturn encodeRichtext(value as Parameters<typeof encodeRichtext>[0])\n\t\tdefault:\n\t\t\treturn value\n\t}\n}\n\nfunction deserializeValue(value: unknown, descriptor: FieldDescriptor): unknown {\n\tswitch (descriptor.kind) {\n\t\tcase 'boolean':\n\t\t\treturn value === 1 || value === true\n\t\tcase 'array':\n\t\t\tif (typeof value === 'string') {\n\t\t\t\treturn JSON.parse(value) as unknown[]\n\t\t\t}\n\t\t\treturn value\n\t\tcase 'richtext':\n\t\t\treturn decodeRichtext(value)\n\t\tdefault:\n\t\t\treturn value\n\t}\n}\n","import * as Y from 'yjs'\nimport {\n\ttype KoraBytesValue,\n\tdecodeRichtextOpDataValue,\n\tisKoraBytesValue,\n\tisLegacyNumericByteObject,\n} from './op-data-encoding'\n\nconst TEXT_KEY = 'content'\n\nexport type RichtextInput = string | Uint8Array | ArrayBuffer | null | undefined\n\n/**\n * Encodes richtext values into Yjs document updates.\n *\n * Also accepts the tagged `{ $koraBytes }` form that binary richtext values\n * take inside `op.data` (and, for old dev databases, the pre-fix numeric-key\n * object shape), so every consumer that writes op-data values to columns\n * inherits the decoding. Plain strings keep their exact historical behavior:\n * encoded as a fresh Yjs document containing the string.\n */\nexport function encodeRichtext(value: RichtextInput | KoraBytesValue): Uint8Array | null {\n\tif (value === null || value === undefined) {\n\t\treturn null\n\t}\n\n\tif (typeof value === 'string') {\n\t\tconst doc = new Y.Doc()\n\t\tdoc.getText(TEXT_KEY).insert(0, value)\n\t\treturn Y.encodeStateAsUpdate(doc)\n\t}\n\n\tif (value instanceof Uint8Array) {\n\t\treturn value\n\t}\n\n\tif (value instanceof ArrayBuffer) {\n\t\treturn new Uint8Array(value)\n\t}\n\n\tif (isKoraBytesValue(value) || isLegacyNumericByteObject(value)) {\n\t\tconst decoded = decodeRichtextOpDataValue(value)\n\t\t// Both accepted shapes decode to bytes; strings were handled above.\n\t\treturn decoded instanceof Uint8Array ? decoded : null\n\t}\n\n\tthrow new Error('Richtext value must be a string, Uint8Array, ArrayBuffer, null, or undefined.')\n}\n\n/**\n * Decodes driver-provided richtext values into Uint8Array.\n */\nexport function decodeRichtext(value: unknown): Uint8Array | null {\n\tif (value === null || value === undefined) {\n\t\treturn null\n\t}\n\n\tif (typeof Buffer !== 'undefined' && Buffer.isBuffer(value)) {\n\t\treturn new Uint8Array(value)\n\t}\n\n\tif (value instanceof Uint8Array) {\n\t\treturn value\n\t}\n\n\tif (value instanceof ArrayBuffer) {\n\t\treturn new Uint8Array(value)\n\t}\n\n\tthrow new Error(\n\t\t'Richtext storage value must be Uint8Array, ArrayBuffer, Buffer, null, or undefined.',\n\t)\n}\n\n/**\n * Reads plain text from a richtext Yjs state update.\n */\nexport function richtextToPlainText(value: RichtextInput): string {\n\tconst encoded = encodeRichtext(value)\n\tif (!encoded) return ''\n\n\tconst doc = new Y.Doc()\n\tY.applyUpdate(doc, encoded)\n\treturn doc.getText(TEXT_KEY).toString()\n}\n\n/**\n * Compares two richtext values by decoded plain text.\n * Yjs update bytes are not stable across separate encodes of the same string.\n */\nexport function richtextStatesEqual(a: unknown, b: unknown): boolean {\n\ttry {\n\t\treturn richtextToPlainText(a as RichtextInput) === richtextToPlainText(b as RichtextInput)\n\t} catch {\n\t\treturn false\n\t}\n}\n","import {\n\ttype KoraBytesValue,\n\tbase64ToBytes,\n\tbytesToBase64,\n\tdecodeBytesFromOpData,\n\tencodeBytesForOpData,\n\tisKoraBytesValue,\n\tisLegacyNumericByteObject,\n} from '@korajs/core'\nimport type { FieldDescriptor } from '@korajs/core'\n\n/**\n * The canonical binary op-data encoding lives in `@korajs/core` because\n * `op.data` is a core concept shared by store (creation, persistence) and merge\n * (CRDT merge). These re-exports keep existing store-internal import paths\n * working while the single source of truth is the core module.\n */\nexport type { KoraBytesValue }\nexport { base64ToBytes, bytesToBase64, isKoraBytesValue, isLegacyNumericByteObject }\n\n/** @deprecated Use {@link encodeRichtextForOpData}; kept for existing imports. */\nexport const encodeRichtextForOpData = encodeBytesForOpData\n/** @deprecated Use {@link decodeRichtextOpDataValue}; kept for existing imports. */\nexport const decodeRichtextOpDataValue = decodeBytesFromOpData\n\n/**\n * Apply {@link encodeBytesForOpData} to every richtext-typed field in an\n * operation's data payload. Called at operation creation, BEFORE the payload\n * is content-hashed, so the hash input, persisted JSON, wire payload, and the\n * value the merge engine sees are the identical canonical value. Non-richtext\n * fields are untouched.\n */\nexport function encodeRichtextFieldsForOpData(\n\tdata: Record<string, unknown>,\n\tfields: Record<string, FieldDescriptor>,\n): Record<string, unknown> {\n\tconst result: Record<string, unknown> = { ...data }\n\tfor (const [key, value] of Object.entries(data)) {\n\t\tif (fields[key]?.kind !== 'richtext') {\n\t\t\tcontinue\n\t\t}\n\t\tif (typeof value === 'string' || value instanceof Uint8Array || value instanceof ArrayBuffer) {\n\t\t\tresult[key] = encodeBytesForOpData(value)\n\t\t}\n\t}\n\treturn result\n}\n\n/**\n * Reverse of {@link encodeRichtextFieldsForOpData}: decode tagged (or legacy\n * numeric-key) richtext values in an op-data payload back to record-shaped\n * values (string or Uint8Array). Null/undefined and plain strings pass\n * through, preserving pre-fix behavior exactly.\n */\nexport function decodeRichtextFieldsFromOpData(\n\tdata: Record<string, unknown>,\n\tfields: Record<string, FieldDescriptor>,\n): Record<string, unknown> {\n\tconst result: Record<string, unknown> = { ...data }\n\tfor (const [key, value] of Object.entries(data)) {\n\t\tif (fields[key]?.kind !== 'richtext' || value === null || value === undefined) {\n\t\t\tcontinue\n\t\t}\n\t\tresult[key] = decodeBytesFromOpData(value)\n\t}\n\treturn result\n}\n","import { KoraError } from '@korajs/core'\n\n/**\n * Thrown when a query is invalid (bad field names, invalid operators, etc.).\n */\nexport class QueryError extends KoraError {\n\tconstructor(message: string, context?: Record<string, unknown>) {\n\t\tsuper(message, 'QUERY_ERROR', context)\n\t\tthis.name = 'QueryError'\n\t}\n}\n\n/**\n * Thrown when a record is not found by ID (findById, update, delete on missing record).\n */\nexport class RecordNotFoundError extends KoraError {\n\tconstructor(collection: string, recordId: string) {\n\t\tsuper(`Record \"${recordId}\" not found in collection \"${collection}\"`, 'RECORD_NOT_FOUND', {\n\t\t\tcollection,\n\t\t\trecordId,\n\t\t})\n\t\tthis.name = 'RecordNotFoundError'\n\t}\n}\n\n/**\n * Thrown inside `applyRemoteOperation` when the row's version state changed\n * between the caller's snapshot read and the guarded write (a concurrent local\n * mutation landed in the window). The transaction is rolled back with nothing\n * written; the caller re-reads fresh state, recomputes its merge, and retries.\n * This is the optimistic-concurrency guard that keeps merge-engine results\n * (richtext, add-wins arrays, constraint resolutions) from clobbering newer\n * local edits they never saw.\n */\nexport class OptimisticLockError extends KoraError {\n\tconstructor(collection: string, recordId: string) {\n\t\tsuper(\n\t\t\t`Row version changed while merging record \"${recordId}\" in \"${collection}\"; retry with fresh state`,\n\t\t\t'OPTIMISTIC_LOCK',\n\t\t\t{ collection, recordId },\n\t\t)\n\t\tthis.name = 'OptimisticLockError'\n\t}\n}\n\n/**\n * Thrown when a storage adapter operation fails.\n */\nexport class AdapterError extends KoraError {\n\tconstructor(message: string, context?: Record<string, unknown>) {\n\t\tsuper(message, 'ADAPTER_ERROR', context)\n\t\tthis.name = 'AdapterError'\n\t}\n}\n\n/**\n * Thrown when an operation is attempted on a store that has not been opened.\n */\nexport class StoreNotOpenError extends KoraError {\n\tconstructor() {\n\t\tsuper('Store is not open. Call store.open() before performing operations.', 'STORE_NOT_OPEN')\n\t\tthis.name = 'StoreNotOpenError'\n\t}\n}\n\n/**\n * Thrown when the Web Worker fails to initialize (WASM load failure, OPFS unavailable, etc.).\n */\nexport class WorkerInitError extends KoraError {\n\tconstructor(message: string, context?: Record<string, unknown>) {\n\t\tsuper(`Worker initialization failed: ${message}`, 'WORKER_INIT_ERROR', context)\n\t\tthis.name = 'WorkerInitError'\n\t}\n}\n\n/**\n * Thrown when the Web Worker does not respond within the configured timeout.\n */\nexport class WorkerTimeoutError extends KoraError {\n\tconstructor(operation: string, timeoutMs: number) {\n\t\tsuper(\n\t\t\t`Worker did not respond within ${timeoutMs}ms for operation \"${operation}\"`,\n\t\t\t'WORKER_TIMEOUT',\n\t\t\t{ operation, timeoutMs },\n\t\t)\n\t\tthis.name = 'WorkerTimeoutError'\n\t}\n}\n\n/**\n * Thrown when IndexedDB persistence operations fail (serialize/deserialize).\n */\nexport class PersistenceError extends KoraError {\n\tconstructor(message: string, context?: Record<string, unknown>) {\n\t\tsuper(`Persistence error: ${message}`, 'PERSISTENCE_ERROR', context)\n\t\tthis.name = 'PersistenceError'\n\t}\n}\n","import { type HLCTimestamp, HybridLogicalClock } from '@korajs/core'\nimport type { RawCollectionRow } from '../types'\n\n/** Empty _version means legacy rows (compare by wallTime only via fallback). */\nexport const EMPTY_ROW_VERSION = ''\n\n/**\n * Serialize an HLC timestamp for storage in the `_version` column.\n * Lexicographic order matches {@link HybridLogicalClock.compare}.\n */\nexport function serializeRowVersion(timestamp: HLCTimestamp): string {\n\treturn HybridLogicalClock.serialize(timestamp)\n}\n\n/**\n * Read the version stamp stored on a materialized row.\n * Legacy rows without `_version` fall back to wallTime with logical 0.\n */\nexport function rowVersionFromRecord(\n\trow: Pick<RawCollectionRow, '_updated_at' | '_version'>,\n): HLCTimestamp {\n\tconst version = row._version\n\tif (typeof version === 'string' && version.length > 0) {\n\t\treturn HybridLogicalClock.deserialize(version)\n\t}\n\treturn { wallTime: row._updated_at, logical: 0, nodeId: '' }\n}\n\n/**\n * Returns true when `incoming` is strictly newer than the version on `row`.\n */\nexport function isIncomingNewerThanRow(\n\tincoming: HLCTimestamp,\n\trow: Pick<RawCollectionRow, '_updated_at' | '_version'>,\n): boolean {\n\treturn HybridLogicalClock.compare(incoming, rowVersionFromRecord(row)) > 0\n}\n\n/**\n * SQL fragment and params for LWW guards: apply only when row is missing or older.\n * Uses serialized `_version` for total order (matches HLC compare).\n */\nexport function lwwVersionWhereClause(remoteVersion: string): { sql: string; params: string[] } {\n\treturn {\n\t\tsql: '(_version = ? OR _version < ?)',\n\t\tparams: [EMPTY_ROW_VERSION, remoteVersion],\n\t}\n}\n","import type { CollectionDefinition, FieldDescriptor } from '@korajs/core'\nimport { QueryError } from '../errors'\nimport { lwwVersionWhereClause } from '../lww/row-version'\nimport type { QueryDescriptor, WhereOperators } from '../types'\n\n/**\n * Result of building a SQL query: the parameterized SQL string and its bound values.\n */\nexport interface SqlQuery {\n\tsql: string\n\tparams: unknown[]\n}\n\n/**\n * Build a SELECT query from a QueryDescriptor.\n * Automatically adds `WHERE _deleted = 0` to exclude soft-deleted records.\n *\n * @param descriptor - The query descriptor\n * @param fields - The field descriptors from the collection schema\n * @returns A parameterized SQL query\n */\nexport function buildSelectQuery(\n\tdescriptor: QueryDescriptor,\n\tfields: Record<string, FieldDescriptor>,\n): SqlQuery {\n\tconst params: unknown[] = []\n\tconst parts = [`SELECT * FROM ${descriptor.collection}`]\n\n\tconst whereClause = buildWhereClauseParts(descriptor.where, fields, params)\n\t// Always filter out soft-deleted records\n\tconst deletedFilter = '_deleted = 0'\n\tif (whereClause) {\n\t\tparts.push(`WHERE ${deletedFilter} AND ${whereClause}`)\n\t} else {\n\t\tparts.push(`WHERE ${deletedFilter}`)\n\t}\n\n\tif (descriptor.orderBy.length > 0) {\n\t\tconst orderParts = descriptor.orderBy.map((o) => {\n\t\t\tvalidateFieldName(o.field, fields)\n\t\t\treturn `${o.field} ${o.direction.toUpperCase()}`\n\t\t})\n\t\tparts.push(`ORDER BY ${orderParts.join(', ')}`)\n\t}\n\n\tif (descriptor.limit !== undefined) {\n\t\tparts.push(`LIMIT ${descriptor.limit}`)\n\t}\n\n\tif (descriptor.offset !== undefined) {\n\t\tparts.push(`OFFSET ${descriptor.offset}`)\n\t}\n\n\treturn { sql: parts.join(' '), params }\n}\n\n/**\n * Build a COUNT query from a QueryDescriptor.\n * Automatically adds `WHERE _deleted = 0`.\n *\n * @param descriptor - The query descriptor\n * @param fields - The field descriptors from the collection schema\n * @returns A parameterized SQL query that returns { count: number }\n */\nexport function buildCountQuery(\n\tdescriptor: QueryDescriptor,\n\tfields: Record<string, FieldDescriptor>,\n): SqlQuery {\n\tconst params: unknown[] = []\n\tconst parts = [`SELECT COUNT(*) as count FROM ${descriptor.collection}`]\n\n\tconst whereClause = buildWhereClauseParts(descriptor.where, fields, params)\n\tconst deletedFilter = '_deleted = 0'\n\tif (whereClause) {\n\t\tparts.push(`WHERE ${deletedFilter} AND ${whereClause}`)\n\t} else {\n\t\tparts.push(`WHERE ${deletedFilter}`)\n\t}\n\n\treturn { sql: parts.join(' '), params }\n}\n\n/**\n * Build an INSERT query for a collection record.\n *\n * @param collection - The collection name\n * @param record - The record data (already serialized with id, _created_at, _updated_at)\n * @returns A parameterized SQL query\n */\nexport function buildInsertQuery(collection: string, record: Record<string, unknown>): SqlQuery {\n\tconst columns = Object.keys(record)\n\tconst placeholders = columns.map(() => '?')\n\tconst params = Object.values(record)\n\n\tconst sql = `INSERT INTO ${collection} (${columns.join(', ')}) VALUES (${placeholders.join(', ')})`\n\treturn { sql, params }\n}\n\n/**\n * Build an UPDATE query for a collection record.\n *\n * @param collection - The collection name\n * @param id - The record ID\n * @param changes - The fields to update (already serialized)\n * @returns A parameterized SQL query\n */\nexport function buildUpdateQuery(\n\tcollection: string,\n\tid: string,\n\tchanges: Record<string, unknown>,\n): SqlQuery {\n\tconst setClauses = Object.keys(changes).map((col) => `${col} = ?`)\n\tconst params = [...Object.values(changes), id]\n\n\tconst sql = `UPDATE ${collection} SET ${setClauses.join(', ')} WHERE id = ?`\n\treturn { sql, params }\n}\n\n/**\n * Build a field-level fast-forward UPDATE: writes the changed field values\n * unconditionally (the caller has already proven per-field that the local value\n * still equals the base the remote wrote from, so the remote is the newest known\n * writer of those fields), while advancing the row's `_version` / `_updated_at`\n * watermark MONOTONICALLY — never regressing it below its current value.\n *\n * This is what makes per-field LWW correct on a per-row `_version` column: a\n * concurrent edit to a different field may have pushed `_version` past this\n * operation's timestamp, but that must not cause this operation's own field\n * change to be dropped, nor may materializing it move the watermark backward\n * (which would let a genuinely stale later operation win).\n *\n * @param collection - The collection name\n * @param id - The record ID\n * @param fieldChanges - Serialized field values to write unconditionally (must NOT include _version / _updated_at)\n * @param remoteVersion - The operation's serialized row version (lexicographically comparable)\n * @param wallTime - The operation's wall-clock time in ms\n * @param options - Optional extras. `maxCreatedAt` advances `_created_at` to the\n * greater of its current value and the given wall time — used for insert\n * collisions so every node converges on the max insert wall time regardless\n * of arrival order.\n */\nexport function buildFieldFastForwardUpdateQuery(\n\tcollection: string,\n\tid: string,\n\tfieldChanges: Record<string, unknown>,\n\tremoteVersion: string,\n\twallTime: number,\n\toptions?: { maxCreatedAt?: number },\n): SqlQuery {\n\tconst fieldClauses = Object.keys(fieldChanges).map((col) => `${col} = ?`)\n\t// _version is a lexicographically-sortable string; _updated_at is a number.\n\t// Keep the greater of the current and incoming value for each (monotonic).\n\tconst setClauses = [\n\t\t...fieldClauses,\n\t\t'_version = CASE WHEN _version >= ? THEN _version ELSE ? END',\n\t\t'_updated_at = CASE WHEN _updated_at >= ? THEN _updated_at ELSE ? END',\n\t]\n\tconst params: unknown[] = [\n\t\t...Object.values(fieldChanges),\n\t\tremoteVersion,\n\t\tremoteVersion,\n\t\twallTime,\n\t\twallTime,\n\t]\n\tif (options?.maxCreatedAt !== undefined) {\n\t\tsetClauses.push('_created_at = CASE WHEN _created_at >= ? THEN _created_at ELSE ? END')\n\t\tparams.push(options.maxCreatedAt, options.maxCreatedAt)\n\t}\n\tparams.push(id)\n\tconst sql = `UPDATE ${collection} SET ${setClauses.join(', ')} WHERE id = ?`\n\treturn { sql, params }\n}\n\n/**\n * Build a soft-delete query (SET _deleted = 1).\n *\n * @param collection - The collection name\n * @param id - The record ID\n * @param updatedAt - The timestamp to set on _updated_at\n * @returns A parameterized SQL query\n */\nexport function buildSoftDeleteQuery(\n\tcollection: string,\n\tid: string,\n\tupdatedAt: number,\n\tversion?: string,\n): SqlQuery {\n\tif (version !== undefined) {\n\t\treturn {\n\t\t\tsql: `UPDATE ${collection} SET _deleted = 1, _updated_at = ?, _version = ? WHERE id = ?`,\n\t\t\tparams: [updatedAt, version, id],\n\t\t}\n\t}\n\treturn {\n\t\tsql: `UPDATE ${collection} SET _deleted = 1, _updated_at = ? WHERE id = ?`,\n\t\tparams: [updatedAt, id],\n\t}\n}\n\n/**\n * Build an UPDATE that applies only when the row is missing or older than `remoteVersion`\n * (serialized HLC). Prevents stale remote sync from overwriting newer local materialized state.\n */\nexport function buildLwwUpdateQuery(\n\tcollection: string,\n\tid: string,\n\tchanges: Record<string, unknown>,\n\tremoteVersion: string,\n): SqlQuery {\n\tconst setClauses = Object.keys(changes).map((col) => `${col} = ?`)\n\tconst lww = lwwVersionWhereClause(remoteVersion)\n\tconst sql = `UPDATE ${collection} SET ${setClauses.join(', ')} WHERE id = ? AND ${lww.sql}`\n\tconst params = [...Object.values(changes), id, ...lww.params]\n\treturn { sql, params }\n}\n\n/**\n * Build a soft-delete that applies only when the row is older than `remoteVersion`.\n */\nexport function buildLwwSoftDeleteQuery(\n\tcollection: string,\n\tid: string,\n\tupdatedAt: number,\n\tversion: string,\n): SqlQuery {\n\tconst lww = lwwVersionWhereClause(version)\n\treturn {\n\t\tsql: `UPDATE ${collection} SET _deleted = 1, _updated_at = ?, _version = ? WHERE id = ? AND ${lww.sql}`,\n\t\tparams: [updatedAt, version, id, ...lww.params],\n\t}\n}\n\n/**\n * Build a WHERE clause from conditions, validating field names against the schema.\n *\n * @param where - The where conditions\n * @param fields - The field descriptors from the collection schema\n * @returns The SQL WHERE clause string and params, or null if no conditions\n */\nexport function buildWhereClause(\n\twhere: Record<string, unknown>,\n\tfields: Record<string, FieldDescriptor>,\n): SqlQuery | null {\n\tconst params: unknown[] = []\n\tconst result = buildWhereClauseParts(where, fields, params)\n\tif (!result) return null\n\treturn { sql: result, params }\n}\n\n// --- Internal helpers ---\n\nconst VALID_OPERATORS = new Set(['$eq', '$ne', '$gt', '$gte', '$lt', '$lte', '$in'])\n\nfunction buildWhereClauseParts(\n\twhere: Record<string, unknown>,\n\tfields: Record<string, FieldDescriptor>,\n\tparams: unknown[],\n): string | null {\n\tconst conditions: string[] = []\n\n\tfor (const [fieldName, value] of Object.entries(where)) {\n\t\tvalidateFieldName(fieldName, fields)\n\t\tconst descriptor = fields[fieldName]\n\n\t\tif (value !== null && typeof value === 'object' && !Array.isArray(value)) {\n\t\t\t// Operator object: { $gt: 5, $lt: 10 }\n\t\t\tconst ops = value as WhereOperators\n\t\t\tfor (const [op, opValue] of Object.entries(ops)) {\n\t\t\t\tif (!VALID_OPERATORS.has(op)) {\n\t\t\t\t\tthrow new QueryError(`Unknown operator \"${op}\" on field \"${fieldName}\"`, {\n\t\t\t\t\t\tfield: fieldName,\n\t\t\t\t\t\toperator: op,\n\t\t\t\t\t\tvalidOperators: [...VALID_OPERATORS],\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\tconditions.push(buildOperatorCondition(fieldName, op, opValue, descriptor, params))\n\t\t\t}\n\t\t} else {\n\t\t\t// Shorthand: { completed: false } means { completed: { $eq: false } }\n\t\t\tconditions.push(buildOperatorCondition(fieldName, '$eq', value, descriptor, params))\n\t\t}\n\t}\n\n\tif (conditions.length === 0) return null\n\treturn conditions.join(' AND ')\n}\n\nfunction buildOperatorCondition(\n\tfieldName: string,\n\toperator: string,\n\tvalue: unknown,\n\tdescriptor: FieldDescriptor | undefined,\n\tparams: unknown[],\n): string {\n\t// Serialize boolean values to 0/1 for SQL comparison\n\tconst sqlValue =\n\t\tdescriptor?.kind === 'boolean' && typeof value === 'boolean' ? (value ? 1 : 0) : value\n\n\tswitch (operator) {\n\t\tcase '$eq':\n\t\t\tif (sqlValue === null) {\n\t\t\t\treturn `${fieldName} IS NULL`\n\t\t\t}\n\t\t\tparams.push(sqlValue)\n\t\t\treturn `${fieldName} = ?`\n\t\tcase '$ne':\n\t\t\tif (sqlValue === null) {\n\t\t\t\treturn `${fieldName} IS NOT NULL`\n\t\t\t}\n\t\t\tparams.push(sqlValue)\n\t\t\treturn `${fieldName} != ?`\n\t\tcase '$gt':\n\t\t\tparams.push(sqlValue)\n\t\t\treturn `${fieldName} > ?`\n\t\tcase '$gte':\n\t\t\tparams.push(sqlValue)\n\t\t\treturn `${fieldName} >= ?`\n\t\tcase '$lt':\n\t\t\tparams.push(sqlValue)\n\t\t\treturn `${fieldName} < ?`\n\t\tcase '$lte':\n\t\t\tparams.push(sqlValue)\n\t\t\treturn `${fieldName} <= ?`\n\t\tcase '$in': {\n\t\t\tif (!Array.isArray(sqlValue)) {\n\t\t\t\tthrow new QueryError(`$in operator requires an array value for field \"${fieldName}\"`, {\n\t\t\t\t\tfield: fieldName,\n\t\t\t\t\treceived: typeof sqlValue,\n\t\t\t\t})\n\t\t\t}\n\t\t\tconst placeholders = sqlValue.map(() => '?')\n\t\t\tfor (const item of sqlValue) {\n\t\t\t\tparams.push(\n\t\t\t\t\tdescriptor?.kind === 'boolean' && typeof item === 'boolean' ? (item ? 1 : 0) : item,\n\t\t\t\t)\n\t\t\t}\n\t\t\treturn `${fieldName} IN (${placeholders.join(', ')})`\n\t\t}\n\t\tdefault:\n\t\t\tthrow new QueryError(`Unknown operator \"${operator}\"`, { operator })\n\t}\n}\n\nfunction validateFieldName(fieldName: string, fields: Record<string, FieldDescriptor>): void {\n\t// Allow schema fields plus metadata fields that map to query-able columns\n\tconst allowedFields = new Set([\n\t\t...Object.keys(fields),\n\t\t'id',\n\t\t'createdAt',\n\t\t'updatedAt',\n\t\t'_created_at',\n\t\t'_updated_at',\n\t])\n\tif (!allowedFields.has(fieldName)) {\n\t\tthrow new QueryError(\n\t\t\t`Unknown field \"${fieldName}\" in query. Available fields: ${[...allowedFields].join(', ')}`,\n\t\t\t{ field: fieldName },\n\t\t)\n\t}\n}\n","import { createOperation, generateUUIDv7, validateRecord } from '@korajs/core'\nimport { fieldVersionsForFields, serializeFieldVersions } from '../lww/field-versions'\nimport { serializeRowVersion } from '../lww/row-version'\nimport { buildInsertQuery } from '../query/sql-builder'\nimport { encodeRichtextFieldsForOpData } from '../serialization/op-data-encoding'\nimport { serializeOperation, serializeRecord } from '../serialization/serializer'\nimport { allocateNextSequenceInTransaction } from '../store/sequence-allocator'\nimport type { CollectionRecord } from '../types'\nimport { resolveCausalDeps } from './resolve-causal-deps'\nimport type { LocalMutationContext } from './types'\n\n/**\n * Insert a record and persist the operation log entry atomically.\n */\nexport async function executeInsert(\n\tctx: LocalMutationContext,\n\tdata: Record<string, unknown>,\n): Promise<CollectionRecord> {\n\tconst validated = validateRecord(ctx.collection, ctx.definition, data, 'insert')\n\tconst recordId = generateUUIDv7()\n\n\tfor (const [fieldName, descriptor] of Object.entries(ctx.definition.fields)) {\n\t\tif (descriptor.auto && descriptor.kind === 'timestamp') {\n\t\t\tvalidated[fieldName] = Date.now()\n\t\t}\n\t}\n\n\tconst causalDeps = resolveCausalDeps(ctx)\n\n\tlet operation!: Awaited<ReturnType<typeof createOperation>>\n\tlet record!: Record<string, unknown>\n\n\tawait ctx.adapter.transaction(async (tx) => {\n\t\tconst sequenceNumber = await allocateNextSequenceInTransaction(tx, ctx.nodeId)\n\t\toperation = await createOperation(\n\t\t\t{\n\t\t\t\tnodeId: ctx.nodeId,\n\t\t\t\ttype: 'insert',\n\t\t\t\tcollection: ctx.collection,\n\t\t\t\trecordId,\n\t\t\t\t// Binary richtext values are tagged as canonical JSON BEFORE the\n\t\t\t\t// operation is content-hashed, so the hash input, persisted JSON,\n\t\t\t\t// and wire payload are the identical value.\n\t\t\t\tdata: encodeRichtextFieldsForOpData(validated, ctx.definition.fields),\n\t\t\t\tpreviousData: null,\n\t\t\t\tsequenceNumber,\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(ctx.collection, operation.id, ctx.inTransaction)\n\n\t\tconst serializedData = serializeRecord(validated, ctx.definition.fields)\n\t\tconst version = serializeRowVersion(operation.timestamp)\n\t\trecord = {\n\t\t\tid: recordId,\n\t\t\t...serializedData,\n\t\t\t_created_at: operation.timestamp.wallTime,\n\t\t\t_updated_at: operation.timestamp.wallTime,\n\t\t\t_version: version,\n\t\t\t// Stamp every inserted field with this operation's version so later\n\t\t\t// per-field LWW compares against a real writer, not the fallback.\n\t\t\t_field_versions: serializeFieldVersions(\n\t\t\t\tfieldVersionsForFields(Object.keys(serializedData), version),\n\t\t\t),\n\t\t}\n\n\t\tconst builtInsert = buildInsertQuery(ctx.collection, record)\n\t\tconst opInsert = buildInsertQuery(\n\t\t\t`_kora_ops_${ctx.collection}`,\n\t\t\tserializeOperation(operation) as unknown as Record<string, unknown>,\n\t\t)\n\n\t\tawait tx.execute(builtInsert.sql, builtInsert.params)\n\t\tawait tx.execute(opInsert.sql, opInsert.params)\n\t})\n\n\tctx.onMutation(ctx.collection, operation)\n\n\treturn {\n\t\tid: recordId,\n\t\t...validated,\n\t\tcreatedAt: operation.timestamp.wallTime,\n\t\tupdatedAt: operation.timestamp.wallTime,\n\t}\n}\n","import { EMPTY_ROW_VERSION } from './row-version'\n\n/**\n * Per-field last-writer versions for a materialized row.\n *\n * Each entry maps a field name to a serialized HLC timestamp (the same\n * lexicographically-sortable form used by the row `_version` column). Because\n * the serialized form sorts identically to {@link HybridLogicalClock.compare},\n * per-field last-write-wins is a plain string comparison: the greater string is\n * the newer writer. This makes field-level convergence deterministic and\n * independent of the order operations happen to arrive in.\n */\nexport type FieldVersions = Record<string, string>\n\n/**\n * Parse the `_field_versions` JSON column into a map. Tolerates null, empty,\n * and malformed values by returning an empty map — a row that predates\n * per-field tracking simply has no field versions and falls back to `_version`.\n */\nexport function parseFieldVersions(raw: unknown): FieldVersions {\n\tif (typeof raw !== 'string' || raw.length === 0) {\n\t\treturn {}\n\t}\n\ttry {\n\t\tconst parsed = JSON.parse(raw) as unknown\n\t\tif (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {\n\t\t\treturn {}\n\t\t}\n\t\tconst result: FieldVersions = {}\n\t\tfor (const [key, value] of Object.entries(parsed as Record<string, unknown>)) {\n\t\t\tif (typeof value === 'string') {\n\t\t\t\tresult[key] = value\n\t\t\t}\n\t\t}\n\t\treturn result\n\t} catch {\n\t\treturn {}\n\t}\n}\n\n/**\n * Serialize a field-version map for storage in the `_field_versions` column.\n */\nexport function serializeFieldVersions(versions: FieldVersions): string {\n\treturn JSON.stringify(versions)\n}\n\n/**\n * Build the initial field-version map for an insert: every supplied field is\n * stamped with the operation's version.\n */\nexport function fieldVersionsForFields(\n\tfieldNames: Iterable<string>,\n\tversion: string,\n): FieldVersions {\n\tconst versions: FieldVersions = {}\n\tfor (const field of fieldNames) {\n\t\tversions[field] = version\n\t}\n\treturn versions\n}\n\n/**\n * The effective stored version for a field: its own tracked version if present,\n * otherwise the row-level `_version` (so rows written before per-field tracking\n * still compare correctly), otherwise the empty sentinel (older than anything).\n */\nexport function effectiveFieldVersion(\n\tcurrent: FieldVersions,\n\tfield: string,\n\trowVersion: string | undefined,\n): string {\n\tconst own = current[field]\n\tif (own !== undefined) {\n\t\treturn own\n\t}\n\treturn rowVersion ?? EMPTY_ROW_VERSION\n}\n\n/**\n * Result of resolving an incoming operation against the current per-field\n * versions of a row.\n */\nexport interface PerFieldLwwResult {\n\t/** Fields the incoming operation wins (strictly newer than the stored version). */\n\twinners: string[]\n\t/** The merged field-version map to persist (winners advanced to `incomingVersion`). */\n\tmerged: FieldVersions\n}\n\n/**\n * Resolve per-field last-write-wins for an incoming operation.\n *\n * For each incoming field, the operation wins only when its version is strictly\n * greater than the field's effective stored version. Ties (identical version,\n * i.e. the same operation re-applied) are losses, keeping the resolution\n * idempotent. The comparison is a total order, so every node resolves the same\n * winner regardless of the order operations arrive.\n *\n * @param current - Parsed `_field_versions` of the target row\n * @param incomingFields - Field names carried by the incoming operation\n * @param incomingVersion - Serialized HLC version of the incoming operation\n * @param rowVersion - The row's `_version` (fallback for untracked fields)\n */\nexport function resolvePerFieldLww(\n\tcurrent: FieldVersions,\n\tincomingFields: Iterable<string>,\n\tincomingVersion: string,\n\trowVersion: string | undefined,\n): PerFieldLwwResult {\n\tconst winners: string[] = []\n\tconst merged: FieldVersions = { ...current }\n\tfor (const field of incomingFields) {\n\t\tconst stored = effectiveFieldVersion(current, field, rowVersion)\n\t\tif (incomingVersion > stored) {\n\t\t\twinners.push(field)\n\t\t\tmerged[field] = incomingVersion\n\t\t}\n\t\t// Losing fields are left untouched: their existing tracked version (or the\n\t\t// row-level `_version` fallback) already reflects the newer writer.\n\t}\n\treturn { winners, merged }\n}\n","import type { StorageAdapter, Transaction } from '../types'\n\ninterface SequenceRow {\n\tsequence_number: number\n}\n\n/**\n * Atomically increment and return the next sequence number for a node.\n * Uses SQLite UPSERT + RETURNING so concurrent tabs do not reuse sequence slots.\n */\nexport async function allocateNextSequenceNumber(\n\tadapter: StorageAdapter,\n\tnodeId: string,\n): Promise<number> {\n\tconst rows = await adapter.query<SequenceRow>(\n\t\t`INSERT INTO _kora_version_vector (node_id, sequence_number) VALUES (?, 1)\n ON CONFLICT(node_id) DO UPDATE SET sequence_number = sequence_number + 1\n RETURNING sequence_number`,\n\t\t[nodeId],\n\t)\n\tconst seq = rows[0]?.sequence_number\n\tif (seq === undefined) {\n\t\tthrow new Error(`Failed to allocate sequence number for node \"${nodeId}\"`)\n\t}\n\treturn seq\n}\n\n/**\n * Allocate the next sequence inside an existing storage transaction.\n */\nexport async function allocateNextSequenceInTransaction(\n\ttx: Transaction,\n\tnodeId: string,\n): Promise<number> {\n\tconst rows = await tx.query<SequenceRow>(\n\t\t`INSERT INTO _kora_version_vector (node_id, sequence_number) VALUES (?, 1)\n ON CONFLICT(node_id) DO UPDATE SET sequence_number = sequence_number + 1\n RETURNING sequence_number`,\n\t\t[nodeId],\n\t)\n\tconst seq = rows[0]?.sequence_number\n\tif (seq === undefined) {\n\t\tthrow new Error(`Failed to allocate sequence number for node \"${nodeId}\" in transaction`)\n\t}\n\treturn seq\n}\n\n/**\n * Read the current sequence for a node without incrementing.\n */\nexport async function readSequenceNumber(adapter: StorageAdapter, nodeId: string): Promise<number> {\n\tconst rows = await adapter.query<SequenceRow>(\n\t\t'SELECT sequence_number FROM _kora_version_vector WHERE node_id = ?',\n\t\t[nodeId],\n\t)\n\treturn rows[0]?.sequence_number ?? 0\n}\n","import type { LocalMutationContext } from './types'\n\n/**\n * Merge explicit parent deps (e.g. referential cascade) with tracker-derived deps.\n */\nexport function resolveCausalDeps(ctx: LocalMutationContext): string[] {\n\tconst merged: string[] = []\n\tfor (const id of ctx.extraCausalDeps ?? []) {\n\t\tif (!merged.includes(id)) {\n\t\t\tmerged.push(id)\n\t\t}\n\t}\n\tfor (const id of ctx.causalTracker?.nextCausalDeps(ctx.collection, ctx.inTransaction) ?? []) {\n\t\tif (!merged.includes(id)) {\n\t\t\tmerged.push(id)\n\t\t}\n\t}\n\treturn merged\n}\n","import type { AtomicOp } from '@korajs/core'\nimport {\n\tcreateOperation,\n\tisAtomicOp,\n\tresolveAtomicOp,\n\ttoAtomicOp,\n\tvalidateRecord,\n} from '@korajs/core'\nimport { RecordNotFoundError } from '../errors'\nimport { parseFieldVersions, serializeFieldVersions } from '../lww/field-versions'\nimport { serializeRowVersion } from '../lww/row-version'\nimport { buildInsertQuery, buildUpdateQuery } from '../query/sql-builder'\nimport { encodeRichtextFieldsForOpData } from '../serialization/op-data-encoding'\nimport { deserializeRecord, serializeOperation, serializeRecord } from '../serialization/serializer'\nimport { validateUpdateStateMachine } from '../state-machine/state-validator'\nimport { allocateNextSequenceInTransaction } from '../store/sequence-allocator'\nimport type { CollectionRecord, RawCollectionRow } from '../types'\nimport { resolveCausalDeps } from './resolve-causal-deps'\nimport type { LocalMutationContext } from './types'\n\n/**\n * Update a record and persist the operation log entry atomically.\n */\nexport async function executeUpdate(\n\tctx: LocalMutationContext,\n\tid: string,\n\tdata: Record<string, unknown>,\n): Promise<CollectionRecord> {\n\tconst currentRows = await ctx.adapter.query<RawCollectionRow>(\n\t\t`SELECT * FROM ${ctx.collection} WHERE id = ? AND _deleted = 0`,\n\t\t[id],\n\t)\n\tconst currentRow = currentRows[0]\n\tif (!currentRow) {\n\t\tthrow new RecordNotFoundError(ctx.collection, id)\n\t}\n\n\tlet validated = validateRecord(ctx.collection, ctx.definition, data, 'update')\n\tconst currentRecord = deserializeRecord(currentRow, ctx.definition.fields)\n\tvalidated = validateUpdateStateMachine(\n\t\tctx.collection,\n\t\tid,\n\t\tctx.definition,\n\t\tcurrentRecord,\n\t\tvalidated,\n\t)\n\n\tif (Object.keys(validated).length === 0) {\n\t\treturn { ...currentRecord }\n\t}\n\n\tconst previousData: Record<string, unknown> = {}\n\tconst resolvedData: Record<string, unknown> = {}\n\tconst atomicOps: Record<string, AtomicOp> = {}\n\n\tfor (const key of Object.keys(validated)) {\n\t\tconst value = validated[key]\n\t\tpreviousData[key] = currentRecord[key]\n\n\t\tif (isAtomicOp(value)) {\n\t\t\tresolvedData[key] = resolveAtomicOp(currentRecord[key], value)\n\t\t\tatomicOps[key] = toAtomicOp(value)\n\t\t} else {\n\t\t\tresolvedData[key] = value\n\t\t}\n\t}\n\n\tconst hasAtomicOps = Object.keys(atomicOps).length > 0\n\tconst causalDeps = resolveCausalDeps(ctx)\n\tlet operation!: Awaited<ReturnType<typeof createOperation>>\n\n\tawait ctx.adapter.transaction(async (tx) => {\n\t\tconst sequenceNumber = await allocateNextSequenceInTransaction(tx, ctx.nodeId)\n\t\toperation = await createOperation(\n\t\t\t{\n\t\t\t\tnodeId: ctx.nodeId,\n\t\t\t\ttype: 'update',\n\t\t\t\tcollection: ctx.collection,\n\t\t\t\trecordId: id,\n\t\t\t\t// Binary richtext values (new and previous) are tagged as canonical\n\t\t\t\t// JSON BEFORE the operation is content-hashed, so the hash input,\n\t\t\t\t// persisted JSON, and wire payload are the identical value.\n\t\t\t\tdata: encodeRichtextFieldsForOpData(resolvedData, ctx.definition.fields),\n\t\t\t\tpreviousData: encodeRichtextFieldsForOpData(previousData, ctx.definition.fields),\n\t\t\t\tsequenceNumber,\n\t\t\t\tcausalDeps,\n\t\t\t\tschemaVersion: ctx.schema.version,\n\t\t\t\t...(hasAtomicOps ? { atomicOps } : {}),\n\t\t\t},\n\t\t\tctx.clock,\n\t\t)\n\t\tctx.causalTracker?.afterOperation(ctx.collection, operation.id, ctx.inTransaction)\n\n\t\tconst serializedChanges = serializeRecord(resolvedData, ctx.definition.fields)\n\t\tconst version = serializeRowVersion(operation.timestamp)\n\t\t// A local edit is always the newest writer of the fields it touches (the\n\t\t// HLC advances past every timestamp this device has seen), so stamp each\n\t\t// changed field with this operation's version.\n\t\tconst mergedFieldVersions = parseFieldVersions(currentRow._field_versions)\n\t\tfor (const changedField of Object.keys(serializedChanges)) {\n\t\t\tmergedFieldVersions[changedField] = version\n\t\t}\n\t\tconst updateQuery = buildUpdateQuery(ctx.collection, id, {\n\t\t\t...serializedChanges,\n\t\t\t_updated_at: operation.timestamp.wallTime,\n\t\t\t_version: version,\n\t\t\t_field_versions: serializeFieldVersions(mergedFieldVersions),\n\t\t})\n\t\tconst opInsert = buildInsertQuery(\n\t\t\t`_kora_ops_${ctx.collection}`,\n\t\t\tserializeOperation(operation) as unknown as Record<string, unknown>,\n\t\t)\n\n\t\tawait tx.execute(updateQuery.sql, updateQuery.params)\n\t\tawait tx.execute(opInsert.sql, opInsert.params)\n\t})\n\n\tctx.onMutation(ctx.collection, operation)\n\n\tconst rows = await ctx.adapter.query<RawCollectionRow>(\n\t\t`SELECT * FROM ${ctx.collection} WHERE id = ? AND _deleted = 0`,\n\t\t[id],\n\t)\n\tconst row = rows[0]\n\tif (!row) {\n\t\tthrow new RecordNotFoundError(ctx.collection, id)\n\t}\n\treturn deserializeRecord(row, ctx.definition.fields)\n}\n","import { KoraError, validateTransition } from '@korajs/core'\nimport type {\n\tCollectionDefinition,\n\tStateMachineConstraint,\n\tStateMachineDefinition,\n} from '@korajs/core'\n\n/**\n * Error thrown when a local mutation attempts an invalid state transition.\n *\n * Contains enough context to debug without reproduction:\n * the collection, record, field, current state, attempted state, and allowed transitions.\n */\nexport class InvalidStateTransitionError extends KoraError {\n\tconstructor(\n\t\tpublic readonly collection: string,\n\t\tpublic readonly recordId: string,\n\t\tpublic readonly field: string,\n\t\tpublic readonly fromState: string,\n\t\tpublic readonly toState: string,\n\t\tpublic readonly allowedStates: string[],\n\t) {\n\t\tsuper(\n\t\t\t`Invalid state transition in collection \"${collection}\": ` +\n\t\t\t\t`cannot transition field \"${field}\" from \"${fromState}\" to \"${toState}\". ` +\n\t\t\t\t`Allowed transitions from \"${fromState}\": ${allowedStates.length > 0 ? allowedStates.join(', ') : '(none -- terminal state)'}`,\n\t\t\t'INVALID_STATE_TRANSITION',\n\t\t\t{ collection, recordId, field, fromState, toState, allowedStates },\n\t\t)\n\t\tthis.name = 'InvalidStateTransitionError'\n\t}\n}\n\n/**\n * Validates a state machine transition for a local mutation (insert or update).\n *\n * For inserts: validates that the initial state (from the data or the default value)\n * is a known state in the state machine.\n *\n * For updates: looks up the current state field value and checks whether\n * the transition to the new value is allowed.\n *\n * @param collectionName - Name of the collection\n * @param recordId - The record being mutated\n * @param stateMachine - The state machine definition\n * @param currentState - The current value of the state field (null for inserts)\n * @param newState - The new value being set for the state field\n * @returns An object indicating whether the transition is valid, and if not, the allowed states.\n * When `onInvalidTransition` is 'last-valid-state', callers should suppress the field update\n * rather than throwing.\n */\nexport function validateStateTransition(\n\tcollectionName: string,\n\trecordId: string,\n\tstateMachine: StateMachineDefinition,\n\tcurrentState: string | null,\n\tnewState: string,\n): { valid: boolean; allowedStates: string[] } {\n\t// For inserts, any valid enum value is acceptable as the initial state\n\t// (schema validation already ensures the value is a valid enum value)\n\tif (currentState === null) {\n\t\treturn { valid: true, allowedStates: [] }\n\t}\n\n\t// Same-state transitions are always valid (idempotent updates)\n\tif (currentState === newState) {\n\t\treturn { valid: true, allowedStates: stateMachine.transitions[currentState] ?? [] }\n\t}\n\n\tconst constraint: StateMachineConstraint = {\n\t\tfield: stateMachine.field,\n\t\tcollection: collectionName,\n\t\ttransitions: stateMachine.transitions,\n\t}\n\tconst transitionResult = validateTransition(constraint, currentState, newState)\n\tif (transitionResult.valid) {\n\t\treturn { valid: true, allowedStates: transitionResult.allowedTargets }\n\t}\n\n\tconst allowedStates = transitionResult.allowedTargets\n\n\tif (stateMachine.onInvalidTransition === 'reject') {\n\t\tthrow new InvalidStateTransitionError(\n\t\t\tcollectionName,\n\t\t\trecordId,\n\t\t\tstateMachine.field,\n\t\t\tcurrentState,\n\t\t\tnewState,\n\t\t\tallowedStates,\n\t\t)\n\t}\n\n\t// 'last-valid-state': return invalid so the caller can suppress the field update\n\treturn { valid: false, allowedStates }\n}\n\n/**\n * Checks whether a collection update data object contains a change to the state machine field,\n * and if so, validates the transition.\n *\n * If the state field is not in the update data, returns the data unchanged.\n * If the transition is invalid and mode is 'last-valid-state', removes the field from the data.\n * If the transition is invalid and mode is 'reject', throws InvalidStateTransitionError.\n *\n * @param collectionName - Name of the collection\n * @param recordId - The record being updated\n * @param collectionDef - The collection definition from the schema\n * @param currentRecord - The current record data (must include the state field)\n * @param updateData - The partial update data\n * @returns The update data, potentially with the state field removed if invalid and mode is 'last-valid-state'\n */\nexport function validateUpdateStateMachine(\n\tcollectionName: string,\n\trecordId: string,\n\tcollectionDef: CollectionDefinition,\n\tcurrentRecord: Record<string, unknown>,\n\tupdateData: Record<string, unknown>,\n): Record<string, unknown> {\n\tconst stateMachine = collectionDef.stateMachine\n\tif (stateMachine === undefined) {\n\t\treturn updateData\n\t}\n\n\tconst stateField = stateMachine.field\n\tif (!(stateField in updateData)) {\n\t\t// State field not being changed -- no validation needed\n\t\treturn updateData\n\t}\n\n\tconst currentState = currentRecord[stateField]\n\tconst newState = updateData[stateField]\n\n\t// Both values must be strings for state machine validation\n\tif (typeof currentState !== 'string' || typeof newState !== 'string') {\n\t\treturn updateData\n\t}\n\n\tconst result = validateStateTransition(\n\t\tcollectionName,\n\t\trecordId,\n\t\tstateMachine,\n\t\tcurrentState,\n\t\tnewState,\n\t)\n\n\tif (result.valid) {\n\t\treturn updateData\n\t}\n\n\t// Mode is 'last-valid-state': silently remove the state field from the update\n\tconst filtered = { ...updateData }\n\tdelete filtered[stateField]\n\n\t// If no fields remain after removing the state field, the update becomes a no-op.\n\t// Return the empty object -- the caller can decide whether to proceed.\n\treturn filtered\n}\n","import { createOperation } from '@korajs/core'\nimport type { Operation } from '@korajs/core'\nimport { RecordNotFoundError } from '../errors'\nimport { serializeRowVersion } from '../lww/row-version'\nimport { buildInsertQuery, buildSoftDeleteQuery } from '../query/sql-builder'\nimport { serializeOperation } from '../serialization/serializer'\nimport { allocateNextSequenceInTransaction } from '../store/sequence-allocator'\nimport type { RawCollectionRow } from '../types'\nimport { resolveCausalDeps } from './resolve-causal-deps'\nimport type { LocalMutationContext } from './types'\n\nexport interface ExecuteDeleteOptions {\n\t/** When true, skip RelationEnforcer (caller already enforced referential integrity). */\n\tskipReferentialEnforcement?: boolean\n\t/** Pre-built delete operation (avoids duplicate sequence allocation). */\n\toperation?: Operation\n}\n\n/**\n * Soft-delete a record and persist the operation log entry atomically.\n * Returns the primary delete operation and any cascaded side-effect operations.\n */\nexport async function executeDelete(\n\tctx: LocalMutationContext,\n\tid: string,\n\toptions?: ExecuteDeleteOptions,\n): Promise<Operation[]> {\n\tconst currentRows = await ctx.adapter.query<RawCollectionRow>(\n\t\t`SELECT * FROM ${ctx.collection} WHERE id = ? AND _deleted = 0`,\n\t\t[id],\n\t)\n\tif (!currentRows[0]) {\n\t\tthrow new RecordNotFoundError(ctx.collection, id)\n\t}\n\n\tconst causalDeps = resolveCausalDeps(ctx)\n\tlet operation = options?.operation\n\tconst cascadedOps: Operation[] = []\n\n\tawait ctx.adapter.transaction(async (tx) => {\n\t\tif (!operation) {\n\t\t\tconst sequenceNumber = await allocateNextSequenceInTransaction(tx, ctx.nodeId)\n\t\t\toperation = await createOperation(\n\t\t\t\t{\n\t\t\t\t\tnodeId: ctx.nodeId,\n\t\t\t\t\ttype: 'delete',\n\t\t\t\t\tcollection: ctx.collection,\n\t\t\t\t\trecordId: id,\n\t\t\t\t\tdata: null,\n\t\t\t\t\tpreviousData: null,\n\t\t\t\t\tsequenceNumber,\n\t\t\t\t\tcausalDeps,\n\t\t\t\t\tschemaVersion: ctx.schema.version,\n\t\t\t\t},\n\t\t\t\tctx.clock,\n\t\t\t)\n\t\t\tctx.causalTracker?.afterOperation(ctx.collection, operation.id, ctx.inTransaction)\n\t\t}\n\n\t\tif (ctx.relationEnforcer && !options?.skipReferentialEnforcement) {\n\t\t\tconst enforcementResult = await ctx.relationEnforcer.enforceDelete(ctx.collection, id, tx, [\n\t\t\t\toperation.id,\n\t\t\t])\n\t\t\tcascadedOps.push(...enforcementResult.operations)\n\t\t}\n\n\t\tconst version = serializeRowVersion(operation.timestamp)\n\t\tconst deleteQuery = buildSoftDeleteQuery(\n\t\t\tctx.collection,\n\t\t\tid,\n\t\t\toperation.timestamp.wallTime,\n\t\t\tversion,\n\t\t)\n\t\tconst opInsert = buildInsertQuery(\n\t\t\t`_kora_ops_${ctx.collection}`,\n\t\t\tserializeOperation(operation) as unknown as Record<string, unknown>,\n\t\t)\n\n\t\tawait tx.execute(deleteQuery.sql, deleteQuery.params)\n\t\tawait tx.execute(opInsert.sql, opInsert.params)\n\t})\n\n\tif (!operation) {\n\t\tthrow new Error('Delete operation was not created')\n\t}\n\n\tctx.onMutation(ctx.collection, operation)\n\tfor (const cascadedOp of cascadedOps) {\n\t\tctx.onMutation(cascadedOp.collection, cascadedOp)\n\t}\n\n\treturn [operation, ...cascadedOps]\n}\n"],"mappings":"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","names":["import_core","import_core","import_core","import_core","import_core","import_core","import_core"]}
@@ -1,7 +1,7 @@
1
1
  import { Operation, FieldDescriptor, HLCTimestamp } from '@korajs/core';
2
- import { O as OperationRow, R as RawCollectionRow, C as CollectionRecord, Q as QueryDescriptor } from './types-DepnRDk_.cjs';
3
- export { a as MetaRow, b as Subscription, V as VersionVectorRow } from './types-DepnRDk_.cjs';
4
- import { L as LocalMutationContext } from './types-CTr00g_d.cjs';
2
+ import { O as OperationRow, R as RawCollectionRow, C as CollectionRecord, Q as QueryDescriptor } from './types-CJOVKxLw.cjs';
3
+ export { a as MetaRow, b as Subscription, V as VersionVectorRow } from './types-CJOVKxLw.cjs';
4
+ import { L as LocalMutationContext } from './types-CyjXwrjW.cjs';
5
5
 
6
6
  /**
7
7
  * Serialize a JS record to SQL-compatible values for INSERT/UPDATE.
@@ -1,7 +1,7 @@
1
1
  import { Operation, FieldDescriptor, HLCTimestamp } from '@korajs/core';
2
- import { O as OperationRow, R as RawCollectionRow, C as CollectionRecord, Q as QueryDescriptor } from './types-DepnRDk_.js';
3
- export { a as MetaRow, b as Subscription, V as VersionVectorRow } from './types-DepnRDk_.js';
4
- import { L as LocalMutationContext } from './types-BMyHmwvn.js';
2
+ import { O as OperationRow, R as RawCollectionRow, C as CollectionRecord, Q as QueryDescriptor } from './types-CJOVKxLw.js';
3
+ export { a as MetaRow, b as Subscription, V as VersionVectorRow } from './types-CJOVKxLw.js';
4
+ import { L as LocalMutationContext } from './types-DAxCladl.js';
5
5
 
6
6
  /**
7
7
  * Serialize a JS record to SQL-compatible values for INSERT/UPDATE.