@ashlar-blue/x402-trust 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +198 -0
  3. package/dist/attested-directory.d.ts +78 -0
  4. package/dist/attested-directory.d.ts.map +1 -0
  5. package/dist/attested-directory.js +163 -0
  6. package/dist/attested-directory.js.map +1 -0
  7. package/dist/badges.d.ts +131 -0
  8. package/dist/badges.d.ts.map +1 -0
  9. package/dist/badges.js +213 -0
  10. package/dist/badges.js.map +1 -0
  11. package/dist/catalog-mcp.d.ts +145 -0
  12. package/dist/catalog-mcp.d.ts.map +1 -0
  13. package/dist/catalog-mcp.js +409 -0
  14. package/dist/catalog-mcp.js.map +1 -0
  15. package/dist/census-reconcile.d.ts +69 -0
  16. package/dist/census-reconcile.d.ts.map +1 -0
  17. package/dist/census-reconcile.js +162 -0
  18. package/dist/census-reconcile.js.map +1 -0
  19. package/dist/directory-classify.d.ts +47 -0
  20. package/dist/directory-classify.d.ts.map +1 -0
  21. package/dist/directory-classify.js +54 -0
  22. package/dist/directory-classify.js.map +1 -0
  23. package/dist/discovery.d.ts +304 -0
  24. package/dist/discovery.d.ts.map +1 -0
  25. package/dist/discovery.js +926 -0
  26. package/dist/discovery.js.map +1 -0
  27. package/dist/evidence-ref.d.ts +96 -0
  28. package/dist/evidence-ref.d.ts.map +1 -0
  29. package/dist/evidence-ref.js +179 -0
  30. package/dist/evidence-ref.js.map +1 -0
  31. package/dist/facilitator-config.d.ts +83 -0
  32. package/dist/facilitator-config.d.ts.map +1 -0
  33. package/dist/facilitator-config.js +94 -0
  34. package/dist/facilitator-config.js.map +1 -0
  35. package/dist/index.d.ts +15 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +18 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/manifest-sig.d.ts +131 -0
  40. package/dist/manifest-sig.d.ts.map +1 -0
  41. package/dist/manifest-sig.js +262 -0
  42. package/dist/manifest-sig.js.map +1 -0
  43. package/dist/merkle-transcript.d.ts +34 -0
  44. package/dist/merkle-transcript.d.ts.map +1 -0
  45. package/dist/merkle-transcript.js +162 -0
  46. package/dist/merkle-transcript.js.map +1 -0
  47. package/dist/open-catalog.d.ts +111 -0
  48. package/dist/open-catalog.d.ts.map +1 -0
  49. package/dist/open-catalog.js +307 -0
  50. package/dist/open-catalog.js.map +1 -0
  51. package/dist/reconcile.d.ts +150 -0
  52. package/dist/reconcile.d.ts.map +1 -0
  53. package/dist/reconcile.js +136 -0
  54. package/dist/reconcile.js.map +1 -0
  55. package/dist/trust-sdk.d.ts +127 -0
  56. package/dist/trust-sdk.d.ts.map +1 -0
  57. package/dist/trust-sdk.js +147 -0
  58. package/dist/trust-sdk.js.map +1 -0
  59. package/dist/types.d.ts +213 -0
  60. package/dist/types.d.ts.map +1 -0
  61. package/dist/types.js +68 -0
  62. package/dist/types.js.map +1 -0
  63. package/package.json +52 -0
package/dist/badges.js ADDED
@@ -0,0 +1,213 @@
1
+ // GENERATED from src/x402/badges.ts by scripts/sdk/sync-sdk.ts — do not edit here.
2
+ // The canonical module is the one FlareClaw runs in production; this is a copy so
3
+ // that what we publish and what we run cannot diverge. Edit the canonical file.
4
+ /**
5
+ * badges — reading the x402 `attestations` extension registry (#3000)
6
+ * with ZERO dependencies.
7
+ *
8
+ * ── WHY ZERO DEPENDENCIES ──
9
+ * This ships as the reference client for a trust extension. A package
10
+ * whose job is "decide whether to trust a stranger before paying them"
11
+ * cannot credibly arrive with a dependency tree the reader will never
12
+ * audit. Everything here is one `eth_call` over `fetch` and some hex
13
+ * slicing, so the whole trust path is readable in one sitting.
14
+ *
15
+ * The cost of that choice is that we cannot compute keccak256 at
16
+ * runtime, so the function selector and the well-known `kind` hashes
17
+ * are compile-time constants below. `tests/x402/badges.test.ts` derives
18
+ * all of them with ethers and asserts equality, so a typo cannot
19
+ * survive — the constants are verified, not trusted.
20
+ */
21
+ /** keccak256("hasActiveBadge(address,bytes32)")[0..4] */
22
+ const HAS_ACTIVE_BADGE_SELECTOR = '0x322ad60a';
23
+ /**
24
+ * keccak256(utf8(kind)) for the kinds this ecosystem has defined so far.
25
+ * Callers may also pass a pre-hashed 0x-prefixed bytes32 for any other
26
+ * kind, or supply their own keccak via `hashKind`.
27
+ */
28
+ export const KNOWN_BADGE_KINDS = Object.freeze({
29
+ 'x402-facilitator-attested': '0xdd51a17aff71777ed7ca01b179f89a5754182ef754023c65de446ce7abeb611e',
30
+ 'bingo-verifiable-venue': '0xf886e00578ed56c02ff72c2950ac3141e4d7221e874b739ab807b8c8f7e9370b',
31
+ 'agent-audits-before-paying': '0x7b93d3c0d725755d8d14df7aaef4fd20ed4d5b1c0c92c5a41a177787e5b72a42',
32
+ });
33
+ const BYTES32 = /^0x[0-9a-fA-F]{64}$/;
34
+ const ADDRESS = /^0x[0-9a-fA-F]{40}$/;
35
+ /** Resolve a kind name (or pass through a pre-hashed bytes32). */
36
+ export function resolveKind(kind, hashKind) {
37
+ if (BYTES32.test(kind))
38
+ return kind.toLowerCase();
39
+ const known = KNOWN_BADGE_KINDS[kind];
40
+ if (known)
41
+ return known;
42
+ if (hashKind) {
43
+ const h = hashKind(kind);
44
+ if (!BYTES32.test(h))
45
+ throw new Error(`hashKind returned a non-bytes32 value for "${kind}"`);
46
+ return h.toLowerCase();
47
+ }
48
+ throw new Error(`unknown badge kind "${kind}" — pass a 0x-prefixed bytes32, or supply hashKind (e.g. ethers.id)`);
49
+ }
50
+ /**
51
+ * `hasActiveBadge(subject, kind)` on a conforming registry.
52
+ *
53
+ * ⚠️ Spec rule (Security considerations, "Registry substitution"): a
54
+ * malicious manifest can point at a lookalike registry, so a caller MUST
55
+ * pin or allowlist the registries it accepts. This function deliberately
56
+ * takes the registry as an explicit argument rather than reading it from
57
+ * a manifest — so that pinning is a decision you make, not one you
58
+ * forget to make.
59
+ *
60
+ * Throws on RPC failure rather than returning false: "I could not check"
61
+ * and "I checked and it is not active" are different answers, and
62
+ * collapsing them is how a chain outage turns into a silent trust
63
+ * upgrade. Callers decide their own failure policy.
64
+ */
65
+ export async function hasActiveBadge(q) {
66
+ if (!ADDRESS.test(q.registry))
67
+ throw new Error(`registry is not an address: ${q.registry}`);
68
+ if (!ADDRESS.test(q.subject))
69
+ throw new Error(`subject is not an address: ${q.subject}`);
70
+ const kindHash = resolveKind(q.kind, q.hashKind);
71
+ const data = HAS_ACTIVE_BADGE_SELECTOR
72
+ + q.subject.toLowerCase().replace(/^0x/, '').padStart(64, '0')
73
+ + kindHash.replace(/^0x/, '');
74
+ const doFetch = q.fetchImpl ?? fetch;
75
+ const res = await doFetch(q.rpcUrl, {
76
+ method: 'POST',
77
+ headers: { 'Content-Type': 'application/json' },
78
+ body: JSON.stringify({
79
+ jsonrpc: '2.0', id: 1, method: 'eth_call',
80
+ params: [{ to: q.registry, data }, 'latest'],
81
+ }),
82
+ signal: AbortSignal.timeout(q.timeoutMs ?? 10_000),
83
+ });
84
+ if (!res.ok)
85
+ throw new Error(`badge RPC failed: HTTP ${res.status}`);
86
+ const body = await res.json();
87
+ if (body.error)
88
+ throw new Error(`badge RPC error: ${body.error.message ?? 'unknown'}`);
89
+ if (typeof body.result !== 'string')
90
+ throw new Error('badge RPC returned no result');
91
+ // A bool is abi-encoded as a 32-byte word; anything nonzero is true.
92
+ // An empty result means there is no contract at that address — which
93
+ // is a misconfiguration, not a negative answer.
94
+ const word = body.result.replace(/^0x/, '');
95
+ if (word.length === 0)
96
+ throw new Error(`no contract at registry ${q.registry}`);
97
+ return /[1-9a-f]/i.test(word);
98
+ }
99
+ /**
100
+ * `hasActiveBadge` across N independent endpoints, requiring agreement.
101
+ *
102
+ * ── WHY THIS EXISTS ──
103
+ * Badge status GATES PAYMENTS, and a single `eth_call` is one endpoint's
104
+ * word. Failover fixes liveness, not honesty: with one source, a hostile
105
+ * or buggy RPC can report `active` for a revoked venue (or `inactive` to
106
+ * censor a competitor) and the caller cannot tell. Any read whose answer
107
+ * we act on without a second source needs a second source.
108
+ *
109
+ * Three outcomes, deliberately distinct — collapsing them is how a trust
110
+ * check quietly stops being one:
111
+ * agreed — quorum endpoints returned the same answer. Act on it.
112
+ * disputed — endpoints DISAGREED. This is not "unknown", it is
113
+ * evidence that one of them is wrong about a
114
+ * payment-gating fact. Callers should refuse, not retry.
115
+ * unavailable — too few answered. "I could not check" ≠ "not active".
116
+ */
117
+ export async function hasActiveBadgeQuorum(q) {
118
+ const urls = [...new Set(q.rpcUrls)];
119
+ if (urls.length === 0)
120
+ throw new Error('hasActiveBadgeQuorum: rpcUrls is empty');
121
+ // Deliberately NOT clamped to urls.length. Clamping would silently
122
+ // turn a requested 2-of-N into 1-of-1 whenever a caller passed too
123
+ // few (or duplicate) endpoints — the guarantee evaporating exactly
124
+ // where nobody looks. Too few sources yields `unavailable`, which is
125
+ // the truthful answer: this could not be checked to the requested
126
+ // standard.
127
+ const required = Math.max(1, q.quorum ?? 2);
128
+ const settled = await Promise.allSettled(urls.map(rpcUrl => hasActiveBadge({ ...q, rpcUrl })));
129
+ const answers = [];
130
+ const errors = [];
131
+ for (const r of settled) {
132
+ if (r.status === 'fulfilled')
133
+ answers.push(r.value);
134
+ else
135
+ errors.push(r.reason instanceof Error ? r.reason.message : String(r.reason));
136
+ }
137
+ const yes = answers.filter(Boolean).length;
138
+ const no = answers.length - yes;
139
+ // Disagreement is checked BEFORE quorum: 2 yes + 1 no is not a
140
+ // 2-of-3 pass, it is a contradiction about a fact that has exactly
141
+ // one true value on one chain.
142
+ if (yes > 0 && no > 0)
143
+ return { status: 'disputed', answers, errors };
144
+ if (answers.length >= required) {
145
+ return { status: 'agreed', active: yes > 0, agreed: answers.length, queried: urls.length };
146
+ }
147
+ return { status: 'unavailable', agreed: answers.length, quorum: required, errors };
148
+ }
149
+ /**
150
+ * Evaluate an operator the way the spec requires for any decision that
151
+ * depends on RUNTIME state (e.g. "is settlement attested right now?").
152
+ *
153
+ * ── THE MISTAKE THIS FUNCTION EXISTS TO PREVENT ──
154
+ * A registry record is soulbound, therefore durable. TEE attestation is
155
+ * transient. Pointing the first at the second produces a claim that is
156
+ * true when written and silently false later, with nothing in the record
157
+ * to reveal the drift. We shipped exactly that: our own
158
+ * `x402-facilitator-attested` record read `active` on-chain while our own
159
+ * manifest honestly reported `attestation: none` because the enclave was
160
+ * down. The record was not lying about what it attested — a verification
161
+ * really did happen — it was being READ as a liveness signal it cannot
162
+ * carry.
163
+ *
164
+ * So the two answers are kept separate and only combined explicitly:
165
+ * verified — "was this operator verified?" (registry)
166
+ * liveAttestation — "is it in that mode right now?" (manifest)
167
+ * attestedNow — both, which is what you actually gate on.
168
+ *
169
+ * Fails CLOSED: any inability to establish the live state yields
170
+ * attestedNow === false.
171
+ */
172
+ export async function checkOperatorTrust(opts) {
173
+ const notes = [];
174
+ const att = opts.manifest.attestation;
175
+ // Apply the extension's own "absent verification, treat as none" rule:
176
+ // a TEE block whose verifier is not dereferenceable cannot be checked
177
+ // by anyone, so it must not read as attested.
178
+ let liveAttestation;
179
+ if (!att) {
180
+ liveAttestation = 'absent';
181
+ notes.push('manifest carries no attestation block');
182
+ }
183
+ else if (att.type === 'tee' && typeof att.verifier === 'string' && att.verifier.startsWith('https://')) {
184
+ liveAttestation = 'tee';
185
+ }
186
+ else {
187
+ liveAttestation = 'none';
188
+ notes.push(att.type === 'tee'
189
+ ? 'manifest claims tee but its verifier is not a dereferenceable HTTPS URL — treated as none per spec'
190
+ : `manifest reports attestation: ${att.type ?? 'unknown'}`);
191
+ }
192
+ let verified = false;
193
+ try {
194
+ // Spread conditionally: under exactOptionalPropertyTypes an
195
+ // explicit `undefined` is not the same as an absent key.
196
+ verified = await hasActiveBadge({
197
+ rpcUrl: opts.rpcUrl, registry: opts.registry, subject: opts.subject,
198
+ kind: opts.kind,
199
+ ...(opts.hashKind ? { hashKind: opts.hashKind } : {}),
200
+ ...(opts.fetchImpl ? { fetchImpl: opts.fetchImpl } : {}),
201
+ });
202
+ if (!verified)
203
+ notes.push('no active record for this subject+kind in the pinned registry');
204
+ }
205
+ catch (e) {
206
+ notes.push(`registry unreadable (${e instanceof Error ? e.message : String(e)}) — treating as unverified`);
207
+ }
208
+ if (verified && liveAttestation !== 'tee') {
209
+ notes.push('RECORD IS DURABLE, STATE IS NOT: the operator was verified, but is not running in the verified mode right now. Do not treat the record as a liveness signal.');
210
+ }
211
+ return { verified, liveAttestation, attestedNow: verified && liveAttestation === 'tee', notes };
212
+ }
213
+ //# sourceMappingURL=badges.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"badges.js","sourceRoot":"","sources":["../src/badges.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,145 @@
1
+ import type { ReconcileQuery, ReconcileVerdict } from './reconcile.js';
2
+ export declare const MCP_PROTOCOL_STATELESS = "2026-07-28";
3
+ /** Newest first; `initialize` negotiation answers with the first of these. */
4
+ export declare const MCP_PROTOCOL_LEGACY: readonly ["2025-11-25", "2025-06-18", "2025-03-26"];
5
+ export declare const MCP_SUPPORTED_VERSIONS: string[];
6
+ export declare const CATALOG_MCP_SERVER_INFO: {
7
+ readonly name: "flareclaw-open-catalog";
8
+ readonly title: "The x402 Open Catalog";
9
+ readonly version: "0.1.0";
10
+ };
11
+ export interface CatalogAnchorInfo {
12
+ tx: string;
13
+ digest: string;
14
+ at: string;
15
+ }
16
+ export interface HostResolution {
17
+ via: 'dns-txt' | 'well-known';
18
+ kind: string;
19
+ attestationUsable: boolean;
20
+ kindsMatchLive?: boolean;
21
+ baseUrl?: string;
22
+ }
23
+ export interface CatalogMcpDeps {
24
+ statePath: string;
25
+ /** Live anchor state from the serving process; null before first anchor. */
26
+ anchor?: () => CatalogAnchorInfo | null;
27
+ /** How often the serving process refreshes the snapshot (ttl honesty). */
28
+ refreshIntervalMs?: number;
29
+ /** Live discovery resolution for verify_host; absent → tool reports unavailable. */
30
+ resolveHost?: (domain: string) => Promise<HostResolution>;
31
+ /** Rail-side settlement reconciliation (src/x402/reconcile.ts);
32
+ * absent → the reconcile tool reports unavailable. */
33
+ reconcile?: (q: ReconcileQuery) => Promise<ReconcileVerdict>;
34
+ explorerBase?: string;
35
+ now?: () => number;
36
+ }
37
+ export interface CatalogMcpHeaders {
38
+ /** MCP-Protocol-Version */
39
+ protocolVersion?: string;
40
+ /** Mcp-Method (SEP-2243) — when present it MUST match the body method. */
41
+ mcpMethod?: string;
42
+ }
43
+ export interface McpHttpAnswer {
44
+ status: number;
45
+ body: unknown | null;
46
+ }
47
+ /** Alphabetical and stays that way: deterministic tools/list order is a
48
+ * spec requirement (prompt-cache friendliness), enforced by a test. */
49
+ export declare const CATALOG_MCP_TOOLS: readonly [{
50
+ readonly name: "catalog_get";
51
+ readonly description: "Look up Open Catalog entries for one resource URL or domain, across both provenance lanes (bazaar-mirror + discovery). Returns every matching row with its source and re-derivation recipe.";
52
+ readonly inputSchema: {
53
+ readonly type: "object";
54
+ readonly properties: {
55
+ readonly resource: {
56
+ readonly type: "string";
57
+ readonly description: "Resource URL (exact or prefix) or a bare domain name";
58
+ };
59
+ };
60
+ readonly required: readonly ["resource"];
61
+ };
62
+ }, {
63
+ readonly name: "catalog_search";
64
+ readonly description: "Query the Open Catalog: filter by source (bazaar-mirror | discovery), network, or independently-verifiable attestation; paginated. Every row is provenance-tagged — how to re-derive it without trusting this server.";
65
+ readonly inputSchema: {
66
+ readonly type: "object";
67
+ readonly properties: {
68
+ readonly source: {
69
+ readonly type: "string";
70
+ readonly enum: readonly ["bazaar-mirror", "discovery"];
71
+ };
72
+ readonly network: {
73
+ readonly type: "string";
74
+ readonly description: "e.g. \"coston2\", \"base\", \"eip155:114\"";
75
+ };
76
+ readonly attested: {
77
+ readonly type: "boolean";
78
+ readonly description: "true → only entries whose attestation claim is independently checkable";
79
+ };
80
+ readonly limit: {
81
+ readonly type: "number";
82
+ readonly description: "1–500, default 50";
83
+ };
84
+ readonly offset: {
85
+ readonly type: "number";
86
+ };
87
+ };
88
+ };
89
+ }, {
90
+ readonly name: "catalog_stats";
91
+ readonly description: "Headline numbers: mirrored vs discovered vs attested counts, networks the Bazaar structurally excludes, the served snapshot's sha256 digest and its on-chain anchor.";
92
+ readonly inputSchema: {
93
+ readonly type: "object";
94
+ readonly properties: {};
95
+ };
96
+ }, {
97
+ readonly name: "reconcile";
98
+ readonly description: "Determinate verdict for one EIP-3009 payment authorization on the Coston2 rail: settled (with the settlement tx + transfers), refused-not-charged (window closed, nonce unconsumed — can never settle), or indeterminate with a machine-readable reason. Every verdict re-derivable from public RPC: authorizationState + AuthorizationUsed logs.";
99
+ readonly inputSchema: {
100
+ readonly type: "object";
101
+ readonly properties: {
102
+ readonly asset: {
103
+ readonly type: "string";
104
+ readonly description: "EIP-3009 asset contract address (0x…)";
105
+ };
106
+ readonly payer: {
107
+ readonly type: "string";
108
+ readonly description: "The authorizer — the `from` of the authorization (0x…)";
109
+ };
110
+ readonly nonce: {
111
+ readonly type: "string";
112
+ readonly description: "The 32-byte authorization nonce (0x + 64 hex)";
113
+ };
114
+ readonly validBefore: {
115
+ readonly type: "number";
116
+ readonly description: "The authorization's validBefore (unix seconds). Required to prove refused-not-charged: an unconsumed nonce inside its window could still settle.";
117
+ };
118
+ };
119
+ readonly required: readonly ["asset", "payer", "nonce"];
120
+ };
121
+ }, {
122
+ readonly name: "verify_host";
123
+ readonly description: "Two-observation verdict for a hostname: a LIVE x402 discovery resolution (DNS TXT → /.well-known/x402 → live capability cross-check) compared against this catalog's last anchored crawl observation. Discovery is not endorsement; this reports checkability, not trustworthiness.";
124
+ readonly inputSchema: {
125
+ readonly type: "object";
126
+ readonly properties: {
127
+ readonly domain: {
128
+ readonly type: "string";
129
+ readonly description: "Bare hostname, e.g. \"api.flareclaw.app\"";
130
+ };
131
+ };
132
+ readonly required: readonly ["domain"];
133
+ };
134
+ }];
135
+ /** Map a body-parse failure (transport layer) to the spec's JSON-RPC shape. */
136
+ export declare function catalogMcpParseError(message?: string): McpHttpAnswer;
137
+ export declare function handleCatalogMcp(body: unknown, headers: CatalogMcpHeaders, deps: CatalogMcpDeps): Promise<McpHttpAnswer>;
138
+ /**
139
+ * Same shape family as /.well-known/x402: one host, two well-knowns, one
140
+ * signed identity — the facilitator serves this next to the x402 manifest
141
+ * and signs it with the same per-serve Ed25519 lane, so the DNS-published
142
+ * key vouches for the MCP surface too.
143
+ */
144
+ export declare function buildMcpServerCard(base: string, deps: CatalogMcpDeps): Record<string, unknown>;
145
+ //# sourceMappingURL=catalog-mcp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog-mcp.d.ts","sourceRoot":"","sources":["../src/catalog-mcp.ts"],"names":[],"mappings":"AAqCA,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEvE,eAAO,MAAM,sBAAsB,eAAe,CAAC;AACnD,8EAA8E;AAC9E,eAAO,MAAM,mBAAmB,qDAAsD,CAAC;AACvF,eAAO,MAAM,sBAAsB,UAAmD,CAAC;AAavF,eAAO,MAAM,uBAAuB;;;;CAI1B,CAAC;AAUX,MAAM,WAAW,iBAAiB;IAAG,EAAE,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE;AAE7E,MAAM,WAAW,cAAc;IAC3B,GAAG,EAAE,SAAS,GAAG,YAAY,CAAC;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,iBAAiB,EAAE,OAAO,CAAC;IAC3B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,4EAA4E;IAC5E,MAAM,CAAC,EAAE,MAAM,iBAAiB,GAAG,IAAI,CAAC;IACxC,0EAA0E;IAC1E,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,oFAAoF;IACpF,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;IAC1D;2DACuD;IACvD,SAAS,CAAC,EAAE,CAAC,CAAC,EAAE,cAAc,KAAK,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAC7D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,iBAAiB;IAC9B,2BAA2B;IAC3B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,0EAA0E;IAC1E,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAAG,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAAA;CAAE;AA0EvE;wEACwE;AACxE,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAwDpB,CAAC;AAyJX,+EAA+E;AAC/E,wBAAgB,oBAAoB,CAAC,OAAO,SAA2B,GAAG,aAAa,CAEtF;AAED,wBAAsB,gBAAgB,CAClC,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,iBAAiB,EAAE,IAAI,EAAE,cAAc,GAChE,OAAO,CAAC,aAAa,CAAC,CA6FxB;AAID;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAe9F"}