@cello-protocol/daemon 0.0.167 → 0.0.169
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/daemon.d.ts.map +1 -1
- package/dist/daemon.js +115 -254
- package/dist/daemon.js.map +1 -1
- package/dist/document-amendment-store.d.ts +94 -46
- package/dist/document-amendment-store.d.ts.map +1 -1
- package/dist/document-amendment-store.js +217 -102
- package/dist/document-amendment-store.js.map +1 -1
- package/dist/document-delivery-transport.d.ts +41 -52
- package/dist/document-delivery-transport.d.ts.map +1 -1
- package/dist/document-delivery-transport.js +6 -156
- package/dist/document-delivery-transport.js.map +1 -1
- package/dist/document-frame-router.d.ts +13 -17
- package/dist/document-frame-router.d.ts.map +1 -1
- package/dist/document-frame-router.js +21 -93
- package/dist/document-frame-router.js.map +1 -1
- package/dist/document-handlers.d.ts +1 -1
- package/dist/document-handlers.d.ts.map +1 -1
- package/dist/document-handlers.js +471 -466
- package/dist/document-handlers.js.map +1 -1
- package/dist/document-handshake.d.ts +4 -1
- package/dist/document-handshake.d.ts.map +1 -1
- package/dist/document-handshake.js +3 -1
- package/dist/document-handshake.js.map +1 -1
- package/dist/document-inbound.d.ts +18 -5
- package/dist/document-inbound.d.ts.map +1 -1
- package/dist/document-inbound.js +94 -110
- package/dist/document-inbound.js.map +1 -1
- package/dist/document-layer.d.ts +28 -67
- package/dist/document-layer.d.ts.map +1 -1
- package/dist/document-layer.js +670 -565
- package/dist/document-layer.js.map +1 -1
- package/dist/document-lifecycle.d.ts +11 -157
- package/dist/document-lifecycle.d.ts.map +1 -1
- package/dist/document-lifecycle.js +26 -561
- package/dist/document-lifecycle.js.map +1 -1
- package/dist/document-publish.d.ts +13 -0
- package/dist/document-publish.d.ts.map +1 -1
- package/dist/document-publish.js +19 -11
- package/dist/document-publish.js.map +1 -1
- package/dist/document-reconcile-engine.d.ts +66 -0
- package/dist/document-reconcile-engine.d.ts.map +1 -0
- package/dist/document-reconcile-engine.js +225 -0
- package/dist/document-reconcile-engine.js.map +1 -0
- package/dist/document-reconcile-scheduler.d.ts +91 -0
- package/dist/document-reconcile-scheduler.d.ts.map +1 -0
- package/dist/document-reconcile-scheduler.js +153 -0
- package/dist/document-reconcile-scheduler.js.map +1 -0
- package/dist/document-rejection.d.ts +2 -0
- package/dist/document-rejection.d.ts.map +1 -1
- package/dist/document-rejection.js +5 -1
- package/dist/document-rejection.js.map +1 -1
- package/dist/document-store.d.ts +18 -220
- package/dist/document-store.d.ts.map +1 -1
- package/dist/document-store.js +95 -717
- package/dist/document-store.js.map +1 -1
- package/dist/initiate-session-handler.d.ts +5 -0
- package/dist/initiate-session-handler.d.ts.map +1 -1
- package/dist/initiate-session-handler.js +1 -0
- package/dist/initiate-session-handler.js.map +1 -1
- package/package.json +5 -5
- package/dist/delivery-sweep-bound.d.ts +0 -79
- package/dist/delivery-sweep-bound.d.ts.map +0 -1
- package/dist/delivery-sweep-bound.js +0 -109
- package/dist/delivery-sweep-bound.js.map +0 -1
- package/dist/document-ack-inbound.d.ts +0 -71
- package/dist/document-ack-inbound.d.ts.map +0 -1
- package/dist/document-ack-inbound.js +0 -210
- package/dist/document-ack-inbound.js.map +0 -1
- package/dist/document-control-notifier.d.ts +0 -107
- package/dist/document-control-notifier.d.ts.map +0 -1
- package/dist/document-control-notifier.js +0 -137
- package/dist/document-control-notifier.js.map +0 -1
- package/dist/document-delivery.d.ts +0 -229
- package/dist/document-delivery.d.ts.map +0 -1
- package/dist/document-delivery.js +0 -449
- package/dist/document-delivery.js.map +0 -1
- package/dist/document-join-store.d.ts +0 -80
- package/dist/document-join-store.d.ts.map +0 -1
- package/dist/document-join-store.js +0 -197
- package/dist/document-join-store.js.map +0 -1
|
@@ -1,72 +1,120 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* SYNC-P1 (daemon half) — the fork-tolerant entry store.
|
|
3
3
|
*
|
|
4
|
-
* One row per
|
|
5
|
-
* re-encode. The bytes are the truth: `chain` decodes them on
|
|
6
|
-
* exactly what was signed, and a codec asymmetry can never
|
|
7
|
-
* (the class of defect TRACE-1 found in the proposal codec).
|
|
4
|
+
* One row per ENTRY (keyed by entry hash — never by an epoch slot), holding the entry AS
|
|
5
|
+
* RECEIVED — the wire bytes, never a re-encode. The bytes are the truth: `chain` decodes them on
|
|
6
|
+
* read, so what the fold consumes is exactly what was signed, and a codec asymmetry can never
|
|
7
|
+
* silently rewrite an agreed record (the class of defect TRACE-1 found in the proposal codec).
|
|
8
8
|
*
|
|
9
|
-
* The store owns persistence and
|
|
10
|
-
* - **
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
9
|
+
* The store owns persistence and ANCESTRY CLOSURE:
|
|
10
|
+
* - **Held until whole (R14)** — an entry lands in `document_entries` only when every parent has
|
|
11
|
+
* landed. Otherwise it waits in `document_entries_pending`: recorded, never applied, never in a
|
|
12
|
+
* watermark, promoted the moment its ancestry completes — cascade included. The invariant this
|
|
13
|
+
* buys: everything in `document_entries` has its FULL ancestry there too.
|
|
14
|
+
* - **Fork tolerance** — two entries claiming the same epoch or the same author seq are BOTH
|
|
15
|
+
* stored. Ruling on conflicts is the causal fold's job (`deriveDocumentState`), not the
|
|
16
|
+
* store's; the old chain-gap and epoch-conflict refusals are gone WITH the epoch spine.
|
|
17
|
+
* - **Idempotent redelivery** — the same bytes again is `recorded: false`, not an error and not
|
|
18
|
+
* a second row.
|
|
19
|
+
* - **Watermarks** — per author, the highest CONTIGUOUS seq with its head hash(es). Two heads at
|
|
20
|
+
* one seq is an equivocation made visible for the exchange to resolve, never silently picked.
|
|
18
21
|
*
|
|
19
|
-
* What the store does NOT judge: signatures, policy, subject semantics.
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
+
* What the store does NOT judge: signatures, policy, subject semantics. The fold rules on those
|
|
23
|
+
* at every consumption, and the inbound path rules BEFORE appending. A row in these tables is a
|
|
24
|
+
* claim to be folded, not an admitted fact.
|
|
22
25
|
*/
|
|
23
26
|
import { type DocumentAmendmentEnvelope } from "@cello-protocol/protocol-types";
|
|
24
27
|
import type { DaemonDatabase } from "./sqlcipher-db.js";
|
|
25
28
|
import type { Logger } from "./types.js";
|
|
26
29
|
/**
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
30
|
+
* The PRE-PIVOT table, epoch-keyed. Still created because `DocumentStore` execs this too and the
|
|
31
|
+
* pre-pivot readers live until P4 deletes them (SYNC-D2); the entry store neither reads nor
|
|
32
|
+
* writes it. Rows predating the pivot stay untouched — old-shape bytes are not decodable by the
|
|
33
|
+
* v2 codec and are not migrated (no compatibility owed; essentially no documents exist).
|
|
34
|
+
*/
|
|
35
|
+
/**
|
|
36
|
+
* Shared with `DocumentStore` (the :352 shared-definition precedent): its membership walk and
|
|
37
|
+
* epoch read consume `document_entries`, so the tables must exist whichever module constructs
|
|
38
|
+
* first. Keep both consumers on THIS string.
|
|
31
39
|
*/
|
|
32
|
-
export declare const DOCUMENT_AMENDMENTS_CREATE_SQL = "\n CREATE TABLE IF NOT EXISTS document_amendments (\n owner_agent_id TEXT NOT NULL,\n document_id TEXT NOT NULL,\n epoch_id INTEGER NOT NULL,\n amendment_hash TEXT NOT NULL,\n received_bytes BLOB NOT NULL,\n recorded_at INTEGER NOT NULL,\n PRIMARY KEY (owner_agent_id, document_id, epoch_id)\n );\n";
|
|
33
|
-
export interface MembershipVerdict {
|
|
34
|
-
state: "holder" | "removed" | "untouched";
|
|
35
|
-
epochId: number | null;
|
|
36
|
-
}
|
|
37
40
|
/**
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
+
* D7 — the epoch spine is deleted. A database born before that carries a NOT NULL `epoch_id`
|
|
42
|
+
* with no default, which would refuse every insert from this build. Dropped in place (SQLite
|
|
43
|
+
* ≥3.35 / SQLCipher 4.5); a fresh database never has it.
|
|
41
44
|
*/
|
|
42
|
-
|
|
45
|
+
type ColumnDropper = {
|
|
46
|
+
exec(sql: string): void;
|
|
47
|
+
prepare(sql: string): {
|
|
48
|
+
all(...a: unknown[]): unknown[];
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Drop columns a previous milestone left behind, birth-gated: only what the table actually still
|
|
53
|
+
* has is touched, so this is safe on a database created yesterday and on one created before the
|
|
54
|
+
* column existed. Dead schema is not free — it is the design a future author reads and rebuilds.
|
|
55
|
+
*/
|
|
56
|
+
export declare function dropLegacyColumns(db: ColumnDropper, table: string, columns: readonly string[]): void;
|
|
57
|
+
export declare function dropLegacyEpochColumn(db: ColumnDropper, table: string): void;
|
|
58
|
+
export declare const DOCUMENT_ENTRIES_CREATE_SQL = "\n CREATE TABLE IF NOT EXISTS document_entries (\n owner_agent_id TEXT NOT NULL,\n document_id TEXT NOT NULL,\n entry_hash TEXT NOT NULL,\n author_agent_id TEXT NOT NULL,\n author_seq INTEGER NOT NULL,\n received_bytes BLOB NOT NULL,\n recorded_at INTEGER NOT NULL,\n PRIMARY KEY (owner_agent_id, document_id, entry_hash)\n );\n CREATE INDEX IF NOT EXISTS idx_document_entries_author\n ON document_entries (owner_agent_id, document_id, author_agent_id, author_seq);\n CREATE TABLE IF NOT EXISTS document_entries_pending (\n owner_agent_id TEXT NOT NULL,\n document_id TEXT NOT NULL,\n entry_hash TEXT NOT NULL,\n author_agent_id TEXT NOT NULL,\n received_bytes BLOB NOT NULL,\n recorded_at INTEGER NOT NULL,\n PRIMARY KEY (owner_agent_id, document_id, entry_hash)\n );\n";
|
|
43
59
|
export interface AmendmentAppendResult {
|
|
44
|
-
/** False on an idempotent redelivery — the
|
|
60
|
+
/** False on an idempotent redelivery — the entry (or its pending row) already existed. */
|
|
45
61
|
recorded: boolean;
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
62
|
+
/** True when the entry is waiting on missing parents (R14) — recorded but not yet applied. */
|
|
63
|
+
held: boolean;
|
|
64
|
+
/** Hex of the entry's TBS hash. */
|
|
65
|
+
entryHash: string;
|
|
66
|
+
/** Previously-held entries this arrival completed, now applied — envelopes included, so the
|
|
67
|
+
* caller can run the same post-apply surfacing it runs for a direct arrival (review F2: the
|
|
68
|
+
* held path silently dropped removal notices and lifecycle completion). */
|
|
69
|
+
promoted: PromotedEntry[];
|
|
70
|
+
}
|
|
71
|
+
export interface PromotedEntry {
|
|
72
|
+
entryHash: string;
|
|
73
|
+
envelope: DocumentAmendmentEnvelope;
|
|
74
|
+
}
|
|
75
|
+
export interface PendingEntry {
|
|
76
|
+
entryHash: string;
|
|
77
|
+
/** The parents not yet held — the exchange asks for exactly these. */
|
|
78
|
+
missingParents: string[];
|
|
79
|
+
recordedAtMs: number;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Ceiling on HELD entries per (document, author). An honest author's pending set is a short gap
|
|
83
|
+
* awaiting one delivery; a hostile known author fabricating parents could otherwise grow the
|
|
84
|
+
* pending table without bound (review F4).
|
|
85
|
+
*/
|
|
86
|
+
export declare const MAX_PENDING_PER_AUTHOR = 64;
|
|
87
|
+
export interface AuthorWatermark {
|
|
88
|
+
/** Highest CONTIGUOUS seq held from this author. */
|
|
89
|
+
seq: number;
|
|
90
|
+
/** Entry hash(es) at that seq — more than one is an equivocation, visible by design. */
|
|
91
|
+
headHashes: string[];
|
|
49
92
|
}
|
|
50
93
|
export declare class DocumentAmendmentStore {
|
|
51
94
|
#private;
|
|
52
95
|
constructor(db: DaemonDatabase, logger: Logger);
|
|
53
96
|
/**
|
|
54
|
-
* Append one
|
|
55
|
-
* decoder's named reason and nothing is stored.
|
|
97
|
+
* Append one entry from its wire bytes. Decodes first — malformed bytes refuse with the
|
|
98
|
+
* decoder's named reason and nothing is stored. An entry with missing parents is HELD; an
|
|
99
|
+
* arrival that completes held ancestry promotes the whole cascade.
|
|
56
100
|
*/
|
|
57
101
|
append(ownerAgentId: string, documentId: string, receivedBytes: Uint8Array, nowMs: number): AmendmentAppendResult;
|
|
58
|
-
/**
|
|
102
|
+
/** Every applied entry, decoded from the stored received bytes. The set is ancestry-closed. */
|
|
59
103
|
chain(ownerAgentId: string, documentId: string): DocumentAmendmentEnvelope[];
|
|
104
|
+
/** Held entries and exactly which parents they still wait on (R37's receiver-side record). */
|
|
105
|
+
pending(ownerAgentId: string, documentId: string): PendingEntry[];
|
|
106
|
+
/**
|
|
107
|
+
* This author's applied entries with seq strictly beyond `afterSeq`, as WIRE BYTES in seq
|
|
108
|
+
* order — what a reconcile reply carries to a peer whose watermark for this author is behind
|
|
109
|
+
* ours (R10 step 2/3). Forked seqs both ship: the peer's fold rules on them like ours did.
|
|
110
|
+
*/
|
|
111
|
+
entriesByAuthorAfter(ownerAgentId: string, documentId: string, authorAgentId: string, afterSeq: number): Uint8Array[];
|
|
60
112
|
/**
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
* remove_holder, with the epoch it happened at, so a refusal can name the removal rather than
|
|
65
|
-
* a generic condition. Reads the recorded chain only — validity was ruled before append
|
|
66
|
-
* (the standing invariant).
|
|
113
|
+
* Per-author position: the highest CONTIGUOUS seq held and the head hash(es) at it. A held
|
|
114
|
+
* (pending) entry is not counted — a gap ends the walk (R13: report contiguous, never highest
|
|
115
|
+
* received).
|
|
67
116
|
*/
|
|
68
|
-
|
|
69
|
-
/** The highest recorded epoch, or 0 — genesis — when no amendment exists. */
|
|
70
|
-
currentEpoch(ownerAgentId: string, documentId: string): number;
|
|
117
|
+
watermarks(ownerAgentId: string, documentId: string): Map<string, AuthorWatermark>;
|
|
71
118
|
}
|
|
119
|
+
export {};
|
|
72
120
|
//# sourceMappingURL=document-amendment-store.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"document-amendment-store.d.ts","sourceRoot":"","sources":["../src/document-amendment-store.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"document-amendment-store.d.ts","sourceRoot":"","sources":["../src/document-amendment-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,EAGL,KAAK,yBAAyB,EAC/B,MAAM,gCAAgC,CAAC;AACxC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEzC;;;;;GAKG;AACH;;;;GAIG;AACH;;;;GAIG;AACH,KAAK,aAAa,GAAG;IAAE,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG;QAAE,GAAG,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,GAAG,OAAO,EAAE,CAAA;KAAE,CAAA;CAAE,CAAC;AAE5G;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAOpG;AAED,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAE5E;AAED,eAAO,MAAM,2BAA2B,63BAsBvC,CAAC;AAEF,MAAM,WAAW,qBAAqB;IACpC,0FAA0F;IAC1F,QAAQ,EAAE,OAAO,CAAC;IAClB,8FAA8F;IAC9F,IAAI,EAAE,OAAO,CAAC;IACd,mCAAmC;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB;;gFAE4E;IAC5E,QAAQ,EAAE,aAAa,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,yBAAyB,CAAC;CACrC;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,sEAAsE;IACtE,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,KAAK,CAAC;AAEzC,MAAM,WAAW,eAAe;IAC9B,oDAAoD;IACpD,GAAG,EAAE,MAAM,CAAC;IACZ,wFAAwF;IACxF,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,qBAAa,sBAAsB;;gBAIrB,EAAE,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM;IAW9C;;;;OAIG;IACH,MAAM,CACJ,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,aAAa,EAAE,UAAU,EACzB,KAAK,EAAE,MAAM,GACZ,qBAAqB;IA0DxB,+FAA+F;IAC/F,KAAK,CAAC,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,yBAAyB,EAAE;IAW5E,8FAA8F;IAC9F,OAAO,CAAC,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,YAAY,EAAE;IAwBjE;;;;OAIG;IACH,oBAAoB,CAClB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,GACf,UAAU,EAAE;IAaf;;;;OAIG;IACH,UAAU,CAAC,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC;CAqInF"}
|
|
@@ -1,76 +1,90 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* SYNC-P1 (daemon half) — the fork-tolerant entry store.
|
|
3
3
|
*
|
|
4
|
-
* One row per
|
|
5
|
-
* re-encode. The bytes are the truth: `chain` decodes them on
|
|
6
|
-
* exactly what was signed, and a codec asymmetry can never
|
|
7
|
-
* (the class of defect TRACE-1 found in the proposal codec).
|
|
4
|
+
* One row per ENTRY (keyed by entry hash — never by an epoch slot), holding the entry AS
|
|
5
|
+
* RECEIVED — the wire bytes, never a re-encode. The bytes are the truth: `chain` decodes them on
|
|
6
|
+
* read, so what the fold consumes is exactly what was signed, and a codec asymmetry can never
|
|
7
|
+
* silently rewrite an agreed record (the class of defect TRACE-1 found in the proposal codec).
|
|
8
8
|
*
|
|
9
|
-
* The store owns persistence and
|
|
10
|
-
* - **
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
9
|
+
* The store owns persistence and ANCESTRY CLOSURE:
|
|
10
|
+
* - **Held until whole (R14)** — an entry lands in `document_entries` only when every parent has
|
|
11
|
+
* landed. Otherwise it waits in `document_entries_pending`: recorded, never applied, never in a
|
|
12
|
+
* watermark, promoted the moment its ancestry completes — cascade included. The invariant this
|
|
13
|
+
* buys: everything in `document_entries` has its FULL ancestry there too.
|
|
14
|
+
* - **Fork tolerance** — two entries claiming the same epoch or the same author seq are BOTH
|
|
15
|
+
* stored. Ruling on conflicts is the causal fold's job (`deriveDocumentState`), not the
|
|
16
|
+
* store's; the old chain-gap and epoch-conflict refusals are gone WITH the epoch spine.
|
|
17
|
+
* - **Idempotent redelivery** — the same bytes again is `recorded: false`, not an error and not
|
|
18
|
+
* a second row.
|
|
19
|
+
* - **Watermarks** — per author, the highest CONTIGUOUS seq with its head hash(es). Two heads at
|
|
20
|
+
* one seq is an equivocation made visible for the exchange to resolve, never silently picked.
|
|
18
21
|
*
|
|
19
|
-
* What the store does NOT judge: signatures, policy, subject semantics.
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
+
* What the store does NOT judge: signatures, policy, subject semantics. The fold rules on those
|
|
23
|
+
* at every consumption, and the inbound path rules BEFORE appending. A row in these tables is a
|
|
24
|
+
* claim to be folded, not an admitted fact.
|
|
22
25
|
*/
|
|
23
26
|
import { decodeDocumentAmendment, documentAmendmentHash, } from "@cello-protocol/protocol-types";
|
|
24
27
|
/**
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
* on THIS one string.
|
|
28
|
+
* Drop columns a previous milestone left behind, birth-gated: only what the table actually still
|
|
29
|
+
* has is touched, so this is safe on a database created yesterday and on one created before the
|
|
30
|
+
* column existed. Dead schema is not free — it is the design a future author reads and rebuilds.
|
|
29
31
|
*/
|
|
30
|
-
export
|
|
31
|
-
|
|
32
|
+
export function dropLegacyColumns(db, table, columns) {
|
|
33
|
+
const held = new Set(db.prepare(`PRAGMA table_info(${table})`).all().map((c) => c.name));
|
|
34
|
+
for (const column of columns) {
|
|
35
|
+
if (held.has(column))
|
|
36
|
+
db.exec(`ALTER TABLE ${table} DROP COLUMN ${column}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
export function dropLegacyEpochColumn(db, table) {
|
|
40
|
+
dropLegacyColumns(db, table, ["epoch_id"]);
|
|
41
|
+
}
|
|
42
|
+
export const DOCUMENT_ENTRIES_CREATE_SQL = `
|
|
43
|
+
CREATE TABLE IF NOT EXISTS document_entries (
|
|
44
|
+
owner_agent_id TEXT NOT NULL,
|
|
45
|
+
document_id TEXT NOT NULL,
|
|
46
|
+
entry_hash TEXT NOT NULL,
|
|
47
|
+
author_agent_id TEXT NOT NULL,
|
|
48
|
+
author_seq INTEGER NOT NULL,
|
|
49
|
+
received_bytes BLOB NOT NULL,
|
|
50
|
+
recorded_at INTEGER NOT NULL,
|
|
51
|
+
PRIMARY KEY (owner_agent_id, document_id, entry_hash)
|
|
52
|
+
);
|
|
53
|
+
CREATE INDEX IF NOT EXISTS idx_document_entries_author
|
|
54
|
+
ON document_entries (owner_agent_id, document_id, author_agent_id, author_seq);
|
|
55
|
+
CREATE TABLE IF NOT EXISTS document_entries_pending (
|
|
32
56
|
owner_agent_id TEXT NOT NULL,
|
|
33
57
|
document_id TEXT NOT NULL,
|
|
34
|
-
|
|
35
|
-
|
|
58
|
+
entry_hash TEXT NOT NULL,
|
|
59
|
+
author_agent_id TEXT NOT NULL,
|
|
36
60
|
received_bytes BLOB NOT NULL,
|
|
37
61
|
recorded_at INTEGER NOT NULL,
|
|
38
|
-
PRIMARY KEY (owner_agent_id, document_id,
|
|
62
|
+
PRIMARY KEY (owner_agent_id, document_id, entry_hash)
|
|
39
63
|
);
|
|
40
64
|
`;
|
|
41
65
|
/**
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
66
|
+
* Ceiling on HELD entries per (document, author). An honest author's pending set is a short gap
|
|
67
|
+
* awaiting one delivery; a hostile known author fabricating parents could otherwise grow the
|
|
68
|
+
* pending table without bound (review F4).
|
|
45
69
|
*/
|
|
46
|
-
export
|
|
47
|
-
let state = "untouched";
|
|
48
|
-
let epochId = null;
|
|
49
|
-
for (const env of chain) {
|
|
50
|
-
if (env.body.subject_agent_id !== agentId)
|
|
51
|
-
continue;
|
|
52
|
-
if (env.body.kind === "add_holder") {
|
|
53
|
-
state = "holder";
|
|
54
|
-
epochId = env.body.epoch_id;
|
|
55
|
-
}
|
|
56
|
-
else if (env.body.kind === "remove_holder") {
|
|
57
|
-
state = "removed";
|
|
58
|
-
epochId = env.body.epoch_id;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
return { state, epochId };
|
|
62
|
-
}
|
|
70
|
+
export const MAX_PENDING_PER_AUTHOR = 64;
|
|
63
71
|
export class DocumentAmendmentStore {
|
|
64
72
|
#db;
|
|
65
73
|
#logger;
|
|
66
74
|
constructor(db, logger) {
|
|
67
75
|
this.#db = db;
|
|
68
76
|
this.#logger = logger;
|
|
69
|
-
|
|
77
|
+
// D7/D9 residue sweep (review F5/F6): the epoch-keyed legacy table and the withdrawals
|
|
78
|
+
// table have no reader or writer left — never born on a fresh database, dropped in place
|
|
79
|
+
// on one that predates the pivot.
|
|
80
|
+
this.#db.exec(`DROP TABLE IF EXISTS document_amendments`);
|
|
81
|
+
this.#db.exec(DOCUMENT_ENTRIES_CREATE_SQL);
|
|
82
|
+
dropLegacyEpochColumn(this.#db, "document_entries");
|
|
70
83
|
}
|
|
71
84
|
/**
|
|
72
|
-
* Append one
|
|
73
|
-
* decoder's named reason and nothing is stored.
|
|
85
|
+
* Append one entry from its wire bytes. Decodes first — malformed bytes refuse with the
|
|
86
|
+
* decoder's named reason and nothing is stored. An entry with missing parents is HELD; an
|
|
87
|
+
* arrival that completes held ancestry promotes the whole cascade.
|
|
74
88
|
*/
|
|
75
89
|
append(ownerAgentId, documentId, receivedBytes, nowMs) {
|
|
76
90
|
const env = decodeDocumentAmendment(receivedBytes);
|
|
@@ -78,74 +92,175 @@ export class DocumentAmendmentStore {
|
|
|
78
92
|
throw new Error(`document_amendment_wrong_document: the bytes name ${env.body.document_id}, appending ` +
|
|
79
93
|
`under ${documentId}`);
|
|
80
94
|
}
|
|
81
|
-
const epochId = env.body.epoch_id;
|
|
82
95
|
const hash = Buffer.from(documentAmendmentHash(env.body)).toString("hex");
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
96
|
+
if (this.#hasEntry(ownerAgentId, documentId, hash)) {
|
|
97
|
+
return { recorded: false, held: false, entryHash: hash, promoted: [] };
|
|
98
|
+
}
|
|
99
|
+
if (this.#hasPending(ownerAgentId, documentId, hash)) {
|
|
100
|
+
return { recorded: false, held: true, entryHash: hash, promoted: [] };
|
|
101
|
+
}
|
|
102
|
+
const missing = env.body.parents.filter((p) => !this.#hasEntry(ownerAgentId, documentId, p));
|
|
103
|
+
if (missing.length > 0) {
|
|
104
|
+
const author = env.body.author_agent_id;
|
|
105
|
+
const backlog = this.#db
|
|
106
|
+
.prepare(`SELECT COUNT(*) AS n FROM document_entries_pending
|
|
107
|
+
WHERE owner_agent_id = ? AND document_id = ? AND author_agent_id = ?`)
|
|
108
|
+
.get(ownerAgentId, documentId, author);
|
|
109
|
+
if (backlog.n >= MAX_PENDING_PER_AUTHOR) {
|
|
110
|
+
throw new Error(`document_pending_cap: ${author} already has ${backlog.n} entries held awaiting ` +
|
|
111
|
+
`parents — the ceiling is ${MAX_PENDING_PER_AUTHOR}, and an honest gap is never ` +
|
|
112
|
+
`this deep; deliver the missing ancestry first`);
|
|
90
113
|
}
|
|
91
|
-
this.#
|
|
114
|
+
this.#db
|
|
115
|
+
.prepare(`INSERT INTO document_entries_pending
|
|
116
|
+
(owner_agent_id, document_id, entry_hash, author_agent_id, received_bytes, recorded_at)
|
|
117
|
+
VALUES (?, ?, ?, ?, ?, ?)`)
|
|
118
|
+
.run(ownerAgentId, documentId, hash, author, Buffer.from(receivedBytes), nowMs);
|
|
119
|
+
this.#logger.info("document.entry.held", {
|
|
92
120
|
documentId,
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
121
|
+
entryHash: hash,
|
|
122
|
+
author: env.body.author_agent_id,
|
|
123
|
+
authorSeq: env.body.author_seq,
|
|
124
|
+
kind: env.body.kind,
|
|
125
|
+
missingParents: missing,
|
|
96
126
|
});
|
|
97
|
-
|
|
98
|
-
`${existing.amendment_hash} and a rival amendment ${hash} arrived — a governance fork, ` +
|
|
99
|
-
`refused with the first record kept`);
|
|
100
|
-
}
|
|
101
|
-
const prior = this.currentEpoch(ownerAgentId, documentId);
|
|
102
|
-
if (epochId !== prior + 1) {
|
|
103
|
-
throw new Error(`document_amendment_chain_gap: epoch ${epochId} cannot append onto epoch ${prior} — ` +
|
|
104
|
-
`amendments land contiguously, and an out-of-order arrival is retried by its sender, ` +
|
|
105
|
-
`never buffered silently`);
|
|
127
|
+
return { recorded: true, held: true, entryHash: hash, promoted: [] };
|
|
106
128
|
}
|
|
107
|
-
this.#
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
VALUES (?, ?, ?, ?, ?, ?)`)
|
|
111
|
-
.run(ownerAgentId, documentId, epochId, hash,
|
|
112
|
-
// Copied — the caller may reuse or zero its buffer after we return.
|
|
113
|
-
Buffer.from(receivedBytes), nowMs);
|
|
114
|
-
this.#logger.info("document.amendment.recorded", {
|
|
115
|
-
documentId,
|
|
116
|
-
epochId,
|
|
117
|
-
amendmentHash: hash,
|
|
118
|
-
kind: env.body.kind,
|
|
119
|
-
});
|
|
120
|
-
return { recorded: true, epochId, amendmentHash: hash };
|
|
129
|
+
this.#insertEntry(ownerAgentId, documentId, hash, env, receivedBytes, nowMs);
|
|
130
|
+
const promoted = this.#promoteReady(ownerAgentId, documentId, nowMs);
|
|
131
|
+
return { recorded: true, held: false, entryHash: hash, promoted };
|
|
121
132
|
}
|
|
122
|
-
/**
|
|
133
|
+
/** Every applied entry, decoded from the stored received bytes. The set is ancestry-closed. */
|
|
123
134
|
chain(ownerAgentId, documentId) {
|
|
124
135
|
const rows = this.#db
|
|
125
|
-
.prepare(`SELECT received_bytes FROM
|
|
136
|
+
.prepare(`SELECT received_bytes FROM document_entries
|
|
126
137
|
WHERE owner_agent_id = ? AND document_id = ?
|
|
127
|
-
ORDER BY
|
|
138
|
+
ORDER BY author_seq ASC, entry_hash ASC`)
|
|
128
139
|
.all(ownerAgentId, documentId);
|
|
129
140
|
return rows.map((r) => decodeDocumentAmendment(new Uint8Array(r.received_bytes)));
|
|
130
141
|
}
|
|
142
|
+
/** Held entries and exactly which parents they still wait on (R37's receiver-side record). */
|
|
143
|
+
pending(ownerAgentId, documentId) {
|
|
144
|
+
const rows = this.#db
|
|
145
|
+
.prepare(`SELECT entry_hash, received_bytes, recorded_at FROM document_entries_pending
|
|
146
|
+
WHERE owner_agent_id = ? AND document_id = ?
|
|
147
|
+
ORDER BY recorded_at ASC, entry_hash ASC`)
|
|
148
|
+
.all(ownerAgentId, documentId);
|
|
149
|
+
return rows.map((r) => {
|
|
150
|
+
const env = decodeDocumentAmendment(new Uint8Array(r.received_bytes));
|
|
151
|
+
return {
|
|
152
|
+
entryHash: r.entry_hash,
|
|
153
|
+
missingParents: env.body.parents.filter((p) => !this.#hasEntry(ownerAgentId, documentId, p)),
|
|
154
|
+
recordedAtMs: r.recorded_at,
|
|
155
|
+
};
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* This author's applied entries with seq strictly beyond `afterSeq`, as WIRE BYTES in seq
|
|
160
|
+
* order — what a reconcile reply carries to a peer whose watermark for this author is behind
|
|
161
|
+
* ours (R10 step 2/3). Forked seqs both ship: the peer's fold rules on them like ours did.
|
|
162
|
+
*/
|
|
163
|
+
entriesByAuthorAfter(ownerAgentId, documentId, authorAgentId, afterSeq) {
|
|
164
|
+
const rows = this.#db
|
|
165
|
+
.prepare(`SELECT received_bytes FROM document_entries
|
|
166
|
+
WHERE owner_agent_id = ? AND document_id = ? AND author_agent_id = ? AND author_seq > ?
|
|
167
|
+
ORDER BY author_seq ASC, entry_hash ASC`)
|
|
168
|
+
.all(ownerAgentId, documentId, authorAgentId, afterSeq);
|
|
169
|
+
return rows.map((r) => new Uint8Array(r.received_bytes));
|
|
170
|
+
}
|
|
131
171
|
/**
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
* remove_holder, with the epoch it happened at, so a refusal can name the removal rather than
|
|
136
|
-
* a generic condition. Reads the recorded chain only — validity was ruled before append
|
|
137
|
-
* (the standing invariant).
|
|
172
|
+
* Per-author position: the highest CONTIGUOUS seq held and the head hash(es) at it. A held
|
|
173
|
+
* (pending) entry is not counted — a gap ends the walk (R13: report contiguous, never highest
|
|
174
|
+
* received).
|
|
138
175
|
*/
|
|
139
|
-
|
|
140
|
-
|
|
176
|
+
watermarks(ownerAgentId, documentId) {
|
|
177
|
+
const rows = this.#db
|
|
178
|
+
.prepare(`SELECT author_agent_id, author_seq, entry_hash FROM document_entries
|
|
179
|
+
WHERE owner_agent_id = ? AND document_id = ?
|
|
180
|
+
ORDER BY author_agent_id ASC, author_seq ASC, entry_hash ASC`)
|
|
181
|
+
.all(ownerAgentId, documentId);
|
|
182
|
+
const byAuthor = new Map();
|
|
183
|
+
for (const r of rows) {
|
|
184
|
+
let seqs = byAuthor.get(r.author_agent_id);
|
|
185
|
+
if (!seqs) {
|
|
186
|
+
seqs = new Map();
|
|
187
|
+
byAuthor.set(r.author_agent_id, seqs);
|
|
188
|
+
}
|
|
189
|
+
const at = seqs.get(r.author_seq);
|
|
190
|
+
if (at)
|
|
191
|
+
at.push(r.entry_hash);
|
|
192
|
+
else
|
|
193
|
+
seqs.set(r.author_seq, [r.entry_hash]);
|
|
194
|
+
}
|
|
195
|
+
const out = new Map();
|
|
196
|
+
for (const [author, seqs] of byAuthor) {
|
|
197
|
+
let seq = 0;
|
|
198
|
+
while (seqs.has(seq + 1))
|
|
199
|
+
seq++;
|
|
200
|
+
if (seq === 0)
|
|
201
|
+
continue;
|
|
202
|
+
out.set(author, { seq, headHashes: seqs.get(seq) });
|
|
203
|
+
}
|
|
204
|
+
return out;
|
|
205
|
+
}
|
|
206
|
+
#hasEntry(ownerAgentId, documentId, hash) {
|
|
207
|
+
return (this.#db
|
|
208
|
+
.prepare(`SELECT 1 FROM document_entries
|
|
209
|
+
WHERE owner_agent_id = ? AND document_id = ? AND entry_hash = ?`)
|
|
210
|
+
.get(ownerAgentId, documentId, hash) !== undefined);
|
|
211
|
+
}
|
|
212
|
+
#hasPending(ownerAgentId, documentId, hash) {
|
|
213
|
+
return (this.#db
|
|
214
|
+
.prepare(`SELECT 1 FROM document_entries_pending
|
|
215
|
+
WHERE owner_agent_id = ? AND document_id = ? AND entry_hash = ?`)
|
|
216
|
+
.get(ownerAgentId, documentId, hash) !== undefined);
|
|
141
217
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
218
|
+
#insertEntry(ownerAgentId, documentId, hash, env, bytes, nowMs) {
|
|
219
|
+
this.#db
|
|
220
|
+
.prepare(`INSERT INTO document_entries
|
|
221
|
+
(owner_agent_id, document_id, entry_hash, author_agent_id, author_seq,
|
|
222
|
+
received_bytes, recorded_at)
|
|
223
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)`)
|
|
224
|
+
.run(ownerAgentId, documentId, hash, env.body.author_agent_id, env.body.author_seq,
|
|
225
|
+
// Copied — the caller may reuse or zero its buffer after we return.
|
|
226
|
+
Buffer.from(bytes), nowMs);
|
|
227
|
+
this.#logger.info("document.entry.recorded", {
|
|
228
|
+
documentId,
|
|
229
|
+
entryHash: hash,
|
|
230
|
+
author: env.body.author_agent_id,
|
|
231
|
+
authorSeq: env.body.author_seq,
|
|
232
|
+
kind: env.body.kind,
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
/** Move every pending entry whose ancestry is now complete — repeated until a pass moves none. */
|
|
236
|
+
#promoteReady(ownerAgentId, documentId, nowMs) {
|
|
237
|
+
const promoted = [];
|
|
238
|
+
for (;;) {
|
|
239
|
+
const rows = this.#db
|
|
240
|
+
.prepare(`SELECT entry_hash, received_bytes FROM document_entries_pending
|
|
241
|
+
WHERE owner_agent_id = ? AND document_id = ?`)
|
|
242
|
+
.all(ownerAgentId, documentId);
|
|
243
|
+
let movedThisPass = false;
|
|
244
|
+
for (const row of rows) {
|
|
245
|
+
const env = decodeDocumentAmendment(new Uint8Array(row.received_bytes));
|
|
246
|
+
const ready = env.body.parents.every((p) => this.#hasEntry(ownerAgentId, documentId, p));
|
|
247
|
+
if (!ready)
|
|
248
|
+
continue;
|
|
249
|
+
this.#insertEntry(ownerAgentId, documentId, row.entry_hash, env, new Uint8Array(row.received_bytes), nowMs);
|
|
250
|
+
this.#db
|
|
251
|
+
.prepare(`DELETE FROM document_entries_pending
|
|
252
|
+
WHERE owner_agent_id = ? AND document_id = ? AND entry_hash = ?`)
|
|
253
|
+
.run(ownerAgentId, documentId, row.entry_hash);
|
|
254
|
+
this.#logger.info("document.entry.promoted", {
|
|
255
|
+
documentId,
|
|
256
|
+
entryHash: row.entry_hash,
|
|
257
|
+
});
|
|
258
|
+
promoted.push({ entryHash: row.entry_hash, envelope: env });
|
|
259
|
+
movedThisPass = true;
|
|
260
|
+
}
|
|
261
|
+
if (!movedThisPass)
|
|
262
|
+
return promoted;
|
|
263
|
+
}
|
|
149
264
|
}
|
|
150
265
|
}
|
|
151
266
|
//# sourceMappingURL=document-amendment-store.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"document-amendment-store.js","sourceRoot":"","sources":["../src/document-amendment-store.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"document-amendment-store.js","sourceRoot":"","sources":["../src/document-amendment-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,EACL,uBAAuB,EACvB,qBAAqB,GAEtB,MAAM,gCAAgC,CAAC;AAsBxC;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,EAAiB,EAAE,KAAa,EAAE,OAA0B;IAC5F,MAAM,IAAI,GAAG,IAAI,GAAG,CACjB,EAAE,CAAC,OAAO,CAAC,qBAAqB,KAAK,GAAG,CAAC,CAAC,GAAG,EAA+B,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CACjG,CAAC;IACF,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC;YAAE,EAAE,CAAC,IAAI,CAAC,eAAe,KAAK,gBAAgB,MAAM,EAAE,CAAC,CAAC;IAC9E,CAAC;AACH,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,EAAiB,EAAE,KAAa;IACpE,iBAAiB,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;AAC7C,CAAC;AAED,MAAM,CAAC,MAAM,2BAA2B,GAAG;;;;;;;;;;;;;;;;;;;;;;CAsB1C,CAAC;AA2BF;;;;GAIG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,EAAE,CAAC;AASzC,MAAM,OAAO,sBAAsB;IACxB,GAAG,CAAiB;IACpB,OAAO,CAAS;IAEzB,YAAY,EAAkB,EAAE,MAAc;QAC5C,IAAI,CAAC,GAAG,GAAG,EAAE,CAAC;QACd,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;QACtB,uFAAuF;QACvF,yFAAyF;QACzF,kCAAkC;QAClC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,0CAA0C,CAAC,CAAC;QAC1D,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;QAC3C,qBAAqB,CAAC,IAAI,CAAC,GAAG,EAAE,kBAAkB,CAAC,CAAC;IACtD,CAAC;IAED;;;;OAIG;IACH,MAAM,CACJ,YAAoB,EACpB,UAAkB,EAClB,aAAyB,EACzB,KAAa;QAEb,MAAM,GAAG,GAAG,uBAAuB,CAAC,aAAa,CAAC,CAAC;QACnD,IAAI,GAAG,CAAC,IAAI,CAAC,WAAW,KAAK,UAAU,EAAE,CAAC;YACxC,MAAM,IAAI,KAAK,CACb,qDAAqD,GAAG,CAAC,IAAI,CAAC,WAAW,cAAc;gBACrF,SAAS,UAAU,EAAE,CACxB,CAAC;QACJ,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAE1E,IAAI,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,UAAU,EAAE,IAAI,CAAC,EAAE,CAAC;YACnD,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;QACzE,CAAC;QACD,IAAI,IAAI,CAAC,WAAW,CAAC,YAAY,EAAE,UAAU,EAAE,IAAI,CAAC,EAAE,CAAC;YACrD,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;QACxE,CAAC;QAED,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CACrC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,UAAU,EAAE,CAAC,CAAC,CACpD,CAAC;QACF,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvB,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,eAAe,CAAC;YACxC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG;iBACrB,OAAO,CACN;iFACuE,CACxE;iBACA,GAAG,CAAC,YAAY,EAAE,UAAU,EAAE,MAAM,CAAkB,CAAC;YAC1D,IAAI,OAAO,CAAC,CAAC,IAAI,sBAAsB,EAAE,CAAC;gBACxC,MAAM,IAAI,KAAK,CACb,yBAAyB,MAAM,gBAAgB,OAAO,CAAC,CAAC,yBAAyB;oBAC/E,4BAA4B,sBAAsB,+BAA+B;oBACjF,+CAA+C,CAClD,CAAC;YACJ,CAAC;YACD,IAAI,CAAC,GAAG;iBACL,OAAO,CACN;;qCAE2B,CAC5B;iBACA,GAAG,CAAC,YAAY,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,KAAK,CAAC,CAAC;YAClF,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,qBAAqB,EAAE;gBACvC,UAAU;gBACV,SAAS,EAAE,IAAI;gBACf,MAAM,EAAE,GAAG,CAAC,IAAI,CAAC,eAAe;gBAChC,SAAS,EAAE,GAAG,CAAC,IAAI,CAAC,UAAU;gBAC9B,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI;gBACnB,cAAc,EAAE,OAAO;aACxB,CAAC,CAAC;YACH,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;QACvE,CAAC;QAED,IAAI,CAAC,YAAY,CAAC,YAAY,EAAE,UAAU,EAAE,IAAI,EAAE,GAAG,EAAE,aAAa,EAAE,KAAK,CAAC,CAAC;QAC7E,MAAM,QAAQ,GAAG,IAAI,CAAC,aAAa,CAAC,YAAY,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC;QACrE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;IACpE,CAAC;IAED,+FAA+F;IAC/F,KAAK,CAAC,YAAoB,EAAE,UAAkB;QAC5C,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG;aAClB,OAAO,CACN;;kDAE0C,CAC3C;aACA,GAAG,CAAC,YAAY,EAAE,UAAU,CAA0C,CAAC;QAC1E,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,uBAAuB,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;IACpF,CAAC;IAED,8FAA8F;IAC9F,OAAO,CAAC,YAAoB,EAAE,UAAkB;QAC9C,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG;aAClB,OAAO,CACN;;mDAE2C,CAC5C;aACA,GAAG,CAAC,YAAY,EAAE,UAAU,CAI7B,CAAC;QACH,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YACpB,MAAM,GAAG,GAAG,uBAAuB,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC;YACtE,OAAO;gBACL,SAAS,EAAE,CAAC,CAAC,UAAU;gBACvB,cAAc,EAAE,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CACrC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,UAAU,EAAE,CAAC,CAAC,CACpD;gBACD,YAAY,EAAE,CAAC,CAAC,WAAW;aAC5B,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;OAIG;IACH,oBAAoB,CAClB,YAAoB,EACpB,UAAkB,EAClB,aAAqB,EACrB,QAAgB;QAEhB,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG;aAClB,OAAO,CACN;;kDAE0C,CAC3C;aACA,GAAG,CAAC,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,QAAQ,CAEtD,CAAC;QACH,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC;IAC3D,CAAC;IAED;;;;OAIG;IACH,UAAU,CAAC,YAAoB,EAAE,UAAkB;QACjD,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG;aAClB,OAAO,CACN;;uEAE+D,CAChE;aACA,GAAG,CAAC,YAAY,EAAE,UAAU,CAI7B,CAAC;QACH,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAiC,CAAC;QAC1D,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;YACrB,IAAI,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC;YAC3C,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,IAAI,GAAG,IAAI,GAAG,EAAE,CAAC;gBACjB,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,eAAe,EAAE,IAAI,CAAC,CAAC;YACxC,CAAC;YACD,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;YAClC,IAAI,EAAE;gBAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;;gBACzB,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;QAC9C,CAAC;QACD,MAAM,GAAG,GAAG,IAAI,GAAG,EAA2B,CAAC;QAC/C,KAAK,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,QAAQ,EAAE,CAAC;YACtC,IAAI,GAAG,GAAG,CAAC,CAAC;YACZ,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC;gBAAE,GAAG,EAAE,CAAC;YAChC,IAAI,GAAG,KAAK,CAAC;gBAAE,SAAS;YACxB,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAE,EAAE,CAAC,CAAC;QACvD,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IAED,SAAS,CAAC,YAAoB,EAAE,UAAkB,EAAE,IAAY;QAC9D,OAAO,CACL,IAAI,CAAC,GAAG;aACL,OAAO,CACN;4EACkE,CACnE;aACA,GAAG,CAAC,YAAY,EAAE,UAAU,EAAE,IAAI,CAAC,KAAK,SAAS,CACrD,CAAC;IACJ,CAAC;IAED,WAAW,CAAC,YAAoB,EAAE,UAAkB,EAAE,IAAY;QAChE,OAAO,CACL,IAAI,CAAC,GAAG;aACL,OAAO,CACN;4EACkE,CACnE;aACA,GAAG,CAAC,YAAY,EAAE,UAAU,EAAE,IAAI,CAAC,KAAK,SAAS,CACrD,CAAC;IACJ,CAAC;IAED,YAAY,CACV,YAAoB,EACpB,UAAkB,EAClB,IAAY,EACZ,GAA8B,EAC9B,KAAiB,EACjB,KAAa;QAEb,IAAI,CAAC,GAAG;aACL,OAAO,CACN;;;sCAG8B,CAC/B;aACA,GAAG,CACF,YAAY,EACZ,UAAU,EACV,IAAI,EACJ,GAAG,CAAC,IAAI,CAAC,eAAe,EACxB,GAAG,CAAC,IAAI,CAAC,UAAU;QACnB,oEAAoE;QACpE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAClB,KAAK,CACN,CAAC;QACJ,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,yBAAyB,EAAE;YAC3C,UAAU;YACV,SAAS,EAAE,IAAI;YACf,MAAM,EAAE,GAAG,CAAC,IAAI,CAAC,eAAe;YAChC,SAAS,EAAE,GAAG,CAAC,IAAI,CAAC,UAAU;YAC9B,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI;SACpB,CAAC,CAAC;IACL,CAAC;IAED,kGAAkG;IAClG,aAAa,CAAC,YAAoB,EAAE,UAAkB,EAAE,KAAa;QACnE,MAAM,QAAQ,GAAoB,EAAE,CAAC;QACrC,SAAS,CAAC;YACR,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG;iBAClB,OAAO,CACN;yDAC+C,CAChD;iBACA,GAAG,CAAC,YAAY,EAAE,UAAU,CAG7B,CAAC;YACH,IAAI,aAAa,GAAG,KAAK,CAAC;YAC1B,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;gBACvB,MAAM,GAAG,GAAG,uBAAuB,CAAC,IAAI,UAAU,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC;gBACxE,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CACzC,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,UAAU,EAAE,CAAC,CAAC,CAC5C,CAAC;gBACF,IAAI,CAAC,KAAK;oBAAE,SAAS;gBACrB,IAAI,CAAC,YAAY,CACf,YAAY,EACZ,UAAU,EACV,GAAG,CAAC,UAAU,EACd,GAAG,EACH,IAAI,UAAU,CAAC,GAAG,CAAC,cAAc,CAAC,EAClC,KAAK,CACN,CAAC;gBACF,IAAI,CAAC,GAAG;qBACL,OAAO,CACN;8EACkE,CACnE;qBACA,GAAG,CAAC,YAAY,EAAE,UAAU,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC;gBACjD,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,yBAAyB,EAAE;oBAC3C,UAAU;oBACV,SAAS,EAAE,GAAG,CAAC,UAAU;iBAC1B,CAAC,CAAC;gBACH,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,GAAG,CAAC,UAAU,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC;gBAC5D,aAAa,GAAG,IAAI,CAAC;YACvB,CAAC;YACD,IAAI,CAAC,aAAa;gBAAE,OAAO,QAAQ,CAAC;QACtC,CAAC;IACH,CAAC;CACF"}
|