@attestry/sdk 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +190 -0
- package/README.md +1269 -0
- package/dist/client.d.ts +58 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +74 -0
- package/dist/client.js.map +1 -0
- package/dist/constants.d.ts +7 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +43 -0
- package/dist/constants.js.map +1 -0
- package/dist/errors.d.ts +16 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +41 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/lines-parser.d.ts +50 -0
- package/dist/lines-parser.d.ts.map +1 -0
- package/dist/lines-parser.js +211 -0
- package/dist/lines-parser.js.map +1 -0
- package/dist/ndjson-parser.d.ts +57 -0
- package/dist/ndjson-parser.d.ts.map +1 -0
- package/dist/ndjson-parser.js +245 -0
- package/dist/ndjson-parser.js.map +1 -0
- package/dist/resources/abac-policies.d.ts +1034 -0
- package/dist/resources/abac-policies.d.ts.map +1 -0
- package/dist/resources/abac-policies.js +1519 -0
- package/dist/resources/abac-policies.js.map +1 -0
- package/dist/resources/audit-log.d.ts +588 -0
- package/dist/resources/audit-log.d.ts.map +1 -0
- package/dist/resources/audit-log.js +629 -0
- package/dist/resources/audit-log.js.map +1 -0
- package/dist/resources/batch.d.ts +845 -0
- package/dist/resources/batch.d.ts.map +1 -0
- package/dist/resources/batch.js +1074 -0
- package/dist/resources/batch.js.map +1 -0
- package/dist/resources/chat.d.ts +151 -0
- package/dist/resources/chat.d.ts.map +1 -0
- package/dist/resources/chat.js +124 -0
- package/dist/resources/chat.js.map +1 -0
- package/dist/resources/check.d.ts +348 -0
- package/dist/resources/check.d.ts.map +1 -0
- package/dist/resources/check.js +543 -0
- package/dist/resources/check.js.map +1 -0
- package/dist/resources/compliance-check.d.ts +330 -0
- package/dist/resources/compliance-check.d.ts.map +1 -0
- package/dist/resources/compliance-check.js +402 -0
- package/dist/resources/compliance-check.js.map +1 -0
- package/dist/resources/decisions.d.ts +1208 -0
- package/dist/resources/decisions.d.ts.map +1 -0
- package/dist/resources/decisions.js +1362 -0
- package/dist/resources/decisions.js.map +1 -0
- package/dist/resources/evidence-pack.d.ts +1080 -0
- package/dist/resources/evidence-pack.d.ts.map +1 -0
- package/dist/resources/evidence-pack.js +1789 -0
- package/dist/resources/evidence-pack.js.map +1 -0
- package/dist/resources/gate.d.ts +613 -0
- package/dist/resources/gate.d.ts.map +1 -0
- package/dist/resources/gate.js +737 -0
- package/dist/resources/gate.js.map +1 -0
- package/dist/resources/incidents.d.ts +136 -0
- package/dist/resources/incidents.d.ts.map +1 -0
- package/dist/resources/incidents.js +229 -0
- package/dist/resources/incidents.js.map +1 -0
- package/dist/resources/regulatory-changes.d.ts +307 -0
- package/dist/resources/regulatory-changes.d.ts.map +1 -0
- package/dist/resources/regulatory-changes.js +365 -0
- package/dist/resources/regulatory-changes.js.map +1 -0
- package/dist/resources/safe-input-read.d.ts +21 -0
- package/dist/resources/safe-input-read.d.ts.map +1 -0
- package/dist/resources/safe-input-read.js +57 -0
- package/dist/resources/safe-input-read.js.map +1 -0
- package/dist/resources/ship-gate.d.ts +475 -0
- package/dist/resources/ship-gate.d.ts.map +1 -0
- package/dist/resources/ship-gate.js +727 -0
- package/dist/resources/ship-gate.js.map +1 -0
- package/dist/resources/vision.d.ts +540 -0
- package/dist/resources/vision.d.ts.map +1 -0
- package/dist/resources/vision.js +1036 -0
- package/dist/resources/vision.js.map +1 -0
- package/dist/retry.d.ts +103 -0
- package/dist/retry.d.ts.map +1 -0
- package/dist/retry.js +224 -0
- package/dist/retry.js.map +1 -0
- package/dist/sse-parser.d.ts +64 -0
- package/dist/sse-parser.d.ts.map +1 -0
- package/dist/sse-parser.js +271 -0
- package/dist/sse-parser.js.map +1 -0
- package/dist/transport.d.ts +142 -0
- package/dist/transport.d.ts.map +1 -0
- package/dist/transport.js +455 -0
- package/dist/transport.js.map +1 -0
- package/dist/types.d.ts +61 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/package.json +44 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"regulatory-changes.js","sourceRoot":"","sources":["../../src/resources/regulatory-changes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read a single field off a consumer-supplied input object, converting
|
|
3
|
+
* a throwing getter's exception into the SDK's documented `TypeError`
|
|
4
|
+
* input contract.
|
|
5
|
+
*
|
|
6
|
+
* The caller MUST have already confirmed `obj` is a non-null object
|
|
7
|
+
* (every resource does the top-level `typeof input === "object"` guard
|
|
8
|
+
* first). The read is a plain index access, so it walks the prototype
|
|
9
|
+
* chain identically to the bare `obj.key` it replaces — callers that
|
|
10
|
+
* need own-property semantics still gate on `Object.hasOwn` (the
|
|
11
|
+
* module-load snapshot) exactly as before; this helper only adds the
|
|
12
|
+
* throwing-getter → `TypeError` conversion.
|
|
13
|
+
*
|
|
14
|
+
* @param obj The consumer-supplied input object (already confirmed non-null).
|
|
15
|
+
* @param key The field name to read.
|
|
16
|
+
* @param context The calling method (e.g. `"abacPolicies.create"`) — prefixes the thrown message.
|
|
17
|
+
* @returns The field value (`undefined` if absent — same as a bare read).
|
|
18
|
+
* @throws {TypeError} If the field's getter throws — the getter's error is preserved on `.cause`.
|
|
19
|
+
*/
|
|
20
|
+
export declare function readInputField(obj: object, key: string, context: string): unknown;
|
|
21
|
+
//# sourceMappingURL=safe-input-read.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"safe-input-read.d.ts","sourceRoot":"","sources":["../../src/resources/safe-input-read.ts"],"names":[],"mappings":"AAwBA;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,GACd,OAAO,CAcT"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// ─── Defensive input-field read ─────────────────────────────────────────────
|
|
2
|
+
//
|
|
3
|
+
// Shared by every SDK resource that validates a consumer-supplied
|
|
4
|
+
// input object by reading fields off it.
|
|
5
|
+
//
|
|
6
|
+
// **The gap this closes** (session-22 hostile review #1 — the SDK-wide
|
|
7
|
+
// MEDIUM-1 getter-throws contract gap, deferred from session 21):
|
|
8
|
+
// every resource's input validation reads fields with a bare property
|
|
9
|
+
// access — `(input as { name?: unknown }).name` or `input.systemId`.
|
|
10
|
+
// A consumer (or a hostile dependency that polluted a prototype) can
|
|
11
|
+
// install a THROWING accessor on the input object —
|
|
12
|
+
// `{ get name() { throw new Error("boom") } }` — and the bare read
|
|
13
|
+
// surfaces that arbitrary exception verbatim. Every resource's JSDoc
|
|
14
|
+
// promises a synchronous `TypeError` for malformed input; a throwing
|
|
15
|
+
// getter breaks that documented cross-SDK contract by leaking a
|
|
16
|
+
// non-`TypeError` (or a `TypeError` the SDK never authored) to the
|
|
17
|
+
// caller.
|
|
18
|
+
//
|
|
19
|
+
// `readInputField` wraps the read in a try/catch and re-throws a
|
|
20
|
+
// getter's exception as a `TypeError` — preserving the original error
|
|
21
|
+
// on `.cause` (the `errors.ts` cause-assignment pattern) — so the
|
|
22
|
+
// synchronous-`TypeError` input contract holds SDK-wide regardless of
|
|
23
|
+
// what the input object's accessors do.
|
|
24
|
+
/**
|
|
25
|
+
* Read a single field off a consumer-supplied input object, converting
|
|
26
|
+
* a throwing getter's exception into the SDK's documented `TypeError`
|
|
27
|
+
* input contract.
|
|
28
|
+
*
|
|
29
|
+
* The caller MUST have already confirmed `obj` is a non-null object
|
|
30
|
+
* (every resource does the top-level `typeof input === "object"` guard
|
|
31
|
+
* first). The read is a plain index access, so it walks the prototype
|
|
32
|
+
* chain identically to the bare `obj.key` it replaces — callers that
|
|
33
|
+
* need own-property semantics still gate on `Object.hasOwn` (the
|
|
34
|
+
* module-load snapshot) exactly as before; this helper only adds the
|
|
35
|
+
* throwing-getter → `TypeError` conversion.
|
|
36
|
+
*
|
|
37
|
+
* @param obj The consumer-supplied input object (already confirmed non-null).
|
|
38
|
+
* @param key The field name to read.
|
|
39
|
+
* @param context The calling method (e.g. `"abacPolicies.create"`) — prefixes the thrown message.
|
|
40
|
+
* @returns The field value (`undefined` if absent — same as a bare read).
|
|
41
|
+
* @throws {TypeError} If the field's getter throws — the getter's error is preserved on `.cause`.
|
|
42
|
+
*/
|
|
43
|
+
export function readInputField(obj, key, context) {
|
|
44
|
+
try {
|
|
45
|
+
return obj[key];
|
|
46
|
+
}
|
|
47
|
+
catch (cause) {
|
|
48
|
+
const err = new TypeError(`${context}: could not read input field \`${key}\` — its getter threw`);
|
|
49
|
+
// Preserve the native ES2022 cause chain — mirror of the
|
|
50
|
+
// `AttestryError` cause-assignment pattern in `errors.ts` (assigned
|
|
51
|
+
// post-construction rather than via the 2-arg `Error` constructor,
|
|
52
|
+
// for compile-target portability).
|
|
53
|
+
err.cause = cause;
|
|
54
|
+
throw err;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=safe-input-read.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"safe-input-read.js","sourceRoot":"","sources":["../../src/resources/safe-input-read.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,EAAE;AACF,kEAAkE;AAClE,yCAAyC;AACzC,EAAE;AACF,uEAAuE;AACvE,kEAAkE;AAClE,sEAAsE;AACtE,qEAAqE;AACrE,qEAAqE;AACrE,oDAAoD;AACpD,mEAAmE;AACnE,qEAAqE;AACrE,qEAAqE;AACrE,gEAAgE;AAChE,mEAAmE;AACnE,UAAU;AACV,EAAE;AACF,iEAAiE;AACjE,sEAAsE;AACtE,kEAAkE;AAClE,sEAAsE;AACtE,wCAAwC;AAExC;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,cAAc,CAC5B,GAAW,EACX,GAAW,EACX,OAAe;IAEf,IAAI,CAAC;QACH,OAAQ,GAA+B,CAAC,GAAG,CAAC,CAAC;IAC/C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,GAAG,GAAG,IAAI,SAAS,CACvB,GAAG,OAAO,kCAAkC,GAAG,uBAAuB,CACvE,CAAC;QACF,yDAAyD;QACzD,oEAAoE;QACpE,mEAAmE;QACnE,mCAAmC;QAClC,GAAmC,CAAC,KAAK,GAAG,KAAK,CAAC;QACnD,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,475 @@
|
|
|
1
|
+
import type { AttestryClient } from "../client.js";
|
|
2
|
+
import type { RequestOptions } from "../types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Stable enum-like reason codes returned in the `reason` field. CI
|
|
5
|
+
* clients key off these strings to render PR comments / build logs.
|
|
6
|
+
* Mirror of the kernel's `ShipGateReasonCode` at
|
|
7
|
+
* `src/lib/workflow/ship-gates.ts:65-68`. **Closed-enum at the type
|
|
8
|
+
* level; runtime validation is `typeof === "string"` only** (faithful
|
|
9
|
+
* courier — gate.evaluate carry-forward). If a future kernel emits
|
|
10
|
+
* a new reason code before the SDK is bumped, the value round-trips
|
|
11
|
+
* at runtime. Drift-pinned via the wire-shape build-round pin.
|
|
12
|
+
*/
|
|
13
|
+
export type ShipGateReasonCode = "awaiting_approvers" | "rejected" | "timed_out";
|
|
14
|
+
/**
|
|
15
|
+
* State of the ship-gate row. Mirror of the kernel's `ShipGateState`
|
|
16
|
+
* at `src/lib/workflow/ship-gates.ts:59`. **Closed-enum at the type
|
|
17
|
+
* level; runtime validation is `typeof === "string"` only** (faithful
|
|
18
|
+
* courier).
|
|
19
|
+
*/
|
|
20
|
+
export type ShipGateState = "gated" | "released" | "rejected" | "timed_out";
|
|
21
|
+
/**
|
|
22
|
+
* Input shape for `shipGate.check`. Source-of-truth at kernel
|
|
23
|
+
* `src/app/api/v1/ship-gate/check/route.ts:41-44` (Zod schema).
|
|
24
|
+
*
|
|
25
|
+
* **`systemId`** — REQUIRED RFC 4122 hyphenated UUID. The SDK
|
|
26
|
+
* pre-validates the format synchronously (`TypeError` for malformed
|
|
27
|
+
* input — D2). The SDK's runtime check always runs regardless of
|
|
28
|
+
* TypeScript types — `as any` casts do NOT bypass it. The kernel-side
|
|
29
|
+
* Zod validation (422 fallback) only fires for kernel rule changes
|
|
30
|
+
* the SDK hasn't synced to.
|
|
31
|
+
*
|
|
32
|
+
* **`attestationId`** — REQUIRED non-empty string of length 1-256.
|
|
33
|
+
* Identifies the specific build / attestation under consideration
|
|
34
|
+
* (e.g., a git SHA, a CI build number, an attestation hash). The
|
|
35
|
+
* kernel uses this together with `systemId` as the lookup key for
|
|
36
|
+
* the `ship_gates` table's UNIQUE `(org_id, system_id, attestation_id)`
|
|
37
|
+
* constraint — calling `check()` with the same tuple repeatedly is
|
|
38
|
+
* idempotent in the no-gate / released cases (no side effect beyond
|
|
39
|
+
* the audit-log entry) and reads the same gated/terminal verdict in
|
|
40
|
+
* the gated case (post-reconciliation). The SDK pre-validates length
|
|
41
|
+
* bounds against `MAX_ATTESTATION_ID_LENGTH = 256` (the kernel
|
|
42
|
+
* constant at `src/lib/workflow/ship-gates.ts:106`).
|
|
43
|
+
*/
|
|
44
|
+
export interface ShipGateInput {
|
|
45
|
+
/**
|
|
46
|
+
* UUID of the system to check. RFC 4122 hyphenated form
|
|
47
|
+
* (8-4-4-4-12 hex, case-insensitive). Required.
|
|
48
|
+
*/
|
|
49
|
+
systemId: string;
|
|
50
|
+
/**
|
|
51
|
+
* Build / attestation identifier (free-text 1-256 chars). Required.
|
|
52
|
+
* Forms a unique tuple with `systemId` for the `ship_gates` lookup
|
|
53
|
+
* — repeated calls on the same `(systemId, attestationId)` pair
|
|
54
|
+
* are idempotent (no side effect beyond the audit-log entry).
|
|
55
|
+
*/
|
|
56
|
+
attestationId: string;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Response shape returned by `shipGate.check`. **UNION of 4 emit
|
|
60
|
+
* shapes** keyed by the gate's existence + state:
|
|
61
|
+
*
|
|
62
|
+
* - **Shape A — no gate exists** (`gated: false` ONLY, 1 field):
|
|
63
|
+
* The default-permissive short-circuit — no `ship_gates` row
|
|
64
|
+
* for this `(systemId, attestationId)` tuple. The gate is
|
|
65
|
+
* opt-in; consumers who never create a gate never block a build.
|
|
66
|
+
* `state`, `executionId`, `chainId`, `reason`, and
|
|
67
|
+
* `approvers_pending` are ALL absent (own-property false).
|
|
68
|
+
* Source: kernel `ship-gates.ts:543-545`.
|
|
69
|
+
* - **Shape B — released** (4 fields): `{ gated: false, state:
|
|
70
|
+
* "released", executionId, chainId }`. The approval chain
|
|
71
|
+
* approved the deployment. `reason` and `approvers_pending` are
|
|
72
|
+
* absent. Source: kernel `ship-gates.ts:275-282`.
|
|
73
|
+
* - **Shape C — rejected or timed_out** (6 fields): `{ gated: true,
|
|
74
|
+
* reason: "rejected" | "timed_out", approvers_pending: [], state:
|
|
75
|
+
* "rejected" | "timed_out", executionId, chainId }`. The approval
|
|
76
|
+
* chain went terminal in a build-blocking state. `approvers_pending`
|
|
77
|
+
* is always `[]` (nobody is pending on a closed chain). Source:
|
|
78
|
+
* kernel `ship-gates.ts:283-302`.
|
|
79
|
+
* - **Shape D — gated awaiting approvers** (6 fields): `{ gated:
|
|
80
|
+
* true, reason: "awaiting_approvers", approvers_pending: [<UUIDs>],
|
|
81
|
+
* state: "gated", executionId, chainId }`. The approval chain is
|
|
82
|
+
* in-flight; `approvers_pending` lists the userIds still owed a
|
|
83
|
+
* decision (pool-order, post-decided filtering — see kernel
|
|
84
|
+
* `computeApproversPending` at `ship-gates.ts:169-205`). Source:
|
|
85
|
+
* kernel `ship-gates.ts:303-311`.
|
|
86
|
+
*
|
|
87
|
+
* **Discriminator pattern**: use `result.gated === true` (closed-enum
|
|
88
|
+
* boolean) to detect "build must block". Use `result.state` (when
|
|
89
|
+
* own-property present) to differentiate Shapes B / C / D. **Do NOT
|
|
90
|
+
* use `result.reason === undefined`** as a discriminator — a hostile
|
|
91
|
+
* dep polluting `Object.prototype.reason` makes the `=== undefined`
|
|
92
|
+
* check return false (reads the polluted value via prototype walk),
|
|
93
|
+
* silently misclassifying Shape A / B as Shape C / D. `gated` has
|
|
94
|
+
* an UNCONDITIONAL own-property check in the validator (every code
|
|
95
|
+
* path reads `obj.gated` first); branching on it is pollution-safe.
|
|
96
|
+
*
|
|
97
|
+
* **`approvers_pending` is SNAKE_CASE on the wire** — asymmetric with
|
|
98
|
+
* the rest of the SDK's camelCase response surface. The kernel
|
|
99
|
+
* emits the literal field name `approvers_pending` (mirror of master
|
|
100
|
+
* plan spec contract). Consumers must use the snake_case spelling.
|
|
101
|
+
*/
|
|
102
|
+
export interface ShipGateCheckResponse {
|
|
103
|
+
/**
|
|
104
|
+
* `true` iff CI/CD must block the build. ALWAYS-PRESENT anchor
|
|
105
|
+
* field. Closed-enum boolean — pollution-safe discriminator for
|
|
106
|
+
* "build must block" decisions.
|
|
107
|
+
*/
|
|
108
|
+
gated: boolean;
|
|
109
|
+
/**
|
|
110
|
+
* Stable reason code. **PRESENT ONLY when `gated: true`** (Shapes
|
|
111
|
+
* C + D). Closed-enum at the type level (`"awaiting_approvers" |
|
|
112
|
+
* "rejected" | "timed_out"`); runtime is open (faithful courier —
|
|
113
|
+
* validator checks `typeof === "string"` only). Drift-pinned via
|
|
114
|
+
* the wire-shape build-round pin.
|
|
115
|
+
*
|
|
116
|
+
* **Discriminator safety**: do NOT use `result.reason === undefined`
|
|
117
|
+
* for Shape A/B vs C/D detection (prototype walk reads polluted
|
|
118
|
+
* values under `Object.prototype.reason` pollution). Branch on
|
|
119
|
+
* `result.gated === true` (the only pollution-safe consumer-side
|
|
120
|
+
* discriminator).
|
|
121
|
+
*/
|
|
122
|
+
reason?: ShipGateReasonCode;
|
|
123
|
+
/**
|
|
124
|
+
* UserIds still owed a decision (pool-order). **PRESENT ONLY when
|
|
125
|
+
* `gated: true`** (Shapes C + D). On Shape C (rejected /
|
|
126
|
+
* timed_out): always `[]` (nobody is pending on a closed chain).
|
|
127
|
+
* On Shape D (awaiting_approvers): the list of pending userIds
|
|
128
|
+
* computed by `computeApproversPending` (serial-mode preserves
|
|
129
|
+
* pool order from currentStep onward; parallel-mode returns ALL
|
|
130
|
+
* non-decided pool members; escalation user appended IFF
|
|
131
|
+
* `lastEscalatedAt` is set).
|
|
132
|
+
*
|
|
133
|
+
* **SNAKE_CASE wire field name** — asymmetric with the rest of
|
|
134
|
+
* the SDK's camelCase response surface. The kernel emits the
|
|
135
|
+
* literal field name `approvers_pending` (master plan spec
|
|
136
|
+
* contract). Consumers must use the snake_case spelling to read
|
|
137
|
+
* the field.
|
|
138
|
+
*
|
|
139
|
+
* **Discriminator safety**: do NOT use
|
|
140
|
+
* `result.approvers_pending === undefined` (prototype walk under
|
|
141
|
+
* `Object.prototype.approvers_pending` pollution returns the
|
|
142
|
+
* polluted value). Branch on `result.gated === true` first.
|
|
143
|
+
*/
|
|
144
|
+
approvers_pending?: string[];
|
|
145
|
+
/**
|
|
146
|
+
* Diagnostic — gate's resolved state after reconciliation.
|
|
147
|
+
* **PRESENT in Shapes B + C + D, ABSENT in Shape A** (no gate
|
|
148
|
+
* exists). Closed-enum at the type level (`"gated" | "released" |
|
|
149
|
+
* "rejected" | "timed_out"`); runtime is open (faithful courier).
|
|
150
|
+
*
|
|
151
|
+
* **Discriminator safety**: do NOT use `result.state === undefined`
|
|
152
|
+
* for Shape A vs B detection (prototype walk under
|
|
153
|
+
* `Object.prototype.state` pollution returns the polluted value).
|
|
154
|
+
* Branch on `result.gated === true` first; for Shape A vs B
|
|
155
|
+
* specifically, neither `result.state === undefined` NOR
|
|
156
|
+
* `Object.hasOwn(result, "state")` is fully pollution-safe on the
|
|
157
|
+
* CONSUMER side (the live `Object.hasOwn` can itself be overridden;
|
|
158
|
+
* only the SDK's module-load snapshot guards its internal
|
|
159
|
+
* validator). For consumer-side defense, prefer
|
|
160
|
+
* `result.gated === false` (anchor field is always own-present and
|
|
161
|
+
* pollution-safe) AND treat the no-state branch as Shape A.
|
|
162
|
+
*/
|
|
163
|
+
state?: ShipGateState;
|
|
164
|
+
/**
|
|
165
|
+
* Diagnostic — UUID of the approval-chain execution backing the
|
|
166
|
+
* gate. **PRESENT in Shapes B + C + D, ABSENT in Shape A**. The
|
|
167
|
+
* kernel column is `uuid` (PostgreSQL `uuid` type, source of truth);
|
|
168
|
+
* the SDK does not re-validate UUID format at runtime — faithful
|
|
169
|
+
* courier for the kernel's column constraint.
|
|
170
|
+
*
|
|
171
|
+
* **Discriminator safety**: same as `state` — branch on
|
|
172
|
+
* `result.gated` first; `executionId === undefined` is NOT a
|
|
173
|
+
* pollution-safe discriminator.
|
|
174
|
+
*/
|
|
175
|
+
executionId?: string;
|
|
176
|
+
/**
|
|
177
|
+
* Diagnostic — UUID of the approval-chain template backing the
|
|
178
|
+
* execution. **PRESENT in Shapes B + C + D, ABSENT in Shape A**.
|
|
179
|
+
* Same `uuid`-column source-of-truth posture as `executionId`.
|
|
180
|
+
*
|
|
181
|
+
* **Discriminator safety**: same as `state` — branch on
|
|
182
|
+
* `result.gated` first; `chainId === undefined` is NOT a
|
|
183
|
+
* pollution-safe discriminator.
|
|
184
|
+
*/
|
|
185
|
+
chainId?: string;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* `shipGate` resource — sibling to `IncidentsResource`,
|
|
189
|
+
* `DecisionsResource`, `ChatResource`, `AuditLogResource`,
|
|
190
|
+
* `RegulatoryChangesResource`, `ComplianceCheckResource`,
|
|
191
|
+
* `CheckResource`, `GateResource`, `BatchResource`. Today wraps a
|
|
192
|
+
* single endpoint (`check`); the class is the landing pad for future
|
|
193
|
+
* ship-gate methods if the kernel adds them (resource-class-per-
|
|
194
|
+
* kernel-resource convention, invariant #43).
|
|
195
|
+
*/
|
|
196
|
+
export declare class ShipGateResource {
|
|
197
|
+
private readonly client;
|
|
198
|
+
constructor(client: AttestryClient);
|
|
199
|
+
/**
|
|
200
|
+
* Check whether a CI/CD build is gated by an in-flight approval
|
|
201
|
+
* chain. Returns a four-shape verdict keyed by the gate's
|
|
202
|
+
* existence + state. Designed for pipeline integration (GitHub
|
|
203
|
+
* Actions / GitLab CI / Buildkite).
|
|
204
|
+
*
|
|
205
|
+
* **Four emit shapes** — the response shape varies by the gate's
|
|
206
|
+
* existence + state:
|
|
207
|
+
* - **Shape A — no gate exists**: `{ gated: false }` (1 field —
|
|
208
|
+
* default-permissive, opt-in gate semantics).
|
|
209
|
+
* - **Shape B — released**: `{ gated: false, state: "released",
|
|
210
|
+
* executionId, chainId }` (4 fields).
|
|
211
|
+
* - **Shape C — rejected / timed_out**: `{ gated: true, reason:
|
|
212
|
+
* "rejected" | "timed_out", approvers_pending: [], state, ... }`
|
|
213
|
+
* (6 fields; `approvers_pending` always `[]` on closed chain).
|
|
214
|
+
* - **Shape D — gated awaiting approvers**: `{ gated: true,
|
|
215
|
+
* reason: "awaiting_approvers", approvers_pending: [<UUIDs>],
|
|
216
|
+
* state: "gated", ... }` (6 fields; `approvers_pending` lists
|
|
217
|
+
* pending userIds).
|
|
218
|
+
*
|
|
219
|
+
* **`approvers_pending` is SNAKE_CASE on the wire** — the kernel
|
|
220
|
+
* emits the literal field name `approvers_pending` (asymmetric
|
|
221
|
+
* with the rest of the SDK's camelCase response surface). The SDK
|
|
222
|
+
* preserves this verbatim; consumers must use the snake_case
|
|
223
|
+
* spelling.
|
|
224
|
+
*
|
|
225
|
+
* **Multi-permission UNION auth scope**: kernel uses
|
|
226
|
+
* `requireApiKeyWithPermission(req, READ_SYSTEMS, READ_ASSESSMENTS)`
|
|
227
|
+
* which is OR semantics (`Array.some()` at
|
|
228
|
+
* `permissions.ts:53-55`). A key with EITHER permission (or
|
|
229
|
+
* `ADMIN`, or null/empty permissions for backwards-compat)
|
|
230
|
+
* succeeds. **HTTP 401** for no/invalid API key, **HTTP 403** for
|
|
231
|
+
* an authenticated key that has NEITHER required permission. Pin
|
|
232
|
+
* BOTH branches separately. Carry-forward invariant #45.
|
|
233
|
+
* **NOTE — argument order is READ_SYSTEMS FIRST** (asymmetric
|
|
234
|
+
* with `check.run` and `gate.evaluate` which list READ_ASSESSMENTS
|
|
235
|
+
* first); `Array.some()` is order-insensitive, but drift-pinned
|
|
236
|
+
* exact-arglist in the spec-diff round catches a kernel-side
|
|
237
|
+
* rename or reordering.
|
|
238
|
+
*
|
|
239
|
+
* **Discriminator pattern**: branch on `result.gated === true`
|
|
240
|
+
* (closed-enum boolean) to detect "build must block". The SDK's
|
|
241
|
+
* P2 validator guarantees `gated` is ALWAYS an own-property of
|
|
242
|
+
* the returned object — that's the only consumer-side discriminator
|
|
243
|
+
* that is genuinely pollution-safe (no prototype-walk hazard).
|
|
244
|
+
*
|
|
245
|
+
* **Do NOT use `result.reason === undefined`** as a discriminator
|
|
246
|
+
* — a hostile dep polluting `Object.prototype.reason` makes the
|
|
247
|
+
* `=== undefined` check return false (reads via prototype walk),
|
|
248
|
+
* silently misclassifying Shape A / B as Shape C / D.
|
|
249
|
+
*
|
|
250
|
+
* **Consumer-side `Object.hasOwn(result, "state")` is NOT a fully
|
|
251
|
+
* safe alternative** — it relies on the LIVE global `Object.hasOwn`,
|
|
252
|
+
* which is itself subject to override by a hostile dep
|
|
253
|
+
* (`Object.hasOwn = () => true`). The SDK's own response-side
|
|
254
|
+
* validator uses a module-load snapshot of `Object.hasOwn` (taken
|
|
255
|
+
* at SDK import time, before consumer-graph deps load) so the
|
|
256
|
+
* SDK-internal validation is hardened; consumer code calling the
|
|
257
|
+
* live `Object.hasOwn` after the SDK resolves is not. For
|
|
258
|
+
* consumer-side defense-in-depth, branch on `result.gated` first
|
|
259
|
+
* (the safe boolean), and only inspect `result.state` after.
|
|
260
|
+
*
|
|
261
|
+
* **Reconciliation-on-read inside transaction** — when the linked
|
|
262
|
+
* `approval_chain_executions` row has gone terminal but the
|
|
263
|
+
* `ship_gates` row still says `gated`, the kernel's `checkShipGate`
|
|
264
|
+
* advances the gate to the corresponding terminal state inside
|
|
265
|
+
* `SELECT … FOR UPDATE` (`ship-gates.ts:567-584`). The SDK does
|
|
266
|
+
* NOT observe the reconciliation step — only the post-reconciliation
|
|
267
|
+
* shape. A consumer calling `check()` twice in quick succession
|
|
268
|
+
* on a chain that just completed sees the gated-state shape on
|
|
269
|
+
* call 1 (if reconciliation hadn't fired yet) and the terminal
|
|
270
|
+
* shape on call 2. Faithful courier; documented kernel behavior.
|
|
271
|
+
*
|
|
272
|
+
* **`writeAuditLog` side effect** — every `shipGate.check(...)`
|
|
273
|
+
* call writes one audit-log entry with `action: "ship_gate.checked"`
|
|
274
|
+
* and `resourceType: "ship_gate"` (route.ts:73-87; both strings
|
|
275
|
+
* drift-pinned). SIEM / observability consumers keying off either
|
|
276
|
+
* field for filter setup should depend on both staying stable.
|
|
277
|
+
* Properties of the write:
|
|
278
|
+
* - Org-scoped, hash-chained (per `writeAuditLog`).
|
|
279
|
+
* - **Time-blocking** but error-tolerant: the kernel uses
|
|
280
|
+
* `await writeAuditLog(...)`, which awaits two DB ops (SELECT
|
|
281
|
+
* previous-hash + INSERT new entry). The check response
|
|
282
|
+
* latency INCLUDES the audit-log write time — a slow audit-log
|
|
283
|
+
* DB will delay every `shipGate.check()` response. Error
|
|
284
|
+
* semantics ARE non-blocking: `writeAuditLog` wraps its body
|
|
285
|
+
* in a try/catch that swallows + logs errors, so a write
|
|
286
|
+
* FAILURE does NOT fail the check request.
|
|
287
|
+
* - NOT counted against `decisionsPerMonth` quota (read-shaped).
|
|
288
|
+
* Invariant #53 carry-forward (matches `gate.evaluate`'s pattern).
|
|
289
|
+
*
|
|
290
|
+
* **Kernel-side 15-second timeout** (`maxDuration = 15` at
|
|
291
|
+
* `route.ts:24`). **Same as `gate.evaluate`'s 15s; tighter than
|
|
292
|
+
* `auditLog.verifyChain`'s 30s.** The SDK does NOT enforce a
|
|
293
|
+
* client-side timeout (consumers manage via `options.signal`),
|
|
294
|
+
* but the kernel's function-runtime cap bounds the request
|
|
295
|
+
* latency on the server side. CI pipeline timeouts should budget
|
|
296
|
+
* relative to this cap.
|
|
297
|
+
*
|
|
298
|
+
* **Documented kernel-side cascade-gap surfaces — TWO distinct
|
|
299
|
+
* paths**:
|
|
300
|
+
* 1. **Execution-missing → HTTP 404** (named-error path). The
|
|
301
|
+
* kernel maps `ShipGateExecutionNotFoundError` to 404 at
|
|
302
|
+
* route.ts:97-99. Thrown by `checkShipGate` only when the
|
|
303
|
+
* inner `executionRows.length === 0` defensive branch fires
|
|
304
|
+
* (`ship-gates.ts:559-564`).
|
|
305
|
+
* 2. **Chain-missing → HTTP 500 (scrubbed)** (plain-Error path).
|
|
306
|
+
* A SEPARATE defensive branch at `ship-gates.ts:610-617`
|
|
307
|
+
* throws a PLAIN `Error` (NOT a named class) when a
|
|
308
|
+
* ship_gate → execution → chain reference is broken on the
|
|
309
|
+
* LAST hop. The route's catch block has only three
|
|
310
|
+
* `instanceof` arms (`AuthError`, `BodyParseError`,
|
|
311
|
+
* `ShipGateExecutionNotFoundError`); a plain `Error` falls
|
|
312
|
+
* through to `internalErrorResponse → 500` with the scrubbed
|
|
313
|
+
* message "An internal error occurred. Please try again
|
|
314
|
+
* later." The caller cannot distinguish this cascade-gap
|
|
315
|
+
* from any other internal error via the HTTP status alone.
|
|
316
|
+
* Both branches are unreachable in normal operation (RESTRICT FK
|
|
317
|
+
* + filter-by-orgId); both documented as "only reachable via
|
|
318
|
+
* direct DB intervention or a cascade-behavior gap." Faithful
|
|
319
|
+
* courier: the SDK surfaces whichever status the kernel chose
|
|
320
|
+
* (404 vs 500), but SIEM consumers running cascade-gap-404
|
|
321
|
+
* filters should know the second branch hides as 500.
|
|
322
|
+
*
|
|
323
|
+
* Errors — **happy-path precedence ordering** is rate-limit → auth
|
|
324
|
+
* → Zod body validation → DB lookup → successResponse. A request
|
|
325
|
+
* with multiple happy-path problems surfaces ONLY the highest-
|
|
326
|
+
* precedence one. **The 500-catchall is a SEPARATE DIMENSION** —
|
|
327
|
+
* any throwable not matched by the named `instanceof` arms (see
|
|
328
|
+
* the 500 bullet below) falls to 500, regardless of where in the
|
|
329
|
+
* happy-path it fired. So e.g. a Zod-library crash during body
|
|
330
|
+
* parsing surfaces as 500 (NOT 422).
|
|
331
|
+
* - `AttestryAPIError` (status 429) — rate limit FIRES FIRST
|
|
332
|
+
* (auto-retried by default — invariant #18; per-IP rate-limit
|
|
333
|
+
* key `v1-ship-gate-check:${ip}` against the standard
|
|
334
|
+
* `apiLimiter`).
|
|
335
|
+
* - `AttestryAPIError` (status 401) — no API key OR invalid key.
|
|
336
|
+
* Fires AFTER rate-limit but BEFORE input validation.
|
|
337
|
+
* - `AttestryAPIError` (status 403) — authenticated key has
|
|
338
|
+
* NEITHER `READ_SYSTEMS` nor `READ_ASSESSMENTS`. Single test
|
|
339
|
+
* case — the union-auth pattern collapses three intuition-
|
|
340
|
+
* suggesting cases to one.
|
|
341
|
+
* - `AttestryAPIError` (status 422) — Zod schema rejection
|
|
342
|
+
* (kernel's `BodyParseError` surface — `parseBody(request,
|
|
343
|
+
* checkSchema)` failed). **Fires BEFORE the cascade-gap 404
|
|
344
|
+
* lookup**. `apiErr.details` carries the full kernel error
|
|
345
|
+
* body verbatim (the transport does NOT strip the
|
|
346
|
+
* `{success:false, ...}` envelope on error responses — only
|
|
347
|
+
* the `{success:true, data}` envelope on success). The wire
|
|
348
|
+
* shape is: `{success: false, error: "Validation failed.",
|
|
349
|
+
* details: Array<{path: string; message: string}>}` — `error`
|
|
350
|
+
* is the literal string "Validation failed." (with trailing
|
|
351
|
+
* period), `details` is an array (NOT a keyed map) of `{path,
|
|
352
|
+
* message}` pairs derived from Zod's `result.error.errors`.
|
|
353
|
+
* **The SDK pre-validates both closed-spec rules** (UUID
|
|
354
|
+
* format on systemId, length 1-256 on attestationId) AND the
|
|
355
|
+
* runtime checks always run regardless of TypeScript types —
|
|
356
|
+
* `as any` casts do NOT bypass them. So 422 reaches consumers
|
|
357
|
+
* ONLY via kernel rule changes the SDK hasn't synced to.
|
|
358
|
+
* Invariant #51.
|
|
359
|
+
* - `AttestryAPIError` (status 404) — cascade-gap rare path:
|
|
360
|
+
* kernel threw `ShipGateExecutionNotFoundError` because a
|
|
361
|
+
* `ship_gates` row references an `executionId` whose row is
|
|
362
|
+
* missing in `approval_chain_executions`. Documented as "only
|
|
363
|
+
* reachable via direct DB intervention".
|
|
364
|
+
* - `AttestryAPIError` (status 500) — internal kernel error
|
|
365
|
+
* (scrubbed message via `internalErrorResponse`). **The 500
|
|
366
|
+
* surface is orthogonal to the precedence list above**: ANY
|
|
367
|
+
* throwable not matched by the three named `instanceof` arms
|
|
368
|
+
* (`AuthError` 401/403, `BodyParseError` 422,
|
|
369
|
+
* `ShipGateExecutionNotFoundError` 404) — INCLUDING throwables
|
|
370
|
+
* that fire DURING any of the happy-path steps — falls to
|
|
371
|
+
* 500. **Includes the chain-missing cascade-gap** (the second
|
|
372
|
+
* defensive branch in `checkShipGate` at `ship-gates.ts:
|
|
373
|
+
* 610-617` throws a plain `Error` that hides as 500, NOT as a
|
|
374
|
+
* named 404 surface).
|
|
375
|
+
* - `AttestryError` ("request aborted by caller") — caller-
|
|
376
|
+
* supplied `options.signal` fired (pre-aborted or mid-flight).
|
|
377
|
+
* - `AttestryError` (P2 hardening) — kernel response failed
|
|
378
|
+
* SDK-side shape validation (not an object, wrong type on
|
|
379
|
+
* `gated`, wrong type on any optional own-property field).
|
|
380
|
+
* - `AttestryAPIError` (P3 hardening) — kernel response had a
|
|
381
|
+
* wrong Content-Type (transport-level guard before body
|
|
382
|
+
* parsing).
|
|
383
|
+
* - `TypeError` (synchronous, no fetch issued) — input failed
|
|
384
|
+
* SDK-side validation (null / array / non-object input,
|
|
385
|
+
* missing systemId, invalid UUID format, missing attestationId,
|
|
386
|
+
* non-string attestationId, attestationId length out of
|
|
387
|
+
* range [1, 256]).
|
|
388
|
+
*
|
|
389
|
+
* **Notably ABSENT**:
|
|
390
|
+
* - **No 400** — all input validation is Zod (422).
|
|
391
|
+
* - **No 402** — read-shaped, doesn't count against
|
|
392
|
+
* decisionsPerMonth quota (despite the audit-log side effect).
|
|
393
|
+
* - **No 413** — body size limit not explicit.
|
|
394
|
+
*
|
|
395
|
+
* **SDK-side validation** (synchronous `TypeError`, no fetch
|
|
396
|
+
* issued):
|
|
397
|
+
* - `input` itself: required; must be a non-null, non-array
|
|
398
|
+
* object.
|
|
399
|
+
* - `input.systemId`: required own-property (Object.hasOwn
|
|
400
|
+
* defends against prototype pollution lying about presence —
|
|
401
|
+
* generalization of invariant #48); must be a non-empty
|
|
402
|
+
* string; must match the RFC 4122 hyphenated UUID format
|
|
403
|
+
* (D2 — SDK pre-validates closed-spec rule). No
|
|
404
|
+
* lone-surrogate URIError defense (POST body uses
|
|
405
|
+
* JSON.stringify).
|
|
406
|
+
* - `input.attestationId`: required own-property; must be a
|
|
407
|
+
* non-empty string; length 1-256 (matches kernel constant
|
|
408
|
+
* `MAX_ATTESTATION_ID_LENGTH = 256` at
|
|
409
|
+
* `src/lib/workflow/ship-gates.ts:106`).
|
|
410
|
+
*
|
|
411
|
+
* **Response-shape validation** (P2 hardening — symmetric defense
|
|
412
|
+
* on response side per the module-load `objectHasOwn` snapshot;
|
|
413
|
+
* mirror of `gate.ts` / `audit-log.ts` patterns):
|
|
414
|
+
* - Rejects with `AttestryError` if the kernel response isn't
|
|
415
|
+
* a non-null, non-array object.
|
|
416
|
+
* - Rejects if `gated` isn't a boolean (ALWAYS-present anchor
|
|
417
|
+
* field — the validator's `gated` branch is UNCONDITIONAL).
|
|
418
|
+
* - Rejects if `reason` (when own-present) isn't a string.
|
|
419
|
+
* - Rejects if `approvers_pending` (when own-present) isn't an
|
|
420
|
+
* array.
|
|
421
|
+
* - Rejects if `state` (when own-present) isn't a string.
|
|
422
|
+
* - Rejects if `executionId` / `chainId` (when own-present)
|
|
423
|
+
* aren't strings.
|
|
424
|
+
* - Each response field read goes through the module-load
|
|
425
|
+
* `objectHasOwn` snapshot — defends against
|
|
426
|
+
* `Object.prototype.<field>` pollution masking a missing field.
|
|
427
|
+
* - Per-element shape on `approvers_pending` (each element must
|
|
428
|
+
* be a string) is validated when the field is own-present.
|
|
429
|
+
*
|
|
430
|
+
* **Transport-shape validation** (P3 hardening):
|
|
431
|
+
* - Rejects with `AttestryAPIError` if the kernel responds with
|
|
432
|
+
* a non-`application/json` Content-Type.
|
|
433
|
+
*
|
|
434
|
+
* @example Basic ship-gate check (typical CI usage)
|
|
435
|
+
* ```ts
|
|
436
|
+
* const verdict = await client.shipGate.check({
|
|
437
|
+
* systemId: "11111111-1111-1111-1111-111111111111",
|
|
438
|
+
* attestationId: "build-1234",
|
|
439
|
+
* });
|
|
440
|
+
* if (verdict.gated) {
|
|
441
|
+
* // Shape C or D — build must block.
|
|
442
|
+
* if (verdict.reason === "awaiting_approvers") {
|
|
443
|
+
* // Shape D — list pending approvers in PR comment.
|
|
444
|
+
* console.error(
|
|
445
|
+
* `Awaiting approval from ${verdict.approvers_pending?.join(", ")}`,
|
|
446
|
+
* );
|
|
447
|
+
* } else {
|
|
448
|
+
* // Shape C — rejected or timed_out.
|
|
449
|
+
* console.error(`Build blocked: ${verdict.reason}`);
|
|
450
|
+
* }
|
|
451
|
+
* process.exit(1);
|
|
452
|
+
* }
|
|
453
|
+
* // Shape A (no gate) or Shape B (released) — build proceeds.
|
|
454
|
+
* console.log("OK to deploy.");
|
|
455
|
+
* ```
|
|
456
|
+
*
|
|
457
|
+
* @example Discriminate Shape A vs Shape B (no-gate vs released)
|
|
458
|
+
* ```ts
|
|
459
|
+
* const verdict = await client.shipGate.check({
|
|
460
|
+
* systemId: "11111111-1111-1111-1111-111111111111",
|
|
461
|
+
* attestationId: "build-1234",
|
|
462
|
+
* });
|
|
463
|
+
* if (!verdict.gated) {
|
|
464
|
+
* if (verdict.state === "released") {
|
|
465
|
+
* console.log(`Approved (execution: ${verdict.executionId})`);
|
|
466
|
+
* } else {
|
|
467
|
+
* // No state field → Shape A (no gate exists).
|
|
468
|
+
* console.log("No gate configured for this build.");
|
|
469
|
+
* }
|
|
470
|
+
* }
|
|
471
|
+
* ```
|
|
472
|
+
*/
|
|
473
|
+
check(input: ShipGateInput, options?: RequestOptions): Promise<ShipGateCheckResponse>;
|
|
474
|
+
}
|
|
475
|
+
//# sourceMappingURL=ship-gate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ship-gate.d.ts","sourceRoot":"","sources":["../../src/resources/ship-gate.ts"],"names":[],"mappings":"AAsMA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEnD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAgClD;;;;;;;;;GASG;AACH,MAAM,MAAM,kBAAkB,GAC1B,oBAAoB,GACpB,UAAU,GACV,WAAW,CAAC;AAEhB;;;;;GAKG;AACH,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,UAAU,GAAG,UAAU,GAAG,WAAW,CAAC;AAE5E;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,WAAW,aAAa;IAC5B;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;OAKG;IACH,aAAa,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;;OAIG;IACH,KAAK,EAAE,OAAO,CAAC;IACf;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,EAAE,kBAAkB,CAAC;IAC5B;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B;;;;;;;;;;;;;;;;;OAiBG;IACH,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB;;;;;;;;;;OAUG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;;;OAQG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;GAQG;AACH,qBAAa,gBAAgB;IACf,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,cAAc;IAEnD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAiRG;IACH,KAAK,CACH,KAAK,EAAE,aAAa,EACpB,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,qBAAqB,CAAC;CAmGlC"}
|