@quereus/sync 3.3.0 → 4.1.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/README.md +17 -7
- package/dist/src/clock/hlc.d.ts +43 -3
- package/dist/src/clock/hlc.d.ts.map +1 -1
- package/dist/src/clock/hlc.js +60 -10
- package/dist/src/clock/hlc.js.map +1 -1
- package/dist/src/create-sync-module.d.ts +46 -9
- package/dist/src/create-sync-module.d.ts.map +1 -1
- package/dist/src/create-sync-module.js +11 -8
- package/dist/src/create-sync-module.js.map +1 -1
- package/dist/src/index.d.ts +10 -8
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +8 -5
- package/dist/src/index.js.map +1 -1
- package/dist/src/metadata/basis-lifecycle.d.ts +180 -0
- package/dist/src/metadata/basis-lifecycle.d.ts.map +1 -0
- package/dist/src/metadata/basis-lifecycle.js +211 -0
- package/dist/src/metadata/basis-lifecycle.js.map +1 -0
- package/dist/src/metadata/change-log.d.ts +1 -1
- package/dist/src/metadata/change-log.d.ts.map +1 -1
- package/dist/src/metadata/change-log.js +6 -6
- package/dist/src/metadata/change-log.js.map +1 -1
- package/dist/src/metadata/column-version.d.ts +14 -5
- package/dist/src/metadata/column-version.d.ts.map +1 -1
- package/dist/src/metadata/column-version.js +22 -12
- package/dist/src/metadata/column-version.js.map +1 -1
- package/dist/src/metadata/index.d.ts +2 -0
- package/dist/src/metadata/index.d.ts.map +1 -1
- package/dist/src/metadata/index.js +2 -0
- package/dist/src/metadata/index.js.map +1 -1
- package/dist/src/metadata/keys.d.ts +52 -2
- package/dist/src/metadata/keys.d.ts.map +1 -1
- package/dist/src/metadata/keys.js +99 -14
- package/dist/src/metadata/keys.js.map +1 -1
- package/dist/src/metadata/peer-state.d.ts +1 -1
- package/dist/src/metadata/peer-state.js +5 -5
- package/dist/src/metadata/quarantine.d.ts +90 -0
- package/dist/src/metadata/quarantine.d.ts.map +1 -0
- package/dist/src/metadata/quarantine.js +167 -0
- package/dist/src/metadata/quarantine.js.map +1 -0
- package/dist/src/metadata/schema-migration.d.ts +1 -1
- package/dist/src/metadata/schema-migration.js +7 -7
- package/dist/src/metadata/schema-version.d.ts +1 -1
- package/dist/src/metadata/schema-version.js +7 -7
- package/dist/src/metadata/tombstones.d.ts +26 -9
- package/dist/src/metadata/tombstones.d.ts.map +1 -1
- package/dist/src/metadata/tombstones.js +42 -19
- package/dist/src/metadata/tombstones.js.map +1 -1
- package/dist/src/sql/basis-lifecycle-tvf.d.ts +34 -0
- package/dist/src/sql/basis-lifecycle-tvf.d.ts.map +1 -0
- package/dist/src/sql/basis-lifecycle-tvf.js +101 -0
- package/dist/src/sql/basis-lifecycle-tvf.js.map +1 -0
- package/dist/src/sync/admission.d.ts +81 -0
- package/dist/src/sync/admission.d.ts.map +1 -0
- package/dist/src/sync/admission.js +94 -0
- package/dist/src/sync/admission.js.map +1 -0
- package/dist/src/sync/change-applicator.d.ts +65 -2
- package/dist/src/sync/change-applicator.d.ts.map +1 -1
- package/dist/src/sync/change-applicator.js +493 -68
- package/dist/src/sync/change-applicator.js.map +1 -1
- package/dist/src/sync/change-grouping.d.ts +43 -0
- package/dist/src/sync/change-grouping.d.ts.map +1 -0
- package/dist/src/sync/change-grouping.js +103 -0
- package/dist/src/sync/change-grouping.js.map +1 -0
- package/dist/src/sync/events.d.ts +159 -1
- package/dist/src/sync/events.d.ts.map +1 -1
- package/dist/src/sync/events.js +50 -0
- package/dist/src/sync/events.js.map +1 -1
- package/dist/src/sync/manager.d.ts +87 -0
- package/dist/src/sync/manager.d.ts.map +1 -1
- package/dist/src/sync/protocol.d.ts +174 -11
- package/dist/src/sync/protocol.d.ts.map +1 -1
- package/dist/src/sync/protocol.js +4 -1
- package/dist/src/sync/protocol.js.map +1 -1
- package/dist/src/sync/snapshot-stream.d.ts.map +1 -1
- package/dist/src/sync/snapshot-stream.js +89 -19
- package/dist/src/sync/snapshot-stream.js.map +1 -1
- package/dist/src/sync/snapshot.d.ts.map +1 -1
- package/dist/src/sync/snapshot.js +63 -44
- package/dist/src/sync/snapshot.js.map +1 -1
- package/dist/src/sync/store-adapter.d.ts +117 -15
- package/dist/src/sync/store-adapter.d.ts.map +1 -1
- package/dist/src/sync/store-adapter.js +247 -91
- package/dist/src/sync/store-adapter.js.map +1 -1
- package/dist/src/sync/sync-context.d.ts +44 -1
- package/dist/src/sync/sync-context.d.ts.map +1 -1
- package/dist/src/sync/sync-context.js +26 -0
- package/dist/src/sync/sync-context.js.map +1 -1
- package/dist/src/sync/sync-manager-impl.d.ts +247 -13
- package/dist/src/sync/sync-manager-impl.d.ts.map +1 -1
- package/dist/src/sync/sync-manager-impl.js +788 -193
- package/dist/src/sync/sync-manager-impl.js.map +1 -1
- package/package.json +9 -9
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import { deserializeColumnVersion } from '../metadata/column-version.js';
|
|
8
8
|
import { deserializeMigration } from '../metadata/schema-migration.js';
|
|
9
9
|
import { buildAllColumnVersionsScanBounds, buildAllTombstonesScanBounds, buildAllSchemaMigrationsScanBounds, buildAllChangeLogScanBounds, parseColumnVersionKey, parseSchemaMigrationKey, encodePK, } from '../metadata/keys.js';
|
|
10
|
-
import {
|
|
10
|
+
import { admitGroup } from './admission.js';
|
|
11
11
|
/**
|
|
12
12
|
* Get a full snapshot of all data and schema state.
|
|
13
13
|
*/
|
|
@@ -115,51 +115,70 @@ export async function applySnapshot(ctx, snapshot) {
|
|
|
115
115
|
});
|
|
116
116
|
}
|
|
117
117
|
}
|
|
118
|
-
//
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
//
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
const
|
|
143
|
-
const
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
118
|
+
// Admit the snapshot as one wholesale all-or-nothing unit: data first (PHASE 2,
|
|
119
|
+
// a bootstrap apply — the adapter skips the engine seam, converged once by the
|
|
120
|
+
// finalize below), then the wholesale metadata replace (PHASE 3), then the
|
|
121
|
+
// clock watermark. A data-apply failure aborts before clearing/rewriting
|
|
122
|
+
// metadata, leaving prior CRDT state intact; the snapshot retries wholesale
|
|
123
|
+
// (idempotent on the store side) and now also emits status:'error'.
|
|
124
|
+
await admitGroup(ctx, {
|
|
125
|
+
dataChanges: dataChangesToApply,
|
|
126
|
+
schemaChanges: schemaChangesToApply,
|
|
127
|
+
applyOptions: { remote: true, bootstrap: true },
|
|
128
|
+
commitMetadata: async () => {
|
|
129
|
+
// Clear existing CRDT metadata and apply new
|
|
130
|
+
const clearBatch = ctx.kv.batch();
|
|
131
|
+
for await (const entry of ctx.kv.iterate(buildAllColumnVersionsScanBounds())) {
|
|
132
|
+
clearBatch.delete(entry.key);
|
|
133
|
+
}
|
|
134
|
+
for await (const entry of ctx.kv.iterate(buildAllTombstonesScanBounds())) {
|
|
135
|
+
clearBatch.delete(entry.key);
|
|
136
|
+
}
|
|
137
|
+
for await (const entry of ctx.kv.iterate(buildAllChangeLogScanBounds())) {
|
|
138
|
+
clearBatch.delete(entry.key);
|
|
139
|
+
}
|
|
140
|
+
await clearBatch.write();
|
|
141
|
+
// Apply snapshot's column versions and rebuild change log
|
|
142
|
+
const applyBatch = ctx.kv.batch();
|
|
143
|
+
for (const tableSnapshot of snapshot.tables) {
|
|
144
|
+
for (const [versionKey, cvEntry] of tableSnapshot.columnVersions) {
|
|
145
|
+
const lastColon = versionKey.lastIndexOf(':');
|
|
146
|
+
if (lastColon === -1)
|
|
147
|
+
continue;
|
|
148
|
+
const rowKey = versionKey.slice(0, lastColon);
|
|
149
|
+
const column = versionKey.slice(lastColon + 1);
|
|
150
|
+
const pk = JSON.parse(rowKey);
|
|
151
|
+
ctx.columnVersions.setColumnVersionBatch(applyBatch, tableSnapshot.schema, tableSnapshot.table, pk, column, { hlc: cvEntry.hlc, value: cvEntry.value });
|
|
152
|
+
ctx.changeLog.recordColumnChangeBatch(applyBatch, cvEntry.hlc, tableSnapshot.schema, tableSnapshot.table, pk, column);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
// Record schema migrations
|
|
156
|
+
for (const migration of snapshot.schemaMigrations) {
|
|
157
|
+
const schemaVersion = migration.schemaVersion ??
|
|
158
|
+
(await ctx.schemaMigrations.getCurrentVersion(migration.schema, migration.table)) + 1;
|
|
159
|
+
await ctx.schemaMigrations.recordMigration(migration.schema, migration.table, {
|
|
160
|
+
type: migration.type,
|
|
161
|
+
ddl: migration.ddl,
|
|
162
|
+
hlc: migration.hlc,
|
|
163
|
+
schemaVersion,
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
await applyBatch.write();
|
|
167
|
+
},
|
|
168
|
+
watermarkHLC: snapshot.hlc,
|
|
169
|
+
});
|
|
170
|
+
// Converge the bootstrap: PHASE 2 deferred MV maintenance and watch capture
|
|
171
|
+
// (seam skipped), so converge every MV once and coarse-notify each
|
|
172
|
+
// bootstrapped table's watchers. Issued before `status: 'synced'` so a
|
|
173
|
+
// finalize failure aborts the apply (the storage rows are already correct, so
|
|
174
|
+
// a retry's finalize rebuilds cleanly).
|
|
175
|
+
if (ctx.applyToStore) {
|
|
176
|
+
await ctx.applyToStore([], [], {
|
|
177
|
+
remote: true,
|
|
178
|
+
bootstrapFinalize: true,
|
|
179
|
+
bootstrapTables: snapshot.tables.map(t => ({ schema: t.schema, table: t.table })),
|
|
157
180
|
});
|
|
158
181
|
}
|
|
159
|
-
await applyBatch.write();
|
|
160
|
-
// Update HLC
|
|
161
|
-
ctx.hlcManager.receive(snapshot.hlc);
|
|
162
|
-
await persistHLCState(ctx);
|
|
163
182
|
// Emit sync state change
|
|
164
183
|
ctx.syncEvents.emitSyncStateChange({ status: 'synced', lastSyncHLC: snapshot.hlc });
|
|
165
184
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"snapshot.js","sourceRoot":"","sources":["../../../src/sync/snapshot.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAAE,wBAAwB,EAAsB,MAAM,+BAA+B,CAAC;AAC7F,OAAO,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AACvE,OAAO,EACN,gCAAgC,EAChC,4BAA4B,EAC5B,kCAAkC,EAClC,2BAA2B,EAC3B,qBAAqB,EACrB,uBAAuB,EACvB,QAAQ,GACR,MAAM,qBAAqB,CAAC;AAS7B,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"snapshot.js","sourceRoot":"","sources":["../../../src/sync/snapshot.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,31 +1,131 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Store adapter for applying remote sync changes.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Implements the ApplyToStoreCallback interface over the store module's
|
|
5
|
+
* external row-write entry point (`StoreTable.applyExternalRowChanges` —
|
|
6
|
+
* table-owned key encoding, secondary-index and stats maintenance) plus the
|
|
7
|
+
* engine's batch ingestion seam (`Database.ingestExternalRowChanges` — change
|
|
8
|
+
* capture for `Database.watch` + global assertions, materialized-view
|
|
9
|
+
* maintenance, opt-in parent-side FK actions).
|
|
10
|
+
*
|
|
11
|
+
* Per `applyToStore(dataChanges, schemaChanges, options)` invocation:
|
|
12
|
+
* 1. Schema changes execute first via `db.exec` (DDL before DML), with the
|
|
13
|
+
* resulting module schema events pre-marked remote.
|
|
14
|
+
* 2. Data changes are grouped per table, then per row; each row group
|
|
15
|
+
* collapses to ONE `ExternalRowOp` (a delete in the group wins over
|
|
16
|
+
* column updates; column updates merge onto the pre-read existing row,
|
|
17
|
+
* or onto a PK+nulls partial row when absent — UPSERT semantics).
|
|
18
|
+
* 3. `StoreTable.applyExternalRowChanges(ops)` applies the table's ops to
|
|
19
|
+
* committed storage and returns the EFFECTIVE changes (no-ops — absent
|
|
20
|
+
* delete, value-identical upsert — are suppressed: no storage write, no
|
|
21
|
+
* module event, no seam report).
|
|
22
|
+
* 4. Module data events are emitted from the effective changes with
|
|
23
|
+
* `remote: true` (so the SyncManager never re-records inbound changes),
|
|
24
|
+
* carrying accurate `oldRow` before-images and derived `changedColumns`.
|
|
25
|
+
* 5. After all tables' storage writes, ONE seam call reports the
|
|
26
|
+
* accumulated effective changes: `db.ingestExternalRowChanges(batch,
|
|
27
|
+
* { applyForeignKeyActions, assertionFailureMode: 'report' })` — capture +
|
|
28
|
+
* MV facets default on, commit-time global assertions in REPORT mode (a
|
|
29
|
+
* violation is collected into the result and the batch still commits).
|
|
30
|
+
* Changes recorded in `result.errors` are excluded from the batch.
|
|
31
|
+
*
|
|
32
|
+
* Snapshot bootstrap (per-call, not sticky): a known-complete wholesale load
|
|
33
|
+
* defers MV maintenance and watch capture for the whole transfer and converges
|
|
34
|
+
* once at the end.
|
|
35
|
+
* - `bootstrap` flush: steps 1–4 run unchanged (storage rows applied, remote
|
|
36
|
+
* module events emitted) but step 5 — the seam call — is SKIPPED. MV
|
|
37
|
+
* maintenance + capture are deferred to the finalize and FK actions are off
|
|
38
|
+
* for a wholesale load, so the only seam facet skipping the call drops
|
|
39
|
+
* outright is commit-time GLOBAL ASSERTION evaluation over the bootstrapped
|
|
40
|
+
* rows — deliberate under the seam's trust-the-origin contract. The
|
|
41
|
+
* incremental path enforces global assertions because it **merges** deltas
|
|
42
|
+
* from possibly many origins into the receiver's existing state, and a
|
|
43
|
+
* cross-origin merge can produce a global-invariant violation no single
|
|
44
|
+
* origin ever saw. Bootstrap does something different: it installs **one**
|
|
45
|
+
* origin's already-converged state **wholesale (replace, not merge)** — no
|
|
46
|
+
* merge means no merge-introduced violation, so a complete snapshot already
|
|
47
|
+
* satisfied the origin's assertions and re-checking is redundant. The
|
|
48
|
+
* `bootstrapFinalize` therefore does NOT evaluate any global assertion —
|
|
49
|
+
* not even a no-dependency one. This uniform skip is consistent with the
|
|
50
|
+
* seam's general trust-the-origin posture for every other constraint type
|
|
51
|
+
* (see `docs/materialized-views.md` § Trust boundary). MV-backed assertions
|
|
52
|
+
* would see the MV only after `refreshAllMaterializedViews()`; under
|
|
53
|
+
* trust-the-origin they are not evaluated at finalize at all, so MV-refresh
|
|
54
|
+
* ordering is moot for assertions. Residual risk (a corrupt/hostile snapshot
|
|
55
|
+
* installs invariant-violating data) is already unguarded for every other
|
|
56
|
+
* constraint type; a one-off assertion sweep would be inconsistent
|
|
57
|
+
* defense-in-depth — a separate integrity layer is the right fix if origins
|
|
58
|
+
* are ever distrusted. Per-flush evaluation also could not serve bootstrap
|
|
59
|
+
* correctly: it could spuriously fail a valid snapshot whose cross-table
|
|
60
|
+
* assertion sees children before parents. The remaining seam work for a
|
|
61
|
+
* wholesale load is otherwise deferred, so skipping the call also removes
|
|
62
|
+
* the per-flush transaction/savepoint and the per-flush full-rebuild.
|
|
63
|
+
* - `bootstrapFinalize` call (empty data/schema): converges every MV in
|
|
64
|
+
* dependency order via `db.refreshAllMaterializedViews()`, then fires a
|
|
65
|
+
* coarse `db.notifyExternalChange` per bootstrapped base table and per
|
|
66
|
+
* refreshed MV — one whole-table watch invalidation instead of per-row
|
|
67
|
+
* capture. The caller issues it before clearing the snapshot checkpoint, so
|
|
68
|
+
* a finalize throw leaves the checkpoint in place and the transfer retries.
|
|
69
|
+
*
|
|
70
|
+
* Inbound assertion violations are DETECT-AND-NOTIFY, not throw. Under the
|
|
71
|
+
* seam's trust-the-origin contract the merged data must land regardless, so a
|
|
72
|
+
* **local** commit-time global assertion can only usefully *notify*: the seam
|
|
73
|
+
* runs in report mode, so a violation is collected and RETURNED in
|
|
74
|
+
* `result.assertionViolations` while the batch commits — the derived effects
|
|
75
|
+
* (MV backing deltas, capture entries) for the violating row land on the FIRST
|
|
76
|
+
* attempt, so an incremental MV / `Database.watch` subscriber stays consistent
|
|
77
|
+
* with the base table and there is no divergence and no retry. The consumer
|
|
78
|
+
* (admission.ts) surfaces each returned violation to the host as an
|
|
79
|
+
* `onAssertionViolation` event; the host decides policy.
|
|
80
|
+
*
|
|
81
|
+
* A genuine per-change STORAGE failure is different and still aborts: the
|
|
82
|
+
* adapter collects it in `result.errors` (it keeps applying other tables), and
|
|
83
|
+
* the consumer treats any non-empty `errors` like a whole-batch throw — emit
|
|
84
|
+
* `status:'error'`, leave CRDT metadata uncommitted, re-resolve next sync.
|
|
85
|
+
* Re-application is idempotent (value-identical upserts suppress). "Orthogonal"
|
|
86
|
+
* (above) means the two outcomes are independent facts, NOT that a co-occurring
|
|
87
|
+
* violation is dropped: when ONE batch carries both a per-change error and a
|
|
88
|
+
* reported violation, the violation's row already committed in report mode, so
|
|
89
|
+
* the consumer surfaces the `onAssertionViolation` event BEFORE the per-change
|
|
90
|
+
* abort throws (see admission.ts `applyDataToStore`). The abort still blocks the
|
|
91
|
+
* metadata commit and the batch still re-resolves.
|
|
92
|
+
*
|
|
93
|
+
* Constraints (see docs/materialized-views.md § External row-change
|
|
94
|
+
* ingestion): the callback is host-driven — never invoke it from within
|
|
95
|
+
* statement execution or vtab callbacks (exec-mutex deadlock), and hosts
|
|
96
|
+
* should not drive it while holding an open explicit transaction on `db`
|
|
97
|
+
* (the seam would join that transaction, so a later rollback diverges
|
|
98
|
+
* MV/capture state from the already-committed storage rows; recoverable via
|
|
99
|
+
* MV refresh).
|
|
7
100
|
*/
|
|
8
|
-
import type { Database
|
|
9
|
-
import type {
|
|
101
|
+
import type { Database } from '@quereus/quereus';
|
|
102
|
+
import type { StoreEventEmitter, StoreModule } from '@quereus/store';
|
|
10
103
|
import type { ApplyToStoreCallback } from './protocol.js';
|
|
11
104
|
/**
|
|
12
105
|
* Options for creating a SyncStoreAdapter.
|
|
13
106
|
*/
|
|
14
107
|
export interface SyncStoreAdapterOptions {
|
|
15
|
-
/** The Quereus database
|
|
108
|
+
/** The Quereus database: DDL execution + `ingestExternalRowChanges` reporting. */
|
|
16
109
|
db: Database;
|
|
17
110
|
/**
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
111
|
+
* The store module owning the synced tables. Each table is resolved per
|
|
112
|
+
* apply via `getTableForExternalWrite`, which owns key encoding (incl.
|
|
113
|
+
* per-PK-column collations), secondary-index maintenance, and per-table
|
|
114
|
+
* store resolution (e.g. IndexedDB's one-database-per-table layout).
|
|
21
115
|
*/
|
|
22
|
-
|
|
23
|
-
/** The event emitter for data change events. */
|
|
116
|
+
storeModule: StoreModule;
|
|
117
|
+
/** The event emitter for data change events (the adapter emits `remote: true`). */
|
|
24
118
|
events: StoreEventEmitter;
|
|
25
|
-
/**
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
119
|
+
/**
|
|
120
|
+
* Parent-side FK actions on inbound update/delete (seam facet). Default
|
|
121
|
+
* false — a replication stream usually carries the origin's cascade
|
|
122
|
+
* effects; opt in only when the deployment's stream does not. When on, an
|
|
123
|
+
* inbound parent delete cascades to local children through the full DML
|
|
124
|
+
* pipeline; those cascaded child writes emit module events WITHOUT
|
|
125
|
+
* `remote`, so they are recorded as local changes and propagate outward —
|
|
126
|
+
* correct for the opt-in posture.
|
|
127
|
+
*/
|
|
128
|
+
applyForeignKeyActions?: boolean;
|
|
29
129
|
}
|
|
30
130
|
/**
|
|
31
131
|
* Creates an ApplyToStoreCallback for applying remote sync changes.
|
|
@@ -34,6 +134,8 @@ export interface SyncStoreAdapterOptions {
|
|
|
34
134
|
* - UPSERT semantics for column changes (insert if row doesn't exist, update if it does)
|
|
35
135
|
* - Row deletions by primary key
|
|
36
136
|
* - DDL execution for schema changes
|
|
137
|
+
* - Post-apply reporting through the engine's ingestion seam (MV maintenance,
|
|
138
|
+
* `Database.watch` capture, opt-in FK actions)
|
|
37
139
|
*
|
|
38
140
|
* All data change events are emitted with `remote: true` to prevent
|
|
39
141
|
* the SyncManager from re-recording CRDT metadata.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store-adapter.d.ts","sourceRoot":"","sources":["../../../src/sync/store-adapter.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"store-adapter.d.ts","sourceRoot":"","sources":["../../../src/sync/store-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmGG;AAEH,OAAO,KAAK,EAAoB,QAAQ,EAAiD,MAAM,kBAAkB,CAAC;AAElH,OAAO,KAAK,EAAiB,iBAAiB,EAAE,WAAW,EAAc,MAAM,gBAAgB,CAAC;AAChG,OAAO,KAAK,EACV,oBAAoB,EAKrB,MAAM,eAAe,CAAC;AAGvB;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,kFAAkF;IAClF,EAAE,EAAE,QAAQ,CAAC;IACb;;;;;OAKG;IACH,WAAW,EAAE,WAAW,CAAC;IACzB,mFAAmF;IACnF,MAAM,EAAE,iBAAiB,CAAC;IAC1B;;;;;;;;OAQG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAC;CAClC;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,uBAAuB,GAAG,oBAAoB,CAwGzF"}
|