@korajs/store 1.0.0-beta.4 → 1.0.0-beta.6

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 (62) hide show
  1. package/dist/adapters/better-sqlite3.d.cts +1 -1
  2. package/dist/adapters/better-sqlite3.d.ts +1 -1
  3. package/dist/adapters/indexeddb.cjs +309 -125
  4. package/dist/adapters/indexeddb.cjs.map +1 -1
  5. package/dist/adapters/indexeddb.d.cts +4 -2
  6. package/dist/adapters/indexeddb.d.ts +4 -2
  7. package/dist/adapters/indexeddb.js +7 -2
  8. package/dist/adapters/indexeddb.js.map +1 -1
  9. package/dist/adapters/sqlite-wasm-worker.cjs +206 -208
  10. package/dist/adapters/sqlite-wasm-worker.cjs.map +1 -1
  11. package/dist/adapters/sqlite-wasm-worker.js +206 -208
  12. package/dist/adapters/sqlite-wasm-worker.js.map +1 -1
  13. package/dist/adapters/sqlite-wasm.cjs +304 -125
  14. package/dist/adapters/sqlite-wasm.cjs.map +1 -1
  15. package/dist/adapters/sqlite-wasm.d.cts +18 -7
  16. package/dist/adapters/sqlite-wasm.d.ts +18 -7
  17. package/dist/adapters/sqlite-wasm.js +2 -2
  18. package/dist/{backup-IQE4QC7Q.js → backup-5S7K2Z35.js} +3 -3
  19. package/dist/{chunk-RCTG3IJG.js → chunk-CYO3YKFL.js} +2 -2
  20. package/dist/{chunk-2ZRQGFEF.js → chunk-FKW56RVZ.js} +306 -126
  21. package/dist/chunk-FKW56RVZ.js.map +1 -0
  22. package/dist/{chunk-6NKLDBTY.js → chunk-GSJ7EEUC.js} +2 -1
  23. package/dist/chunk-GSJ7EEUC.js.map +1 -0
  24. package/dist/{chunk-OCOGQRHW.js → chunk-HS6DBMST.js} +2 -2
  25. package/dist/{chunk-COJSQBXW.js → chunk-VDBJQ75K.js} +1 -1
  26. package/dist/chunk-VDBJQ75K.js.map +1 -0
  27. package/dist/{chunk-UXRWVXBP.js → chunk-YT7MRFCP.js} +6 -6
  28. package/dist/{export-audit-MT2LTMIN.js → export-audit-ODGQTQIK.js} +3 -3
  29. package/dist/index.cjs +136 -3
  30. package/dist/index.cjs.map +1 -1
  31. package/dist/index.d.cts +35 -4
  32. package/dist/index.d.ts +35 -4
  33. package/dist/index.js +160 -27
  34. package/dist/index.js.map +1 -1
  35. package/dist/internal.cjs +1 -0
  36. package/dist/internal.cjs.map +1 -1
  37. package/dist/internal.d.cts +3 -3
  38. package/dist/internal.d.ts +3 -3
  39. package/dist/internal.js +3 -3
  40. package/dist/{sqlite-wasm-channel-NGSBJR44.js → sqlite-wasm-channel-GGHA2BXU.js} +2 -2
  41. package/dist/{sqlite-wasm-channel-CNHRf-m2.d.cts → sqlite-wasm-channel-L6o3bWQK.d.cts} +2 -2
  42. package/dist/{sqlite-wasm-channel-CNHRf-m2.d.ts → sqlite-wasm-channel-L6o3bWQK.d.ts} +2 -2
  43. package/dist/{types-5h4Hqcwc.d.ts → types-BOO9EPt1.d.ts} +1 -1
  44. package/dist/{types-k6AZgiH4.d.ts → types-BslDOTk0.d.cts} +26 -1
  45. package/dist/{types-k6AZgiH4.d.cts → types-BslDOTk0.d.ts} +26 -1
  46. package/dist/{types-DfPiPwKr.d.cts → types-C_GDavG-.d.cts} +1 -1
  47. package/package.json +2 -12
  48. package/dist/adapters/sqlite-wasm-shared-host.cjs +0 -95
  49. package/dist/adapters/sqlite-wasm-shared-host.cjs.map +0 -1
  50. package/dist/adapters/sqlite-wasm-shared-host.d.cts +0 -64
  51. package/dist/adapters/sqlite-wasm-shared-host.d.ts +0 -64
  52. package/dist/adapters/sqlite-wasm-shared-host.js +0 -70
  53. package/dist/adapters/sqlite-wasm-shared-host.js.map +0 -1
  54. package/dist/chunk-2ZRQGFEF.js.map +0 -1
  55. package/dist/chunk-6NKLDBTY.js.map +0 -1
  56. package/dist/chunk-COJSQBXW.js.map +0 -1
  57. /package/dist/{backup-IQE4QC7Q.js.map → backup-5S7K2Z35.js.map} +0 -0
  58. /package/dist/{chunk-RCTG3IJG.js.map → chunk-CYO3YKFL.js.map} +0 -0
  59. /package/dist/{chunk-OCOGQRHW.js.map → chunk-HS6DBMST.js.map} +0 -0
  60. /package/dist/{chunk-UXRWVXBP.js.map → chunk-YT7MRFCP.js.map} +0 -0
  61. /package/dist/{export-audit-MT2LTMIN.js.map → export-audit-ODGQTQIK.js.map} +0 -0
  62. /package/dist/{sqlite-wasm-channel-NGSBJR44.js.map → sqlite-wasm-channel-GGHA2BXU.js.map} +0 -0
package/dist/index.d.cts CHANGED
@@ -1,9 +1,9 @@
1
- import { C as CollectionRecord, S as StorageAdapter, Q as QueryDescriptor, c as SubscriptionCallback, W as WhereClause, d as OrderByDirection, L as LocalMutationHandler, e as StoreConfig, A as ApplyRemoteOptions, f as MaterializedRowSnapshot, g as RowVersionState } from './types-k6AZgiH4.cjs';
2
- export { M as MigrationPlan, h as OrderByClause, i as StoreIsolation, T as Transaction, j as TransactionBufferedEntry, k as TransactionCommitBatch, l as TransactionCommitResult, m as WhereOperators } from './types-k6AZgiH4.cjs';
1
+ import { C as CollectionRecord, S as StorageAdapter, Q as QueryDescriptor, d as SubscriptionCallback, W as WhereClause, e as OrderByDirection, L as LocalMutationHandler, f as StoreConfig, A as ApplyRemoteOptions, g as MaterializedRowSnapshot, h as RowVersionState } from './types-BslDOTk0.cjs';
2
+ export { M as MigrationPlan, i as OrderByClause, j as StorageFallbackReason, a as StorageOpenState, k as StoreIsolation, T as Transaction, l as TransactionBufferedEntry, m as TransactionCommitBatch, n as TransactionCommitResult, o as WhereOperators } from './types-BslDOTk0.cjs';
3
3
  import { Operation, KoraError, VersionVector, SchemaDefinition, HLCTimestamp, MergeTrace, CollectionDefinition, SequenceConfig, HybridLogicalClock, CausalTracker, OperationLog, ApplyResult, StateMachineDefinition, KoraBytesValue, KoraEvent, BlobRefMetadata, BlobRef } from '@korajs/core';
4
4
  export { ApplyResult } from '@korajs/core';
5
- import { R as RelationEnforcer, L as LocalMutationContext } from './types-DfPiPwKr.cjs';
6
- export { C as Collection } from './types-DfPiPwKr.cjs';
5
+ import { R as RelationEnforcer, L as LocalMutationContext } from './types-C_GDavG-.cjs';
6
+ export { C as Collection } from './types-C_GDavG-.cjs';
7
7
  import * as yjs from 'yjs';
8
8
  import { C as ContentAddressedBlobStore, M as MemoryBlobStore } from './content-addressed-blob-store-Dcj3SB9r.cjs';
9
9
  export { B as BlobIntegrityError } from './content-addressed-blob-store-Dcj3SB9r.cjs';
@@ -820,6 +820,14 @@ declare class Store implements OperationLog {
820
820
  * Route local CRUD through the unified apply pipeline (korajs ApplyPipeline).
821
821
  */
822
822
  setLocalMutationHandler(handler: LocalMutationHandler | null): void;
823
+ /**
824
+ * Notify this store that another same-origin runtime committed an operation to
825
+ * the shared local database. The operation has already been persisted and
826
+ * materialized by the database owner; this method only advances in-memory causal
827
+ * watermarks and invalidates local reactive queries so already-open tabs stay
828
+ * live without reapplying or rewriting the operation.
829
+ */
830
+ notifyExternalOperation(operation: Operation): void;
823
831
  /**
824
832
  * Build mutation context for a collection (used by ApplyPipeline side effects).
825
833
  */
@@ -858,6 +866,23 @@ declare class Store implements OperationLog {
858
866
  * Persist or clear the delta cursor for paginated initial sync resume.
859
867
  */
860
868
  saveDeltaCursor(cursor: string | null): Promise<void>;
869
+ /**
870
+ * Load the persisted delivery watermark for a view signature (0 when none recorded).
871
+ * Defaults to the unfiltered view so existing single-watermark reads keep working.
872
+ */
873
+ loadDeliveryWatermark(signature?: string): Promise<number>;
874
+ /**
875
+ * Persist the delivery watermark for a view signature so it survives a client restart.
876
+ */
877
+ saveDeliveryWatermark(signature: string, watermark: number): Promise<void>;
878
+ /**
879
+ * Load every persisted view watermark, keyed by signature.
880
+ */
881
+ loadAllDeliveryWatermarks(): Promise<Record<string, number>>;
882
+ /**
883
+ * Delete a persisted view watermark (safe: the view back-fills from 0 when next visited).
884
+ */
885
+ deleteDeliveryWatermark(signature: string): Promise<void>;
861
886
  /**
862
887
  * Local operations not yet reflected on the server version vector.
863
888
  */
@@ -892,6 +917,12 @@ declare class Store implements OperationLog {
892
917
  * Latest operation for a record from any node (for 3-way merge when local op log is empty).
893
918
  */
894
919
  getLatestOperationForRecord(collection: string, recordId: string): Promise<Operation | null>;
920
+ /**
921
+ * All operations for a record, sorted in HLC total order (wallTime, logical,
922
+ * nodeId). Used by the apply pipeline to materialize atomic-op fields by folding
923
+ * the record's log, matching the server's materialization exactly.
924
+ */
925
+ getOperationsForRecord(collection: string, recordId: string): Promise<Operation[]>;
895
926
  /** Expose the subscription manager for direct access (e.g., by QueryBuilder) */
896
927
  getSubscriptionManager(): SubscriptionManager;
897
928
  /**
package/dist/index.d.ts CHANGED
@@ -1,9 +1,9 @@
1
- import { C as CollectionRecord, S as StorageAdapter, Q as QueryDescriptor, c as SubscriptionCallback, W as WhereClause, d as OrderByDirection, L as LocalMutationHandler, e as StoreConfig, A as ApplyRemoteOptions, f as MaterializedRowSnapshot, g as RowVersionState } from './types-k6AZgiH4.js';
2
- export { M as MigrationPlan, h as OrderByClause, i as StoreIsolation, T as Transaction, j as TransactionBufferedEntry, k as TransactionCommitBatch, l as TransactionCommitResult, m as WhereOperators } from './types-k6AZgiH4.js';
1
+ import { C as CollectionRecord, S as StorageAdapter, Q as QueryDescriptor, d as SubscriptionCallback, W as WhereClause, e as OrderByDirection, L as LocalMutationHandler, f as StoreConfig, A as ApplyRemoteOptions, g as MaterializedRowSnapshot, h as RowVersionState } from './types-BslDOTk0.js';
2
+ export { M as MigrationPlan, i as OrderByClause, j as StorageFallbackReason, a as StorageOpenState, k as StoreIsolation, T as Transaction, l as TransactionBufferedEntry, m as TransactionCommitBatch, n as TransactionCommitResult, o as WhereOperators } from './types-BslDOTk0.js';
3
3
  import { Operation, KoraError, VersionVector, SchemaDefinition, HLCTimestamp, MergeTrace, CollectionDefinition, SequenceConfig, HybridLogicalClock, CausalTracker, OperationLog, ApplyResult, StateMachineDefinition, KoraBytesValue, KoraEvent, BlobRefMetadata, BlobRef } from '@korajs/core';
4
4
  export { ApplyResult } from '@korajs/core';
5
- import { R as RelationEnforcer, L as LocalMutationContext } from './types-5h4Hqcwc.js';
6
- export { C as Collection } from './types-5h4Hqcwc.js';
5
+ import { R as RelationEnforcer, L as LocalMutationContext } from './types-BOO9EPt1.js';
6
+ export { C as Collection } from './types-BOO9EPt1.js';
7
7
  import * as yjs from 'yjs';
8
8
  import { C as ContentAddressedBlobStore, M as MemoryBlobStore } from './content-addressed-blob-store-Dcj3SB9r.js';
9
9
  export { B as BlobIntegrityError } from './content-addressed-blob-store-Dcj3SB9r.js';
@@ -820,6 +820,14 @@ declare class Store implements OperationLog {
820
820
  * Route local CRUD through the unified apply pipeline (korajs ApplyPipeline).
821
821
  */
822
822
  setLocalMutationHandler(handler: LocalMutationHandler | null): void;
823
+ /**
824
+ * Notify this store that another same-origin runtime committed an operation to
825
+ * the shared local database. The operation has already been persisted and
826
+ * materialized by the database owner; this method only advances in-memory causal
827
+ * watermarks and invalidates local reactive queries so already-open tabs stay
828
+ * live without reapplying or rewriting the operation.
829
+ */
830
+ notifyExternalOperation(operation: Operation): void;
823
831
  /**
824
832
  * Build mutation context for a collection (used by ApplyPipeline side effects).
825
833
  */
@@ -858,6 +866,23 @@ declare class Store implements OperationLog {
858
866
  * Persist or clear the delta cursor for paginated initial sync resume.
859
867
  */
860
868
  saveDeltaCursor(cursor: string | null): Promise<void>;
869
+ /**
870
+ * Load the persisted delivery watermark for a view signature (0 when none recorded).
871
+ * Defaults to the unfiltered view so existing single-watermark reads keep working.
872
+ */
873
+ loadDeliveryWatermark(signature?: string): Promise<number>;
874
+ /**
875
+ * Persist the delivery watermark for a view signature so it survives a client restart.
876
+ */
877
+ saveDeliveryWatermark(signature: string, watermark: number): Promise<void>;
878
+ /**
879
+ * Load every persisted view watermark, keyed by signature.
880
+ */
881
+ loadAllDeliveryWatermarks(): Promise<Record<string, number>>;
882
+ /**
883
+ * Delete a persisted view watermark (safe: the view back-fills from 0 when next visited).
884
+ */
885
+ deleteDeliveryWatermark(signature: string): Promise<void>;
861
886
  /**
862
887
  * Local operations not yet reflected on the server version vector.
863
888
  */
@@ -892,6 +917,12 @@ declare class Store implements OperationLog {
892
917
  * Latest operation for a record from any node (for 3-way merge when local op log is empty).
893
918
  */
894
919
  getLatestOperationForRecord(collection: string, recordId: string): Promise<Operation | null>;
920
+ /**
921
+ * All operations for a record, sorted in HLC total order (wallTime, logical,
922
+ * nodeId). Used by the apply pipeline to materialize atomic-op fields by folding
923
+ * the record's log, matching the server's materialization exactly.
924
+ */
925
+ getOperationsForRecord(collection: string, recordId: string): Promise<Operation[]>;
895
926
  /** Expose the subscription manager for direct access (e.g., by QueryBuilder) */
896
927
  getSubscriptionManager(): SubscriptionManager;
897
928
  /**
package/dist/index.js CHANGED
@@ -1,14 +1,8 @@
1
- import {
2
- exportBackup,
3
- readBackupManifest,
4
- restoreBackup,
5
- verifyBackupChecksum
6
- } from "./chunk-OCOGQRHW.js";
7
1
  import {
8
2
  decodeAuditExport,
9
3
  readAuditExportManifest,
10
4
  verifyAuditExportChecksum
11
- } from "./chunk-RCTG3IJG.js";
5
+ } from "./chunk-CYO3YKFL.js";
12
6
  import {
13
7
  persistedAuditTraceFromEvent
14
8
  } from "./chunk-MYSJN3DF.js";
@@ -39,19 +33,7 @@ import {
39
33
  serializeRowVersion,
40
34
  validateStateTransition,
41
35
  validateUpdateStateMachine
42
- } from "./chunk-UXRWVXBP.js";
43
- import {
44
- decodeRichtext,
45
- decodeRichtextFieldsFromOpData,
46
- deserializeOperationWithCollection,
47
- deserializeRecord,
48
- encodeRichtext,
49
- encodeRichtextFieldsForOpData,
50
- richtextStatesEqual,
51
- richtextToPlainText,
52
- serializeOperation,
53
- serializeRecord
54
- } from "./chunk-6NKLDBTY.js";
36
+ } from "./chunk-YT7MRFCP.js";
55
37
  import {
56
38
  AdapterError,
57
39
  NoLeaderError,
@@ -63,6 +45,24 @@ import {
63
45
  WorkerInitError,
64
46
  WorkerTimeoutError
65
47
  } from "./chunk-TUR7RGEP.js";
48
+ import {
49
+ exportBackup,
50
+ readBackupManifest,
51
+ restoreBackup,
52
+ verifyBackupChecksum
53
+ } from "./chunk-HS6DBMST.js";
54
+ import {
55
+ decodeRichtext,
56
+ decodeRichtextFieldsFromOpData,
57
+ deserializeOperationWithCollection,
58
+ deserializeRecord,
59
+ encodeRichtext,
60
+ encodeRichtextFieldsForOpData,
61
+ richtextStatesEqual,
62
+ richtextToPlainText,
63
+ serializeOperation,
64
+ serializeRecord
65
+ } from "./chunk-GSJ7EEUC.js";
66
66
 
67
67
  // src/compaction/types.ts
68
68
  var COMPACTION_BASELINE_META_KEY = "compaction_baseline_at";
@@ -131,6 +131,7 @@ function buildDeleteSql(table, withAge) {
131
131
  import { createVersionVector as createVersionVector2 } from "@korajs/core";
132
132
  var LAST_ACKED_SERVER_VECTOR_META_KEY = "last_acked_server_vector";
133
133
  var DELTA_CURSOR_META_KEY = "delta_cursor";
134
+ var DELIVERY_WATERMARK_META_KEY = "delivery_watermark";
134
135
  function serializeVersionVectorToMeta(vector) {
135
136
  const record = {};
136
137
  for (const [nodeId, seq] of vector) {
@@ -203,6 +204,45 @@ async function saveDeltaCursor(adapter, cursor) {
203
204
  cursor
204
205
  ]);
205
206
  }
207
+ function deliveryWatermarkKey(signature) {
208
+ return signature === "" ? DELIVERY_WATERMARK_META_KEY : `${DELIVERY_WATERMARK_META_KEY}:${signature}`;
209
+ }
210
+ async function loadDeliveryWatermark(adapter, signature) {
211
+ const rows = await adapter.query("SELECT value FROM _kora_meta WHERE key = ?", [
212
+ deliveryWatermarkKey(signature)
213
+ ]);
214
+ const value = rows[0]?.value;
215
+ if (value === void 0 || value === null) {
216
+ return 0;
217
+ }
218
+ const parsed = Number(value);
219
+ return Number.isFinite(parsed) && parsed >= 0 ? parsed : 0;
220
+ }
221
+ async function saveDeliveryWatermark(adapter, signature, watermark) {
222
+ await adapter.execute("INSERT OR REPLACE INTO _kora_meta (key, value) VALUES (?, ?)", [
223
+ deliveryWatermarkKey(signature),
224
+ String(watermark)
225
+ ]);
226
+ }
227
+ async function deleteDeliveryWatermark(adapter, signature) {
228
+ await adapter.execute("DELETE FROM _kora_meta WHERE key = ?", [deliveryWatermarkKey(signature)]);
229
+ }
230
+ async function loadAllDeliveryWatermarks(adapter) {
231
+ const rows = await adapter.query(
232
+ "SELECT key, value FROM _kora_meta WHERE key = ? OR key LIKE ?",
233
+ [DELIVERY_WATERMARK_META_KEY, `${DELIVERY_WATERMARK_META_KEY}:%`]
234
+ );
235
+ const result = {};
236
+ const prefix = `${DELIVERY_WATERMARK_META_KEY}:`;
237
+ for (const row of rows) {
238
+ const signature = row.key === DELIVERY_WATERMARK_META_KEY ? "" : row.key.slice(prefix.length);
239
+ const parsed = Number(row.value);
240
+ if (Number.isFinite(parsed) && parsed >= 0) {
241
+ result[signature] = parsed;
242
+ }
243
+ }
244
+ return result;
245
+ }
206
246
 
207
247
  // src/store/store.ts
208
248
  import {
@@ -211,7 +251,8 @@ import {
211
251
  createVersionVector as createVersionVector3,
212
252
  generateUUIDv7 as generateUUIDv73,
213
253
  migrationStepsToSQL,
214
- quoteIdent as quoteIdent7
254
+ quoteIdent as quoteIdent7,
255
+ replayOperationsForRecord
215
256
  } from "@korajs/core";
216
257
 
217
258
  // src/collection/collection.ts
@@ -2196,7 +2237,8 @@ var Store = class {
2196
2237
  throw new OptimisticLockError(collection, op.recordId);
2197
2238
  }
2198
2239
  };
2199
- if (op.type === "insert" && materializeSource) {
2240
+ if (options?.logOnly) {
2241
+ } else if (op.type === "insert" && materializeSource) {
2200
2242
  const serializedData = serializeRecord(materializeSource, definition.fields);
2201
2243
  const existing2 = await tx.query(
2202
2244
  `SELECT _updated_at, _version, _field_versions, _deleted FROM ${collection} WHERE id = ?`,
@@ -2218,7 +2260,7 @@ var Store = class {
2218
2260
  };
2219
2261
  const insertQuery = buildInsertQuery(collection, record);
2220
2262
  await tx.execute(insertQuery.sql, insertQuery.params);
2221
- await this.foldOrphanedOperations(tx, collection, definition, op.recordId);
2263
+ await this.foldOrphanedOperations(tx, collection, definition, op.recordId, op);
2222
2264
  } else if (row._deleted === 1) {
2223
2265
  if (isIncomingNewerThanRow(materializeTimestamp, row)) {
2224
2266
  const fieldChanges = {
@@ -2370,7 +2412,7 @@ var Store = class {
2370
2412
  * necessarily an orphan (rows are soft-deleted, never removed, so a row
2371
2413
  * that is absent now was never materialized).
2372
2414
  */
2373
- async foldOrphanedOperations(tx, collection, definition, recordId) {
2415
+ async foldOrphanedOperations(tx, collection, definition, recordId, insertOp) {
2374
2416
  const orphanRows = await tx.query(
2375
2417
  `SELECT * FROM ${quoteIdent7(`_kora_ops_${collection}`)} WHERE record_id = ? AND type IN ('update', 'delete')`,
2376
2418
  [recordId]
@@ -2419,6 +2461,37 @@ var Store = class {
2419
2461
  await tx.execute(query.sql, query.params);
2420
2462
  }
2421
2463
  }
2464
+ const atomicFields = /* @__PURE__ */ new Set();
2465
+ for (const orphan of orphans) {
2466
+ if (orphan.type === "update" && orphan.atomicOps) {
2467
+ for (const field of Object.keys(orphan.atomicOps)) {
2468
+ atomicFields.add(field);
2469
+ }
2470
+ }
2471
+ }
2472
+ if (atomicFields.size > 0) {
2473
+ const ordered = [insertOp, ...orphans].sort(
2474
+ (a, b) => HybridLogicalClock3.compare(a.timestamp, b.timestamp)
2475
+ );
2476
+ const folded = replayOperationsForRecord(ordered);
2477
+ if (folded) {
2478
+ const composed = {};
2479
+ for (const field of atomicFields) {
2480
+ if (field in folded) {
2481
+ composed[field] = folded[field];
2482
+ }
2483
+ }
2484
+ const serialized = serializeRecord(composed, definition.fields);
2485
+ const cols = Object.keys(serialized);
2486
+ if (cols.length > 0) {
2487
+ const setClause = cols.map((c) => `${quoteIdent7(c)} = ?`).join(", ");
2488
+ await tx.execute(`UPDATE ${quoteIdent7(collection)} SET ${setClause} WHERE id = ?`, [
2489
+ ...cols.map((c) => serialized[c]),
2490
+ recordId
2491
+ ]);
2492
+ }
2493
+ }
2494
+ }
2422
2495
  }
2423
2496
  /**
2424
2497
  * Get operations from a node within a sequence number range.
@@ -2505,7 +2578,7 @@ var Store = class {
2505
2578
  */
2506
2579
  async exportAudit(options) {
2507
2580
  this.ensureOpen();
2508
- const { exportAudit: doExport } = await import("./export-audit-MT2LTMIN.js");
2581
+ const { exportAudit: doExport } = await import("./export-audit-ODGQTQIK.js");
2509
2582
  return doExport(this.adapter, this.schema, this.nodeId, this.schema.version, options);
2510
2583
  }
2511
2584
  /**
@@ -2523,6 +2596,22 @@ var Store = class {
2523
2596
  col.setMutationHandler(handler);
2524
2597
  }
2525
2598
  }
2599
+ /**
2600
+ * Notify this store that another same-origin runtime committed an operation to
2601
+ * the shared local database. The operation has already been persisted and
2602
+ * materialized by the database owner; this method only advances in-memory causal
2603
+ * watermarks and invalidates local reactive queries so already-open tabs stay
2604
+ * live without reapplying or rewriting the operation.
2605
+ */
2606
+ notifyExternalOperation(operation) {
2607
+ this.ensureOpen();
2608
+ const definition = this.schema.collections[operation.collection];
2609
+ if (!definition) {
2610
+ return;
2611
+ }
2612
+ this.recordOperationSequence(operation);
2613
+ this.subscriptionManager.notify(operation.collection, operation);
2614
+ }
2526
2615
  /**
2527
2616
  * Build mutation context for a collection (used by ApplyPipeline side effects).
2528
2617
  */
@@ -2632,6 +2721,35 @@ var Store = class {
2632
2721
  this.ensureOpen();
2633
2722
  await saveDeltaCursor(this.adapter, cursor);
2634
2723
  }
2724
+ /**
2725
+ * Load the persisted delivery watermark for a view signature (0 when none recorded).
2726
+ * Defaults to the unfiltered view so existing single-watermark reads keep working.
2727
+ */
2728
+ async loadDeliveryWatermark(signature = "") {
2729
+ this.ensureOpen();
2730
+ return loadDeliveryWatermark(this.adapter, signature);
2731
+ }
2732
+ /**
2733
+ * Persist the delivery watermark for a view signature so it survives a client restart.
2734
+ */
2735
+ async saveDeliveryWatermark(signature, watermark) {
2736
+ this.ensureOpen();
2737
+ await saveDeliveryWatermark(this.adapter, signature, watermark);
2738
+ }
2739
+ /**
2740
+ * Load every persisted view watermark, keyed by signature.
2741
+ */
2742
+ async loadAllDeliveryWatermarks() {
2743
+ this.ensureOpen();
2744
+ return loadAllDeliveryWatermarks(this.adapter);
2745
+ }
2746
+ /**
2747
+ * Delete a persisted view watermark (safe: the view back-fills from 0 when next visited).
2748
+ */
2749
+ async deleteDeliveryWatermark(signature) {
2750
+ this.ensureOpen();
2751
+ await deleteDeliveryWatermark(this.adapter, signature);
2752
+ }
2635
2753
  /**
2636
2754
  * Local operations not yet reflected on the server version vector.
2637
2755
  */
@@ -2722,6 +2840,21 @@ var Store = class {
2722
2840
  }
2723
2841
  return latest;
2724
2842
  }
2843
+ /**
2844
+ * All operations for a record, sorted in HLC total order (wallTime, logical,
2845
+ * nodeId). Used by the apply pipeline to materialize atomic-op fields by folding
2846
+ * the record's log, matching the server's materialization exactly.
2847
+ */
2848
+ async getOperationsForRecord(collection, recordId) {
2849
+ this.ensureOpen();
2850
+ const rows = await this.adapter.query(
2851
+ `SELECT * FROM ${quoteIdent7(`_kora_ops_${collection}`)} WHERE record_id = ?`,
2852
+ [recordId]
2853
+ );
2854
+ const ops = rows.map((row) => deserializeOperationWithCollection(row, collection));
2855
+ ops.sort((a, b) => HybridLogicalClock3.compare(a.timestamp, b.timestamp));
2856
+ return ops;
2857
+ }
2725
2858
  /** Expose the subscription manager for direct access (e.g., by QueryBuilder) */
2726
2859
  getSubscriptionManager() {
2727
2860
  return this.subscriptionManager;
@@ -2800,7 +2933,7 @@ var Store = class {
2800
2933
  */
2801
2934
  async exportBackup(options) {
2802
2935
  this.ensureOpen();
2803
- const { exportBackup: doExport } = await import("./backup-IQE4QC7Q.js");
2936
+ const { exportBackup: doExport } = await import("./backup-5S7K2Z35.js");
2804
2937
  return doExport(this.adapter, this.schema, this.nodeId, this.schema.version, options);
2805
2938
  }
2806
2939
  /**
@@ -2812,7 +2945,7 @@ var Store = class {
2812
2945
  */
2813
2946
  async importBackup(data, options) {
2814
2947
  this.ensureOpen();
2815
- const { restoreBackup: doRestore } = await import("./backup-IQE4QC7Q.js");
2948
+ const { restoreBackup: doRestore } = await import("./backup-5S7K2Z35.js");
2816
2949
  return doRestore(this.adapter, this.schema, data, options);
2817
2950
  }
2818
2951
  /**