@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.
Files changed (99) hide show
  1. package/LICENSE +190 -0
  2. package/README.md +1269 -0
  3. package/dist/client.d.ts +58 -0
  4. package/dist/client.d.ts.map +1 -0
  5. package/dist/client.js +74 -0
  6. package/dist/client.js.map +1 -0
  7. package/dist/constants.d.ts +7 -0
  8. package/dist/constants.d.ts.map +1 -0
  9. package/dist/constants.js +43 -0
  10. package/dist/constants.js.map +1 -0
  11. package/dist/errors.d.ts +16 -0
  12. package/dist/errors.d.ts.map +1 -0
  13. package/dist/errors.js +41 -0
  14. package/dist/errors.js.map +1 -0
  15. package/dist/index.d.ts +17 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +20 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/lines-parser.d.ts +50 -0
  20. package/dist/lines-parser.d.ts.map +1 -0
  21. package/dist/lines-parser.js +211 -0
  22. package/dist/lines-parser.js.map +1 -0
  23. package/dist/ndjson-parser.d.ts +57 -0
  24. package/dist/ndjson-parser.d.ts.map +1 -0
  25. package/dist/ndjson-parser.js +245 -0
  26. package/dist/ndjson-parser.js.map +1 -0
  27. package/dist/resources/abac-policies.d.ts +1034 -0
  28. package/dist/resources/abac-policies.d.ts.map +1 -0
  29. package/dist/resources/abac-policies.js +1519 -0
  30. package/dist/resources/abac-policies.js.map +1 -0
  31. package/dist/resources/audit-log.d.ts +588 -0
  32. package/dist/resources/audit-log.d.ts.map +1 -0
  33. package/dist/resources/audit-log.js +629 -0
  34. package/dist/resources/audit-log.js.map +1 -0
  35. package/dist/resources/batch.d.ts +845 -0
  36. package/dist/resources/batch.d.ts.map +1 -0
  37. package/dist/resources/batch.js +1074 -0
  38. package/dist/resources/batch.js.map +1 -0
  39. package/dist/resources/chat.d.ts +151 -0
  40. package/dist/resources/chat.d.ts.map +1 -0
  41. package/dist/resources/chat.js +124 -0
  42. package/dist/resources/chat.js.map +1 -0
  43. package/dist/resources/check.d.ts +348 -0
  44. package/dist/resources/check.d.ts.map +1 -0
  45. package/dist/resources/check.js +543 -0
  46. package/dist/resources/check.js.map +1 -0
  47. package/dist/resources/compliance-check.d.ts +330 -0
  48. package/dist/resources/compliance-check.d.ts.map +1 -0
  49. package/dist/resources/compliance-check.js +402 -0
  50. package/dist/resources/compliance-check.js.map +1 -0
  51. package/dist/resources/decisions.d.ts +1208 -0
  52. package/dist/resources/decisions.d.ts.map +1 -0
  53. package/dist/resources/decisions.js +1362 -0
  54. package/dist/resources/decisions.js.map +1 -0
  55. package/dist/resources/evidence-pack.d.ts +1080 -0
  56. package/dist/resources/evidence-pack.d.ts.map +1 -0
  57. package/dist/resources/evidence-pack.js +1789 -0
  58. package/dist/resources/evidence-pack.js.map +1 -0
  59. package/dist/resources/gate.d.ts +613 -0
  60. package/dist/resources/gate.d.ts.map +1 -0
  61. package/dist/resources/gate.js +737 -0
  62. package/dist/resources/gate.js.map +1 -0
  63. package/dist/resources/incidents.d.ts +136 -0
  64. package/dist/resources/incidents.d.ts.map +1 -0
  65. package/dist/resources/incidents.js +229 -0
  66. package/dist/resources/incidents.js.map +1 -0
  67. package/dist/resources/regulatory-changes.d.ts +307 -0
  68. package/dist/resources/regulatory-changes.d.ts.map +1 -0
  69. package/dist/resources/regulatory-changes.js +365 -0
  70. package/dist/resources/regulatory-changes.js.map +1 -0
  71. package/dist/resources/safe-input-read.d.ts +21 -0
  72. package/dist/resources/safe-input-read.d.ts.map +1 -0
  73. package/dist/resources/safe-input-read.js +57 -0
  74. package/dist/resources/safe-input-read.js.map +1 -0
  75. package/dist/resources/ship-gate.d.ts +475 -0
  76. package/dist/resources/ship-gate.d.ts.map +1 -0
  77. package/dist/resources/ship-gate.js +727 -0
  78. package/dist/resources/ship-gate.js.map +1 -0
  79. package/dist/resources/vision.d.ts +540 -0
  80. package/dist/resources/vision.d.ts.map +1 -0
  81. package/dist/resources/vision.js +1036 -0
  82. package/dist/resources/vision.js.map +1 -0
  83. package/dist/retry.d.ts +103 -0
  84. package/dist/retry.d.ts.map +1 -0
  85. package/dist/retry.js +224 -0
  86. package/dist/retry.js.map +1 -0
  87. package/dist/sse-parser.d.ts +64 -0
  88. package/dist/sse-parser.d.ts.map +1 -0
  89. package/dist/sse-parser.js +271 -0
  90. package/dist/sse-parser.js.map +1 -0
  91. package/dist/transport.d.ts +142 -0
  92. package/dist/transport.d.ts.map +1 -0
  93. package/dist/transport.js +455 -0
  94. package/dist/transport.js.map +1 -0
  95. package/dist/types.d.ts +61 -0
  96. package/dist/types.d.ts.map +1 -0
  97. package/dist/types.js +3 -0
  98. package/dist/types.js.map +1 -0
  99. package/package.json +44 -0
@@ -0,0 +1,613 @@
1
+ import type { AttestryClient } from "../client.js";
2
+ import type { RequestOptions } from "../types.js";
3
+ /**
4
+ * Input shape for `gate.evaluate`. Source-of-truth at kernel
5
+ * `src/app/api/v1/gate/route.ts:31-36` (Zod schema).
6
+ *
7
+ * **`systemId`** — REQUIRED RFC 4122 hyphenated UUID. The SDK
8
+ * pre-validates the format synchronously (`TypeError` for malformed
9
+ * input — D2). The SDK's runtime check always runs regardless of
10
+ * TypeScript types — `as any` casts do NOT bypass it. The kernel-side
11
+ * Zod validation (422 fallback) only fires for kernel rule changes
12
+ * the SDK hasn't synced to.
13
+ *
14
+ * **`minScore`** — OPTIONAL integer in `[0, 100]`. **Defaults to 70
15
+ * kernel-side** (Zod `.default(70)`) when the SDK omits the field
16
+ * from the body. Consumers who omit this get the implicit threshold
17
+ * of 70 — a non-obvious default (carry-forward #44). Pre-validated
18
+ * by the SDK: `typeof === "number"`, `Number.isInteger`, bounds
19
+ * `[0, 100]` inclusive (`Number.isInteger` already rejects NaN /
20
+ * Infinity, so no separate Number.isFinite check needed).
21
+ *
22
+ * **`frameworks`** — OPTIONAL array of up to 20 framework identifiers;
23
+ * each string of length 1-100. **Substring + case-insensitive
24
+ * matching** (kernel uses `aFrameworks.some((af) =>
25
+ * af.toLowerCase().includes(f.toLowerCase()))` at route.ts:94-96).
26
+ * **Asymmetric with `check.run`'s OR-overlap exact-equality** —
27
+ * gate's looser substring match means `["GDPR"]` matches an
28
+ * assessment with frameworks `["EU_GDPR_2024"]`, `["gdpr_compliance_v2"]`,
29
+ * etc. When omitted (or empty), the kernel considers all completed
30
+ * assessments. Empty array `[]` is accepted (Zod `.max(20)` permits
31
+ * length 0; the kernel's `length > 0` guard at route.ts:90 short-
32
+ * circuits the filter to "no filter").
33
+ *
34
+ * Open-spec field — the kernel does NOT enforce a closed enum of
35
+ * valid framework names; any string within the length bounds is
36
+ * accepted. Consumers should align their filter values with the
37
+ * framework identifiers they used when creating assessments
38
+ * (substring matching is forgiving but not magical).
39
+ *
40
+ * **`failOnMissingAssessment`** — OPTIONAL boolean. **Defaults to
41
+ * `true` kernel-side** (Zod `.default(true)`) when the SDK omits the
42
+ * field from the body. Consumers who omit this get strict behavior
43
+ * (no assessment = fail). Pre-validated by the SDK: `typeof ===
44
+ * "boolean"` (rejects truthy/falsy non-booleans like `1` / `"true"` /
45
+ * `null`). Both defaults documented prominently per carry-forward
46
+ * #44.
47
+ */
48
+ export interface GateInput {
49
+ /**
50
+ * UUID of the system to evaluate. RFC 4122 hyphenated form
51
+ * (8-4-4-4-12 hex, case-insensitive). Required.
52
+ */
53
+ systemId: string;
54
+ /**
55
+ * Pass/fail threshold (integer 0-100). **Defaults to 70 kernel-
56
+ * side** when omitted.
57
+ */
58
+ minScore?: number;
59
+ /**
60
+ * Optional framework filter. Each element must be a non-empty
61
+ * string of length ≤100; the array length must be ≤20.
62
+ *
63
+ * **Substring + case-insensitive matching** (kernel uses
64
+ * `.toLowerCase().includes()` — asymmetric with `check.run`'s exact
65
+ * equality). An assessment matches if any of its frameworks
66
+ * contains any filter string as a substring (after lowercasing).
67
+ */
68
+ frameworks?: string[];
69
+ /**
70
+ * When `true` (the kernel default), a missing/incomplete
71
+ * assessment causes the gate to return `gate: "fail"`. When
72
+ * `false`, the gate returns `gate: "pass"` with `score: null` and
73
+ * a `reason` indicating the relaxed mode.
74
+ *
75
+ * **Defaults to `true` kernel-side** when omitted (strict mode).
76
+ */
77
+ failOnMissingAssessment?: boolean;
78
+ }
79
+ /**
80
+ * Structured gap entry returned in the `gaps` array for the normal
81
+ * pass/fail emit path. Source-of-truth at kernel
82
+ * `src/app/api/v1/gate/route.ts:38-43` (`GateGap` interface) +
83
+ * route.ts:156-163 (the emit-site mapping).
84
+ *
85
+ * Built from `schema.remediationTasks` rows for the relevant
86
+ * assessment, filtered to `status !== "resolved" && status !==
87
+ * "wont_fix"` (route.ts:157).
88
+ *
89
+ * **`priority` is OPEN-SPEC** — the kernel does NOT enforce a closed
90
+ * enum on `remediationTasks.priority`; it's a free-text string column.
91
+ * The SDK exposes it as `string` (NOT `"critical" | "high" | "medium"
92
+ * | "low"` enum) to preserve faithful-courier semantics. Consumers
93
+ * needing closed-enum branching should filter post-hoc. **Note**: the
94
+ * kernel uses the literal strings `"critical"` and `"high"` to compute
95
+ * `criticalGaps` / `highGaps` counts (route.ts:193-194), so consumers
96
+ * can safely match those two values; other values (`"medium"`,
97
+ * `"low"`, custom) are not aggregated kernel-side.
98
+ *
99
+ * **`status` is also OPEN-SPEC** — the kernel filters out `"resolved"`
100
+ * and `"wont_fix"` before emitting, so `status` will be neither of
101
+ * those, but the kernel doesn't pin a closed enum on the remaining
102
+ * values (e.g., `"open"`, `"in_progress"`, custom).
103
+ */
104
+ export interface GateGap {
105
+ /**
106
+ * Stable requirement key the gap addresses (e.g., a framework
107
+ * control identifier). Foreign key to `schema.remediationTasks
108
+ * .requirementKey`.
109
+ */
110
+ requirementKey: string;
111
+ /**
112
+ * Human-readable title for the gap (the remediation task's title).
113
+ */
114
+ title: string;
115
+ /**
116
+ * Open-spec priority string. Kernel-aggregated values are
117
+ * `"critical"` and `"high"` (counted into `criticalGaps` /
118
+ * `highGaps` response fields); other values pass through verbatim.
119
+ */
120
+ priority: string;
121
+ /**
122
+ * Open-spec status string. Filtered kernel-side to NOT include
123
+ * `"resolved"` or `"wont_fix"`; remaining values pass through.
124
+ */
125
+ status: string;
126
+ }
127
+ /**
128
+ * Response shape returned by `gate.evaluate`. **UNION of 3 emit
129
+ * paths** keyed by whether a `relevantAssessment` was found
130
+ * (kernel route.ts:88-98) and the value of `failOnMissingAssessment`.
131
+ *
132
+ * Source-of-truth at kernel `src/app/api/v1/gate/route.ts`:
133
+ * - Path 1 — normal pass/fail (route.ts:180-199, 14 fields):
134
+ * `relevantAssessment` found; `score: number`; all 5 emit-only
135
+ * fields (`assessmentId`, `assessmentDate`, `gapCount`,
136
+ * `criticalGaps`, `highGaps`) are present.
137
+ * - Path 2 — fail-on-missing (route.ts:113-123, 9 fields):
138
+ * `failOnMissingAssessment=true` AND `relevantAssessment` is
139
+ * falsy; `gate: "fail"`; `score: null`; `gaps: []`; emit-only
140
+ * fields are ABSENT (not just `undefined` — own-property false).
141
+ * - Path 3 — pass-on-missing (route.ts:126-136, 9 fields):
142
+ * `failOnMissingAssessment=false` AND `relevantAssessment` is
143
+ * falsy; `gate: "pass"`; `score: null`; `gaps: []`; emit-only
144
+ * fields are ABSENT.
145
+ *
146
+ * **`relevantAssessment` is falsy in TWO distinct cases** (kernel
147
+ * route.ts:88-98): (a) NO completed assessment exists within the 10
148
+ * most-recent assessment rows (silent `.limit(10)` truncation), OR
149
+ * (b) — with `frameworks` specified — no completed assessment within
150
+ * those 10 rows matches ANY framework via substring + case-insensitive
151
+ * comparison. A consumer setting `frameworks: ["UNMATCHED_FRAMEWORK"]`
152
+ * on a system with multiple completed assessments would fall into
153
+ * Paths 2/3 and see the literal `reason` string "No completed
154
+ * assessment found for this system." — even though completed
155
+ * assessments DO exist (they just don't match the filter). Consumers
156
+ * should NOT use Paths 2/3 alone to conclude "this system has never
157
+ * had a completed assessment".
158
+ *
159
+ * **Discriminator pattern** (mirrors `check.run`'s `lastAssessedAt ===
160
+ * null`): use `response.score === null` to detect Paths 2 or 3.
161
+ * `Object.hasOwn(response, "assessmentId") === false` is an
162
+ * equivalent own-property-only alternative that is ALSO safe under
163
+ * `Object.prototype.assessmentId` pollution. **Do NOT use
164
+ * `response.assessmentId === undefined`** as the discriminator —
165
+ * a hostile dep polluting `Object.prototype.assessmentId` makes the
166
+ * `=== undefined` check return false (reads the polluted value via
167
+ * prototype walk) even in Paths 2 + 3, silently misclassifying them
168
+ * as Path 1. `score === null` is the canonical safe discriminator
169
+ * (the SDK's P2 validator type-checks `score` as an own property
170
+ * with `objectHasOwn`).
171
+ */
172
+ export interface GateResponse {
173
+ /**
174
+ * Pass/fail verdict. **String enum, NOT a boolean** — kernel
175
+ * emits the literal strings `"pass"` and `"fail"` (route.ts:114,
176
+ * 127, 181). Consumers should NOT compare against `true`/`false`.
177
+ *
178
+ * **Type contract is closed (`"pass" | "fail"`); runtime is open
179
+ * (faithful courier).** The SDK's P2 validator checks `typeof gate
180
+ * === "string"` only — it does NOT reject unknown string values.
181
+ * If a future kernel emits `gate: "warn"` / `gate: "skip"` / etc.
182
+ * before the SDK is bumped, the value round-trips at runtime
183
+ * (typed as the closed union at compile time, but holding the new
184
+ * string at runtime). Consumers using exhaustive type-narrowing
185
+ * (`if (gate === "pass") ... else /* TS: 'fail' *‍/`) would
186
+ * misclassify an unknown value as the `"fail"` branch. The
187
+ * kernel-side `gate` emit-sites are drift-pinned via the wire-
188
+ * shape build-round pin so a kernel extension surfaces in the
189
+ * drift suite before consumer regressions.
190
+ */
191
+ gate: "pass" | "fail";
192
+ /**
193
+ * The system's UUID (echoes the input — kernel route.ts:115, 128,
194
+ * 182).
195
+ */
196
+ systemId: string;
197
+ /**
198
+ * The system's display name (`schema.aiSystems.name`,
199
+ * route.ts:116, 129, 183). Open-spec string.
200
+ */
201
+ systemName: string;
202
+ /**
203
+ * Overall compliance score from the relevant completed
204
+ * assessment's `scores.overall` jsonb field, IF that field is a
205
+ * `number` (route.ts:141: `typeof scoresObj?.overall === "number"
206
+ * ? scoresObj.overall : 0`).
207
+ *
208
+ * **`null` in the no-assessment paths** (Paths 2 + 3, route.ts:118
209
+ * + 131). **Asymmetric with `check.run` which defaulted to 0**;
210
+ * gate's `null` preserves the distinction at the type level.
211
+ * Consumers should use `score === null` (NOT `score === 0`) to
212
+ * detect the no-assessment branch.
213
+ *
214
+ * **In Path 1, `score: 0` is AMBIGUOUS** between (a) the assessment
215
+ * legitimately scored zero, AND (b) the assessment row had a
216
+ * missing or non-numeric `scores.overall` (e.g., `undefined`, a
217
+ * string, or the literal jsonb string `"NaN"` — anything where
218
+ * `typeof !== "number"`). The kernel collapses (b) to 0 via
219
+ * `typeof === "number" ? value : 0` at `route.ts:141`. Consumers
220
+ * CANNOT distinguish (a) from (b) from the wire response alone —
221
+ * both cases emit `score: 0` with all 14 Path-1 fields present. A
222
+ * CI/CD pipeline treating `gate: "fail" && score === 0` as a
223
+ * "broken assessment data" signal would silently miss case (a).
224
+ * Faithful courier; the SDK does NOT mask the kernel's collapse.
225
+ *
226
+ * **Note on IEEE-754 NaN in jsonb**: an exotic edge case — if the
227
+ * jsonb stores IEEE-754 NaN as a number (NOT the string `"NaN"`),
228
+ * `typeof === "number"` returns true, the kernel passes NaN
229
+ * through, and `JSON.stringify(NaN)` emits `null` on the wire. The
230
+ * SDK's P2 validator accepts `score: null` in Path 1 (`score`
231
+ * typed `number | null`). Consumers would see `gate: "fail" &&
232
+ * score: null` with the OTHER 12 Path-1 fields present (NOT the
233
+ * 9-field Path-2/3 shape). This combination is the disambiguator
234
+ * for NaN-in-jsonb specifically vs the no-assessment branch.
235
+ *
236
+ * In Path 1 the value is a `number` (typically 0..100 but
237
+ * unbounded — the kernel does not clamp the jsonb value).
238
+ *
239
+ * Note: kernel internally uses `scoresObj?.overall` (NOT
240
+ * `overallScore` like `check.run`) but the SDK contract is just
241
+ * `score: number | null`; the jsonb key difference is invisible.
242
+ */
243
+ score: number | null;
244
+ /**
245
+ * Pass/fail threshold applied (number). Echoes the consumer's
246
+ * input OR the kernel default (70) when omitted. ALWAYS present
247
+ * in all 3 emit paths.
248
+ */
249
+ minScore: number;
250
+ /**
251
+ * In Paths 2 + 3 (no assessment): echoes the consumer's
252
+ * `frameworks` input (or `[]` if omitted) — route.ts:120 + 133.
253
+ * In Path 1: the **assessment's** frameworks (NOT the consumer's
254
+ * filter) — route.ts:186-188. Type contract is the same
255
+ * (`string[]`) but the SEMANTIC source differs by path.
256
+ * Documented for completeness; consumers should treat this field
257
+ * as "the frameworks relevant to this evaluation" without assuming
258
+ * input echo.
259
+ */
260
+ frameworks: string[];
261
+ /**
262
+ * Structured gap list (kernel emit-site: route.ts:191 in Path 1;
263
+ * empty array in Paths 2 + 3). Each gap is a `GateGap` row from
264
+ * `schema.remediationTasks` filtered to `status !== "resolved" &&
265
+ * status !== "wont_fix"`.
266
+ *
267
+ * **SILENTLY CAPPED AT 100 ROWS-CONSIDERED** — the kernel reads up
268
+ * to 100 remediation tasks (`.limit(100)` at route.ts:154) and
269
+ * filters within that subset. If the assessment has >100
270
+ * unresolved gaps, the 101st+ are invisible. No `total`, no
271
+ * `hasMore`. Faithful courier; documented in JSDoc + README.
272
+ * Invariant candidate #50.
273
+ */
274
+ gaps: GateGap[];
275
+ /**
276
+ * Human-readable reason string. Path-specific contents:
277
+ * - Path 1: `"Score N meets minimum threshold of M."` or
278
+ * `"Score N is below minimum threshold of M. K unresolved
279
+ * gaps."` (route.ts:195-197).
280
+ * - Path 2: `"No completed assessment found for this system."`
281
+ * (route.ts:117).
282
+ * - Path 3: `"No assessment found but failOnMissingAssessment is
283
+ * false."` (route.ts:130).
284
+ * Open-spec string; consumers should NOT pattern-match these for
285
+ * branching (kernel may reword). Use `gate` + `score === null` for
286
+ * programmatic decisions.
287
+ */
288
+ reason: string;
289
+ /**
290
+ * ISO-8601, server-generated at handler end via `new
291
+ * Date().toISOString()` (route.ts:122, 135, 198). Uniquely
292
+ * identifies this evaluation's snapshot — consumers may use it as
293
+ * a freshness marker.
294
+ */
295
+ timestamp: string;
296
+ /**
297
+ * UUID of the assessment used (`schema.assessments.id`,
298
+ * route.ts:189). **PRESENT ONLY in Path 1** — absent (own-property
299
+ * false) in Paths 2 + 3. **Use `score === null` (or
300
+ * `Object.hasOwn(response, "assessmentId") === false`) to detect
301
+ * the no-assessment branch — NOT `response.assessmentId ===
302
+ * undefined`** which reads via prototype walk and is unsafe under
303
+ * `Object.prototype.assessmentId` pollution. See the top-level
304
+ * GateResponse JSDoc's "Discriminator pattern" section for the full
305
+ * rationale.
306
+ */
307
+ assessmentId?: string;
308
+ /**
309
+ * ISO-8601 of the assessment's `completedAt`, OR `null` if the
310
+ * assessment row's `completedAt` column is null (rare — completed
311
+ * assessments usually have a non-null timestamp, but the column
312
+ * is nullable). **PRESENT ONLY in Path 1** — absent in Paths 2 + 3.
313
+ */
314
+ assessmentDate?: string | null;
315
+ /**
316
+ * Count of unresolved gaps after kernel filtering (NOT the raw
317
+ * row count — `blockingGaps.length` at route.ts:192).
318
+ * **PRESENT ONLY in Path 1**. Equivalent to `gaps.length` at the
319
+ * call site; the kernel emits it as a convenience.
320
+ */
321
+ gapCount?: number;
322
+ /**
323
+ * Count of gaps with `priority === "critical"` (route.ts:193).
324
+ * **PRESENT ONLY in Path 1**. Open-spec priority — the kernel
325
+ * matches the literal string `"critical"`; consumers using custom
326
+ * priority taxonomies won't see those aggregated here.
327
+ */
328
+ criticalGaps?: number;
329
+ /**
330
+ * Count of gaps with `priority === "high"` (route.ts:194).
331
+ * **PRESENT ONLY in Path 1**. Same priority-string caveat as
332
+ * `criticalGaps`.
333
+ */
334
+ highGaps?: number;
335
+ }
336
+ /**
337
+ * `gate` resource — sibling to `IncidentsResource`,
338
+ * `DecisionsResource`, `ChatResource`, `AuditLogResource`,
339
+ * `RegulatoryChangesResource`, `ComplianceCheckResource`,
340
+ * `CheckResource`. Today wraps a single endpoint (`evaluate`); the
341
+ * class is the landing pad for future gate methods if the kernel
342
+ * adds them (resource-class-per-kernel-resource convention, invariant
343
+ * #43).
344
+ */
345
+ export declare class GateResource {
346
+ private readonly client;
347
+ constructor(client: AttestryClient);
348
+ /**
349
+ * Evaluate a CI/CD compliance gate for a single system. Returns a
350
+ * structured pass/fail verdict (string enum `"pass"`/`"fail"`),
351
+ * the score, the threshold, and a list of unresolved compliance
352
+ * gaps. Designed for pipeline integration (CI build logs / GitHub
353
+ * Actions / GitLab CI).
354
+ *
355
+ * **Three emit paths** — the response shape varies by whether a
356
+ * completed assessment was found and the value of
357
+ * `failOnMissingAssessment`:
358
+ * - **Path 1 (normal pass/fail)**: assessment found; `score: number`;
359
+ * all 14 fields present (including `assessmentId`,
360
+ * `assessmentDate`, `gapCount`, `criticalGaps`, `highGaps`).
361
+ * - **Path 2 (fail-on-missing)**: `failOnMissingAssessment=true`
362
+ * (the default) AND no completed assessment; `gate: "fail"`;
363
+ * `score: null`; `gaps: []`; emit-only fields ABSENT.
364
+ * - **Path 3 (pass-on-missing)**: `failOnMissingAssessment=false`
365
+ * AND no completed assessment; `gate: "pass"`; `score: null`;
366
+ * `gaps: []`; emit-only fields ABSENT.
367
+ *
368
+ * **Multi-permission UNION auth scope**: kernel uses
369
+ * `requireApiKeyWithPermission(req, READ_ASSESSMENTS, READ_SYSTEMS)`
370
+ * which is OR semantics (`Array.some()` at
371
+ * `permissions.ts:53-55`). A key with EITHER permission (or
372
+ * `ADMIN`, or null/empty permissions for backwards-compat)
373
+ * succeeds. **HTTP 401** for no/invalid API key, **HTTP 403** for
374
+ * an authenticated key that has NEITHER required permission. Pin
375
+ * BOTH branches separately. Carry-forward invariant #45 (same
376
+ * shape as `check.run`).
377
+ *
378
+ * **Asymmetric cross-org error code** (carry-forward #47, partial):
379
+ * cross-org `systemId` returns **404** — the kernel's
380
+ * `and(eq id, eq orgId)` at route.ts:62-75 collapses cross-org
381
+ * to "System not found or access denied" (mirror of
382
+ * `check.run`'s 404 surface; note kernel emits a LONGER literal
383
+ * string than `check.run`'s `"System not found"`). Consumers
384
+ * writing defensive error-handling logic must recognize: a 404
385
+ * may be "not your org" OR "genuine missing UUID". No 403-via-
386
+ * orgName twin here (no orgName input mode).
387
+ *
388
+ * **Two silent kernel-side truncations** (faithful courier;
389
+ * documented as kernel surface gaps — JSDoc + README + drift
390
+ * pinned with ANCHORED regex per session-16 second-review
391
+ * MEDIUM #4). Invariant candidate #50:
392
+ * 1. `assessments` row-population — `.limit(10)` at route.ts:85.
393
+ * If the system has >10 assessment rows, the kernel only
394
+ * considers the 10 most recent by `completedAt` DESC. The
395
+ * "relevant" completed assessment is found by `.find()` over
396
+ * those 10 — a system with the most-recent completed
397
+ * assessment in position 11+ would be misclassified as "no
398
+ * assessment found" (falling into Paths 2 or 3). **Tighter
399
+ * cap than `check.run`'s `.limit(100)`** — gate is strictly
400
+ * less defensive against many-assessment systems.
401
+ * 2. `remediationTasks` row-population — `.limit(100)` at
402
+ * route.ts:154. If the assessment has >100 unresolved
403
+ * remediation tasks, the 101st+ are invisible. The cap
404
+ * applies BEFORE the filter-to-unresolved step
405
+ * (`status !== "resolved" && status !== "wont_fix"`), so the
406
+ * final `gaps.length` may be less than 100 even at the cap.
407
+ *
408
+ * **`score` defaults to `null` in the no-assessment paths**
409
+ * (route.ts:118 + 131). **Asymmetric with `check.run` which used
410
+ * `0`** — gate's `null` preserves the distinction at the type
411
+ * level. Consumers should use `score === null` (NOT `score === 0`)
412
+ * to detect Paths 2 or 3.
413
+ *
414
+ * **`gate` is a STRING ENUM, NOT a boolean** — kernel emits the
415
+ * literal strings `"pass"` and `"fail"` (route.ts:114, 127, 181).
416
+ * Type-narrowing via equality check: `if (result.gate === "pass")`.
417
+ *
418
+ * **`frameworks` filter is substring + case-insensitive** — kernel
419
+ * uses `.toLowerCase().includes()` at route.ts:94-96. **Asymmetric
420
+ * with `check.run`'s exact-equality OR-overlap**. Consumer passing
421
+ * `["GDPR"]` matches an assessment with `["EU_GDPR_2024"]`,
422
+ * `["gdpr_compliance_v2"]`, etc. Looser semantics may surprise.
423
+ *
424
+ * **`writeAuditLog` side effect** — every `gate.evaluate(...)`
425
+ * call writes one `gate.checked` entry to the org's audit log
426
+ * (route.ts:104-111 for the no-assessment paths, route.ts:165-178
427
+ * for the normal path). Properties of the write:
428
+ * - Org-scoped, hash-chained (per `writeAuditLog` at
429
+ * `src/lib/api.ts:125-`).
430
+ * - **Time-blocking** but error-tolerant: the kernel uses
431
+ * `await writeAuditLog(...)`, which awaits two DB ops (SELECT
432
+ * previous-hash + INSERT new entry). The gate response latency
433
+ * INCLUDES the audit-log write time — a slow audit-log DB will
434
+ * delay every gate.evaluate() response. Error semantics ARE
435
+ * non-blocking: `writeAuditLog` wraps its body in a try/catch
436
+ * that swallows errors and logs them, so a write FAILURE does
437
+ * NOT fail the gate request.
438
+ * - NOT counted against `decisionsPerMonth` quota (gate is read-
439
+ * shaped from a quota perspective).
440
+ *
441
+ * **Defaults applied by the kernel when fields are omitted**
442
+ * (carry-forward #44, non-obvious-default-filter pattern):
443
+ * - `minScore` defaults to **70** (Zod `.default(70)` at
444
+ * route.ts:33). Consumers who omit this field get the implicit
445
+ * threshold of 70.
446
+ * - `failOnMissingAssessment` defaults to **true** (Zod
447
+ * `.default(true)` at route.ts:35). Consumers who omit this
448
+ * get strict behavior.
449
+ * The SDK omits these fields from the request body when the
450
+ * consumer omits them, so the kernel applies its defaults
451
+ * (invariant candidate #52).
452
+ *
453
+ * Errors — ordered by kernel firing precedence (rate-limit → auth
454
+ * → Zod body validation → DB lookup → internal). A request with
455
+ * multiple problems surfaces ONLY the highest-precedence one. For
456
+ * example: a request with bad auth AND a malformed body surfaces
457
+ * 401, not 422; a request with valid auth + bad body AND a cross-
458
+ * org systemId surfaces 422, not 404.
459
+ * - `AttestryAPIError` (status 429) — rate limit FIRES FIRST
460
+ * (auto-retried by default — invariant #18; per-IP rate-limit
461
+ * key `v1-gate:${ip}`).
462
+ * - `AttestryAPIError` (status 401) — no API key OR invalid key.
463
+ * Fires AFTER rate-limit but BEFORE input validation.
464
+ * - `AttestryAPIError` (status 403) — authenticated key has
465
+ * NEITHER `READ_ASSESSMENTS` nor `READ_SYSTEMS` (the
466
+ * permission-check branch). Single test case — the union-auth
467
+ * pattern collapses three intuition-suggesting cases to one.
468
+ * - `AttestryAPIError` (status 422) — Zod schema rejection
469
+ * (kernel's `BodyParseError` surface — `parseBody(request,
470
+ * gateSchema)` failed). **Fires BEFORE the systemId/cross-
471
+ * org 404 lookup**, so a request with bad UUID format AND
472
+ * cross-org-correct UUID surfaces 422 (the kernel's Zod
473
+ * `.uuid()` reject), not 404. `apiErr.details` carries the
474
+ * full kernel error body verbatim (the transport does NOT
475
+ * strip the `{success:false, ...}` envelope on error responses
476
+ * — only the `{success:true, data}` envelope on success). The
477
+ * wire shape is: `{success: false, error: "Validation failed.",
478
+ * details: Array<{path: string; message: string}>}` — `error`
479
+ * is the literal string
480
+ * "Validation failed." (with trailing period), `details` is
481
+ * an array (NOT a keyed map) of `{path, message}` pairs
482
+ * derived from Zod's `result.error.errors`. Consumers
483
+ * reading field-by-field errors should iterate
484
+ * `apiErr.details.details` (the kernel's `details` array
485
+ * nested under the SDK's parsed-body wrapper). **The SDK
486
+ * pre-validates all closed-spec rules** (UUID format,
487
+ * minScore int + range, failOnMissingAssessment boolean,
488
+ * framework element length 1-100, array length ≤20) AND the
489
+ * runtime checks always run regardless of TypeScript types —
490
+ * `as any` casts do NOT bypass them. So 422 reaches consumers
491
+ * ONLY via kernel rule changes the SDK hasn't synced to.
492
+ * Invariant candidate #51.
493
+ * - `AttestryAPIError` (status 404) — system not found OR
494
+ * cross-org systemId (kernel collapses to "System not found
495
+ * or access denied", route.ts:74). Fires AFTER Zod validation
496
+ * (422).
497
+ * - `AttestryAPIError` (status 500) — internal kernel error
498
+ * (scrubbed message via `internalErrorResponse`).
499
+ * - `AttestryError` ("request aborted by caller") — caller-
500
+ * supplied `options.signal` fired (pre-aborted or mid-flight).
501
+ * - `AttestryError` (P2 hardening) — kernel response failed
502
+ * SDK-side shape validation (not an object, wrong type on any
503
+ * field).
504
+ * - `AttestryAPIError` (P3 hardening) — kernel response had a
505
+ * wrong Content-Type (transport-level guard before body
506
+ * parsing).
507
+ * - `TypeError` (synchronous, no fetch issued) — input failed
508
+ * SDK-side validation (null / array / non-object input,
509
+ * missing systemId, invalid UUID format, non-integer minScore,
510
+ * out-of-range minScore, non-boolean failOnMissingAssessment,
511
+ * frameworks array too long, frameworks element wrong type or
512
+ * length).
513
+ *
514
+ * **Notably ABSENT**:
515
+ * - **No 400** — all input validation is Zod (422).
516
+ * - **No 413** — body size limit not explicit.
517
+ * - **No 402** — read-shaped, doesn't count against
518
+ * decisionsPerMonth quota (despite the audit-log side effect).
519
+ *
520
+ * **SDK-side validation** (synchronous `TypeError`, no fetch
521
+ * issued):
522
+ * - `input` itself: required; must be a non-null, non-array
523
+ * object.
524
+ * - `input.systemId`: required own-property (Object.hasOwn
525
+ * defends against prototype pollution lying about presence —
526
+ * generalization of invariant #48); must be a non-empty
527
+ * string; must match the RFC 4122 hyphenated UUID format
528
+ * (D2 — SDK pre-validates closed-spec rule). No
529
+ * lone-surrogate URIError defense (D6 — POST body uses
530
+ * JSON.stringify).
531
+ * - `input.minScore` (when own-property present, value not
532
+ * undefined): must be a `number`, an integer (`Number.isInteger`,
533
+ * which excludes NaN / ±Infinity automatically), and within
534
+ * `[0, 100]` inclusive. Mirrors Zod's
535
+ * `z.number().int().min(0).max(100)` exactly (D3).
536
+ * - `input.failOnMissingAssessment` (when own-property present,
537
+ * value not undefined): must be a `boolean` (`typeof ===
538
+ * "boolean"`). Mirrors Zod's `z.boolean()` exactly (D4).
539
+ * - `input.frameworks` (when own-property present, value not
540
+ * undefined): must be an array of ≤20 strings, each of length
541
+ * 1-100. SDK pre-validates each rule (D5). Array is
542
+ * snapshotted via `Array.from` for TOCTOU defense.
543
+ *
544
+ * **Response-shape validation** (P2 hardening — D8, symmetric
545
+ * defense on response side per D7):
546
+ * - Rejects with `AttestryError` if the kernel response isn't a
547
+ * non-null, non-array object.
548
+ * - Rejects if `gate` isn't a string.
549
+ * - Rejects if `systemId` / `systemName` / `reason` / `timestamp`
550
+ * aren't strings.
551
+ * - Rejects if `score` isn't a number OR null.
552
+ * - Rejects if `minScore` isn't a number.
553
+ * - Rejects if `frameworks` / `gaps` aren't arrays.
554
+ * - Rejects if `assessmentId` (when own-present) isn't a string.
555
+ * - Rejects if `assessmentDate` (when own-present) isn't a
556
+ * string or null.
557
+ * - Rejects if `gapCount` / `criticalGaps` / `highGaps` (when
558
+ * own-present) aren't numbers.
559
+ * - Each response field read goes through the module-load
560
+ * `objectHasOwn` snapshot (symmetric to the input-side
561
+ * prototype-pollution defense — D7 generalized to the response
562
+ * boundary). A hostile npm dep that pollutes
563
+ * `Object.prototype.<field>` cannot mask a kernel regression
564
+ * where the field is missing — the SDK requires the field to
565
+ * be a kernel-emitted own property.
566
+ * - Per-gap-element shape (open-spec strings) is faithful-
567
+ * courier — NOT validated.
568
+ *
569
+ * **Transport-shape validation** (P3 hardening):
570
+ * - Rejects with `AttestryAPIError` if the kernel responds with
571
+ * a non-`application/json` Content-Type.
572
+ *
573
+ * @example Basic gate evaluation (defaults: minScore=70, failOnMissingAssessment=true)
574
+ * ```ts
575
+ * const result = await client.gate.evaluate({
576
+ * systemId: "11111111-1111-1111-1111-111111111111",
577
+ * });
578
+ * if (result.gate === "pass") {
579
+ * console.log("OK to deploy — score:", result.score);
580
+ * } else if (result.score === null) {
581
+ * console.warn("No completed assessment — failing strict-mode gate");
582
+ * } else {
583
+ * // Path 1 fail: emit-only fields are present at runtime, but
584
+ * // typed as optional. Use `??` (or a Path-1 narrowing check on
585
+ * // `assessmentId`) so the example compiles without `!` or `as`.
586
+ * console.warn(
587
+ * `Score ${result.score} below threshold ${result.minScore};`,
588
+ * `${result.gapCount ?? 0} unresolved gaps (${result.criticalGaps ?? 0} critical)`
589
+ * );
590
+ * }
591
+ * ```
592
+ *
593
+ * @example Strict threshold + framework filter
594
+ * ```ts
595
+ * const euOnly = await client.gate.evaluate({
596
+ * systemId: "11111111-1111-1111-1111-111111111111",
597
+ * minScore: 85,
598
+ * frameworks: ["EU_AI_ACT", "ISO_42001"],
599
+ * });
600
+ * ```
601
+ *
602
+ * @example Pre-launch / staging — allow missing assessments
603
+ * ```ts
604
+ * const lenient = await client.gate.evaluate({
605
+ * systemId: "11111111-1111-1111-1111-111111111111",
606
+ * failOnMissingAssessment: false,
607
+ * });
608
+ * // `lenient.gate === "pass"` even without a completed assessment.
609
+ * ```
610
+ */
611
+ evaluate(input: GateInput, options?: RequestOptions): Promise<GateResponse>;
612
+ }
613
+ //# sourceMappingURL=gate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gate.d.ts","sourceRoot":"","sources":["../../src/resources/gate.ts"],"names":[],"mappings":"AAiJA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEnD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAkClD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,MAAM,WAAW,SAAS;IACxB;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;;;;OAQG;IACH,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB;;;;;;;OAOG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAC;CACnC;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,WAAW,OAAO;IACtB;;;;OAIG;IACH,cAAc,EAAE,MAAM,CAAC;IACvB;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;;;;;;;;;;;;;;OAiBG;IACH,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAwCG;IACH,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB;;;;OAIG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;;;;;OASG;IACH,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB;;;;;;;;;;;;OAYG;IACH,IAAI,EAAE,OAAO,EAAE,CAAC;IAChB;;;;;;;;;;;;OAYG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB;;;;;;;;;;OAUG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;GAQG;AACH,qBAAa,YAAY;IACX,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,cAAc;IAEnD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAsQG;IACH,QAAQ,CACN,KAAK,EAAE,SAAS,EAChB,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,YAAY,CAAC;CAsVzB"}