@korajs/store 0.4.0 → 0.5.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 (69) 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 +410 -17
  4. package/dist/adapters/indexeddb.cjs.map +1 -1
  5. package/dist/adapters/indexeddb.d.cts +23 -5
  6. package/dist/adapters/indexeddb.d.ts +23 -5
  7. package/dist/adapters/indexeddb.js +163 -18
  8. package/dist/adapters/indexeddb.js.map +1 -1
  9. package/dist/adapters/sqlite-wasm-shared-host.cjs +68 -0
  10. package/dist/adapters/sqlite-wasm-shared-host.cjs.map +1 -0
  11. package/dist/adapters/sqlite-wasm-shared-host.d.cts +2 -0
  12. package/dist/adapters/sqlite-wasm-shared-host.d.ts +2 -0
  13. package/dist/adapters/sqlite-wasm-shared-host.js +66 -0
  14. package/dist/adapters/sqlite-wasm-shared-host.js.map +1 -0
  15. package/dist/adapters/sqlite-wasm-worker.cjs +34 -5
  16. package/dist/adapters/sqlite-wasm-worker.cjs.map +1 -1
  17. package/dist/adapters/sqlite-wasm-worker.js +34 -5
  18. package/dist/adapters/sqlite-wasm-worker.js.map +1 -1
  19. package/dist/adapters/sqlite-wasm.cjs +249 -2
  20. package/dist/adapters/sqlite-wasm.cjs.map +1 -1
  21. package/dist/adapters/sqlite-wasm.d.cts +15 -3
  22. package/dist/adapters/sqlite-wasm.d.ts +15 -3
  23. package/dist/adapters/sqlite-wasm.js +2 -2
  24. package/dist/audit-trace-store-AM4EWQNZ.js +15 -0
  25. package/dist/backup-JN3LB4YT.js +14 -0
  26. package/dist/backup-JN3LB4YT.js.map +1 -0
  27. package/dist/chunk-56LL4XP6.js +205 -0
  28. package/dist/chunk-56LL4XP6.js.map +1 -0
  29. package/dist/chunk-6AHYGQQT.js +425 -0
  30. package/dist/chunk-6AHYGQQT.js.map +1 -0
  31. package/dist/chunk-7BPETY5Y.js +570 -0
  32. package/dist/chunk-7BPETY5Y.js.map +1 -0
  33. package/dist/chunk-AGN3CIPB.js +188 -0
  34. package/dist/chunk-AGN3CIPB.js.map +1 -0
  35. package/dist/chunk-EZSTD2XC.js +380 -0
  36. package/dist/chunk-EZSTD2XC.js.map +1 -0
  37. package/dist/chunk-MYSJN3DF.js +117 -0
  38. package/dist/chunk-MYSJN3DF.js.map +1 -0
  39. package/dist/{chunk-DXKLAQ6P.js → chunk-XO4LMPAH.js} +1 -1
  40. package/dist/chunk-XO4LMPAH.js.map +1 -0
  41. package/dist/export-audit-5GV6VRDZ.js +15 -0
  42. package/dist/export-audit-5GV6VRDZ.js.map +1 -0
  43. package/dist/index.cjs +2183 -587
  44. package/dist/index.cjs.map +1 -1
  45. package/dist/index.d.cts +423 -187
  46. package/dist/index.d.ts +423 -187
  47. package/dist/index.js +886 -726
  48. package/dist/index.js.map +1 -1
  49. package/dist/internal.cjs +789 -0
  50. package/dist/internal.cjs.map +1 -0
  51. package/dist/internal.d.cts +154 -0
  52. package/dist/internal.d.ts +154 -0
  53. package/dist/internal.js +48 -0
  54. package/dist/internal.js.map +1 -0
  55. package/dist/{sqlite-wasm-channel-46AOWNPM.js → sqlite-wasm-channel-HDDW6UBH.js} +2 -2
  56. package/dist/sqlite-wasm-channel-HDDW6UBH.js.map +1 -0
  57. package/dist/{sqlite-wasm-channel-Lakjuk2E.d.cts → sqlite-wasm-channel-I9y_jObg.d.cts} +1 -0
  58. package/dist/{sqlite-wasm-channel-Lakjuk2E.d.ts → sqlite-wasm-channel-I9y_jObg.d.ts} +1 -0
  59. package/dist/types-BMyHmwvn.d.ts +163 -0
  60. package/dist/types-CTr00g_d.d.cts +163 -0
  61. package/dist/types-DepnRDk_.d.cts +212 -0
  62. package/dist/types-DepnRDk_.d.ts +212 -0
  63. package/package.json +23 -2
  64. package/dist/chunk-DXKLAQ6P.js.map +0 -1
  65. package/dist/chunk-ZP5AXQ3Z.js +0 -179
  66. package/dist/chunk-ZP5AXQ3Z.js.map +0 -1
  67. package/dist/types-DF-KDSK1.d.cts +0 -106
  68. package/dist/types-DF-KDSK1.d.ts +0 -106
  69. /package/dist/{sqlite-wasm-channel-46AOWNPM.js.map → audit-trace-store-AM4EWQNZ.js.map} +0 -0
package/dist/index.d.ts CHANGED
@@ -1,6 +1,24 @@
1
- import { Q as QueryDescriptor, a as SubscriptionCallback, C as CollectionRecord, S as StorageAdapter, W as WhereClause, O as OrderByDirection, b as StoreConfig, A as ApplyResult, T as Transaction } from './types-DF-KDSK1.js';
2
- export { M as MigrationPlan, c as OrderByClause, d as WhereOperators } from './types-DF-KDSK1.js';
3
- import { KoraError, Operation, CollectionDefinition, SchemaDefinition, SequenceConfig, HybridLogicalClock, OperationLog, VersionVector, OnDeleteAction, RelationDefinition, StateMachineDefinition } from '@korajs/core';
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 } from './types-DepnRDk_.js';
2
+ export { M as MigrationPlan, g as OrderByClause, h as StoreIsolation, T as Transaction, i as TransactionBufferedEntry, j as TransactionCommitBatch, k as TransactionCommitResult, l as WhereOperators } from './types-DepnRDk_.js';
3
+ import { Operation, KoraError, VersionVector, SchemaDefinition, MergeTrace, CollectionDefinition, SequenceConfig, HybridLogicalClock, CausalTracker, OperationLog, ApplyResult, StateMachineDefinition, KoraEvent } from '@korajs/core';
4
+ export { ApplyResult } from '@korajs/core';
5
+ import { R as RelationEnforcer, L as LocalMutationContext } from './types-BMyHmwvn.js';
6
+ export { C as Collection } from './types-BMyHmwvn.js';
7
+
8
+ /**
9
+ * In-memory materialized state at a causal cut in the operation log.
10
+ * Read-only — does not mutate the live store.
11
+ */
12
+ interface ReplaySnapshot {
13
+ /** The operation whose causal past was replayed (inclusive). */
14
+ targetOperation: Operation;
15
+ /** Operations applied in causal order (ancestors + target). */
16
+ operationsApplied: Operation[];
17
+ /** Non-deleted records per collection after replay. */
18
+ collections: Record<string, CollectionRecord[]>;
19
+ /** Look up a single record at the replay cut. Returns null if deleted or missing. */
20
+ findRecord(collection: string, recordId: string): CollectionRecord | null;
21
+ }
4
22
 
5
23
  /**
6
24
  * Thrown when a query is invalid (bad field names, invalid operators, etc.).
@@ -45,6 +63,205 @@ declare class PersistenceError extends KoraError {
45
63
  constructor(message: string, context?: Record<string, unknown>);
46
64
  }
47
65
 
66
+ /**
67
+ * How the local operation log may be compacted.
68
+ * Materialized collection rows are always kept as the convergence baseline.
69
+ */
70
+ type CompactionStrategy = {
71
+ mode: 'never';
72
+ } | {
73
+ mode: 'after-ack';
74
+ /** Server version vector; defaults to persisted last-acked vector on the store. */
75
+ serverVector?: VersionVector;
76
+ } | {
77
+ mode: 'after-days';
78
+ /** Delete only ops older than this many days (still requires ack watermark). */
79
+ days: number;
80
+ serverVector?: VersionVector;
81
+ };
82
+ /**
83
+ * Result of a compaction run.
84
+ */
85
+ interface CompactionResult {
86
+ /** Number of operation log rows removed. */
87
+ deletedCount: number;
88
+ /** Per-node sequence ceiling used for deletion (from server ack vector). */
89
+ watermark: VersionVector;
90
+ }
91
+ declare const COMPACTION_BASELINE_META_KEY = "compaction_baseline_at";
92
+
93
+ /**
94
+ * Compute per-node sequence watermarks safe to compact (server has acknowledged these ops).
95
+ */
96
+ declare function computeAckCompactionWatermark(serverVector: VersionVector): VersionVector;
97
+ /**
98
+ * Remove acknowledged, materialized operation log entries from `_kora_ops_*` tables.
99
+ * Does not modify collection rows — they are the compaction baseline snapshot.
100
+ */
101
+ declare function compactOperationLog(adapter: StorageAdapter, schema: SchemaDefinition, strategy: CompactionStrategy, serverVector: VersionVector): Promise<CompactionResult>;
102
+
103
+ declare const LAST_ACKED_SERVER_VECTOR_META_KEY = "last_acked_server_vector";
104
+ /**
105
+ * Serialize a version vector for `_kora_meta` storage.
106
+ */
107
+ declare function serializeVersionVectorToMeta(vector: VersionVector): string;
108
+ /**
109
+ * Deserialize a version vector from `_kora_meta`.
110
+ */
111
+ declare function deserializeVersionVectorFromMeta(value: string): VersionVector;
112
+ /**
113
+ * Merge two version vectors, keeping the maximum sequence per node.
114
+ */
115
+ declare function mergeVersionVectors(a: VersionVector, b: VersionVector): VersionVector;
116
+ /**
117
+ * Operations present locally but not yet on the server (per server version vector).
118
+ */
119
+ declare function collectOperationsAheadOfServer(localVector: VersionVector, serverVector: VersionVector, fetchRange: (nodeId: string, fromSeq: number, toSeq: number) => Promise<Operation[]>): Promise<Operation[]>;
120
+
121
+ /**
122
+ * A merge or constraint decision persisted for enterprise audit export.
123
+ */
124
+ interface PersistedAuditTrace {
125
+ /** Unique row id (UUID v7). */
126
+ id: string;
127
+ /** Wall-clock time when the trace was recorded (epoch ms). */
128
+ recordedAt: number;
129
+ /** Source event type from the Kora event bus. */
130
+ eventType: 'merge:completed' | 'merge:conflict' | 'constraint:violated';
131
+ /** Constraint name when {@link eventType} is `constraint:violated`. */
132
+ constraint?: string;
133
+ /** Full merge trace including conflicting operations and resolution details. */
134
+ trace: MergeTrace;
135
+ }
136
+ /**
137
+ * Manifest embedded in audit export files.
138
+ */
139
+ interface AuditExportManifest {
140
+ /** Audit export format version */
141
+ version: 1;
142
+ /** When the export was created (epoch ms) */
143
+ exportedAt: number;
144
+ /** Node ID of the originating device */
145
+ nodeId: string;
146
+ /** Schema version at export time */
147
+ schemaVersion: number;
148
+ /** Number of operations included */
149
+ operationCount: number;
150
+ /** Number of merge traces included */
151
+ mergeTraceCount: number;
152
+ /** SHA-256 hex checksum of content sections */
153
+ checksum: string;
154
+ }
155
+ /**
156
+ * Decoded audit export payload.
157
+ */
158
+ interface AuditExportPayload {
159
+ manifest: AuditExportManifest;
160
+ operations: Operation[];
161
+ mergeTraces: PersistedAuditTrace[];
162
+ }
163
+ /**
164
+ * Progress reported during audit export.
165
+ */
166
+ interface AuditExportProgress {
167
+ phase: 'reading' | 'writing' | 'verifying';
168
+ /** 0-1 progress ratio */
169
+ progress: number;
170
+ message: string;
171
+ }
172
+ /**
173
+ * Options for {@link exportAudit}.
174
+ */
175
+ interface AuditExportOptions {
176
+ /** Subset of collections for operations and traces. All if omitted. */
177
+ collections?: string[];
178
+ /** Include only traces recorded at or after this timestamp (epoch ms). */
179
+ since?: number;
180
+ /** Include only traces recorded at or before this timestamp (epoch ms). */
181
+ until?: number;
182
+ /** Progress callback */
183
+ onProgress?: (progress: AuditExportProgress) => void;
184
+ }
185
+ /**
186
+ * Query filters for reading persisted audit traces.
187
+ */
188
+ interface AuditTraceQuery {
189
+ collections?: string[];
190
+ since?: number;
191
+ until?: number;
192
+ }
193
+
194
+ /**
195
+ * Manifest embedded in every backup file.
196
+ */
197
+ interface BackupManifest {
198
+ /** Backup format version */
199
+ version: 1;
200
+ /** When the backup was created (epoch ms) */
201
+ createdAt: number;
202
+ /** Node ID of the originating device */
203
+ nodeId: string;
204
+ /** Schema version at backup time */
205
+ schemaVersion: number;
206
+ /** Total number of operations in the backup */
207
+ operationCount: number;
208
+ /** Collection names included in the backup */
209
+ collections: string[];
210
+ /** Whether materialized records are included */
211
+ includesRecords: boolean;
212
+ /** SHA-256 hex checksum of all content sections */
213
+ checksum: string;
214
+ }
215
+ /**
216
+ * Progress reported during backup/restore operations.
217
+ */
218
+ interface BackupProgress {
219
+ phase: 'reading' | 'writing' | 'verifying' | 'restoring';
220
+ /** 0-1 progress ratio */
221
+ progress: number;
222
+ message: string;
223
+ }
224
+ /**
225
+ * Result of a restore operation.
226
+ */
227
+ interface RestoreResult {
228
+ /** Number of operations restored */
229
+ operationsRestored: number;
230
+ /** Number of records restored */
231
+ recordsRestored: number;
232
+ /** Whether the restore completed successfully */
233
+ success: boolean;
234
+ /** Error message if failed */
235
+ error?: string;
236
+ /** Duration in ms */
237
+ duration: number;
238
+ }
239
+ /**
240
+ * Options for exporting a backup.
241
+ */
242
+ interface BackupOptions {
243
+ /** Include materialized record snapshots (default: true) */
244
+ includeRecords?: boolean;
245
+ /** Subset of collections to backup. All if omitted. */
246
+ collections?: string[];
247
+ /** Progress callback */
248
+ onProgress?: (progress: BackupProgress) => void;
249
+ }
250
+ /**
251
+ * Options for restoring from a backup.
252
+ */
253
+ interface RestoreOptions {
254
+ /** Subset of collections to restore. All if omitted. */
255
+ collections?: string[];
256
+ /** Progress callback */
257
+ onProgress?: (progress: BackupProgress) => void;
258
+ /**
259
+ * If true, merge operations with existing data (replay through applyRemoteOperation).
260
+ * If false, clear and replace all data (default: false).
261
+ */
262
+ merge?: boolean;
263
+ }
264
+
48
265
  /**
49
266
  * Configuration options for the SubscriptionManager.
50
267
  */
@@ -66,6 +283,8 @@ interface SubscriptionManagerOptions {
66
283
  * @default 0.01
67
284
  */
68
285
  bloomFalsePositiveRate?: number;
286
+ /** Called when a query subscription is registered (e.g. to register sync query subsets). */
287
+ onQuerySubscribed?: (descriptor: QueryDescriptor) => () => void;
69
288
  }
70
289
  /**
71
290
  * Performance statistics for monitoring subscription checking efficiency.
@@ -106,6 +325,7 @@ declare class SubscriptionManager {
106
325
  private subscriptions;
107
326
  private pendingCollections;
108
327
  private flushScheduled;
328
+ private readonly onQuerySubscribed?;
109
329
  private bloomFilter;
110
330
  private bloomDirty;
111
331
  private readonly bloomThreshold;
@@ -179,8 +399,9 @@ declare class SubscriptionManager {
179
399
  private rebuildBloomFilter;
180
400
  private scheduleFlush;
181
401
  /**
182
- * Compare two result sets. Uses length check + JSON comparison as pragmatic approach.
183
- * Sufficient for typical query results. Can be optimized to id-based diffing if profiling shows need.
402
+ * Compare two result sets. Uses ID-based comparison first (same length, same IDs),
403
+ * then deep comparison of remaining fields when IDs match.
404
+ * Avoids JSON.stringify which is O(n) and fragile to field ordering differences.
184
405
  */
185
406
  private resultsEqual;
186
407
  }
@@ -334,6 +555,20 @@ declare class SequenceManager {
334
555
  }): Promise<void>;
335
556
  }
336
557
 
558
+ /**
559
+ * Allocates monotonic sequence numbers for a single open transaction.
560
+ * Loads the current DB watermark once, then increments in memory until commit.
561
+ */
562
+ declare class TransactionSequenceAllocator {
563
+ private readonly adapter;
564
+ private readonly nodeId;
565
+ private loaded;
566
+ private watermark;
567
+ constructor(adapter: StorageAdapter, nodeId: string);
568
+ allocate(): Promise<number>;
569
+ getHighWaterMark(): number;
570
+ }
571
+
337
572
  /**
338
573
  * Internal configuration for creating a TransactionContext.
339
574
  * Passed from Store to avoid exposing Store internals publicly.
@@ -343,7 +578,10 @@ interface TransactionContextConfig {
343
578
  adapter: StorageAdapter;
344
579
  clock: HybridLogicalClock;
345
580
  nodeId: string;
346
- getSequenceNumber: () => number;
581
+ sequenceAllocator: TransactionSequenceAllocator;
582
+ relationEnforcer: RelationEnforcer | null;
583
+ causalTracker: CausalTracker | null;
584
+ localMutationHandler: LocalMutationHandler | null;
347
585
  }
348
586
  /**
349
587
  * A collection accessor within a transaction.
@@ -447,7 +685,12 @@ declare class Store implements OperationLog {
447
685
  private readonly schema;
448
686
  private readonly adapter;
449
687
  private readonly configNodeId;
688
+ private readonly dbName;
689
+ private readonly isolation;
450
690
  private readonly emitter;
691
+ private localMutationHandler;
692
+ private relationEnforcer;
693
+ private causalTracker;
451
694
  constructor(config: StoreConfig);
452
695
  /**
453
696
  * Open the store: initialize the database, load or generate a node ID,
@@ -477,20 +720,101 @@ declare class Store implements OperationLog {
477
720
  * Checks for duplicates, applies to the data table, persists the operation,
478
721
  * and updates the version vector.
479
722
  */
480
- applyRemoteOperation(op: Operation): Promise<ApplyResult>;
723
+ applyRemoteOperation(op: Operation, options?: ApplyRemoteOptions): Promise<ApplyResult>;
481
724
  /**
482
725
  * Get operations from a node within a sequence number range.
483
726
  * Implements the OperationLog interface for computeDelta.
484
727
  */
485
- getRange(nodeId: string, fromSeq: number, toSeq: number): Operation[];
728
+ getRange(nodeId: string, fromSeq: number, toSeq: number): Promise<Operation[]>;
486
729
  /**
487
- * Async version of getRange for use by the sync layer.
730
+ * Get operations from a node within a sequence number range.
488
731
  */
489
732
  getOperationRange(nodeId: string, fromSeq: number, toSeq: number): Promise<Operation[]>;
733
+ /**
734
+ * Load every operation from the local append-only log across all collections.
735
+ * Used by sync delta computation, backup export, and time-travel replay.
736
+ */
737
+ getAllOperations(): Promise<Operation[]>;
738
+ /**
739
+ * Rebuild an in-memory snapshot of materialized state at a causal cut in the op log.
740
+ * Does not mutate the live store — intended for DevTools time-travel inspection.
741
+ *
742
+ * @param operationId - Content-addressed id of the operation to replay through (inclusive)
743
+ * @throws {OperationError} When the operation id is not present in the local log
744
+ */
745
+ replayTo(operationId: string): Promise<ReplaySnapshot>;
746
+ /**
747
+ * Persist a merge trace to the durable audit log.
748
+ */
749
+ appendAuditTrace(trace: PersistedAuditTrace): Promise<void>;
750
+ /**
751
+ * Read persisted audit traces with optional filters.
752
+ */
753
+ getAuditTraces(query?: AuditTraceQuery): Promise<PersistedAuditTrace[]>;
754
+ /**
755
+ * Export operations and merge traces as a portable audit bundle.
756
+ */
757
+ exportAudit(options?: AuditExportOptions): Promise<Uint8Array>;
490
758
  /**
491
759
  * Get the schema definition.
492
760
  */
493
761
  getSchema(): SchemaDefinition;
762
+ /**
763
+ * Route local CRUD through the unified apply pipeline (korajs ApplyPipeline).
764
+ */
765
+ setLocalMutationHandler(handler: LocalMutationHandler | null): void;
766
+ /**
767
+ * Build mutation context for a collection (used by ApplyPipeline side effects).
768
+ */
769
+ createMutationContext(collection: string, options?: {
770
+ inTransaction?: boolean;
771
+ extraCausalDeps?: string[];
772
+ }): LocalMutationContext;
773
+ /**
774
+ * Load a materialized row by ID, including soft-deleted tombstones.
775
+ */
776
+ findMaterializedRow(collection: string, recordId: string): Promise<MaterializedRowSnapshot | null>;
777
+ /**
778
+ * Latest operation from this device for a record (used for delete-vs-update merge on sync).
779
+ */
780
+ /**
781
+ * Load the last server version vector acknowledged by this client (persisted in `_kora_meta`).
782
+ */
783
+ loadLastAckedServerVector(): Promise<VersionVector>;
784
+ /**
785
+ * Persist the last server version vector this client believes the server has applied.
786
+ */
787
+ saveLastAckedServerVector(vector: VersionVector): Promise<void>;
788
+ /**
789
+ * Load persisted delta cursor for resuming paginated initial sync.
790
+ */
791
+ loadDeltaCursor(): Promise<string | null>;
792
+ /**
793
+ * Persist or clear the delta cursor for paginated initial sync resume.
794
+ */
795
+ saveDeltaCursor(cursor: string | null): Promise<void>;
796
+ /**
797
+ * Local operations not yet reflected on the server version vector.
798
+ */
799
+ getUnsyncedOperations(serverVector: VersionVector): Promise<Operation[]>;
800
+ /**
801
+ * Count of local operations ahead of the server version vector.
802
+ */
803
+ countUnsyncedOperations(serverVector: VersionVector): Promise<number>;
804
+ /**
805
+ * Compact the local operation log using materialized rows as the baseline.
806
+ * Only removes ops the server has acknowledged (per {@link CompactionStrategy}).
807
+ */
808
+ compact(strategy: CompactionStrategy): Promise<CompactionResult>;
809
+ /**
810
+ * Merge session remote vector with persisted last-acked vector (max per node).
811
+ */
812
+ mergeServerVectors(sessionVector: VersionVector, persistedVector: VersionVector): VersionVector;
813
+ getLatestLocalOperationForRecord(collection: string, recordId: string): Promise<Operation | null>;
814
+ /**
815
+ * Latest operation for a record from any node (for 3-way merge when local op log is empty).
816
+ */
817
+ getLatestOperationForRecord(collection: string, recordId: string): Promise<Operation | null>;
494
818
  /** Expose the subscription manager for direct access (e.g., by QueryBuilder) */
495
819
  getSubscriptionManager(): SubscriptionManager;
496
820
  /**
@@ -517,7 +841,31 @@ declare class Store implements OperationLog {
517
841
  * @returns The operations that were committed
518
842
  */
519
843
  transaction(fn: (tx: TransactionContext) => Promise<void>): Promise<Operation[]>;
520
- private nextSequenceNumber;
844
+ /**
845
+ * Export all data as a portable backup binary.
846
+ * Includes operations, version vector, metadata, and optionally materialized records.
847
+ *
848
+ * @param options - Backup options (includeRecords, collections, onProgress)
849
+ * @returns Backup as a Uint8Array
850
+ */
851
+ exportBackup(options?: BackupOptions): Promise<Uint8Array>;
852
+ /**
853
+ * Restore data from a backup binary.
854
+ *
855
+ * @param data - The backup data
856
+ * @param options - Restore options (merge, collections, onProgress)
857
+ * @returns Result of the restore operation
858
+ */
859
+ importBackup(data: Uint8Array, options?: RestoreOptions): Promise<RestoreResult>;
860
+ /**
861
+ * Read backup manifest without loading the entire backup.
862
+ *
863
+ * @param data - The raw backup data
864
+ * @returns The backup manifest
865
+ */
866
+ static readBackupManifest(data: Uint8Array): BackupManifest;
867
+ private recordOperationSequence;
868
+ private allocateSequenceNumber;
521
869
  /**
522
870
  * Check the stored schema version and run any pending migrations.
523
871
  * Migrations are applied in version order within a transaction.
@@ -638,182 +986,6 @@ declare class SubscriptionBloomFilter {
638
986
  private getPositions;
639
987
  }
640
988
 
641
- /**
642
- * A resolved relation reference: describes a relation that points TO a given collection.
643
- * When a record in `targetCollection` is deleted, we must handle records in
644
- * `sourceCollection` that reference it via `foreignKeyField`.
645
- */
646
- interface IncomingRelation {
647
- /** Name of the relation in the schema */
648
- relationName: string;
649
- /** Collection that holds the foreign key (the "from" side) */
650
- sourceCollection: string;
651
- /** Field in the source collection that references the target */
652
- foreignKeyField: string;
653
- /** What to do when the referenced record is deleted */
654
- onDelete: OnDeleteAction;
655
- /** The full relation definition */
656
- relation: RelationDefinition;
657
- }
658
-
659
- /**
660
- * Configuration for the RelationEnforcer.
661
- */
662
- interface RelationEnforcerConfig {
663
- schema: SchemaDefinition;
664
- adapter: StorageAdapter;
665
- clock: HybridLogicalClock;
666
- nodeId: string;
667
- getSequenceNumber: () => number;
668
- }
669
- /**
670
- * Result of enforcing referential integrity on a delete operation.
671
- * Contains all additional operations that were created as side effects
672
- * (cascaded deletes and set-null updates).
673
- */
674
- interface EnforcementResult {
675
- /** Additional operations created by cascading deletes and set-null updates */
676
- operations: Operation[];
677
- }
678
- /**
679
- * Enforces referential integrity constraints during local delete operations.
680
- *
681
- * When a record is deleted, this enforcer checks all relations that reference
682
- * the deleted record's collection and applies the appropriate onDelete policy:
683
- *
684
- * - **cascade**: Recursively deletes all referencing records
685
- * - **set-null**: Sets the foreign key to null on all referencing records
686
- * - **restrict**: Throws a ReferentialIntegrityError if any references exist
687
- * - **no-action**: Does nothing (the foreign key is left dangling)
688
- *
689
- * The enforcer operates within a provided transaction to ensure atomicity.
690
- * All generated operations (cascaded deletes, set-null updates) share a
691
- * causal dependency chain through the original delete operation.
692
- *
693
- * @example
694
- * ```typescript
695
- * const enforcer = new RelationEnforcer({
696
- * schema, adapter, clock, nodeId,
697
- * getSequenceNumber: () => ++seq,
698
- * })
699
- * const result = await enforcer.enforceDelete(
700
- * 'projects', 'proj-1', tx, ['delete-op-id']
701
- * )
702
- * // result.operations contains any cascaded delete/update ops
703
- * ```
704
- */
705
- declare class RelationEnforcer {
706
- private readonly lookup;
707
- private readonly schema;
708
- private readonly adapter;
709
- private readonly clock;
710
- private readonly nodeId;
711
- private readonly getSequenceNumber;
712
- constructor(config: RelationEnforcerConfig);
713
- /**
714
- * Enforce referential integrity after deleting a record.
715
- *
716
- * Must be called within a transaction. The transaction handle is used
717
- * for all cascaded writes to ensure atomicity.
718
- *
719
- * @param collection - The collection the deleted record belongs to
720
- * @param recordId - The ID of the deleted record
721
- * @param tx - The active transaction handle
722
- * @param causalDeps - Causal dependencies for generated operations
723
- * @returns All additional operations created as side effects
724
- * @throws {ReferentialIntegrityError} If a 'restrict' policy is violated
725
- */
726
- enforceDelete(collection: string, recordId: string, tx: Transaction, causalDeps: string[]): Promise<EnforcementResult>;
727
- /**
728
- * Enforce a single relation's onDelete policy.
729
- */
730
- private enforceRelation;
731
- /**
732
- * Cascade: delete all records in the source collection that reference
733
- * the deleted record, then recursively cascade those deletes.
734
- */
735
- private enforceCascade;
736
- /**
737
- * Set-null: update all referencing records to set the foreign key to null.
738
- */
739
- private enforceSetNull;
740
- /**
741
- * Restrict: refuse the delete if any referencing records exist.
742
- */
743
- private enforceRestrict;
744
- /**
745
- * Get the relation lookup map for external use (e.g., by the merge engine).
746
- */
747
- getRelationLookup(): Map<string, IncomingRelation[]>;
748
- }
749
-
750
- /**
751
- * Callback invoked after a mutation so the Store can notify subscriptions.
752
- */
753
- type MutationCallback = (collection: string, operation: Operation) => void;
754
- /**
755
- * Collection provides CRUD operations on a single schema collection.
756
- * Each mutation creates an Operation and persists both the data and the operation atomically.
757
- *
758
- * When a RelationEnforcer is provided, delete operations enforce referential integrity
759
- * policies (cascade, set-null, restrict) defined in the schema's relations.
760
- */
761
- declare class Collection {
762
- private readonly name;
763
- private readonly definition;
764
- private readonly schema;
765
- private readonly adapter;
766
- private readonly clock;
767
- private readonly nodeId;
768
- private readonly getSequenceNumber;
769
- private readonly onMutation;
770
- private readonly relationEnforcer;
771
- constructor(name: string, definition: CollectionDefinition, schema: SchemaDefinition, adapter: StorageAdapter, clock: HybridLogicalClock, nodeId: string, getSequenceNumber: () => number, onMutation: MutationCallback, relationEnforcer?: RelationEnforcer);
772
- /**
773
- * Insert a new record into the collection.
774
- * Generates a UUID v7 for the id, validates data, and persists atomically.
775
- *
776
- * @param data - The record data (auto fields and defaults are applied automatically)
777
- * @returns The inserted record with id, createdAt, updatedAt
778
- */
779
- insert(data: Record<string, unknown>): Promise<CollectionRecord>;
780
- /**
781
- * Find a record by its ID. Returns null if not found or soft-deleted.
782
- */
783
- findById(id: string): Promise<CollectionRecord | null>;
784
- /**
785
- * Update an existing record. Only the provided fields are changed.
786
- *
787
- * @param id - The record ID to update
788
- * @param data - Partial data with only the fields to change
789
- * @returns The updated record
790
- * @throws {RecordNotFoundError} If the record doesn't exist or is deleted
791
- */
792
- update(id: string, data: Record<string, unknown>): Promise<CollectionRecord>;
793
- /**
794
- * Soft-delete a record by its ID.
795
- *
796
- * When a RelationEnforcer is configured, referential integrity policies
797
- * are enforced within the same transaction:
798
- * - **cascade**: Recursively deletes all referencing records
799
- * - **set-null**: Sets foreign keys to null on referencing records
800
- * - **restrict**: Throws ReferentialIntegrityError if references exist
801
- * - **no-action**: Does nothing (dangling references are left)
802
- *
803
- * All cascaded operations are created atomically within the same transaction
804
- * and share causal dependencies with the original delete.
805
- *
806
- * @param id - The record ID to delete
807
- * @throws {RecordNotFoundError} If the record doesn't exist or is already deleted
808
- * @throws {ReferentialIntegrityError} If a 'restrict' policy is violated
809
- */
810
- delete(id: string): Promise<void>;
811
- /** Get the collection name */
812
- getName(): string;
813
- /** Get the collection definition */
814
- getDefinition(): CollectionDefinition;
815
- }
816
-
817
989
  /**
818
990
  * Error thrown when a local mutation attempts an invalid state transition.
819
991
  *
@@ -881,6 +1053,11 @@ declare function decodeRichtext(value: unknown): Uint8Array | null;
881
1053
  * Reads plain text from a richtext Yjs state update.
882
1054
  */
883
1055
  declare function richtextToPlainText(value: RichtextInput): string;
1056
+ /**
1057
+ * Compares two richtext values by decoded plain text.
1058
+ * Yjs update bytes are not stable across separate encodes of the same string.
1059
+ */
1060
+ declare function richtextStatesEqual(a: unknown, b: unknown): boolean;
884
1061
 
885
1062
  /**
886
1063
  * Minimal pluralization/singularization utilities for relation name resolution.
@@ -909,4 +1086,63 @@ declare function pluralize(word: string): string;
909
1086
  */
910
1087
  declare function singularize(word: string): string;
911
1088
 
912
- export { AdapterError, ApplyResult, Collection, type CollectionAccessor, CollectionRecord, InvalidStateTransitionError, OrderByDirection, PersistenceError, QueryBuilder, QueryDescriptor, QueryError, RecordNotFoundError, SequenceManager, StorageAdapter, Store, StoreConfig, StoreNotOpenError, SubscriptionBloomFilter, SubscriptionCallback, SubscriptionManager, type SubscriptionManagerOptions, type SubscriptionStats, Transaction, type TransactionCollectionAccessor, TransactionContext, type TransactionContextConfig, WhereClause, WorkerInitError, WorkerTimeoutError, decodeRichtext, encodeRichtext, pluralize, richtextToPlainText, singularize, validateStateTransition, validateUpdateStateMachine };
1089
+ /**
1090
+ * Export a backup from a store.
1091
+ *
1092
+ * Reads all data via the adapter and produces a portable binary backup.
1093
+ *
1094
+ * @param adapter - The storage adapter
1095
+ * @param schema - The schema definition
1096
+ * @param nodeId - Current node ID
1097
+ * @param schemaVersion - Schema version
1098
+ * @param options - Backup options
1099
+ * @returns Backup as a Uint8Array
1100
+ */
1101
+ declare function exportBackup(adapter: StorageAdapter, schema: SchemaDefinition, nodeId: string, schemaVersion: number, options?: BackupOptions): Promise<Uint8Array>;
1102
+ /**
1103
+ * Read backup manifest without loading the entire backup.
1104
+ * Parses only the first section (which is always the manifest).
1105
+ *
1106
+ * @param data - The raw backup data
1107
+ * @returns The backup manifest
1108
+ */
1109
+ declare function readBackupManifest(data: Uint8Array): BackupManifest;
1110
+ /**
1111
+ * Validate the backup checksum.
1112
+ *
1113
+ * @param data - The raw backup data
1114
+ * @returns True if the checksum is valid
1115
+ */
1116
+ declare function verifyBackupChecksum(data: Uint8Array): Promise<boolean>;
1117
+ /**
1118
+ * Restore a backup into a store.
1119
+ *
1120
+ * @param adapter - The storage adapter
1121
+ * @param schema - The schema definition
1122
+ * @param data - The backup data
1123
+ * @param options - Restore options
1124
+ * @returns Result of the restore operation
1125
+ */
1126
+ declare function restoreBackup(adapter: StorageAdapter, schema: SchemaDefinition, data: Uint8Array, options?: RestoreOptions): Promise<RestoreResult>;
1127
+
1128
+ /**
1129
+ * Build a {@link PersistedAuditTrace} from a merge-related Kora event.
1130
+ */
1131
+ declare function persistedAuditTraceFromEvent(event: Extract<KoraEvent, {
1132
+ type: 'merge:completed' | 'merge:conflict' | 'constraint:violated';
1133
+ }>): PersistedAuditTrace;
1134
+
1135
+ /**
1136
+ * Decode an audit export binary into structured data.
1137
+ */
1138
+ declare function decodeAuditExport(data: Uint8Array): AuditExportPayload;
1139
+ /**
1140
+ * Read only the manifest from an audit export without decoding all sections.
1141
+ */
1142
+ declare function readAuditExportManifest(data: Uint8Array): AuditExportManifest;
1143
+ /**
1144
+ * Verify the checksum of an audit export file.
1145
+ */
1146
+ declare function verifyAuditExportChecksum(data: Uint8Array): Promise<boolean>;
1147
+
1148
+ export { AdapterError, ApplyRemoteOptions, type AuditExportManifest, type AuditExportOptions, type AuditExportPayload, type AuditExportProgress, type AuditTraceQuery, type BackupManifest, type BackupOptions, type BackupProgress, COMPACTION_BASELINE_META_KEY, type CollectionAccessor, CollectionRecord, type CompactionResult, type CompactionStrategy, InvalidStateTransitionError, LAST_ACKED_SERVER_VECTOR_META_KEY, LocalMutationHandler, MaterializedRowSnapshot, OrderByDirection, type PersistedAuditTrace, PersistenceError, QueryBuilder, QueryDescriptor, QueryError, RecordNotFoundError, type ReplaySnapshot, type RestoreOptions, type RestoreResult, SequenceManager, StorageAdapter, Store, StoreConfig, StoreNotOpenError, SubscriptionBloomFilter, SubscriptionCallback, SubscriptionManager, type SubscriptionManagerOptions, type SubscriptionStats, type TransactionCollectionAccessor, TransactionContext, type TransactionContextConfig, WhereClause, WorkerInitError, WorkerTimeoutError, collectOperationsAheadOfServer, compactOperationLog, computeAckCompactionWatermark, decodeAuditExport, decodeRichtext, deserializeVersionVectorFromMeta, encodeRichtext, exportBackup, mergeVersionVectors, persistedAuditTraceFromEvent, pluralize, readAuditExportManifest, readBackupManifest, restoreBackup, richtextStatesEqual, richtextToPlainText, serializeVersionVectorToMeta, singularize, validateStateTransition, validateUpdateStateMachine, verifyAuditExportChecksum, verifyBackupChecksum };