@korajs/core 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.
package/dist/index.cjs CHANGED
@@ -22,6 +22,7 @@ var index_exports = {};
22
22
  __export(index_exports, {
23
23
  APPLY_FAILURE_CODES: () => APPLY_FAILURE_CODES,
24
24
  APPLY_RESULTS: () => APPLY_RESULTS,
25
+ AppNotReadyError: () => AppNotReadyError,
25
26
  ArrayFieldBuilder: () => ArrayFieldBuilder,
26
27
  CONNECTION_QUALITIES: () => CONNECTION_QUALITIES,
27
28
  CausalTracker: () => CausalTracker,
@@ -29,21 +30,26 @@ __export(index_exports, {
29
30
  EnumFieldBuilder: () => EnumFieldBuilder,
30
31
  FieldBuilder: () => FieldBuilder,
31
32
  HybridLogicalClock: () => HybridLogicalClock,
33
+ InvalidTimestampError: () => InvalidTimestampError,
32
34
  KORA_ERROR_FIX_SUGGESTIONS: () => KORA_ERROR_FIX_SUGGESTIONS,
33
35
  KoraError: () => KoraError,
36
+ MAX_LOGICAL: () => MAX_LOGICAL,
34
37
  MERGE_STRATEGIES: () => MERGE_STRATEGIES,
35
38
  MergeConflictError: () => MergeConflictError,
36
39
  MigrationBuilder: () => MigrationBuilder,
37
40
  MigrationRollbackError: () => MigrationRollbackError,
38
41
  OperationError: () => OperationError,
42
+ RemoteClockDriftError: () => RemoteClockDriftError,
39
43
  RollbackBuilder: () => RollbackBuilder,
40
44
  SchemaValidationError: () => SchemaValidationError,
41
45
  StorageError: () => StorageError,
42
46
  SyncError: () => SyncError,
43
47
  advanceVector: () => advanceVector,
44
48
  applyOperationTransforms: () => applyOperationTransforms,
49
+ base64ToBytes: () => base64ToBytes,
45
50
  buildScopeMap: () => buildScopeMap,
46
51
  buildStateMachineConstraints: () => buildStateMachineConstraints,
52
+ bytesToBase64: () => bytesToBase64,
47
53
  canAutoRollback: () => canAutoRollback,
48
54
  collectSchemaScopeFields: () => collectSchemaScopeFields,
49
55
  collectSchemaScopeValueKeys: () => collectSchemaScopeValueKeys,
@@ -51,11 +57,13 @@ __export(index_exports, {
51
57
  createOperation: () => createOperation,
52
58
  createReversibleMigration: () => createReversibleMigration,
53
59
  createVersionVector: () => createVersionVector,
60
+ decodeBytesFromOpData: () => decodeBytesFromOpData,
54
61
  defaultApplyFailureReason: () => defaultApplyFailureReason,
55
62
  defaultSequenceFormat: () => defaultSequenceFormat,
56
63
  defineSchema: () => defineSchema,
57
64
  deserializeVector: () => deserializeVector,
58
65
  dominates: () => dominates,
66
+ encodeBytesForOpData: () => encodeBytesForOpData,
59
67
  extractScopeValuesFromClaims: () => extractScopeValuesFromClaims,
60
68
  extractTimestamp: () => extractTimestamp,
61
69
  formatSequenceValue: () => formatSequenceValue,
@@ -71,6 +79,8 @@ __export(index_exports, {
71
79
  isApplyFailure: () => isApplyFailure,
72
80
  isAtomicOp: () => isAtomicOp,
73
81
  isCollectionSyncScoped: () => isCollectionSyncScoped,
82
+ isKoraBytesValue: () => isKoraBytesValue,
83
+ isLegacyNumericByteObject: () => isLegacyNumericByteObject,
74
84
  isValidOperation: () => isValidOperation,
75
85
  isValidUUIDv7: () => isValidUUIDv7,
76
86
  mergeVectors: () => mergeVectors,
@@ -107,6 +117,7 @@ var KORA_ERROR_FIX_SUGGESTIONS = {
107
117
  SYNC_ERROR: "Verify the sync server URL, auth token, and that the server accepts your schema version.",
108
118
  STORAGE_ERROR: "Confirm the storage adapter is supported in this environment and the database path is writable.",
109
119
  CLOCK_DRIFT: "Sync device wall-clock time (NTP). Kora refuses new timestamps when drift exceeds five minutes.",
120
+ INVALID_TIMESTAMP_FIELDS: "HLC timestamps need non-negative integer wallTime (< 10^15) and logical (<= 99999). Generate timestamps through HybridLogicalClock instead of building them by hand.",
110
121
  PERSISTENCE_ERROR: "IndexedDB persistence failed; check browser storage settings and available disk quota.",
111
122
  MISSING_WORKER_URL: "Pass store.workerUrl pointing to sqlite-wasm-worker.js (see create-kora-app templates).",
112
123
  INVALID_SYNC_URL: "Use ws:// or wss:// for WebSocket transport, or http(s):// for HTTP long-polling.",
@@ -177,6 +188,39 @@ var StorageError = class extends KoraError {
177
188
  this.name = "StorageError";
178
189
  }
179
190
  };
191
+ var AppNotReadyError = class extends KoraError {
192
+ constructor(detail) {
193
+ super(detail, "APP_NOT_READY", {
194
+ fix: "Await app.ready, or wrap your UI in <KoraProvider app={app}> before calling useQuery()."
195
+ });
196
+ this.name = "AppNotReadyError";
197
+ }
198
+ };
199
+ var RemoteClockDriftError = class extends KoraError {
200
+ constructor(remoteWallTime, localReferenceTime) {
201
+ const aheadSeconds = Math.round((remoteWallTime - localReferenceTime) / 1e3);
202
+ super(
203
+ `Rejected remote timestamp ${aheadSeconds}s ahead of local reference time. The sending device's clock is set too far in the future.`,
204
+ "REMOTE_CLOCK_DRIFT",
205
+ { remoteWallTime, localReferenceTime, aheadSeconds }
206
+ );
207
+ this.remoteWallTime = remoteWallTime;
208
+ this.localReferenceTime = localReferenceTime;
209
+ this.name = "RemoteClockDriftError";
210
+ }
211
+ remoteWallTime;
212
+ localReferenceTime;
213
+ };
214
+ var InvalidTimestampError = class extends KoraError {
215
+ constructor(message, wallTime, logical) {
216
+ super(message, "INVALID_TIMESTAMP_FIELDS", { wallTime, logical });
217
+ this.wallTime = wallTime;
218
+ this.logical = logical;
219
+ this.name = "InvalidTimestampError";
220
+ }
221
+ wallTime;
222
+ logical;
223
+ };
180
224
  var ClockDriftError = class extends KoraError {
181
225
  constructor(currentHlcTime, physicalTime) {
182
226
  const driftSeconds = Math.round((currentHlcTime - physicalTime) / 1e3);
@@ -195,24 +239,51 @@ var ClockDriftError = class extends KoraError {
195
239
 
196
240
  // src/clock/hlc.ts
197
241
  var systemTimeSource = { now: () => Date.now() };
242
+ var MAX_LOGICAL = 99999;
243
+ var LOGICAL_MODULUS = MAX_LOGICAL + 1;
244
+ var WALL_TIME_LIMIT = 10 ** 15;
198
245
  var DRIFT_WARN_MS = 6e4;
199
246
  var DRIFT_ERROR_MS = 5 * 6e4;
200
- var HybridLogicalClock = class {
201
- constructor(nodeId, timeSource = systemTimeSource, onDriftWarning) {
247
+ var MAX_REMOTE_FUTURE_MS = 5 * 6e4;
248
+ var HybridLogicalClock = class _HybridLogicalClock {
249
+ constructor(nodeId, timeSource = systemTimeSource, onDriftWarning, onDriftError) {
202
250
  this.nodeId = nodeId;
203
251
  this.timeSource = timeSource;
204
252
  this.onDriftWarning = onDriftWarning;
253
+ this.onDriftError = onDriftError;
205
254
  }
206
255
  nodeId;
207
256
  timeSource;
208
257
  onDriftWarning;
258
+ onDriftError;
209
259
  wallTime = 0;
210
260
  logical = 0;
261
+ referenceOffsetMs = null;
262
+ /**
263
+ * Records the known offset between an external time reference (usually the
264
+ * sync server, learned at handshake) and this device's physical clock:
265
+ * `referenceTime - localPhysicalTime`. Once set, drift evaluation and remote
266
+ * timestamp validation are performed against reference-corrected time, so a
267
+ * device with a wrong local clock still validates remote timestamps correctly.
268
+ */
269
+ setReferenceOffset(offsetMs) {
270
+ this.referenceOffsetMs = offsetMs;
271
+ }
272
+ getReferenceOffset() {
273
+ return this.referenceOffsetMs;
274
+ }
275
+ /** Physical time corrected by the known reference offset, when available. */
276
+ effectiveTime(physicalTime) {
277
+ return physicalTime + (this.referenceOffsetMs ?? 0);
278
+ }
211
279
  /**
212
280
  * Generate a new timestamp for a local event.
213
281
  * Guarantees monotonicity: each call returns a timestamp strictly greater than the previous.
214
282
  *
215
- * @throws {ClockDriftError} If physical time is more than 5 minutes behind the HLC wallTime
283
+ * Never throws and never blocks a local write: if the physical clock has
284
+ * fallen behind the HLC (e.g. the user corrected a fast clock), the HLC
285
+ * freezes wallTime and advances the logical counter, and drift is reported
286
+ * through the onDriftWarning / onDriftError callbacks instead.
216
287
  */
217
288
  now() {
218
289
  const physicalTime = this.timeSource.now();
@@ -223,17 +294,40 @@ var HybridLogicalClock = class {
223
294
  } else {
224
295
  this.logical++;
225
296
  }
297
+ this.carryLogicalOverflow();
226
298
  return { wallTime: this.wallTime, logical: this.logical, nodeId: this.nodeId };
227
299
  }
228
300
  /**
229
301
  * Update clock on receiving a remote timestamp.
230
302
  * Merges the remote clock state with the local state to maintain causal ordering.
231
303
  *
232
- * @throws {ClockDriftError} If physical time is more than 5 minutes behind the resulting wallTime
304
+ * @throws {InvalidTimestampError} If the remote timestamp has non-integer or
305
+ * negative wallTime/logical, or logical beyond {@link MAX_LOGICAL}. Checked
306
+ * BEFORE any state change, so malformed input cannot corrupt this clock.
307
+ * @throws {RemoteClockDriftError} If the remote timestamp is more than 5 minutes
308
+ * ahead of reference-corrected local time. Validation happens BEFORE any state
309
+ * is adopted, so a rejected timestamp cannot poison this clock. When no
310
+ * reference offset is known and this clock is uninitialized (cold start with
311
+ * a possibly-wrong local clock), validation is skipped, matching the previous
312
+ * cold-start behavior but now without a corrupting failure mode afterward.
233
313
  */
234
314
  receive(remote) {
235
315
  const physicalTime = this.timeSource.now();
236
316
  const wasColdStart = this.wallTime === 0;
317
+ if (!Number.isInteger(remote.wallTime) || remote.wallTime < 0 || !Number.isInteger(remote.logical) || remote.logical < 0 || remote.logical > MAX_LOGICAL) {
318
+ throw new InvalidTimestampError(
319
+ `Rejected remote HLC timestamp with invalid fields (wallTime=${remote.wallTime}, logical=${remote.logical}). wallTime and logical must be non-negative integers and logical must not exceed ${MAX_LOGICAL}.`,
320
+ remote.wallTime,
321
+ remote.logical
322
+ );
323
+ }
324
+ const canValidate = this.referenceOffsetMs !== null || !wasColdStart;
325
+ if (canValidate) {
326
+ const reference = this.effectiveTime(physicalTime);
327
+ if (remote.wallTime > reference + MAX_REMOTE_FUTURE_MS) {
328
+ throw new RemoteClockDriftError(remote.wallTime, reference);
329
+ }
330
+ }
237
331
  if (physicalTime > this.wallTime && physicalTime > remote.wallTime) {
238
332
  this.wallTime = physicalTime;
239
333
  this.logical = 0;
@@ -245,11 +339,54 @@ var HybridLogicalClock = class {
245
339
  } else {
246
340
  this.logical++;
247
341
  }
342
+ this.carryLogicalOverflow();
248
343
  if (!wasColdStart) {
249
344
  this.checkDrift(physicalTime);
250
345
  }
251
346
  return { wallTime: this.wallTime, logical: this.logical, nodeId: this.nodeId };
252
347
  }
348
+ /**
349
+ * Advance this clock to at least the given timestamp.
350
+ *
351
+ * Used after a timestamp rebase rewrites unsynced operations: future `now()`
352
+ * timestamps must sort after every rebased operation, otherwise a write issued
353
+ * immediately after the rebase could interleave with (or precede) rebased ops
354
+ * and break the log's total order. Never moves the clock backward — a
355
+ * timestamp at or before the current state is a no-op, preserving the
356
+ * monotonicity guarantee of `now()`.
357
+ *
358
+ * Inputs with logical > MAX_LOGICAL are normalized deterministically by
359
+ * carrying the excess into wallTime, so the adopted state always leaves room
360
+ * for the next increment inside the serializable range.
361
+ */
362
+ advanceTo(ts) {
363
+ const normalized = {
364
+ wallTime: ts.wallTime + Math.floor(ts.logical / LOGICAL_MODULUS),
365
+ logical: ts.logical % LOGICAL_MODULUS,
366
+ nodeId: ts.nodeId
367
+ };
368
+ const current = {
369
+ wallTime: this.wallTime,
370
+ logical: this.logical,
371
+ nodeId: this.nodeId
372
+ };
373
+ if (_HybridLogicalClock.compare(normalized, current) > 0) {
374
+ this.wallTime = normalized.wallTime;
375
+ this.logical = normalized.logical;
376
+ }
377
+ }
378
+ /**
379
+ * Carry the logical counter into wallTime when an increment pushed it past
380
+ * MAX_LOGICAL. Bumping wallTime by 1ms keeps the timestamp strictly greater
381
+ * than everything issued before (monotonicity) while keeping the logical
382
+ * counter inside the 5-digit slot the serialized form depends on.
383
+ */
384
+ carryLogicalOverflow() {
385
+ if (this.logical > MAX_LOGICAL) {
386
+ this.wallTime += 1;
387
+ this.logical = 0;
388
+ }
389
+ }
253
390
  /**
254
391
  * Compare two timestamps. Returns negative if a < b, positive if a > b, zero if equal.
255
392
  * Total order: wallTime first, then logical, then nodeId (lexicographic).
@@ -264,8 +401,23 @@ var HybridLogicalClock = class {
264
401
  /**
265
402
  * Serialize an HLC timestamp to a string that sorts lexicographically.
266
403
  * Format: zero-padded wallTime:logical:nodeId
404
+ *
405
+ * @throws {InvalidTimestampError} If wallTime does not fit 15 digits or
406
+ * logical does not fit 5 digits (or either is negative/non-integer). Such a
407
+ * value would overflow its zero-padded slot and the serialized string would
408
+ * no longer sort in the same order as {@link HybridLogicalClock.compare} —
409
+ * silently corrupting every LWW comparison on stored `_version` columns.
410
+ * Internal clocks can no longer produce such values (the logical counter
411
+ * carries into wallTime); this guards against hand-built timestamps.
267
412
  */
268
413
  static serialize(ts) {
414
+ if (!Number.isInteger(ts.wallTime) || ts.wallTime < 0 || ts.wallTime >= WALL_TIME_LIMIT || !Number.isInteger(ts.logical) || ts.logical < 0 || ts.logical > MAX_LOGICAL) {
415
+ throw new InvalidTimestampError(
416
+ `Cannot serialize HLC timestamp (wallTime=${ts.wallTime}, logical=${ts.logical}): wallTime must be an integer in [0, 10^15) and logical an integer in [0, ${MAX_LOGICAL}]. Values outside these ranges overflow the zero-padded serialized form, which must sort lexicographically identically to HybridLogicalClock.compare.`,
417
+ ts.wallTime,
418
+ ts.logical
419
+ );
420
+ }
269
421
  const wall = ts.wallTime.toString().padStart(15, "0");
270
422
  const log = ts.logical.toString().padStart(5, "0");
271
423
  return `${wall}:${log}:${ts.nodeId}`;
@@ -285,10 +437,16 @@ var HybridLogicalClock = class {
285
437
  nodeId: parts.slice(2).join(":")
286
438
  };
287
439
  }
440
+ /**
441
+ * Reports drift between the HLC and (reference-corrected) physical time.
442
+ * Reporting only: local timestamp generation is never blocked, because the
443
+ * user's data always outranks the quality of its timestamps.
444
+ */
288
445
  checkDrift(physicalTime) {
289
- const drift = this.wallTime - physicalTime;
446
+ const drift = this.wallTime - this.effectiveTime(physicalTime);
290
447
  if (drift > DRIFT_ERROR_MS) {
291
- throw new ClockDriftError(this.wallTime, physicalTime);
448
+ this.onDriftError?.(drift);
449
+ return;
292
450
  }
293
451
  if (drift > DRIFT_WARN_MS) {
294
452
  this.onDriftWarning?.(drift);
@@ -671,6 +829,106 @@ function toAtomicOp(sentinel) {
671
829
  return { type: sentinel.type, value: sentinel.value };
672
830
  }
673
831
 
832
+ // src/operations/op-data-binary.ts
833
+ function isKoraBytesValue(value) {
834
+ if (typeof value !== "object" || value === null) {
835
+ return false;
836
+ }
837
+ const record = value;
838
+ return Object.keys(record).length === 1 && typeof record.$koraBytes === "string";
839
+ }
840
+ function isLegacyNumericByteObject(value) {
841
+ if (typeof value !== "object" || value === null || ArrayBuffer.isView(value)) {
842
+ return false;
843
+ }
844
+ const record = value;
845
+ const keys = Object.keys(record);
846
+ if (keys.length === 0) {
847
+ return false;
848
+ }
849
+ for (let i = 0; i < keys.length; i++) {
850
+ const byte = record[String(i)];
851
+ if (typeof byte !== "number" || !Number.isInteger(byte) || byte < 0 || byte > 255) {
852
+ return false;
853
+ }
854
+ }
855
+ return true;
856
+ }
857
+ var BASE64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
858
+ var BASE64_REVERSE = new Map(
859
+ Array.from(BASE64_ALPHABET, (char, index) => [char, index])
860
+ );
861
+ function bytesToBase64(bytes) {
862
+ let out = "";
863
+ for (let i = 0; i < bytes.length; i += 3) {
864
+ const b0 = bytes[i] ?? 0;
865
+ const b1 = bytes[i + 1] ?? 0;
866
+ const b2 = bytes[i + 2] ?? 0;
867
+ const triple = b0 << 16 | b1 << 8 | b2;
868
+ out += BASE64_ALPHABET[triple >> 18 & 63] ?? "";
869
+ out += BASE64_ALPHABET[triple >> 12 & 63] ?? "";
870
+ out += i + 1 < bytes.length ? BASE64_ALPHABET[triple >> 6 & 63] ?? "" : "=";
871
+ out += i + 2 < bytes.length ? BASE64_ALPHABET[triple & 63] ?? "" : "=";
872
+ }
873
+ return out;
874
+ }
875
+ function base64ToBytes(base64) {
876
+ const cleaned = base64.replace(/=+$/, "");
877
+ const out = new Uint8Array(Math.floor(cleaned.length * 6 / 8));
878
+ let buffer = 0;
879
+ let bits = 0;
880
+ let index = 0;
881
+ for (const char of cleaned) {
882
+ const value = BASE64_REVERSE.get(char);
883
+ if (value === void 0) {
884
+ throw new OperationError(`Invalid base64 character "${char}" in tagged binary value.`, {
885
+ char
886
+ });
887
+ }
888
+ buffer = buffer << 6 | value;
889
+ bits += 6;
890
+ if (bits >= 8) {
891
+ bits -= 8;
892
+ out[index] = buffer >> bits & 255;
893
+ index += 1;
894
+ }
895
+ }
896
+ return out;
897
+ }
898
+ function encodeBytesForOpData(value) {
899
+ if (typeof value === "string") {
900
+ return value;
901
+ }
902
+ const bytes = value instanceof Uint8Array ? value : new Uint8Array(value);
903
+ return { $koraBytes: bytesToBase64(bytes) };
904
+ }
905
+ function decodeBytesFromOpData(value) {
906
+ if (typeof value === "string") {
907
+ return value;
908
+ }
909
+ if (value instanceof Uint8Array) {
910
+ return value;
911
+ }
912
+ if (value instanceof ArrayBuffer) {
913
+ return new Uint8Array(value);
914
+ }
915
+ if (isKoraBytesValue(value)) {
916
+ return base64ToBytes(value.$koraBytes);
917
+ }
918
+ if (isLegacyNumericByteObject(value)) {
919
+ const keys = Object.keys(value);
920
+ const bytes = new Uint8Array(keys.length);
921
+ for (let i = 0; i < keys.length; i++) {
922
+ bytes[i] = value[String(i)] ?? 0;
923
+ }
924
+ return bytes;
925
+ }
926
+ throw new OperationError(
927
+ "Binary op-data value must be a string, Uint8Array, ArrayBuffer, tagged { $koraBytes } object, or legacy numeric-key byte object.",
928
+ { receivedType: typeof value }
929
+ );
930
+ }
931
+
674
932
  // src/scopes/sync-scope-bindings.ts
675
933
  function hasSchemaSyncRules(schema) {
676
934
  return schema.sync !== void 0 && Object.keys(schema.sync).length > 0;
@@ -1100,6 +1358,7 @@ function generateSQL(collectionName, collection, relations) {
1100
1358
  columns.push("_created_at INTEGER NOT NULL");
1101
1359
  columns.push("_updated_at INTEGER NOT NULL");
1102
1360
  columns.push("_version TEXT NOT NULL DEFAULT ''");
1361
+ columns.push("_field_versions TEXT NOT NULL DEFAULT '{}'");
1103
1362
  columns.push("_deleted INTEGER NOT NULL DEFAULT 0");
1104
1363
  statements.push(`CREATE TABLE IF NOT EXISTS ${collectionName} (
1105
1364
  ${columns.join(",\n ")}
@@ -1112,6 +1371,10 @@ ALTER TABLE ${collectionName} ADD COLUMN ${colDef}`);
1112
1371
  statements.push(
1113
1372
  `--kora:safe-alter
1114
1373
  ALTER TABLE ${collectionName} ADD COLUMN _version TEXT NOT NULL DEFAULT ''`
1374
+ );
1375
+ statements.push(
1376
+ `--kora:safe-alter
1377
+ ALTER TABLE ${collectionName} ADD COLUMN _field_versions TEXT NOT NULL DEFAULT '{}'`
1115
1378
  );
1116
1379
  for (const indexField of collection.indexes) {
1117
1380
  statements.push(
@@ -1139,6 +1402,9 @@ ALTER TABLE ${collectionName} ADD COLUMN _version TEXT NOT NULL DEFAULT ''`
1139
1402
  schema_version INTEGER NOT NULL
1140
1403
  )`
1141
1404
  );
1405
+ statements.push(
1406
+ `CREATE INDEX IF NOT EXISTS idx_kora_ops_${collectionName}_record_id ON _kora_ops_${collectionName} (record_id)`
1407
+ );
1142
1408
  return statements;
1143
1409
  }
1144
1410
  function generateFullDDL(schema) {
@@ -1604,9 +1870,9 @@ function validateFieldValue(collection, fieldName, descriptor, value) {
1604
1870
  break;
1605
1871
  }
1606
1872
  case "richtext": {
1607
- if (!(value instanceof Uint8Array) && typeof value !== "string") {
1873
+ if (!(value instanceof Uint8Array) && !(value instanceof ArrayBuffer) && typeof value !== "string") {
1608
1874
  throw new SchemaValidationError(
1609
- `Field "${fieldName}" in collection "${collection}" must be a Uint8Array or string for richtext, got ${typeof value}`,
1875
+ `Field "${fieldName}" in collection "${collection}" must be a Uint8Array, ArrayBuffer, or string for richtext, got ${typeof value}`,
1610
1876
  {
1611
1877
  collection,
1612
1878
  field: fieldName,
@@ -2462,6 +2728,7 @@ function generateProtoDefinitions(schema) {
2462
2728
  0 && (module.exports = {
2463
2729
  APPLY_FAILURE_CODES,
2464
2730
  APPLY_RESULTS,
2731
+ AppNotReadyError,
2465
2732
  ArrayFieldBuilder,
2466
2733
  CONNECTION_QUALITIES,
2467
2734
  CausalTracker,
@@ -2469,21 +2736,26 @@ function generateProtoDefinitions(schema) {
2469
2736
  EnumFieldBuilder,
2470
2737
  FieldBuilder,
2471
2738
  HybridLogicalClock,
2739
+ InvalidTimestampError,
2472
2740
  KORA_ERROR_FIX_SUGGESTIONS,
2473
2741
  KoraError,
2742
+ MAX_LOGICAL,
2474
2743
  MERGE_STRATEGIES,
2475
2744
  MergeConflictError,
2476
2745
  MigrationBuilder,
2477
2746
  MigrationRollbackError,
2478
2747
  OperationError,
2748
+ RemoteClockDriftError,
2479
2749
  RollbackBuilder,
2480
2750
  SchemaValidationError,
2481
2751
  StorageError,
2482
2752
  SyncError,
2483
2753
  advanceVector,
2484
2754
  applyOperationTransforms,
2755
+ base64ToBytes,
2485
2756
  buildScopeMap,
2486
2757
  buildStateMachineConstraints,
2758
+ bytesToBase64,
2487
2759
  canAutoRollback,
2488
2760
  collectSchemaScopeFields,
2489
2761
  collectSchemaScopeValueKeys,
@@ -2491,11 +2763,13 @@ function generateProtoDefinitions(schema) {
2491
2763
  createOperation,
2492
2764
  createReversibleMigration,
2493
2765
  createVersionVector,
2766
+ decodeBytesFromOpData,
2494
2767
  defaultApplyFailureReason,
2495
2768
  defaultSequenceFormat,
2496
2769
  defineSchema,
2497
2770
  deserializeVector,
2498
2771
  dominates,
2772
+ encodeBytesForOpData,
2499
2773
  extractScopeValuesFromClaims,
2500
2774
  extractTimestamp,
2501
2775
  formatSequenceValue,
@@ -2511,6 +2785,8 @@ function generateProtoDefinitions(schema) {
2511
2785
  isApplyFailure,
2512
2786
  isAtomicOp,
2513
2787
  isCollectionSyncScoped,
2788
+ isKoraBytesValue,
2789
+ isLegacyNumericByteObject,
2514
2790
  isValidOperation,
2515
2791
  isValidUUIDv7,
2516
2792
  mergeVectors,