@cello-protocol/daemon 0.0.119 → 0.0.121
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/content-park.d.ts +1 -1
- package/dist/content-park.d.ts.map +1 -1
- package/dist/content-park.js +64 -12
- package/dist/content-park.js.map +1 -1
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +46 -32
- package/dist/daemon.js.map +1 -1
- package/dist/document-engine.d.ts +134 -0
- package/dist/document-engine.d.ts.map +1 -0
- package/dist/document-engine.js +275 -0
- package/dist/document-engine.js.map +1 -0
- package/dist/document-store.d.ts +181 -0
- package/dist/document-store.d.ts.map +1 -0
- package/dist/document-store.js +409 -0
- package/dist/document-store.js.map +1 -0
- package/dist/reconnect-drain.d.ts +15 -0
- package/dist/reconnect-drain.d.ts.map +1 -0
- package/dist/reconnect-drain.js +51 -0
- package/dist/reconnect-drain.js.map +1 -0
- package/dist/session-node-manager.d.ts +41 -2
- package/dist/session-node-manager.d.ts.map +1 -1
- package/dist/session-node-manager.js +168 -14
- package/dist/session-node-manager.js.map +1 -1
- package/dist/session-relay-client.d.ts +6 -0
- package/dist/session-relay-client.d.ts.map +1 -1
- package/dist/session-relay-client.js +20 -1
- package/dist/session-relay-client.js.map +1 -1
- package/dist/session-tree.d.ts +34 -2
- package/dist/session-tree.d.ts.map +1 -1
- package/dist/session-tree.js +21 -0
- package/dist/session-tree.js.map +1 -1
- package/package.json +6 -5
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DOD-DOC-ENGINE-1 — the daemon's Y.Doc lifecycle.
|
|
3
|
+
*
|
|
4
|
+
* The engine owns HOW to apply; the store (DOD-DOC-STORE-1) owns what to replay and in what
|
|
5
|
+
* order. `replay` takes whole envelope rows rather than payload bytes so it can tell a
|
|
6
|
+
* payload-free AUDIT record (a withdrawal or rejection, which is expected and skipped) from a
|
|
7
|
+
* payload-free PURGED update (an operation whose bytes are gone, which must refuse). That is the
|
|
8
|
+
* only thing `kind` is read for — `referencesEnvelopeHash` is pure audit at replay time, never
|
|
9
|
+
* read, because a withdrawal excludes nothing (§16.4; see `replay`).
|
|
10
|
+
*
|
|
11
|
+
* EVERY GUARD BELOW IS A RESPONSE TO A MEASUREMENT, not to a guess. DOD-DOC-FUZZ-1 fuzzed
|
|
12
|
+
* `Y.applyUpdate` and found:
|
|
13
|
+
*
|
|
14
|
+
* - Malformed input THROWS — so a wrapped apply genuinely contains it, and V1 needs no sandbox.
|
|
15
|
+
* - But the dangerous class is what Yjs ACCEPTS. An update whose dependencies the receiver
|
|
16
|
+
* lacks returns success, contributes nothing, and is RETAINED forever in
|
|
17
|
+
* `doc.store.pendingStructs` — a peer streams those until the daemon dies, and a try/catch
|
|
18
|
+
* sees only success. Hence the pending-set check after every apply.
|
|
19
|
+
* - An empty or one-byte update throws a lib0 DECODER error ("Unexpected end of array"), which
|
|
20
|
+
* names Yjs internals rather than a protocol fault. Hence a floor as well as a cap.
|
|
21
|
+
* - Yjs does not bound nesting depth at all, and the size cap bounds it poorly (~16 bytes per
|
|
22
|
+
* level, so roughly 65,000 levels fit in 1 MiB). Structural limits are DOD-DOC-GATE-1's job;
|
|
23
|
+
* the engine's contract is only that a bad update is a typed error, never a crash.
|
|
24
|
+
*
|
|
25
|
+
* ONE TYPED REASON PER FAILURE CLASS. A lib0 string like "Integer out of Range" describes where
|
|
26
|
+
* the decoder gave up, not what the peer did wrong, so it travels as `detail` and never as the
|
|
27
|
+
* reason an operator or a policy log sees.
|
|
28
|
+
*/
|
|
29
|
+
import * as Y from "yjs";
|
|
30
|
+
/** Thrown by the *OrThrow variants and by `replay`, where returning a verdict would let a caller
|
|
31
|
+
* persist a state that was never fully applied. */
|
|
32
|
+
export class DocumentUpdateError extends Error {
|
|
33
|
+
reason;
|
|
34
|
+
detail;
|
|
35
|
+
constructor(reason, detail) {
|
|
36
|
+
super(detail ? `${reason}: ${detail}` : reason);
|
|
37
|
+
this.name = "DocumentUpdateError";
|
|
38
|
+
this.reason = reason;
|
|
39
|
+
this.detail = detail;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/** Pre-parse size cap — bytes are refused on LENGTH before Yjs is invoked at all. */
|
|
43
|
+
const MAX_UPDATE_BYTES = 1024 * 1024;
|
|
44
|
+
/**
|
|
45
|
+
* The minimum valid update. An empty encoded state is two bytes (`[0,0]`), measured — anything
|
|
46
|
+
* shorter throws a decoder error that says nothing about the protocol.
|
|
47
|
+
*/
|
|
48
|
+
const MIN_UPDATE_BYTES = 2;
|
|
49
|
+
/** The single root text field a V1 text document uses. */
|
|
50
|
+
const TEXT_ROOT = "content";
|
|
51
|
+
export class DocumentEngine {
|
|
52
|
+
#logger;
|
|
53
|
+
constructor(logger) {
|
|
54
|
+
this.#logger = logger;
|
|
55
|
+
}
|
|
56
|
+
/** The pre-parse cap, exposed so callers and tests agree on one number. */
|
|
57
|
+
get maxUpdateBytes() {
|
|
58
|
+
return MAX_UPDATE_BYTES;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* A fresh live document.
|
|
62
|
+
*
|
|
63
|
+
* Yjs mints its own random clientID and NOTHING here touches it (§14). Deriving it from agent
|
|
64
|
+
* identity, or persisting and restoring one, means two live docs can share it — and
|
|
65
|
+
* DOD-DOC-FUZZ-1 measured that outcome: the colliding writer silently wins, the honest client's
|
|
66
|
+
* update is accepted-and-dropped, and the document becomes a splice of two authors with an
|
|
67
|
+
* empty pending set and no error on any path.
|
|
68
|
+
*/
|
|
69
|
+
createDocument(startingContent = "") {
|
|
70
|
+
const doc = new Y.Doc();
|
|
71
|
+
if (startingContent.length > 0)
|
|
72
|
+
doc.getText(TEXT_ROOT).insert(0, startingContent);
|
|
73
|
+
return doc;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Read the single text root a text-typed document uses.
|
|
77
|
+
*
|
|
78
|
+
* Named for the root it reads, not for "the document's content". `DocumentRow.documentType`
|
|
79
|
+
* admits markdown, json and xml; on the latter two the data does not live in this root, and an
|
|
80
|
+
* unnamed `readText` would return "" — indistinguishable from an empty document. Structured
|
|
81
|
+
* types get their own accessors when a unit needs them.
|
|
82
|
+
*/
|
|
83
|
+
readTextRoot(doc) {
|
|
84
|
+
return doc.getText(TEXT_ROOT).toString();
|
|
85
|
+
}
|
|
86
|
+
insertIntoTextRoot(doc, index, text) {
|
|
87
|
+
doc.getText(TEXT_ROOT).insert(index, text);
|
|
88
|
+
}
|
|
89
|
+
/** The full state, or just what a peer holding `sinceStateVector` is missing (§7). */
|
|
90
|
+
encodeState(doc, sinceStateVector) {
|
|
91
|
+
return Y.encodeStateAsUpdate(doc, sinceStateVector);
|
|
92
|
+
}
|
|
93
|
+
encodeStateVector(doc) {
|
|
94
|
+
return Y.encodeStateVector(doc);
|
|
95
|
+
}
|
|
96
|
+
snapshot(doc) {
|
|
97
|
+
return { binary: Y.encodeStateAsUpdate(doc), stateVector: Y.encodeStateVector(doc) };
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Materialize a document from a snapshot binary.
|
|
101
|
+
*
|
|
102
|
+
* The restored document mints a FRESH clientID — the binary carries the operations, never an
|
|
103
|
+
* identity to resume under. See `createDocument` for what sharing one costs.
|
|
104
|
+
*/
|
|
105
|
+
restore(binary) {
|
|
106
|
+
const doc = new Y.Doc();
|
|
107
|
+
try {
|
|
108
|
+
Y.applyUpdate(doc, binary);
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
// This is the one method that reads bytes off disk, and it used to be a bare applyUpdate —
|
|
112
|
+
// so a corrupt `document_snapshots` row surfaced as "Unexpected end of array", the exact
|
|
113
|
+
// lib0 string this module says must never be a reason. It named Yjs internals and pointed
|
|
114
|
+
// an operator at the wrong subsystem.
|
|
115
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
116
|
+
this.#logger.error("document.snapshot.malformed", { detail });
|
|
117
|
+
throw new DocumentUpdateError("document_snapshot_malformed", detail);
|
|
118
|
+
}
|
|
119
|
+
if (doc.store.pendingStructs !== null) {
|
|
120
|
+
// A snapshot that decodes but is incomplete would otherwise restore SHORT and silent.
|
|
121
|
+
this.#logger.error("document.snapshot.incomplete", {
|
|
122
|
+
missing: doc.store.pendingStructs.missing.size,
|
|
123
|
+
});
|
|
124
|
+
// Its OWN class. An incomplete snapshot is not "an incoming update depends on absent
|
|
125
|
+
// structs" — same symptom, different fault, and one reason per class is this module's rule.
|
|
126
|
+
throw new DocumentUpdateError("document_snapshot_incomplete", `snapshot is missing operations from ${doc.store.pendingStructs.missing.size} client(s)`);
|
|
127
|
+
}
|
|
128
|
+
return doc;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Apply one update, with every guard the fuzz pass motivated.
|
|
132
|
+
*
|
|
133
|
+
* Never throws and never leaves the document half-integrated: an update that cannot be fully
|
|
134
|
+
* resolved is applied to a THROWAWAY doc first, so the caller's document is untouched when the
|
|
135
|
+
* answer is no.
|
|
136
|
+
*/
|
|
137
|
+
/**
|
|
138
|
+
* Apply one update to a caller's live document, leaving it untouched if the answer is no.
|
|
139
|
+
*
|
|
140
|
+
* The trial runs on a FRESH scratch document every time. Reusing one across calls is unsound:
|
|
141
|
+
* `Y.applyUpdate` MERGES, it does not reset, so a scratch doc seeded from an empty document
|
|
142
|
+
* still holds the previous trial's operations — and with that residue present, an update whose
|
|
143
|
+
* dependencies the target lacks reports an EMPTY pending set. The one guard that catches the
|
|
144
|
+
* accept class would go green on exactly the input it exists to refuse. (Measured, not
|
|
145
|
+
* reasoned: a shadow holding "AAA" re-seeded from an empty doc still reads "AAA".)
|
|
146
|
+
*/
|
|
147
|
+
applyUpdate(doc, update) {
|
|
148
|
+
return this.#applyChecked(doc, new Y.Doc(), update);
|
|
149
|
+
}
|
|
150
|
+
#applyChecked(doc, shadow, update) {
|
|
151
|
+
if (update.length > MAX_UPDATE_BYTES) {
|
|
152
|
+
return this.#refuse("document_update_too_large", `${update.length} bytes exceeds the ${MAX_UPDATE_BYTES}-byte cap`, update);
|
|
153
|
+
}
|
|
154
|
+
if (update.length < MIN_UPDATE_BYTES) {
|
|
155
|
+
return this.#refuse("document_update_too_small", `${update.length} bytes is below the ${MIN_UPDATE_BYTES}-byte minimum for a Yjs update`, update);
|
|
156
|
+
}
|
|
157
|
+
// Trial it on scratch state first. Yjs has no atomic-apply mode, and an update that resolves
|
|
158
|
+
// only partially would otherwise leave the caller's document in a state nobody chose.
|
|
159
|
+
try {
|
|
160
|
+
Y.applyUpdate(shadow, Y.encodeStateAsUpdate(doc));
|
|
161
|
+
Y.applyUpdate(shadow, update);
|
|
162
|
+
}
|
|
163
|
+
catch (err) {
|
|
164
|
+
return this.#refuse("document_update_malformed", err instanceof Error ? err.message : String(err), update);
|
|
165
|
+
}
|
|
166
|
+
// THE ACCEPT CLASS. Yjs returned success — that is not evidence the update integrated. A
|
|
167
|
+
// non-empty pending set means it is waiting on structs that never arrived; admitting it would
|
|
168
|
+
// retain them indefinitely while contributing nothing (measured, DOD-DOC-FUZZ-1).
|
|
169
|
+
//
|
|
170
|
+
// PRECONDITION THIS IMPLIES: a sender's envelopes must be delivered in chain order. Yjs would
|
|
171
|
+
// otherwise BUFFER an out-of-order update and resolve it on the next state-vector exchange;
|
|
172
|
+
// this refuses instead. That is right for replay, where a gap means a corrupt log — a live
|
|
173
|
+
// receive path wanting buffer-and-re-request semantics needs its own entry point, not this one.
|
|
174
|
+
if (shadow.store.pendingStructs !== null) {
|
|
175
|
+
return this.#refuse("document_update_unresolved_dependencies", `depends on ${shadow.store.pendingStructs.missing.size} client(s) whose earlier operations are absent`, update);
|
|
176
|
+
}
|
|
177
|
+
Y.applyUpdate(doc, update);
|
|
178
|
+
return { ok: true };
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Apply straight to `doc`, checking the pending set afterwards.
|
|
182
|
+
*
|
|
183
|
+
* No trial copy, because atomicity buys nothing here: `replay` throws on the first failure and
|
|
184
|
+
* the half-built document is discarded whole. Trialling each envelope would cost a full
|
|
185
|
+
* encode/decode of a growing document per envelope — the fold is O(n·|doc|) either way, but
|
|
186
|
+
* this halves the constant and removes the aliasing hazard entirely.
|
|
187
|
+
*/
|
|
188
|
+
#applyDirect(doc, update) {
|
|
189
|
+
if (update.length > MAX_UPDATE_BYTES) {
|
|
190
|
+
return this.#refuse("document_update_too_large", `${update.length} bytes exceeds the ${MAX_UPDATE_BYTES}-byte cap`, update);
|
|
191
|
+
}
|
|
192
|
+
if (update.length < MIN_UPDATE_BYTES) {
|
|
193
|
+
return this.#refuse("document_update_too_small", `${update.length} bytes is below the ${MIN_UPDATE_BYTES}-byte minimum for a Yjs update`, update);
|
|
194
|
+
}
|
|
195
|
+
try {
|
|
196
|
+
Y.applyUpdate(doc, update);
|
|
197
|
+
}
|
|
198
|
+
catch (err) {
|
|
199
|
+
return this.#refuse("document_update_malformed", err instanceof Error ? err.message : String(err), update);
|
|
200
|
+
}
|
|
201
|
+
if (doc.store.pendingStructs !== null) {
|
|
202
|
+
return this.#refuse("document_update_unresolved_dependencies", `depends on ${doc.store.pendingStructs.missing.size} client(s) whose earlier operations are absent`, update);
|
|
203
|
+
}
|
|
204
|
+
return { ok: true };
|
|
205
|
+
}
|
|
206
|
+
/** Every refusal is logged, not merely returned — a return value nobody reads is not observable. */
|
|
207
|
+
#refuse(reason, detail, update) {
|
|
208
|
+
this.#logger.warn("document.update.refused", { reason, detail, bytes: update.length });
|
|
209
|
+
return { ok: false, reason, detail };
|
|
210
|
+
}
|
|
211
|
+
/** `applyUpdate` for callers that want the failure to be unmissable. */
|
|
212
|
+
applyUpdateOrThrow(doc, update) {
|
|
213
|
+
const res = this.applyUpdate(doc, update);
|
|
214
|
+
if (!res.ok)
|
|
215
|
+
throw new DocumentUpdateError(res.reason, res.detail);
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Fold an ordered envelope log into a materialized state — the `ReplayFn` the store injects.
|
|
219
|
+
*
|
|
220
|
+
* **A WITHDRAWAL EXCLUDES NOTHING.** §16.4 is explicit: withdrawing rolls the change back with
|
|
221
|
+
* a *Yjs undo* and writes a record "beside the original envelope — marked withdrawn, never
|
|
222
|
+
* deleted, so the log stays intact". Rejection resolves the same way, by supersession —
|
|
223
|
+
* "inverses, not erasure" (§3.2). So the undo is itself an ordinary update in the log, and
|
|
224
|
+
* replay simply applies every payload in order.
|
|
225
|
+
*
|
|
226
|
+
* An earlier version of this method excluded the referenced envelope instead, which is
|
|
227
|
+
* unsound in a CRDT log and was measured to be so: Yjs operations are causally chained, so
|
|
228
|
+
* dropping any but the LAST envelope leaves every later one depending on structs that never
|
|
229
|
+
* arrive — the document rebuilds until the next daemon restart and is permanently unopenable
|
|
230
|
+
* after it. It also let ANY sender suppress ANY other sender's content by appending a
|
|
231
|
+
* payload-free row, since nothing upstream checks authorship of a reference. Both problems
|
|
232
|
+
* dissolve when the log is simply replayed, which is what the spec said to do.
|
|
233
|
+
*
|
|
234
|
+
* REFUSES rather than skipping. A payload that will not apply means the log is corrupt, and
|
|
235
|
+
* folding the rest would produce a document that reads as complete while missing operations —
|
|
236
|
+
* the silent divergence the whole two-layer design exists to prevent.
|
|
237
|
+
*/
|
|
238
|
+
replay(envelopes) {
|
|
239
|
+
const doc = new Y.Doc();
|
|
240
|
+
let applied = 0;
|
|
241
|
+
for (const e of envelopes) {
|
|
242
|
+
if (e.payload === null) {
|
|
243
|
+
// A withdrawal or rejection RECORD legitimately carries no payload — it is audit, not
|
|
244
|
+
// content. An `update` row with no payload is different: it is a PURGED operation whose
|
|
245
|
+
// bytes are gone (§16.7-12), and folding around it would produce a document that reads
|
|
246
|
+
// as complete while missing an operation. Purge is V2, so this cannot happen yet — which
|
|
247
|
+
// is exactly why it must refuse now rather than become a silent skip later.
|
|
248
|
+
if (e.kind === "update") {
|
|
249
|
+
this.#logger.error("document.replay.failed", {
|
|
250
|
+
documentId: e.documentId,
|
|
251
|
+
envelopeHash: e.envelopeHash,
|
|
252
|
+
reason: "document_envelope_purged",
|
|
253
|
+
});
|
|
254
|
+
throw new DocumentUpdateError("document_envelope_purged", `envelope ${e.envelopeHash.slice(0, 16)}… is an update whose payload has been purged — ` +
|
|
255
|
+
`the document cannot be rebuilt without it`);
|
|
256
|
+
}
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
259
|
+
const res = this.#applyDirect(doc, e.payload);
|
|
260
|
+
if (!res.ok) {
|
|
261
|
+
this.#logger.error("document.replay.failed", {
|
|
262
|
+
documentId: e.documentId,
|
|
263
|
+
envelopeHash: e.envelopeHash,
|
|
264
|
+
reason: res.reason,
|
|
265
|
+
detail: res.detail,
|
|
266
|
+
});
|
|
267
|
+
throw new DocumentUpdateError(res.reason, `envelope ${e.envelopeHash.slice(0, 16)}…: ${res.detail ?? ""}`);
|
|
268
|
+
}
|
|
269
|
+
applied++;
|
|
270
|
+
}
|
|
271
|
+
this.#logger.info("document.replay.completed", { envelopes: envelopes.length, applied });
|
|
272
|
+
return { binary: Y.encodeStateAsUpdate(doc), stateVector: Y.encodeStateVector(doc) };
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
//# sourceMappingURL=document-engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document-engine.js","sourceRoot":"","sources":["../src/document-engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AAkBzB;oDACoD;AACpD,MAAM,OAAO,mBAAoB,SAAQ,KAAK;IACnC,MAAM,CAAwB;IAC9B,MAAM,CAAU;IACzB,YAAY,MAA6B,EAAE,MAAe;QACxD,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,KAAK,MAAM,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QAChD,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;QAClC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF;AAED,qFAAqF;AACrF,MAAM,gBAAgB,GAAG,IAAI,GAAG,IAAI,CAAC;AAErC;;;GAGG;AACH,MAAM,gBAAgB,GAAG,CAAC,CAAC;AAE3B,0DAA0D;AAC1D,MAAM,SAAS,GAAG,SAAS,CAAC;AAE5B,MAAM,OAAO,cAAc;IAChB,OAAO,CAAS;IAEzB,YAAY,MAAc;QACxB,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;IACxB,CAAC;IAED,2EAA2E;IAC3E,IAAI,cAAc;QAChB,OAAO,gBAAgB,CAAC;IAC1B,CAAC;IAED;;;;;;;;OAQG;IACH,cAAc,CAAC,eAAe,GAAG,EAAE;QACjC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,GAAG,EAAE,CAAC;QACxB,IAAI,eAAe,CAAC,MAAM,GAAG,CAAC;YAAE,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,eAAe,CAAC,CAAC;QAClF,OAAO,GAAG,CAAC;IACb,CAAC;IAED;;;;;;;OAOG;IACH,YAAY,CAAC,GAAU;QACrB,OAAO,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC3C,CAAC;IAED,kBAAkB,CAAC,GAAU,EAAE,KAAa,EAAE,IAAY;QACxD,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IAC7C,CAAC;IAED,sFAAsF;IACtF,WAAW,CAAC,GAAU,EAAE,gBAA6B;QACnD,OAAO,CAAC,CAAC,mBAAmB,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC;IACtD,CAAC;IAED,iBAAiB,CAAC,GAAU;QAC1B,OAAO,CAAC,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC;IAClC,CAAC;IAED,QAAQ,CAAC,GAAU;QACjB,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,mBAAmB,CAAC,GAAG,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,iBAAiB,CAAC,GAAG,CAAC,EAAE,CAAC;IACvF,CAAC;IAED;;;;;OAKG;IACH,OAAO,CAAC,MAAkB;QACxB,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,GAAG,EAAE,CAAC;QACxB,IAAI,CAAC;YACH,CAAC,CAAC,WAAW,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QAC7B,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,2FAA2F;YAC3F,yFAAyF;YACzF,0FAA0F;YAC1F,sCAAsC;YACtC,MAAM,MAAM,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAChE,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,6BAA6B,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;YAC9D,MAAM,IAAI,mBAAmB,CAAC,6BAA6B,EAAE,MAAM,CAAC,CAAC;QACvE,CAAC;QACD,IAAI,GAAG,CAAC,KAAK,CAAC,cAAc,KAAK,IAAI,EAAE,CAAC;YACtC,sFAAsF;YACtF,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,8BAA8B,EAAE;gBACjD,OAAO,EAAE,GAAG,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,IAAI;aAC/C,CAAC,CAAC;YACH,qFAAqF;YACrF,4FAA4F;YAC5F,MAAM,IAAI,mBAAmB,CAC3B,8BAA8B,EAC9B,uCAAuC,GAAG,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,IAAI,YAAY,CACzF,CAAC;QACJ,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IAED;;;;;;OAMG;IACH;;;;;;;;;OASG;IACH,WAAW,CAAC,GAAU,EAAE,MAAkB;QACxC,OAAO,IAAI,CAAC,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,MAAM,CAAC,CAAC;IACtD,CAAC;IAED,aAAa,CAAC,GAAU,EAAE,MAAa,EAAE,MAAkB;QACzD,IAAI,MAAM,CAAC,MAAM,GAAG,gBAAgB,EAAE,CAAC;YACrC,OAAO,IAAI,CAAC,OAAO,CAAC,2BAA2B,EAAE,GAAG,MAAM,CAAC,MAAM,sBAAsB,gBAAgB,WAAW,EAAE,MAAM,CAAC,CAAC;QAC9H,CAAC;QACD,IAAI,MAAM,CAAC,MAAM,GAAG,gBAAgB,EAAE,CAAC;YACrC,OAAO,IAAI,CAAC,OAAO,CAAC,2BAA2B,EAAE,GAAG,MAAM,CAAC,MAAM,uBAAuB,gBAAgB,gCAAgC,EAAE,MAAM,CAAC,CAAC;QACpJ,CAAC;QAED,6FAA6F;QAC7F,sFAAsF;QACtF,IAAI,CAAC;YACH,CAAC,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC,CAAC;YAClD,CAAC,CAAC,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAChC,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,OAAO,IAAI,CAAC,OAAO,CAAC,2BAA2B,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC;QAC7G,CAAC;QAED,yFAAyF;QACzF,8FAA8F;QAC9F,kFAAkF;QAClF,EAAE;QACF,8FAA8F;QAC9F,4FAA4F;QAC5F,2FAA2F;QAC3F,gGAAgG;QAChG,IAAI,MAAM,CAAC,KAAK,CAAC,cAAc,KAAK,IAAI,EAAE,CAAC;YACzC,OAAO,IAAI,CAAC,OAAO,CACjB,yCAAyC,EACzC,cAAc,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,IAAI,gDAAgD,EACtG,MAAM,CACP,CAAC;QACJ,CAAC;QAED,CAAC,CAAC,WAAW,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QAC3B,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;IACtB,CAAC;IAED;;;;;;;OAOG;IACH,YAAY,CAAC,GAAU,EAAE,MAAkB;QACzC,IAAI,MAAM,CAAC,MAAM,GAAG,gBAAgB,EAAE,CAAC;YACrC,OAAO,IAAI,CAAC,OAAO,CAAC,2BAA2B,EAAE,GAAG,MAAM,CAAC,MAAM,sBAAsB,gBAAgB,WAAW,EAAE,MAAM,CAAC,CAAC;QAC9H,CAAC;QACD,IAAI,MAAM,CAAC,MAAM,GAAG,gBAAgB,EAAE,CAAC;YACrC,OAAO,IAAI,CAAC,OAAO,CAAC,2BAA2B,EAAE,GAAG,MAAM,CAAC,MAAM,uBAAuB,gBAAgB,gCAAgC,EAAE,MAAM,CAAC,CAAC;QACpJ,CAAC;QACD,IAAI,CAAC;YACH,CAAC,CAAC,WAAW,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QAC7B,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,OAAO,IAAI,CAAC,OAAO,CAAC,2BAA2B,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC;QAC7G,CAAC;QACD,IAAI,GAAG,CAAC,KAAK,CAAC,cAAc,KAAK,IAAI,EAAE,CAAC;YACtC,OAAO,IAAI,CAAC,OAAO,CACjB,yCAAyC,EACzC,cAAc,GAAG,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,IAAI,gDAAgD,EACnG,MAAM,CACP,CAAC;QACJ,CAAC;QACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;IACtB,CAAC;IAED,oGAAoG;IACpG,OAAO,CAAC,MAA6B,EAAE,MAAc,EAAE,MAAkB;QACvE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,yBAAyB,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;QACvF,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IACvC,CAAC;IAED,wEAAwE;IACxE,kBAAkB,CAAC,GAAU,EAAE,MAAkB;QAC/C,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QAC1C,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,MAAM,IAAI,mBAAmB,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACrE,CAAC;IAED;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,MAAM,CAAC,SAAyC;QAC9C,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,GAAG,EAAE,CAAC;QACxB,IAAI,OAAO,GAAG,CAAC,CAAC;QAEhB,KAAK,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;YAC1B,IAAI,CAAC,CAAC,OAAO,KAAK,IAAI,EAAE,CAAC;gBACvB,sFAAsF;gBACtF,wFAAwF;gBACxF,uFAAuF;gBACvF,yFAAyF;gBACzF,4EAA4E;gBAC5E,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;oBACxB,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,wBAAwB,EAAE;wBAC3C,UAAU,EAAE,CAAC,CAAC,UAAU;wBACxB,YAAY,EAAE,CAAC,CAAC,YAAY;wBAC5B,MAAM,EAAE,0BAA0B;qBACnC,CAAC,CAAC;oBACH,MAAM,IAAI,mBAAmB,CAC3B,0BAA0B,EAC1B,YAAY,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,iDAAiD;wBACtF,2CAA2C,CAC9C,CAAC;gBACJ,CAAC;gBACD,SAAS;YACX,CAAC;YAED,MAAM,GAAG,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC;YAC9C,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;gBACZ,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,wBAAwB,EAAE;oBAC3C,UAAU,EAAE,CAAC,CAAC,UAAU;oBACxB,YAAY,EAAE,CAAC,CAAC,YAAY;oBAC5B,MAAM,EAAE,GAAG,CAAC,MAAM;oBAClB,MAAM,EAAE,GAAG,CAAC,MAAM;iBACnB,CAAC,CAAC;gBACH,MAAM,IAAI,mBAAmB,CAC3B,GAAG,CAAC,MAAM,EACV,YAAY,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,GAAG,CAAC,MAAM,IAAI,EAAE,EAAE,CAChE,CAAC;YACJ,CAAC;YACD,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,2BAA2B,EAAE,EAAE,SAAS,EAAE,SAAS,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;QACzF,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,mBAAmB,CAAC,GAAG,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,iBAAiB,CAAC,GAAG,CAAC,EAAE,CAAC;IACvF,CAAC;CACF"}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DOD-DOC-STORE-1 — the daemon's three document tables (§16.7-12).
|
|
3
|
+
*
|
|
4
|
+
* TWO LAYERS, NOT ONE (§14). Storing only a merged Yjs binary would discard the signed envelope
|
|
5
|
+
* chain that makes a seal verifiable, so both are kept:
|
|
6
|
+
*
|
|
7
|
+
* `document_envelopes` — the IMMUTABLE log: signatures, provenance, the per-document chain.
|
|
8
|
+
* This is the truth.
|
|
9
|
+
* `document_snapshots` — a MATERIALIZATION for fast start. Disposable by construction:
|
|
10
|
+
* delete it and it rebuilds from the log, byte-identical.
|
|
11
|
+
*
|
|
12
|
+
* The distinction is load-bearing rather than stylistic. Live Yjs state deliberately does NOT
|
|
13
|
+
* survive a daemon restart — CELLO's invariant is daemon-up-is-CELLO-on — and that is only safe
|
|
14
|
+
* because the log makes rebuilding a lookup rather than an archaeology exercise.
|
|
15
|
+
*
|
|
16
|
+
* THIS MODULE PERSISTS; IT DOES NOT APPLY. Replay is INJECTED (`rebuildSnapshot`), so the store
|
|
17
|
+
* owns *what to replay and in what order* while the engine (DOD-DOC-ENGINE-1) owns *how to
|
|
18
|
+
* apply*. That keeps `yjs` out of this file's imports entirely and keeps the P0/P1 boundary
|
|
19
|
+
* honest — a store that quietly grew a Y.Doc would be the engine wearing a store's name.
|
|
20
|
+
*
|
|
21
|
+
* WHAT IS NEVER STORED HERE: a Yjs clientID. §14's one-line rule is "let Yjs mint its own per
|
|
22
|
+
* live Y.Doc; never derive it from agent identity, never persist and restore one." DOD-DOC-FUZZ-1
|
|
23
|
+
* measured the cost of getting this wrong — two live docs sharing a clientID means the colliding
|
|
24
|
+
* writer silently wins, the honest client's update is accepted-and-dropped, and the result is a
|
|
25
|
+
* splice of two authors with an EMPTY pending set and no error on any path. So the snapshot
|
|
26
|
+
* stores a binary and a state vector, and nothing that could be restored into a live document as
|
|
27
|
+
* an identity.
|
|
28
|
+
*
|
|
29
|
+
* KEYED ON STABLE IDS ONLY. `agent_id` and `document_id`, never `agent_name` — it is a mutable
|
|
30
|
+
* display label and reusable after retirement. The M7 session tables join on `agent_name`; that
|
|
31
|
+
* is a known defect (`DOD-AGENT-ID-JOINKEY-1`), not a precedent to copy.
|
|
32
|
+
*/
|
|
33
|
+
import type { DaemonDatabase } from "./sqlcipher-db.js";
|
|
34
|
+
import type { Logger } from "./types.js";
|
|
35
|
+
/** Lifecycle states a document can hold (§3.5). `stalled` is DOD-DOC-REJECT-1's terminal state. */
|
|
36
|
+
export type DocumentStatus = "active" | "closed" | "killed" | "stalled";
|
|
37
|
+
/**
|
|
38
|
+
* What an envelope IS, as opposed to what it says. A withdrawal or a rejection is a NEW ROW that
|
|
39
|
+
* references an earlier envelope — never an edit to it. The log is append-only, so the only way
|
|
40
|
+
* to say "that one no longer counts" is to add a record saying so.
|
|
41
|
+
*/
|
|
42
|
+
export type DocumentEnvelopeKind = "update" | "withdrawal" | "rejection";
|
|
43
|
+
export interface DocumentProperties {
|
|
44
|
+
/** V1 accepts only `authenticated` — the Tier-2 seam (§16.1). */
|
|
45
|
+
assurance_tier?: string;
|
|
46
|
+
/** V1 accepts only `false` — the Tier-2 seam (§16.1). */
|
|
47
|
+
schema_enforcement?: boolean;
|
|
48
|
+
append_only?: boolean;
|
|
49
|
+
[key: string]: unknown;
|
|
50
|
+
}
|
|
51
|
+
export interface DocumentRow {
|
|
52
|
+
documentId: string;
|
|
53
|
+
ownerAgentId: string;
|
|
54
|
+
peerAgentId: string;
|
|
55
|
+
documentType: string;
|
|
56
|
+
properties: DocumentProperties;
|
|
57
|
+
status: DocumentStatus;
|
|
58
|
+
createdAtMs: number;
|
|
59
|
+
}
|
|
60
|
+
export interface DocumentEnvelopeRow {
|
|
61
|
+
/** Content hash of the envelope — the stable identity, and the log's primary key. */
|
|
62
|
+
envelopeHash: string;
|
|
63
|
+
documentId: string;
|
|
64
|
+
/** WHO authored it. The chain is per-sender, so this is what partitions it. */
|
|
65
|
+
senderAgentId: string;
|
|
66
|
+
/** The sender's previous envelope for this document, or null at genesis (§9.1). */
|
|
67
|
+
docPrevHash: string | null;
|
|
68
|
+
/** Constant 0 in V1 and NEVER omitted — after a compaction an update that does not state its
|
|
69
|
+
* epoch cannot be verified unambiguously (§14, §16.1 seam). */
|
|
70
|
+
epochId: number;
|
|
71
|
+
signature: Uint8Array;
|
|
72
|
+
/** The sender's Yjs state vector at publish time (§7). */
|
|
73
|
+
stateVector: Uint8Array;
|
|
74
|
+
/** NULLABLE — a purged envelope keeps its hash and signature, proving it existed (§16.7-12). */
|
|
75
|
+
payload: Uint8Array | null;
|
|
76
|
+
kind: DocumentEnvelopeKind;
|
|
77
|
+
/** For a withdrawal or rejection: the envelope it concerns. */
|
|
78
|
+
referencesEnvelopeHash?: string | null;
|
|
79
|
+
createdAtMs: number;
|
|
80
|
+
/** Position in this document's log. Assigned on append; absent until then. */
|
|
81
|
+
logIndex?: number;
|
|
82
|
+
}
|
|
83
|
+
export interface DocumentSnapshot {
|
|
84
|
+
binary: Uint8Array;
|
|
85
|
+
stateVector: Uint8Array;
|
|
86
|
+
/**
|
|
87
|
+
* The `log_index` of the last envelope this snapshot reflects. §14 is explicit about why it is
|
|
88
|
+
* stored rather than derived: with it, "where does the snapshot sit relative to the log" is a
|
|
89
|
+
* lookup; without it, every rebuild works it out from scratch.
|
|
90
|
+
*
|
|
91
|
+
* **-1 means nothing has been applied.** The resume point is ALWAYS `lastAppliedIndex + 1`,
|
|
92
|
+
* so an empty log yields 0 and `getEnvelopesSince(0)` reads the whole log — the sentinel and
|
|
93
|
+
* the convention are chosen to agree.
|
|
94
|
+
*/
|
|
95
|
+
lastAppliedIndex: number;
|
|
96
|
+
}
|
|
97
|
+
/** Thrown when a read path refuses to materialize over a chain that does not verify. */
|
|
98
|
+
export declare class DocumentChainError extends Error {
|
|
99
|
+
readonly reason: "document_chain_broken" | "document_chain_forked";
|
|
100
|
+
readonly detail: string;
|
|
101
|
+
constructor(reason: "document_chain_broken" | "document_chain_forked", detail: string);
|
|
102
|
+
}
|
|
103
|
+
export type ChainVerdict = {
|
|
104
|
+
ok: true;
|
|
105
|
+
} | {
|
|
106
|
+
ok: false;
|
|
107
|
+
reason: "document_chain_broken" | "document_chain_forked";
|
|
108
|
+
detail: string;
|
|
109
|
+
};
|
|
110
|
+
/**
|
|
111
|
+
* Injected by the engine: fold an ordered envelope list into a materialized state.
|
|
112
|
+
*
|
|
113
|
+
* Takes ROWS, not bare payloads. The engine has to distinguish an update from a withdrawal or a
|
|
114
|
+
* rejection to fold correctly — a withdrawn envelope's payload must not be applied — and it
|
|
115
|
+
* cannot do that from `Uint8Array[]`. The store supplies the WHOLE log in order — withdrawal and
|
|
116
|
+
* rejection records included, payload-free though they are; deciding what counts is the engine's
|
|
117
|
+
* call, not the store's.
|
|
118
|
+
*/
|
|
119
|
+
export type ReplayFn = (envelopes: DocumentEnvelopeRow[]) => {
|
|
120
|
+
binary: Uint8Array;
|
|
121
|
+
stateVector: Uint8Array;
|
|
122
|
+
};
|
|
123
|
+
export declare class DocumentStore {
|
|
124
|
+
#private;
|
|
125
|
+
constructor(db: DaemonDatabase, logger: Logger);
|
|
126
|
+
createDocument(row: DocumentRow): void;
|
|
127
|
+
getDocument(ownerAgentId: string, documentId: string): DocumentRow | null;
|
|
128
|
+
listDocuments(ownerAgentId: string): DocumentRow[];
|
|
129
|
+
setDocumentStatus(ownerAgentId: string, documentId: string, status: DocumentStatus): void;
|
|
130
|
+
/**
|
|
131
|
+
* Append an envelope at the next log position.
|
|
132
|
+
*
|
|
133
|
+
* IMMUTABLE AT A HASH: the conflict clause is scoped to the envelope hash ALONE, so a
|
|
134
|
+
* re-delivery — or a peer replaying the same hash with different bytes — cannot overwrite what
|
|
135
|
+
* was recorded. Returns whether a new row was written, so the caller can tell a genuine append
|
|
136
|
+
* from a duplicate rather than inferring it.
|
|
137
|
+
*
|
|
138
|
+
* Scoped deliberately, not written as a bare `OR IGNORE`: that form suppresses CHECK, UNIQUE
|
|
139
|
+
* and NOT NULL as well, which on an append-only log means a malformed `kind` or a colliding
|
|
140
|
+
* `log_index` would be DROPPED and reported to the caller as an already-seen duplicate. Every
|
|
141
|
+
* constraint except the hash conflict must throw, or `false` means three different things the
|
|
142
|
+
* caller cannot tell apart.
|
|
143
|
+
*/
|
|
144
|
+
appendEnvelope(ownerAgentId: string, envelope: DocumentEnvelopeRow): boolean;
|
|
145
|
+
/**
|
|
146
|
+
* Envelopes at or after `fromIndex`, in log order. This is what makes `lastAppliedIndex` the
|
|
147
|
+
* lookup §14 asks for: resume an incremental rebuild at `lastAppliedIndex + 1` without reading
|
|
148
|
+
* the whole log.
|
|
149
|
+
*/
|
|
150
|
+
getEnvelopesSince(ownerAgentId: string, documentId: string, fromIndex: number): DocumentEnvelopeRow[];
|
|
151
|
+
getEnvelopeLog(ownerAgentId: string, documentId: string): DocumentEnvelopeRow[];
|
|
152
|
+
/**
|
|
153
|
+
* Verify each sender's `doc_prev_hash` chain independently.
|
|
154
|
+
*
|
|
155
|
+
* The log interleaves both parties' envelopes, so there is no single total order to check —
|
|
156
|
+
* §16.7-5 defines replay set-based per epoch for exactly this reason. What must hold is that
|
|
157
|
+
* every sender's own links form one unbroken chain from a single genesis.
|
|
158
|
+
*
|
|
159
|
+
* A break REFUSES and names the sender and the missing predecessor. Skipping the leaf and
|
|
160
|
+
* carrying on would leave a document that reads as complete while missing operations, which is
|
|
161
|
+
* the silent-divergence failure the chain exists to prevent.
|
|
162
|
+
*
|
|
163
|
+
* LINKAGE ONLY — the name says so deliberately. This verifies no signature and does not check
|
|
164
|
+
* that `envelope_hash` hashes the content; neither is possible here (no key, no encoder). A
|
|
165
|
+
* caller must not read `ok: true` as authenticity — that belongs to the engine.
|
|
166
|
+
*/
|
|
167
|
+
verifyChainLinkage(ownerAgentId: string, documentId: string): ChainVerdict;
|
|
168
|
+
getSnapshot(ownerAgentId: string, documentId: string): DocumentSnapshot | null;
|
|
169
|
+
/** REPLACES — a snapshot is a cache of the log, not a second log. */
|
|
170
|
+
putSnapshot(ownerAgentId: string, documentId: string, snapshot: DocumentSnapshot): void;
|
|
171
|
+
deleteSnapshot(ownerAgentId: string, documentId: string): void;
|
|
172
|
+
/**
|
|
173
|
+
* Rebuild a snapshot from the envelope log alone, using the caller's replay function.
|
|
174
|
+
*
|
|
175
|
+
* Payload-stripped envelopes (purged, or withdrawal/rejection records that carry none)
|
|
176
|
+
* contribute nothing to replay but STILL COUNT toward `lastAppliedIndex` — otherwise the next
|
|
177
|
+
* incremental rebuild would start behind them and replay them forever.
|
|
178
|
+
*/
|
|
179
|
+
rebuildSnapshot(ownerAgentId: string, documentId: string, replay: ReplayFn): DocumentSnapshot;
|
|
180
|
+
}
|
|
181
|
+
//# sourceMappingURL=document-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document-store.d.ts","sourceRoot":"","sources":["../src/document-store.ts"],"names":[],"mappings":"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"}
|