@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.
- package/dist/adapters/better-sqlite3.d.cts +1 -1
- package/dist/adapters/better-sqlite3.d.ts +1 -1
- package/dist/adapters/indexeddb.cjs +309 -125
- package/dist/adapters/indexeddb.cjs.map +1 -1
- package/dist/adapters/indexeddb.d.cts +4 -2
- package/dist/adapters/indexeddb.d.ts +4 -2
- package/dist/adapters/indexeddb.js +7 -2
- package/dist/adapters/indexeddb.js.map +1 -1
- package/dist/adapters/sqlite-wasm-worker.cjs +206 -208
- package/dist/adapters/sqlite-wasm-worker.cjs.map +1 -1
- package/dist/adapters/sqlite-wasm-worker.js +206 -208
- package/dist/adapters/sqlite-wasm-worker.js.map +1 -1
- package/dist/adapters/sqlite-wasm.cjs +304 -125
- package/dist/adapters/sqlite-wasm.cjs.map +1 -1
- package/dist/adapters/sqlite-wasm.d.cts +18 -7
- package/dist/adapters/sqlite-wasm.d.ts +18 -7
- package/dist/adapters/sqlite-wasm.js +2 -2
- package/dist/{backup-IQE4QC7Q.js → backup-5S7K2Z35.js} +3 -3
- package/dist/{chunk-RCTG3IJG.js → chunk-CYO3YKFL.js} +2 -2
- package/dist/{chunk-2ZRQGFEF.js → chunk-FKW56RVZ.js} +306 -126
- package/dist/chunk-FKW56RVZ.js.map +1 -0
- package/dist/{chunk-6NKLDBTY.js → chunk-GSJ7EEUC.js} +2 -1
- package/dist/chunk-GSJ7EEUC.js.map +1 -0
- package/dist/{chunk-OCOGQRHW.js → chunk-HS6DBMST.js} +2 -2
- package/dist/{chunk-COJSQBXW.js → chunk-VDBJQ75K.js} +1 -1
- package/dist/chunk-VDBJQ75K.js.map +1 -0
- package/dist/{chunk-UXRWVXBP.js → chunk-YT7MRFCP.js} +6 -6
- package/dist/{export-audit-MT2LTMIN.js → export-audit-ODGQTQIK.js} +3 -3
- package/dist/index.cjs +136 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +35 -4
- package/dist/index.d.ts +35 -4
- package/dist/index.js +160 -27
- package/dist/index.js.map +1 -1
- package/dist/internal.cjs +1 -0
- package/dist/internal.cjs.map +1 -1
- package/dist/internal.d.cts +3 -3
- package/dist/internal.d.ts +3 -3
- package/dist/internal.js +3 -3
- package/dist/{sqlite-wasm-channel-NGSBJR44.js → sqlite-wasm-channel-GGHA2BXU.js} +2 -2
- package/dist/{sqlite-wasm-channel-CNHRf-m2.d.cts → sqlite-wasm-channel-L6o3bWQK.d.cts} +2 -2
- package/dist/{sqlite-wasm-channel-CNHRf-m2.d.ts → sqlite-wasm-channel-L6o3bWQK.d.ts} +2 -2
- package/dist/{types-5h4Hqcwc.d.ts → types-BOO9EPt1.d.ts} +1 -1
- package/dist/{types-k6AZgiH4.d.ts → types-BslDOTk0.d.cts} +26 -1
- package/dist/{types-k6AZgiH4.d.cts → types-BslDOTk0.d.ts} +26 -1
- package/dist/{types-DfPiPwKr.d.cts → types-C_GDavG-.d.cts} +1 -1
- package/package.json +2 -12
- package/dist/adapters/sqlite-wasm-shared-host.cjs +0 -95
- package/dist/adapters/sqlite-wasm-shared-host.cjs.map +0 -1
- package/dist/adapters/sqlite-wasm-shared-host.d.cts +0 -64
- package/dist/adapters/sqlite-wasm-shared-host.d.ts +0 -64
- package/dist/adapters/sqlite-wasm-shared-host.js +0 -70
- package/dist/adapters/sqlite-wasm-shared-host.js.map +0 -1
- package/dist/chunk-2ZRQGFEF.js.map +0 -1
- package/dist/chunk-6NKLDBTY.js.map +0 -1
- package/dist/chunk-COJSQBXW.js.map +0 -1
- /package/dist/{backup-IQE4QC7Q.js.map → backup-5S7K2Z35.js.map} +0 -0
- /package/dist/{chunk-RCTG3IJG.js.map → chunk-CYO3YKFL.js.map} +0 -0
- /package/dist/{chunk-OCOGQRHW.js.map → chunk-HS6DBMST.js.map} +0 -0
- /package/dist/{chunk-UXRWVXBP.js.map → chunk-YT7MRFCP.js.map} +0 -0
- /package/dist/{export-audit-MT2LTMIN.js.map → export-audit-ODGQTQIK.js.map} +0 -0
- /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,
|
|
2
|
-
export { M as MigrationPlan,
|
|
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-
|
|
6
|
-
export { C as Collection } from './types-
|
|
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,
|
|
2
|
-
export { M as MigrationPlan,
|
|
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-
|
|
6
|
-
export { C as Collection } from './types-
|
|
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-
|
|
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-
|
|
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 (
|
|
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-
|
|
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-
|
|
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-
|
|
2948
|
+
const { restoreBackup: doRestore } = await import("./backup-5S7K2Z35.js");
|
|
2816
2949
|
return doRestore(this.adapter, this.schema, data, options);
|
|
2817
2950
|
}
|
|
2818
2951
|
/**
|