@gnolith/taproot 0.2.0 → 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 (51) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/COMPATIBILITY.md +5 -3
  3. package/README.md +106 -33
  4. package/SECURITY.md +6 -3
  5. package/dist/authorization-maintenance.d.ts +55 -0
  6. package/dist/authorization-maintenance.d.ts.map +1 -0
  7. package/dist/authorization-maintenance.js +686 -0
  8. package/dist/authorization-maintenance.js.map +1 -0
  9. package/dist/authorization.d.ts +98 -0
  10. package/dist/authorization.d.ts.map +1 -0
  11. package/dist/authorization.js +1137 -0
  12. package/dist/authorization.js.map +1 -0
  13. package/dist/canonical.d.ts +2 -1
  14. package/dist/canonical.d.ts.map +1 -1
  15. package/dist/canonical.js +9 -1
  16. package/dist/canonical.js.map +1 -1
  17. package/dist/errors.d.ts +4 -0
  18. package/dist/errors.d.ts.map +1 -1
  19. package/dist/errors.js +4 -0
  20. package/dist/errors.js.map +1 -1
  21. package/dist/index.d.ts +125 -49
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +351 -44
  24. package/dist/index.js.map +1 -1
  25. package/dist/migrations.d.ts +9 -3
  26. package/dist/migrations.d.ts.map +1 -1
  27. package/dist/migrations.js +77 -5
  28. package/dist/migrations.js.map +1 -1
  29. package/dist/repository.d.ts +20 -9
  30. package/dist/repository.d.ts.map +1 -1
  31. package/dist/repository.js +593 -48
  32. package/dist/repository.js.map +1 -1
  33. package/dist/schema.d.ts +14 -5
  34. package/dist/schema.d.ts.map +1 -1
  35. package/dist/schema.js +461 -18
  36. package/dist/schema.js.map +1 -1
  37. package/dist/types.d.ts +59 -0
  38. package/dist/types.d.ts.map +1 -1
  39. package/docs/api.md +56 -18
  40. package/docs/architecture.md +19 -7
  41. package/docs/authorization.md +82 -0
  42. package/docs/completion-audit.md +15 -15
  43. package/docs/operations.md +28 -5
  44. package/docs/product-scope.md +5 -3
  45. package/docs/testing.md +18 -1
  46. package/docs/threat-model.md +30 -3
  47. package/examples/d1-diamond-interop/README.md +2 -1
  48. package/examples/d1-diamond-interop/demo.ts +150 -21
  49. package/migrations/0003_canonical_statement_text.sql +31 -0
  50. package/migrations/0004_canonical_authorization_policy.sql +213 -0
  51. package/package.json +4 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,58 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.0
4
+
5
+ - **Breaking 0.3 API:** removed `TaprootRepository`, `createTaproot`, and every
6
+ unscoped canonical read helper from the normal package export. Canonical
7
+ entity, history, list, term-search, audit, export, integrity, and repair
8
+ access now exists only through mandatory `AuthorizedTaprootReader` context.
9
+ - Added host-issued non-extractable AES-GCM cursor capability, authenticated
10
+ cursors bound to caller/grants/query/filter/auth revision/data generation,
11
+ fixed-size plaintext padding, identifier-only candidate scans, denied-heavy
12
+ page filling, and final authorization rechecks. Revision and audit generation
13
+ invalidate cursors after writes and repair. Stale, tampered, and cross-context
14
+ cursors fail generically.
15
+ - Public mutation helpers now return minimal receipts and reject validator/RDF
16
+ factory callbacks and configurable entity-size probes, so write configuration
17
+ cannot observe preexisting canonical content. They require a process-local
18
+ opaque installation authorization guard bound to the exact database object
19
+ and installation base IRI. Normal writes require current `knowledge:write`;
20
+ policy changes require orthogonal `knowledge:policy`. Raw repository
21
+ internals are not package-exported.
22
+ - Added host-created authorization contexts, canonical CNF visibility scopes,
23
+ lossless scope intersection, portable fingerprints, explicit `search:admin`
24
+ checks, and fail-closed pre/post-hydration canonical reads.
25
+ - Added checksummed migration 4 with immutable installation authorization
26
+ state, current and per-revision entity/statement policy, atomic projection
27
+ outbox and counter advances, fail-closed legacy quarantine, and bounded
28
+ hash-attested `search:admin` backfill. Unique durable advance IDs prevent
29
+ same-target ABA races for canonical and cross-package ordered batches.
30
+ - Runtime JavaScript writes now fail closed when authorization metadata is
31
+ omitted, authorize before loading existing canonical state, validate redirect
32
+ targets and historical reverts against current policy, and preserve generic
33
+ denial behavior for missing, stale, or inaccessible targets.
34
+ - Cross-package authorization fencing is guard-executed and inseparable from
35
+ the ordered database batch. Authorization singleton/audit rows reject
36
+ replacement, readiness verifies current and historical statement-policy
37
+ coverage, and authorized bulk import advances its context between entities.
38
+ - Added host-issued fence-only domain guards bound to one exact non-Knowledge
39
+ capability. Task/Memory-style writes can share the installation revision
40
+ without borrowing Knowledge authority or advancing counters; Knowledge
41
+ advances require orthogonal policy authority and bind the prior durable
42
+ advance ID.
43
+ - Authorization readiness and persisted sources now require exact parity
44
+ between mutable current policy and its immutable matching revision, and
45
+ recompute historical statement coverage/effective visibility before use.
46
+ Operational inspection also validates exact trigger definitions.
47
+
48
+ - Added required, explicitly authored nonblank `Statement.text` to canonical
49
+ JSON and to every logical statement mutation.
50
+ - Added canonical JSON migration 3. Existing databases with no unauthored
51
+ statements upgrade atomically; persisted statements without text fail closed
52
+ rather than receiving inferred fallback prose.
53
+ - Whole-entity replacement and historical revert now require an exact
54
+ statement-ID-to-text resupply map, preventing silent stale-text carry.
55
+
3
56
  ## 0.2.0
4
57
 
5
58
  - Added a runtime-neutral SQLite persistence surface while retaining D1
package/COMPATIBILITY.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Wikibase compatibility target
2
2
 
3
- Taproot 0.2.x requires `@gnolith/diamond` 0.4.0 exactly. Existing Cloudflare D1
3
+ Taproot 0.3.x requires `@gnolith/diamond` 0.4.0 exactly. Existing Cloudflare D1
4
4
  objects remain compatible with the exported `D1DatabaseLike` surface. New
5
5
  embedders may use the equivalent `SqliteDatabaseLike`; both require one
6
6
  adapter/connection with ordered atomic batch semantics.
@@ -25,8 +25,10 @@ Intentional differences:
25
25
  lifecycle RDF; deleted content remains available in immutable revisions.
26
26
  - Search is a deterministic D1 term projection using case-insensitive
27
27
  substring matching. FTS5 is not required.
28
- - Taproot stores attribution claims but does not authenticate them. Identity
29
- verification, authorization, and agent/MCP transport remain host concerns.
28
+ - Taproot stores attribution claims but does not authenticate them. Normal
29
+ canonical reads require a host-created authorization context and use
30
+ Taproot's persisted canonical policy. Authentication, principals,
31
+ memberships, sessions, and agent/MCP transport remain host concerns.
30
32
  - The compatibility target is Wikibase core Items and Properties. Lexemes,
31
33
  Forms, Senses, EntitySchemas, MediaInfo, MediaWiki page metadata, and
32
34
  normalized external-ID formatter URLs are not claimed as supported entity
package/README.md CHANGED
@@ -12,7 +12,7 @@ editing commands, term search, repairable projections, and a deterministic RDF p
12
12
 
13
13
  ## Status
14
14
 
15
- Version `0.2.0` supports Node 22 and 24 and depends exactly on Diamond `0.4.0`,
15
+ Version `0.3.0` supports Node 22 and 24 and depends exactly on Diamond `0.4.0`,
16
16
  which exposes transaction-composable RDF patches, a runtime-neutral SQLite
17
17
  capability, and a process-local `node:sqlite` adapter.
18
18
 
@@ -21,6 +21,8 @@ capability, and a process-local `node:sqlite` adapter.
21
21
  - Items and Properties with Wikibase-style canonical JSON.
22
22
  - Labels, descriptions, aliases, sitelinks, statements, qualifiers,
23
23
  references, ranks, and all three snak types.
24
+ - Nonblank, explicitly authored text for every logical statement revision;
25
+ Taproot never generates prose from properties or values.
24
26
  - Item, Property, Lexeme, Form, Sense, and EntitySchema links; string,
25
27
  external ID, URL, Commons media, monolingual text, time,
26
28
  quantity, coordinate, math, musical notation, geo-shape, and tabular-data
@@ -46,25 +48,57 @@ tables idempotently. First initialization requires the database's permanent
46
48
  identity:
47
49
 
48
50
  ```ts
49
- import { TaprootRepository, initializeTaproot } from '@gnolith/taproot';
51
+ import {
52
+ createAuthorizationCursorCodec,
53
+ createAuthorizedTaproot,
54
+ createItem,
55
+ bootstrapTaprootAuthorization,
56
+ createInstallationAuthorizationGuard,
57
+ createTaprootHostWriteCapability,
58
+ initializeTaproot,
59
+ setLabel,
60
+ } from '@gnolith/taproot';
50
61
 
51
62
  await initializeTaproot(env.DB, { baseIri: 'https://knowledge.example' });
52
- const knowledge = new TaprootRepository(env.DB, {
63
+ const options = {
53
64
  baseIri: 'https://knowledge.example',
65
+ };
66
+ const writeCapability = createTaprootHostWriteCapability(
67
+ env.DB,
68
+ options,
69
+ nonExtractableHmacSha256Key,
70
+ );
71
+ await bootstrapTaprootAuthorization(
72
+ env.DB,
73
+ options,
74
+ writeCapability,
75
+ 'installation-1',
76
+ );
77
+ const guard = await createInstallationAuthorizationGuard(
78
+ env.DB,
79
+ options,
80
+ writeCapability,
81
+ );
82
+
83
+ const item = await createItem(env.DB, options, guard, writeContext, {
84
+ labels: { en: { language: 'en', value: 'Ada Lovelace' } },
85
+ authorization: canonicalPolicy,
54
86
  });
55
87
 
56
- const property = await knowledge.createProperty({
57
- datatype: 'string',
58
- labels: { en: { language: 'en', value: 'occupation' } },
59
- });
60
- const item = await knowledge.createItem({
61
- labels: { en: { language: 'en', value: 'Ada Lovelace' } },
88
+ // The host derives context only from authenticated state. Taproot loads its
89
+ // persisted canonical policy itself. The cursor key is durable and host-held.
90
+ const knowledge = createAuthorizedTaproot(env.DB, options, readContext, {
91
+ cursorCodec: createAuthorizationCursorCodec(nonExtractableAesGcmKey),
62
92
  });
93
+ const canonical = await knowledge.getEntity(item.entityId);
63
94
  ```
64
95
 
96
+ Never accept either host key, host capability, authorization guard, context, or
97
+ policy from a request, MCP argument, prompt, or query.
98
+
65
99
  Use Taproot's `planTaprootMigrations`, `applyTaprootMigrations`, and
66
100
  `initializeTaproot` APIs for schema changes. The numbered SQL files document
67
- the historical 0.1 layout and are not an operator migration interface in 0.2.
101
+ the historical 0.1 layout and are not an operator migration interface in 0.3.
68
102
  The package APIs own checksums, conservative adoption, application-level
69
103
  SHA-256 backfills, and RDF reprojection.
70
104
 
@@ -78,35 +112,72 @@ Diamond patch together. A stale guard or any SQL/RDF failure rolls the whole
78
112
  batch back.
79
113
 
80
114
  ```ts
81
- const edited = await knowledge.setLabel(item.entityId, 'fr', 'Ada Lovelace', {
82
- expectedRevision: item.newRevision,
83
- attribution: {
84
- id: 'agent:cataloguer',
85
- kind: 'agent',
86
- tool: 'gnolith-mcp',
115
+ const edited = await setLabel(
116
+ env.DB,
117
+ options,
118
+ guard,
119
+ currentWriteContext,
120
+ item.entityId,
121
+ 'fr',
122
+ 'Ada Lovelace',
123
+ {
124
+ expectedRevision: item.newRevision,
125
+ attribution: {
126
+ id: 'agent:cataloguer',
127
+ kind: 'agent',
128
+ tool: 'gnolith-mcp',
129
+ },
130
+ editSummary: 'add French label',
131
+ tags: ['agent'],
132
+ requestId: 'mcp-request-123',
133
+ authorization: currentCanonicalPolicy,
87
134
  },
88
- editSummary: 'add French label',
89
- tags: ['agent'],
90
- requestId: 'mcp-request-123',
91
- });
135
+ );
92
136
  ```
93
137
 
94
- The public API includes reads/search; create/import/replace; soft delete,
95
- restore, and redirect; all term/sitelink commands; complete statement,
96
- qualifier, reference, and rank commands; audit/history and integrity reads;
97
- bulk workflows; and canonical JSON parse, validate, create, and export helpers. Top-level function forms are exported alongside
98
- `TaprootRepository`.
99
-
100
- Set `requireAttribution: true` to reject unattributed writes. `validators`
101
- provide host policy checks without coupling Taproot to authentication, and
102
- `observe` receives isolated success/error timing records for committed writes.
138
+ The public API exposes canonical reads only on `AuthorizedTaprootReader`.
139
+ Entity/history/list/term-search/audit/export and integrity operations require a
140
+ host-created authorization context and Taproot's persisted policy source.
141
+ Public mutation helpers require the DB/installation-bound opaque authorization
142
+ guard, a current context with exact `knowledge:write`, and canonical policy
143
+ input. Policy changes additionally require exact `knowledge:policy`. They
144
+ return only entity ID, previous/new revision, authorization/search generation,
145
+ and committed status;
146
+ they do not return canonical JSON, text, RDF counts, hashes, or audit bodies.
147
+ `TaprootRepository` and raw read helpers are intentionally absent from package
148
+ exports in the breaking 0.3 line.
149
+
150
+ The opaque guard also owns execution of ordered cross-package batches that
151
+ need an exact authorization-revision fence or advance. It does not expose raw
152
+ counter-update statements that a caller could separate from the corresponding
153
+ audit, assertion, or domain writes.
154
+ Hosts issue a distinct fence-only domain guard for each exact non-Knowledge
155
+ domain capability, such as Task or Memory writes. The capability is bound at
156
+ issuance, cannot be supplied at the call site, and an ordinary domain fence
157
+ does not advance authorization or search counters. Knowledge authorization
158
+ advances additionally require `knowledge:policy`.
159
+
160
+ Statement creation and replacement include `text` on the `Statement` itself.
161
+ Rank, qualifier, and reference mutation methods require authored text for the
162
+ new logical statement revision. `replaceEntity` and `revertEntity` require an
163
+ exact `statementTexts` map for every statement they carry forward. Reusing old
164
+ wording is allowed only when the caller deliberately supplies it again.
165
+
166
+ Set `requireAttribution: true` to reject unattributed writes. `observe` receives
167
+ isolated success/error timing records. Public write options cannot install
168
+ validators or RDF factories over canonical state and cannot vary the canonical
169
+ entity-size limit; hosts perform domain validation before invoking the write
170
+ using separately authorized input.
103
171
 
104
172
  ## SPARQL prefixes
105
173
 
106
174
  `wikibasePrefixes(baseIri)` returns site-owned `wd:`, `wds:`, `wdv:`,
107
175
  `wdref:`, `wdt:`, `p:`, `ps:`, `psv:`, `pq:`, `pqv:`, `pr:`, `prv:`, and
108
- `wdno:` namespaces. Pass the D1 binding to Diamond's read-only SPARQL handler
109
- to query them.
176
+ `wdno:` namespaces. Diamond's database-level SPARQL handler can query them, but
177
+ it sees the complete graph and is privileged host maintenance/debug
178
+ infrastructure. Do not expose it to a user, agent, MCP, or search caller.
179
+ Normal SPARQL needs an authorization-scoped dataset and final canonical policy
180
+ recheck in the owning host.
110
181
 
111
182
  ## Limits
112
183
 
@@ -116,8 +187,10 @@ that as `QuadPatchTooLargeError`. Store PDFs, images, audio, OCR, transcripts,
116
187
  and article bodies externally and represent them as knowledge Items.
117
188
 
118
189
  Bulk imports default to create-only, can opt into `upsert`, are capped at 100
119
- entities by default, and commit one entity atomically at a time. Multi-command
120
- edits apply up to 100 commands in one revision. All list limits are capped at 500.
190
+ entities by default, and commit one entity atomically at a time. Authorized
191
+ bulk policies use sequential expected authorization revisions; Taproot carries
192
+ each successful advance into the next entity's context. Multi-command edits
193
+ apply up to 100 commands in one revision. All list limits are capped at 500.
121
194
 
122
195
  See the [local D1 and Diamond interoperability example](examples/d1-diamond-interop/README.md),
123
196
  [`COMPATIBILITY.md`](COMPATIBILITY.md), and the architecture, API, operations,
package/SECURITY.md CHANGED
@@ -11,9 +11,12 @@ canonical history or RDF query results, and whether untrusted JSON or SPARQL
11
11
  input is required. Do not include production data or credentials.
12
12
 
13
13
  Taproot records attribution claims but does not authenticate identities or
14
- authorize writes. It assumes mutation routes admit trusted callers. Canonical JSON,
15
- revision/audit immutability, size limits, optimistic revision guards, and
16
- read-only Diamond SPARQL are security boundaries; projection tables are not.
14
+ persist principals, memberships, or sessions. It does persist canonical entity
15
+ authorization policy and requires a host-created current context plus an
16
+ opaque DB-bound guard for normal writes. Canonical JSON, authorization policy,
17
+ revision/audit immutability, size limits, optimistic revision/authorization
18
+ guards, and read-only Diamond SPARQL are security boundaries; rebuildable
19
+ projection content is not authoritative.
17
20
 
18
21
  The threat model and host responsibilities are documented in
19
22
  `docs/threat-model.md`.
@@ -0,0 +1,55 @@
1
+ import type { SqliteDatabaseLike } from '@gnolith/diamond';
2
+ import type { EntityId, VisibilityScopeV1, AuthorizationContext } from './types.js';
3
+ export type AuthorizationReadinessCode = 'missing-current-policy' | 'current-revision-mismatch' | 'cross-installation-policy' | 'authorization-revision-invalid' | 'entity-policy-mismatch' | 'missing-revision-policy' | 'statement-policy-mismatch';
4
+ export interface AuthorizationReadinessIssue {
5
+ entityId: EntityId;
6
+ currentRevision: number;
7
+ codes: AuthorizationReadinessCode[];
8
+ }
9
+ export interface AuthorizationReadinessInspection {
10
+ installationId: string;
11
+ authorizationRevision: number;
12
+ searchGeneration: number;
13
+ counts: {
14
+ canonicalEntities: number;
15
+ canonicalRevisions: number;
16
+ currentPolicies: number;
17
+ revisionPolicies: number;
18
+ quarantinedEntities: number;
19
+ revisionPolicyMismatches: number;
20
+ entityPolicyMismatches: number;
21
+ statementPolicyMismatches: number;
22
+ currentHistoryParityMismatches: number;
23
+ };
24
+ ready: boolean;
25
+ issues: AuthorizationReadinessIssue[];
26
+ cursor: EntityId | null;
27
+ }
28
+ export interface AuthorizationBackfillRevisionInput {
29
+ revision: number;
30
+ contentHash: string;
31
+ workspaceId: string | null;
32
+ ownerPrincipalId: string;
33
+ visibility: VisibilityScopeV1;
34
+ statementRestrictions: Readonly<Record<string, readonly VisibilityScopeV1[]>>;
35
+ }
36
+ export interface AuthorizationBackfillEntityInput {
37
+ entityId: EntityId;
38
+ revisions: readonly AuthorizationBackfillRevisionInput[];
39
+ }
40
+ export interface AuthorizationBackfillPlan {
41
+ planId: string;
42
+ installationId: string;
43
+ baseAuthorizationRevision: number;
44
+ manifestHash: string;
45
+ entityCount: number;
46
+ revisionCount: number;
47
+ status: 'planned' | 'complete';
48
+ }
49
+ export declare function inspectAuthorizationReadiness(db: SqliteDatabaseLike, rawContext: AuthorizationContext, options?: {
50
+ limit?: number;
51
+ cursor?: EntityId;
52
+ }): Promise<AuthorizationReadinessInspection>;
53
+ export declare function planAuthorizationBackfill(db: SqliteDatabaseLike, rawContext: AuthorizationContext, inputs: readonly AuthorizationBackfillEntityInput[], now?: string): Promise<AuthorizationBackfillPlan>;
54
+ export declare function applyAuthorizationBackfill(db: SqliteDatabaseLike, rawContext: AuthorizationContext, planId: string, now?: string): Promise<AuthorizationBackfillPlan>;
55
+ //# sourceMappingURL=authorization-maintenance.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authorization-maintenance.d.ts","sourceRoot":"","sources":["../src/authorization-maintenance.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,kBAAkB,EAEnB,MAAM,kBAAkB,CAAC;AAc1B,OAAO,KAAK,EACV,QAAQ,EACR,iBAAiB,EAEjB,oBAAoB,EACrB,MAAM,YAAY,CAAC;AAOpB,MAAM,MAAM,0BAA0B,GAClC,wBAAwB,GACxB,2BAA2B,GAC3B,2BAA2B,GAC3B,gCAAgC,GAChC,wBAAwB,GACxB,yBAAyB,GACzB,2BAA2B,CAAC;AAEhC,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,EAAE,QAAQ,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,KAAK,EAAE,0BAA0B,EAAE,CAAC;CACrC;AAED,MAAM,WAAW,gCAAgC;IAC/C,cAAc,EAAE,MAAM,CAAC;IACvB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,gBAAgB,EAAE,MAAM,CAAC;IACzB,MAAM,EAAE;QACN,iBAAiB,EAAE,MAAM,CAAC;QAC1B,kBAAkB,EAAE,MAAM,CAAC;QAC3B,eAAe,EAAE,MAAM,CAAC;QACxB,gBAAgB,EAAE,MAAM,CAAC;QACzB,mBAAmB,EAAE,MAAM,CAAC;QAC5B,wBAAwB,EAAE,MAAM,CAAC;QACjC,sBAAsB,EAAE,MAAM,CAAC;QAC/B,yBAAyB,EAAE,MAAM,CAAC;QAClC,8BAA8B,EAAE,MAAM,CAAC;KACxC,CAAC;IACF,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,2BAA2B,EAAE,CAAC;IACtC,MAAM,EAAE,QAAQ,GAAG,IAAI,CAAC;CACzB;AAED,MAAM,WAAW,kCAAkC;IACjD,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,gBAAgB,EAAE,MAAM,CAAC;IACzB,UAAU,EAAE,iBAAiB,CAAC;IAC9B,qBAAqB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,iBAAiB,EAAE,CAAC,CAAC,CAAC;CAC/E;AAED,MAAM,WAAW,gCAAgC;IAC/C,QAAQ,EAAE,QAAQ,CAAC;IACnB,SAAS,EAAE,SAAS,kCAAkC,EAAE,CAAC;CAC1D;AAED,MAAM,WAAW,yBAAyB;IACxC,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,yBAAyB,EAAE,MAAM,CAAC;IAClC,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,SAAS,GAAG,UAAU,CAAC;CAChC;AAoCD,wBAAsB,6BAA6B,CACjD,EAAE,EAAE,kBAAkB,EACtB,UAAU,EAAE,oBAAoB,EAChC,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,QAAQ,CAAA;CAAO,GAClD,OAAO,CAAC,gCAAgC,CAAC,CAoK3C;AA4JD,wBAAsB,yBAAyB,CAC7C,EAAE,EAAE,kBAAkB,EACtB,UAAU,EAAE,oBAAoB,EAChC,MAAM,EAAE,SAAS,gCAAgC,EAAE,EACnD,GAAG,GAAE,MAAiC,GACrC,OAAO,CAAC,yBAAyB,CAAC,CA8KpC;AAED,wBAAsB,0BAA0B,CAC9C,EAAE,EAAE,kBAAkB,EACtB,UAAU,EAAE,oBAAoB,EAChC,MAAM,EAAE,MAAM,EACd,GAAG,GAAE,MAAiC,GACrC,OAAO,CAAC,yBAAyB,CAAC,CA+OpC"}