@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,845 @@
1
+ import type { AttestryClient } from "../client.js";
2
+ import type { RequestOptions } from "../types.js";
3
+ /**
4
+ * Closed enum for `BatchSubmitInput.jobType`. Mirrors the kernel's
5
+ * `batchSubmitSchema.jobType` at `src/app/api/v1/batch/route.ts:30`:
6
+ * `z.enum(["classify", "assess", "classify_and_assess"])`.
7
+ *
8
+ * Frozen at module load to prevent runtime mutation by hostile /
9
+ * buggy dependencies (P1 hardening — mirrors the freeze on
10
+ * `AUDIT_LOG_EXPORT_FORMATS` / `CHAT_MESSAGE_ROLES` etc.). Iterating
11
+ * `for (const t of BATCH_JOB_TYPES)` lists the 3 valid values; the
12
+ * SDK's `submit()` pre-rejects any unknown string with `TypeError`
13
+ * (invariant #41 — closed-enum SDK pre-rejection-eligible surface).
14
+ *
15
+ * Drift-pinned in `sdk-drift.test.ts` spec-diff round against the
16
+ * kernel's Zod enum to catch a kernel-side widening (e.g., adding
17
+ * `"generate_docs"` — the stale db/schema.ts:1030 comment mentions
18
+ * this value but the route's Zod schema does NOT include it; the
19
+ * comment is stale, the Zod is authoritative).
20
+ *
21
+ * **Semantics of each value**:
22
+ * - `"classify"` — run the rule-based classifier on each system
23
+ * and PERSIST the new `riskClassifications` to the system row
24
+ * (write-side effect). Per-row `classifications` contains the
25
+ * fresh classification.
26
+ * - `"assess"` — emit each system's CURRENT `riskClassifications`
27
+ * state from the DB (read-only; no write side effect, despite
28
+ * `WRITE_ASSESSMENTS` being a valid auth permission). Per-row
29
+ * `classifications` contains whatever was already on the row
30
+ * (may be `null` if no prior classification).
31
+ * - `"classify_and_assess"` — same as `"classify"` (the kernel
32
+ * branches `classify || classify_and_assess` together at
33
+ * route.ts:112). The two-name distinction is purely semantic
34
+ * for the consumer — both write the new classification and
35
+ * emit it.
36
+ */
37
+ export declare const BATCH_JOB_TYPES: readonly ["classify", "assess", "classify_and_assess"];
38
+ export type BatchJobType = (typeof BATCH_JOB_TYPES)[number];
39
+ /**
40
+ * Closed enum for `BatchJobStatus.status` (the GET response's wider
41
+ * batch-job-level status). Mirrors the kernel's
42
+ * `schema.batchJobs.status` DB column comment at
43
+ * `src/lib/db/schema.ts:1031`: `'pending' | 'processing' | 'completed' |
44
+ * 'failed'`.
45
+ *
46
+ * **Wider than the POST response's `status`** — `submit()` returns
47
+ * `status: "completed" | "failed"` only (computed at handler end from
48
+ * `failed === total`). A `get()` call against a job submitted by the
49
+ * SDK observes only `"completed" | "failed"` in practice (the job
50
+ * processed inline before the row was committed), but a `get()`
51
+ * against a job submitted via a future async path OR an out-of-band
52
+ * caller mid-flight could observe `"pending"` / `"processing"`.
53
+ *
54
+ * Frozen at module load (P1 hardening — same rationale as
55
+ * `BATCH_JOB_TYPES`). Iterating `for (const s of BATCH_JOB_STATUSES)`
56
+ * lists all 4 values. **The DB column has no kernel-side enum
57
+ * constraint** — the SDK exposes the closed union at the type level
58
+ * but the runtime validator checks `typeof status === "string"` only
59
+ * (faithful courier — same asymmetry as gate's `gate: "pass" |
60
+ * "fail"` pattern).
61
+ *
62
+ * Drift-pinned in the spec-diff round (sdk-drift.test.ts —
63
+ * "BATCH_JOB_STATUSES in SDK matches the kernel db/schema.ts
64
+ * comment + .default() literal") via TWO assertions inside the
65
+ * same `it()`:
66
+ * - **Assertion 1**: the schema's `.default("pending")` literal
67
+ * at `src/lib/db/schema.ts:1031` (machine-checkable). Fires
68
+ * on a default-change (e.g., from `"pending"` to `"queued"`).
69
+ * - **Assertion 2**: the schema column COMMENT listing all 4
70
+ * values (documentation source-of-truth). Fires on a
71
+ * widening (e.g., a new `"cancelled"` status added to the
72
+ * comment) OR a comment removal.
73
+ * The pin's failure message distinguishes which assertion fires.
74
+ */
75
+ export declare const BATCH_JOB_STATUSES: readonly ["pending", "processing", "completed", "failed"];
76
+ export type BatchJobStatusValue = (typeof BATCH_JOB_STATUSES)[number];
77
+ /**
78
+ * One per-system result row in `BatchSubmitResponse.results` /
79
+ * `BatchJobStatus.results`. Source-of-truth at kernel
80
+ * `src/app/api/v1/batch/route.ts:42-48` (`BatchSystemResult`
81
+ * interface).
82
+ *
83
+ * **Discriminator pattern**: branch on `status: "success" | "error"`
84
+ * (closed-enum string match). The kernel guarantees `classifications`
85
+ * is present on `"success"` rows and `errorMessage` is present on
86
+ * `"error"` rows — but **do NOT use `row.errorMessage === undefined`
87
+ * or `row.classifications === undefined` as the discriminator**.
88
+ * Under `Object.prototype.errorMessage = <value>` pollution, the
89
+ * `=== undefined` equality walks the prototype and reads the polluted
90
+ * value — returning false even when the own-property is genuinely
91
+ * absent, silently misclassifying an `"error"` row as `"success"`.
92
+ * The `status` field is the pollution-safe discriminator (the SDK's
93
+ * own-property check would reject a missing `status` field anyway).
94
+ *
95
+ * **`classifications` is `unknown`** because the kernel emits the
96
+ * full `classifySystem()` output OR the system's
97
+ * `riskClassifications` jsonb cell — both open-spec objects whose
98
+ * exact shape lives in `src/lib/classification.ts`. Consumers
99
+ * casting to a specific shape should align with that module.
100
+ *
101
+ * **`errorMessage` is `string`** — the kernel scrubs at
102
+ * route.ts:153-157 in this order: (1) take first line via
103
+ * `.split("\n")[0]`, (2) **TRUNCATE** to 500 chars via
104
+ * `.slice(0, 500)`, THEN (3) **REDACT** matches of:
105
+ * - alternation `(?:password|secret|token|key)` (literal,
106
+ * case-insensitive),
107
+ * - followed by `=`,
108
+ * - followed by **zero-or-more** characters that are NOT
109
+ * whitespace and NOT `&` (so `password=` with empty value
110
+ * IS matched; the actual kernel regex flags are `g` + `i`).
111
+ *
112
+ * **Order matters**: truncation happens BEFORE redaction, so a
113
+ * credential straddling the 500-char boundary may be partially
114
+ * sliced (the regex's zero-or-more arm matches the truncated
115
+ * prefix, redacting whatever survived the slice — but the
116
+ * sliced-off suffix is gone before redaction; whatever made it
117
+ * past the slice gets redacted to `[REDACTED]`). The regex only
118
+ * catches `<keyword>=<value>` shapes — Bearer tokens,
119
+ * JSON-quoted secrets like `"token":"abc"`, or other formats
120
+ * are NOT scrubbed. The SDK does NOT add a second scrubbing
121
+ * pass — faithful courier.
122
+ *
123
+ * Note: per-row shape is NOT P2-validated by the SDK (`Array.isArray`
124
+ * only on the `results` array — same faithful-courier pattern as
125
+ * `gate.evaluate`'s `gaps: GateGap[]`). The kernel emits well-formed
126
+ * rows reliably; consumers who paranoid-validate should do so post-
127
+ * hoc.
128
+ */
129
+ export interface BatchSystemResult {
130
+ /**
131
+ * UUID of the system this row describes. Always echoes the
132
+ * corresponding entry in `BatchSubmitInput.systemIds`.
133
+ */
134
+ systemId: string;
135
+ /**
136
+ * Human-readable system name from `schema.aiSystems.name`. The
137
+ * kernel uses `systemMap.get(systemId)?.name ?? "Unknown"` at
138
+ * route.ts:161 — a defensive fallback that is **dead code today**.
139
+ * Verified: (a) the prior membership check at route.ts:79-85
140
+ * guarantees every `systemId` is present in `systemMap`, so
141
+ * `systemMap.get(...)?.name` cannot return undefined via the `?.`
142
+ * arm; (b) `schema.aiSystems.name` is `text("name").notNull()` at
143
+ * `src/lib/db/schema.ts:156` — the column cannot be null, so the
144
+ * `?? "Unknown"` arm cannot fire either. Both arms are unreachable
145
+ * under the current schema; the fallback exists for defense-in-
146
+ * depth if a future migration relaxes the `notNull()` constraint.
147
+ * The SDK passes the literal string `"Unknown"` through faithfully
148
+ * in that hypothetical future.
149
+ */
150
+ systemName: string;
151
+ /**
152
+ * Closed enum — discriminator for `classifications` vs
153
+ * `errorMessage`. Use `row.status === "success"` (closed-enum
154
+ * string match) to branch — NOT `row.errorMessage === undefined`
155
+ * (prototype-pollution-unsafe).
156
+ */
157
+ status: "success" | "error";
158
+ /**
159
+ * Present only when `status === "success"`. The system's
160
+ * classification output (the kernel's `classifySystem()` result
161
+ * for `"classify"` / `"classify_and_assess"` job types, OR the
162
+ * system's CURRENT `riskClassifications` for the `"assess"` job
163
+ * type). Open-spec — typed `unknown` because the underlying
164
+ * `classifySystem` return shape lives outside the kernel route
165
+ * (`src/lib/classification.ts`).
166
+ */
167
+ classifications?: unknown;
168
+ /**
169
+ * Present only when `status === "error"`. Human-readable error
170
+ * message. **Kernel-scrubbed** at `route.ts:153-157` in this
171
+ * order: (1) first line only via `.split("\n")[0]`, (2)
172
+ * **TRUNCATE** to 500 chars via `.slice(0, 500)`, then (3)
173
+ * **REDACT** matches of `(?:password|secret|token|key)`
174
+ * followed by `=` followed by **zero-or-more** characters
175
+ * that are NOT whitespace and NOT `&` (case-insensitive,
176
+ * global). **`password=` with empty value IS matched and
177
+ * redacted**; the regex's quantifier is zero-or-more, not
178
+ * one-or-more. **Order matters**: truncation BEFORE redaction
179
+ * means a credential straddling the 500-char boundary is
180
+ * sliced before the regex sees it — whatever survived the
181
+ * slice gets redacted; whatever was sliced off is gone. The
182
+ * regex only catches `<keyword>=<value>` shapes — Bearer
183
+ * tokens, JSON-quoted secrets (`"token":"abc"`), or other
184
+ * formats are NOT scrubbed. The SDK does NOT add a second
185
+ * scrubbing pass — faithful courier.
186
+ */
187
+ errorMessage?: string;
188
+ }
189
+ /**
190
+ * Optional config object on `BatchSubmitInput.config`. Mirrors the
191
+ * kernel's `batchSubmitSchema.config` at
192
+ * `src/app/api/v1/batch/route.ts:35-39` — a single-field wrapper
193
+ * around `frameworks?`. The wrapper (rather than top-level fields)
194
+ * matches the kernel wire literal `{config: {frameworks}}` and
195
+ * leaves room for future top-level additions without breaking the
196
+ * surface.
197
+ *
198
+ * Round-tripped on `get()` (the kernel persists `config` to the
199
+ * `batch_jobs.config` jsonb column and emits it back on GET — see
200
+ * `BatchJobStatus.config`).
201
+ *
202
+ * **`config.frameworks` carry-forward from gate / check exactly** —
203
+ * array length ≤20 + per-element string length [1, 100]. The kernel
204
+ * does NOT pin `frameworks` to a closed enum of values; any string
205
+ * within the length bounds is accepted. Today the kernel does NOT
206
+ * use `config.frameworks` in the inline classification path
207
+ * (`classifySystem` doesn't take a frameworks filter) — the field is
208
+ * persisted for forward-compat with future job types but has NO
209
+ * visible effect on the current `classify` / `assess` paths.
210
+ * Documented as a kernel surface gap; consumers passing
211
+ * `config.frameworks` today get round-trip-only behavior.
212
+ */
213
+ export interface BatchConfig {
214
+ /**
215
+ * Optional array of framework identifiers. Up to 20 entries; each
216
+ * string of length 1-100. Round-tripped to `BatchJobStatus.config
217
+ * .frameworks` on `get()`; no visible effect on the current
218
+ * inline classification paths.
219
+ */
220
+ frameworks?: string[];
221
+ }
222
+ /**
223
+ * Input shape for `batch.submit()`. Source-of-truth at kernel
224
+ * `src/app/api/v1/batch/route.ts:29-40` (`batchSubmitSchema`).
225
+ *
226
+ * **`jobType`** — REQUIRED, closed enum of 3 strings (`BatchJobType`).
227
+ * The SDK pre-validates membership in `BATCH_JOB_TYPES`
228
+ * synchronously (invariant #41 — closed-enum SDK pre-rejection-
229
+ * eligible). `TypeError` for an unknown value lists the valid set.
230
+ *
231
+ * **`systemIds`** — REQUIRED array of 1-50 UUIDs. The SDK pre-
232
+ * validates: `Array.isArray`, length [1, 50] inclusive, each
233
+ * element a non-empty string matching the RFC 4122 UUID regex (D4
234
+ * — SDK pre-validates closed-spec rule per invariant #49). Snapshot
235
+ * via `Array.from` up front for TOCTOU defense (a Proxy whose
236
+ * `.length` or `[i]` changes between reads can't slip past
237
+ * validation). **The `.min(1)` is new** — gate/check's `frameworks`
238
+ * allowed empty arrays via `.optional().max(20)`; batch's
239
+ * `systemIds` rejects empty at the Zod level, so the SDK also
240
+ * pre-rejects empty.
241
+ *
242
+ * **`config`** — OPTIONAL. When provided, must be a non-null
243
+ * non-array object. `config.frameworks` (when provided) is an
244
+ * array of 1-100-char strings, length ≤20 (carry-forward from
245
+ * gate / check). Today the kernel persists `config` to the row but
246
+ * does NOT use it in the inline classification path — the field is
247
+ * forward-compat. Documented as a kernel surface gap; consumers get
248
+ * round-trip-only behavior.
249
+ *
250
+ * **No defaults** — `batchSubmitSchema` has NO `.default()` clauses
251
+ * (carry-forward invariant #52 N/A here, asymmetric with gate's two
252
+ * defaults). All fields without explicit values are simply absent
253
+ * from the body when the consumer omits them.
254
+ */
255
+ export interface BatchSubmitInput {
256
+ /**
257
+ * Closed enum: `"classify"` | `"assess"` | `"classify_and_assess"`.
258
+ * See `BATCH_JOB_TYPES` for semantics.
259
+ */
260
+ jobType: BatchJobType;
261
+ /**
262
+ * 1-50 UUIDs (RFC 4122 hyphenated form, case-insensitive). The
263
+ * `.min(1)` is enforced kernel-side AND SDK-side (empty arrays
264
+ * rejected synchronously).
265
+ */
266
+ systemIds: string[];
267
+ /**
268
+ * Optional. Round-tripped to `BatchJobStatus.config` on `get()`;
269
+ * no visible effect on the current inline classification paths.
270
+ */
271
+ config?: BatchConfig;
272
+ }
273
+ /**
274
+ * Response shape returned by `batch.submit()`. 10 fields, ALL always
275
+ * present (no emit-only optionality — distinct from `gate.evaluate`).
276
+ *
277
+ * Source-of-truth at kernel `src/app/api/v1/batch/route.ts:197-208`
278
+ * (the `successResponse({...})` literal).
279
+ *
280
+ * **`status: "completed" | "failed"`** — kernel-computed at handler
281
+ * end (route.ts:170): `failed === body.systemIds.length ? "failed" :
282
+ * "completed"`. **STRICTLY NARROWER than `BatchJobStatus.status`**
283
+ * (the GET response uses the wider 4-value enum). A POST-submitted
284
+ * job is always fully-processed by the time the response is built,
285
+ * so `"pending"` / `"processing"` are never observed on this method.
286
+ * **Two distinct status enums on the same wire-shape family** —
287
+ * invariant candidate #56. Type contract is closed at the call site;
288
+ * runtime is open (faithful courier — P2 validator checks `typeof
289
+ * === "string"` only).
290
+ *
291
+ * **`results: BatchSystemResult[]`** — partial-success envelope.
292
+ * Each row describes one system's outcome with
293
+ * `status: "success" | "error"` plus either `classifications` or
294
+ * `errorMessage`. The call resolves successfully (no throw) even
295
+ * when every row failed — top-level failures (auth, rate limit, plan
296
+ * limit, Zod rejection, cross-org systemId, internal) DO throw
297
+ * `AttestryAPIError`. Mirror of `decisions.bulk`'s contract — the
298
+ * canonical SDK partial-success pattern.
299
+ *
300
+ * **`startedAt: string | null`** — the kernel sets `startedAt: new
301
+ * Date()` at insert time (route.ts:99) so in practice this is
302
+ * always a non-null ISO-8601 string. The `?? null` fallback at
303
+ * route.ts:206 is defensive against a schema migration making the
304
+ * column nullable; the SDK's wire-shape type follows the defensive
305
+ * shape (`string | null`).
306
+ *
307
+ * **`completedAt: string`** — ALWAYS a string in the POST response
308
+ * (route.ts:207 emits `new Date().toISOString()` unconditionally).
309
+ * Asymmetric with `BatchJobStatus.completedAt` which is nullable
310
+ * (DB column allows null for non-completed jobs).
311
+ */
312
+ export interface BatchSubmitResponse {
313
+ /** UUID of the newly-created batch job row. */
314
+ id: string;
315
+ /**
316
+ * Echoes the input — one of the 3 `BatchJobType` values. Open at
317
+ * runtime (P2 validates `typeof === "string"` only).
318
+ */
319
+ jobType: BatchJobType;
320
+ /**
321
+ * **Batch-job-level** status — closed to `"completed" | "failed"`
322
+ * on POST (kernel-computed). Open at runtime (P2 validates
323
+ * `typeof === "string"` only). Distinct from
324
+ * `results[i].status` (per-row `"success" | "error"`).
325
+ */
326
+ status: "completed" | "failed";
327
+ /** Echoes `systemIds.length` from the input (1-50). */
328
+ totalSystems: number;
329
+ /**
330
+ * Count of rows whose `status === "success"`. May be less than
331
+ * `totalSystems` when some systems failed; the call still
332
+ * resolves successfully.
333
+ */
334
+ processedSystems: number;
335
+ /**
336
+ * Count of rows whose `status === "error"`. Equals
337
+ * `totalSystems - processedSystems`. Both counts are kernel-
338
+ * authoritative (NOT derived client-side).
339
+ */
340
+ failedSystems: number;
341
+ /**
342
+ * One entry per input `systemIds[i]`, in input order. Always
343
+ * present, always an array (the kernel processes every input row
344
+ * inline before emitting the response).
345
+ */
346
+ results: BatchSystemResult[];
347
+ /** ISO-8601, from the row's `createdAt` column. */
348
+ createdAt: string;
349
+ /**
350
+ * ISO-8601 OR null. In practice always a string on POST (the
351
+ * kernel sets `startedAt: new Date()` at insert time); the null
352
+ * fallback is defensive against future schema changes.
353
+ */
354
+ startedAt: string | null;
355
+ /**
356
+ * ISO-8601 — ALWAYS present on POST (kernel emits
357
+ * `new Date().toISOString()` unconditionally at route.ts:207).
358
+ * Asymmetric with `BatchJobStatus.completedAt` which is nullable.
359
+ */
360
+ completedAt: string;
361
+ }
362
+ /**
363
+ * Response shape returned by `batch.get(id)`. 11 fields — includes
364
+ * `config` (POST omits config from its response because it's already
365
+ * in the request body, but GET re-emits for callers who didn't
366
+ * submit and want the full picture).
367
+ *
368
+ * Source-of-truth at kernel `src/app/api/v1/batch/[id]/route.ts:57-69`.
369
+ *
370
+ * **`status: BatchJobStatusValue`** — the WIDER 4-value enum
371
+ * (`"pending" | "processing" | "completed" | "failed"`). DB column
372
+ * pass-through; the runtime value MAY observe any of the four for
373
+ * non-SDK-submitted jobs. Type contract is closed at the call site;
374
+ * runtime is open (faithful courier).
375
+ *
376
+ * **`results: BatchSystemResult[] | null`** — nullable on GET (DB
377
+ * jsonb column allows null for `"pending"` jobs that haven't been
378
+ * processed yet). SDK-submitted jobs always have non-null `results`
379
+ * by the time their row is committed.
380
+ *
381
+ * **`config: BatchConfig | null`** — round-trips whatever was
382
+ * submitted (`null` when consumer omitted `config`, or the
383
+ * submitted shape when provided). Per-field shape is open-spec
384
+ * (faithful courier — P2 validates `config === null` OR
385
+ * `typeof === "object"` only).
386
+ *
387
+ * **`startedAt: string | null`** + **`completedAt: string | null`**
388
+ * — both nullable on GET. `"pending"` jobs have both null;
389
+ * `"processing"` has startedAt set but completedAt null;
390
+ * `"completed"` / `"failed"` have both set.
391
+ */
392
+ export interface BatchJobStatus {
393
+ /** UUID of the batch job (echoes the `id` arg passed to `get()`). */
394
+ id: string;
395
+ /**
396
+ * One of the 3 `BatchJobType` values. Open at runtime (P2
397
+ * validates `typeof === "string"` only). DB column has no closed-
398
+ * enum constraint, but rows can only reach the table via POST
399
+ * which Zod-validates.
400
+ */
401
+ jobType: BatchJobType;
402
+ /**
403
+ * **Batch-job-level** status — closed to the 4-value
404
+ * `BatchJobStatusValue` enum on GET (DB column pass-through).
405
+ * Open at runtime (P2 validates `typeof === "string"` only).
406
+ * Distinct from `results[i].status` (per-row `"success" |
407
+ * "error"`).
408
+ */
409
+ status: BatchJobStatusValue;
410
+ /** Echoes the original input `systemIds.length`. */
411
+ totalSystems: number;
412
+ /** Count of rows whose `status === "success"`. */
413
+ processedSystems: number;
414
+ /** Count of rows whose `status === "error"`. */
415
+ failedSystems: number;
416
+ /**
417
+ * Array of per-system results OR `null`. **Nullable on GET** —
418
+ * `"pending"` jobs have not yet been processed and their
419
+ * `results` column is null. SDK-submitted jobs always have
420
+ * non-null `results` by the time the row is committed.
421
+ */
422
+ results: BatchSystemResult[] | null;
423
+ /**
424
+ * The config object the submission used, OR `null`. **Three
425
+ * distinct round-trip cases**:
426
+ * - `null` when the caller OMITTED `config` from the submit
427
+ * body (kernel writes `body.config ?? null` to the column —
428
+ * omission becomes literal `null`).
429
+ * - `{}` (empty object) when the caller passed an explicit
430
+ * empty `config: {}` — kernel writes the empty object
431
+ * verbatim.
432
+ * - `{frameworks: [...]}` (or any other valid shape) when the
433
+ * caller passed an explicit config.
434
+ * **You CANNOT distinguish "consumer omitted" from "kernel wrote
435
+ * null" via this field on GET** — both surface as `null`. To
436
+ * detect explicit-empty-object, check `config !== null` after a
437
+ * known submission. Round-trip only — the kernel does NOT use
438
+ * `config.frameworks` in the current inline classification path.
439
+ */
440
+ config: BatchConfig | null;
441
+ /** ISO-8601, from the row's `createdAt` column. */
442
+ createdAt: string;
443
+ /**
444
+ * ISO-8601 OR null. `"pending"` jobs have null; jobs that have
445
+ * been picked up by an inline or async worker have it set.
446
+ */
447
+ startedAt: string | null;
448
+ /**
449
+ * ISO-8601 OR null. `"pending"` and `"processing"` jobs have
450
+ * null; `"completed"` / `"failed"` have it set.
451
+ */
452
+ completedAt: string | null;
453
+ }
454
+ /**
455
+ * `batch` resource — sibling to `IncidentsResource`,
456
+ * `DecisionsResource`, `ChatResource`, `AuditLogResource`,
457
+ * `RegulatoryChangesResource`, `ComplianceCheckResource`,
458
+ * `CheckResource`, `GateResource`.
459
+ *
460
+ * Multi-method resource (mirror of `ChatResource`'s `send` +
461
+ * `stream`). Wraps TWO kernel routes:
462
+ * - `POST /api/v1/batch` via `submit(input, options?)`
463
+ * - `GET /api/v1/batch/<UUID>` via `get(id, options?)`
464
+ *
465
+ * **First SDK resource with asymmetric auth between methods on the
466
+ * same resource** (invariant candidate #54). `submit()` requires a
467
+ * key with `CLASSIFY` or `WRITE_ASSESSMENTS` AND enterprise plan;
468
+ * `get()` requires only `READ_ASSESSMENTS`. See per-method JSDoc.
469
+ */
470
+ export declare class BatchResource {
471
+ private readonly client;
472
+ constructor(client: AttestryClient);
473
+ /**
474
+ * Submit a batch job — classify and/or read the current
475
+ * classification state for 1-50 systems in one call. Returns a
476
+ * `BatchSubmitResponse` with a per-row `results` envelope
477
+ * describing each system's outcome.
478
+ *
479
+ * **Partial-success contract**: the call resolves successfully
480
+ * (no throw) even when every row failed. Inspect
481
+ * `response.failedSystems` (or iterate `response.results` filtering
482
+ * `row.status === "error"`) to detect per-row errors. Top-level
483
+ * failures (auth, plan, rate limit, Zod, cross-org systemId,
484
+ * internal) DO throw `AttestryAPIError`. Mirror of
485
+ * `decisions.bulk`'s contract.
486
+ *
487
+ * **Multi-permission UNION auth scope (WRITE-side)**: kernel uses
488
+ * `requireApiKeyWithPermission(req, CLASSIFY, WRITE_ASSESSMENTS)`
489
+ * — OR semantics (`Array.some()` at `permissions.ts:53-55`).
490
+ * **First SDK route to use a WRITE-side union pair** (every prior
491
+ * SDK union has been READ-side). A key with EITHER permission
492
+ * (or `ADMIN`, or null/empty permissions for backwards-compat)
493
+ * succeeds. **HTTP 401** for no/invalid API key; **HTTP 403** for
494
+ * an authenticated key that has NEITHER required permission. Pin
495
+ * BOTH branches separately. Invariant #45 / #54.
496
+ *
497
+ * **NEW plan-guard 403 surface** (invariant candidate #55).
498
+ * **BEFORE Zod body parsing**, the kernel calls
499
+ * `requirePlan(org, "hasBatchProcessing")` at route.ts:67. A
500
+ * free-tier (or trial-expired non-enterprise) org hits the plan
501
+ * gate FIRST, regardless of body validity or systemIds. The
502
+ * kernel emits `PlanLimitError` which the route catches at line
503
+ * 216 and surfaces as **403** with a literal message of the form
504
+ * `'The "hasBatchProcessing" feature is not available on your
505
+ * current plan (<plan>). Please upgrade to access this feature.'`
506
+ * Distinct from the permission-403 message
507
+ * `'API key lacks required permission. Required: ... Key has: ...'`
508
+ * — consumers regex-match the message contents if they need to
509
+ * distinguish "upgrade your plan" from "grant more permissions to
510
+ * your key". Both surface uniformly as `AttestryAPIError(403)`
511
+ * (no SDK-side discriminator helper today).
512
+ *
513
+ * **Asymmetric cross-org / not-found error code (404 with
514
+ * EMBEDDED IDs)**: the kernel verifies every requested system
515
+ * belongs to the caller's org and collapses cross-org OR missing
516
+ * to 404. **NEW shape vs gate's literal 404** — the message
517
+ * embeds the comma-joined invalid UUIDs:
518
+ * `'Systems not found or not in your organization: <id1>, <id2>, ...'`.
519
+ * The SDK does NOT parse the embedded IDs — faithful courier;
520
+ * consumers can regex-match if they want to surface specific IDs
521
+ * to users.
522
+ *
523
+ * **TWO silent kernel-side truncations** (invariant candidate
524
+ * #50):
525
+ * 1. `orgSystems` row-population — `.limit(500)` at route.ts:76.
526
+ * The kernel reads up to 500 systems from the caller's org
527
+ * to verify membership. Orgs with >500 systems may see
528
+ * spurious 404s on batch submissions referencing systems
529
+ * outside the first 500 rows. **Documented kernel surface
530
+ * gap**; the SDK does NOT mask. Pin anchored to
531
+ * `.from(schema.aiSystems)[\s\S]*?.limit(500)` in the spec-
532
+ * diff round.
533
+ * 2. (GET-side `.limit(1)` is documented under `get()` below.)
534
+ *
535
+ * **`writeAuditLog` side effect** — every successful `submit()`
536
+ * call writes one `batch.submitted` entry to the org's audit log
537
+ * (route.ts:182-195). Properties of the write:
538
+ * - Org-scoped, hash-chained (per `writeAuditLog` at
539
+ * `src/lib/api.ts:125-`).
540
+ * - **Time-blocking** but error-tolerant: the kernel uses
541
+ * `await writeAuditLog(...)`, which awaits two DB ops (SELECT
542
+ * previous-hash + INSERT new entry). The submit-call response
543
+ * latency INCLUDES the audit-log write time. Error semantics
544
+ * ARE non-blocking: `writeAuditLog` wraps its body in a
545
+ * try/catch that swallows errors and logs them, so a write
546
+ * FAILURE does NOT fail the submit request.
547
+ * - NOT counted against `decisionsPerMonth` quota.
548
+ *
549
+ * **Closed-enum input `jobType`** — pre-rejected SDK-side if not
550
+ * one of `BATCH_JOB_TYPES`. Use `BATCH_JOB_TYPES` to iterate or
551
+ * narrow at call sites.
552
+ *
553
+ * **Per-row discriminator** — use `row.status === "success"` (NOT
554
+ * `row.errorMessage === undefined`, which is prototype-pollution
555
+ * unsafe). See `BatchSystemResult` JSDoc for the full rationale.
556
+ *
557
+ * Errors — ordered by kernel firing precedence (rate-limit →
558
+ * auth → org-load (404 if missing) → plan-guard → Zod body
559
+ * validation → DB membership check → inline processing →
560
+ * internal). A request with multiple problems surfaces ONLY the
561
+ * highest-precedence one. For example: a request with bad auth
562
+ * AND a free-tier org surfaces 401, not 403 (plan-guard fires
563
+ * AFTER auth). A request whose org row was deleted between key
564
+ * issuance and request time surfaces a 404 BEFORE the plan-
565
+ * guard 403 fires (rare in practice). A request with valid auth
566
+ * + valid org + free-tier + a malformed body surfaces 403
567
+ * (plan-guard fires BEFORE Zod body validation).
568
+ *
569
+ * - `AttestryAPIError` (status 429) — rate limit FIRES FIRST
570
+ * (auto-retried by default — invariant #18; per-IP rate-limit
571
+ * key `v1-batch:${ip}`; tighter limiter than apiLimiter —
572
+ * `assessmentLimiter` at 30 req/min vs apiLimiter's 60).
573
+ * - `AttestryAPIError` (status 401) — no API key OR invalid key.
574
+ * - `AttestryAPIError` (status 403, permission branch) — key
575
+ * has NEITHER `CLASSIFY` nor `WRITE_ASSESSMENTS`.
576
+ * - `AttestryAPIError` (status 404, org-not-found branch) — the
577
+ * caller's org row was deleted (route.ts:66: `if (!org)
578
+ * return errorResponse("Organization not found", 404)`).
579
+ * **Distinct from the systems-not-found 404 below** — same
580
+ * status code, different message. Rare in practice (orgs
581
+ * aren't deleted while keys are active).
582
+ * - `AttestryAPIError` (status 403, plan-gate branch) — the
583
+ * org's effective plan doesn't have `hasBatchProcessing`.
584
+ * Distinct wording from the permission-403 (above) — consumers
585
+ * regex-match to distinguish.
586
+ * - `AttestryAPIError` (status 422) — Zod schema rejection
587
+ * (kernel's `BodyParseError` surface — `parseBody(request,
588
+ * batchSubmitSchema)` failed). `apiErr.details` carries the
589
+ * full kernel error body verbatim (the transport does NOT
590
+ * strip the `{success:false, ...}` envelope on error
591
+ * responses — only the `{success:true, data}` envelope on
592
+ * success). The wire shape is: `{success: false, error:
593
+ * "Validation failed.", details: Array<{path: string;
594
+ * message: string}>}` — `error` is the literal string
595
+ * "Validation failed." (with trailing period), `details` is
596
+ * an array (NOT a keyed map) of `{path, message}` pairs
597
+ * derived from Zod's `result.error.errors`. Consumers reading
598
+ * field-by-field errors should iterate `apiErr.details.details`
599
+ * (the kernel's `details` array nested under the SDK's parsed-
600
+ * body wrapper). **The SDK pre-validates all closed-spec
601
+ * rules** (jobType enum membership, systemIds array length
602
+ * [1, 50] + per-element UUID format, frameworks array length
603
+ * ≤20 + per-element string length [1, 100]) AND the runtime
604
+ * checks always run regardless of TypeScript types — `as any`
605
+ * casts do NOT bypass them. So 422 reaches consumers ONLY
606
+ * via kernel rule changes the SDK hasn't synced to. Invariant
607
+ * #51.
608
+ * - `AttestryAPIError` (status 404, systems-not-found branch) —
609
+ * one or more `systemIds[i]` are not in the caller's org (or
610
+ * don't exist). The kernel collapses cross-org and genuine-
611
+ * missing to 404 with the literal message
612
+ * `"Systems not found or not in your organization: <id1>, <id2>, ..."`.
613
+ * **Embedded IDs** — the SDK does NOT parse the offending UUIDs
614
+ * out of the message; consumers can regex-match if needed.
615
+ * - `AttestryAPIError` (status 500) — internal kernel error
616
+ * (scrubbed message via `internalErrorResponse`).
617
+ * - `AttestryError` ("request aborted by caller") — caller-
618
+ * supplied `options.signal` fired (pre-aborted or mid-flight).
619
+ * - `AttestryError` (P2 hardening) — kernel response failed
620
+ * SDK-side shape validation (not an object, wrong type on
621
+ * any of the 10 response fields).
622
+ * - `AttestryAPIError` (P3 hardening) — kernel response had a
623
+ * wrong Content-Type (transport-level guard before body
624
+ * parsing).
625
+ * - `TypeError` — input failed SDK-side validation (null /
626
+ * array / non-object input, missing jobType, unknown
627
+ * jobType, missing systemIds, non-array systemIds, empty
628
+ * systemIds, oversize systemIds, non-string systemIds
629
+ * element, non-UUID systemIds element, non-object config,
630
+ * non-array config.frameworks, oversize config.frameworks,
631
+ * non-string config.frameworks element, oversize/empty
632
+ * config.frameworks element). **THROWN SYNCHRONOUSLY** (no
633
+ * fetch issued; the function does NOT return a promise in
634
+ * this case). Distinct from `AttestryAPIError` /
635
+ * `AttestryError` above, which reject through the returned
636
+ * promise. Consumers using `await client.batch.submit(...)`
637
+ * see both surfaces uniformly; consumers wrapping the call
638
+ * in a non-awaiting context (e.g., `client.batch.submit(...)
639
+ * .then(...)`) must catch the synchronous throw with a
640
+ * surrounding try/catch — the `.then()` chain alone does
641
+ * NOT catch synchronous TypeErrors.
642
+ *
643
+ * **Notably ABSENT**:
644
+ * - **No 400** on POST — all input validation is Zod (422).
645
+ * The GET method DOES have a 400 (malformed `id` path
646
+ * parameter).
647
+ * - **No 413** — body size limit not explicit.
648
+ * - **No 402** — read-shaped from a quota perspective (despite
649
+ * writing per-system classifications, doesn't count against
650
+ * `decisionsPerMonth`).
651
+ *
652
+ * **SDK-side validation** (synchronous `TypeError`, no fetch
653
+ * issued):
654
+ * - `input` itself: required; must be a non-null, non-array
655
+ * object.
656
+ * - `input.jobType`: required own-property; must be a string;
657
+ * must be one of `BATCH_JOB_TYPES`.
658
+ * - `input.systemIds`: required own-property; must be an Array;
659
+ * length [1, 50] inclusive; each element a non-empty string
660
+ * matching `UUID_REGEX`. Snapshot via `Array.from` for TOCTOU
661
+ * defense.
662
+ * - `input.config` (when own-property present, value not
663
+ * undefined): must be a non-null non-array object.
664
+ * - `input.config.frameworks` (when own-property present, value
665
+ * not undefined): must be an array of ≤20 strings, each of
666
+ * length 1-100. Snapshot via `Array.from` for TOCTOU defense.
667
+ *
668
+ * **Response-shape validation** (P2 hardening — symmetric defense
669
+ * on response side, mirror of session-16 second-hostile-review
670
+ * MEDIUM #3 carry-forward):
671
+ * - Rejects with `AttestryError` if the kernel response isn't a
672
+ * non-null, non-array object.
673
+ * - Rejects if `id` / `jobType` / `status` / `createdAt` /
674
+ * `completedAt` aren't strings.
675
+ * - Rejects if `startedAt` isn't a string or null.
676
+ * - Rejects if `totalSystems` / `processedSystems` /
677
+ * `failedSystems` aren't numbers.
678
+ * - Rejects if `results` isn't an array.
679
+ * - Per-row shape (open-spec — `BatchSystemResult`) is faithful-
680
+ * courier — NOT validated.
681
+ * - Each response field read goes through the module-load
682
+ * `objectHasOwn` snapshot (symmetric to input-side defense).
683
+ *
684
+ * **Transport-shape validation** (P3 hardening):
685
+ * - Rejects with `AttestryAPIError` if the kernel responds with
686
+ * a non-`application/json` Content-Type.
687
+ *
688
+ * @example Submit a classify job for 3 systems
689
+ * ```ts
690
+ * const result = await client.batch.submit({
691
+ * jobType: "classify",
692
+ * systemIds: [
693
+ * "11111111-1111-1111-1111-111111111111",
694
+ * "22222222-2222-2222-2222-222222222222",
695
+ * "33333333-3333-3333-3333-333333333333",
696
+ * ],
697
+ * });
698
+ * console.log(`Processed ${result.processedSystems}/${result.totalSystems}`);
699
+ * for (const row of result.results) {
700
+ * if (row.status === "success") {
701
+ * console.log(`OK ${row.systemId}:`, row.classifications);
702
+ * } else {
703
+ * // CRITICAL: branch on `row.status === "error"` — NOT
704
+ * // `row.errorMessage === undefined` (prototype-pollution
705
+ * // unsafe).
706
+ * console.error(`FAIL ${row.systemId}: ${row.errorMessage}`);
707
+ * }
708
+ * }
709
+ * ```
710
+ *
711
+ * @example Submit with framework filter (round-trip only today)
712
+ * ```ts
713
+ * const job = await client.batch.submit({
714
+ * jobType: "classify_and_assess",
715
+ * systemIds: ["11111111-1111-1111-1111-111111111111"],
716
+ * config: { frameworks: ["EU_AI_ACT", "ISO_42001"] },
717
+ * });
718
+ * // config.frameworks is persisted on the row but has no effect on
719
+ * // the current inline classification path.
720
+ * ```
721
+ */
722
+ submit(input: BatchSubmitInput, options?: RequestOptions): Promise<BatchSubmitResponse>;
723
+ /**
724
+ * Retrieve a batch job's status and results by UUID. Returns a
725
+ * `BatchJobStatus` with the wider 4-value `status` enum (NOT the
726
+ * narrower `"completed" | "failed"` of POST) plus the original
727
+ * `config` (round-tripped from submission).
728
+ *
729
+ * **Single-permission auth scope (DIFFERENT from `submit()`)** —
730
+ * kernel uses `requireApiKeyWithPermission(req, READ_ASSESSMENTS)`
731
+ * with ONLY ONE required permission, NOT a union. Status reads
732
+ * don't need `CLASSIFY` or `WRITE_ASSESSMENTS`. **First SDK
733
+ * resource with asymmetric auth between methods on the same
734
+ * resource** (invariant candidate #54). Pin BOTH 401 (no/invalid
735
+ * key) AND 403 (key lacks `READ_ASSESSMENTS`) branches.
736
+ *
737
+ * **NO plan-guard surface on `get()`** — `requirePlan` is invoked
738
+ * only in `submit()`. A free-tier org can `get()` a job that was
739
+ * previously submitted (e.g., on a higher plan that has since
740
+ * downgraded). The submission would have been gated; the read
741
+ * isn't.
742
+ *
743
+ * **400 surface on malformed UUID path parameter** — the kernel's
744
+ * `isValidUuid(id)` check at route.ts:36 returns false →
745
+ * `errorResponse("Invalid batch job ID format", 400)`. The SDK
746
+ * pre-validates the UUID format synchronously (`TypeError`) — so
747
+ * the 400 reaches consumers only via `as any` casts or a kernel-
748
+ * side switch to a different UUID flavor (ULID, KSUID, etc.).
749
+ *
750
+ * **404 surface (literal string)** — the kernel's `where(id +
751
+ * orgId)` query returns zero rows → `errorResponse("Batch job not
752
+ * found", 404)`. **NEW shape** vs `submit()`'s 404 with embedded
753
+ * IDs — the `get()` 404 is a LITERAL string with no variable
754
+ * data. Cross-org `id` collapses to the same 404 (the `eq(orgId,
755
+ * apiKeyUser.orgId)` clause silently filters out matching IDs in
756
+ * other orgs).
757
+ *
758
+ * **No `writeAuditLog` side effect on `get()`** — status reads
759
+ * are quiet. Asymmetric with `submit()`'s `batch.submitted`
760
+ * write.
761
+ *
762
+ * **Defensive `.limit(1)` on the batchJobs query** (route.ts:49)
763
+ * — the `where` clause already narrows to one row by primary-key
764
+ * UUID, so this cap is belt-and-suspenders against a hypothetical
765
+ * future schema change (composite primary key, soft-deleted-rows
766
+ * union). Pin separately as a kernel surface gap. Invariant
767
+ * candidate #50.
768
+ *
769
+ * Errors — ordered by kernel firing precedence (rate-limit →
770
+ * auth → UUID format → DB lookup → internal):
771
+ * - `AttestryAPIError` (status 429) — rate limit (auto-retried;
772
+ * per-IP key `v1-batch-status:${ip}`; uses the standard
773
+ * `apiLimiter` at 60 req/min — looser than `submit()`'s 30/
774
+ * min `assessmentLimiter`).
775
+ * - `AttestryAPIError` (status 401) — no API key OR invalid key.
776
+ * - `AttestryAPIError` (status 403) — authenticated key lacks
777
+ * `READ_ASSESSMENTS` permission (single-permission check,
778
+ * NOT a union). Pin separately from `submit()`'s 403.
779
+ * - `AttestryAPIError` (status 400) — kernel's `isValidUuid(id)`
780
+ * returned false. **The SDK pre-validates UUID format**, so
781
+ * this 400 reaches consumers ONLY via `as any` casts or
782
+ * kernel-side UUID flavor changes.
783
+ * - `AttestryAPIError` (status 404) — batch job not found OR
784
+ * cross-org `id` (kernel collapses to "Batch job not found";
785
+ * literal string with NO embedded variable data — distinct
786
+ * from `submit()`'s 404 shape).
787
+ * - `AttestryAPIError` (status 500) — internal kernel error
788
+ * (scrubbed message).
789
+ * - `AttestryError` ("request aborted by caller") — caller-
790
+ * supplied `options.signal` fired.
791
+ * - `AttestryError` (P2 hardening) — kernel response failed
792
+ * SDK-side shape validation (11 fields).
793
+ * - `AttestryAPIError` (P3 hardening) — wrong Content-Type.
794
+ * - `TypeError` — input failed SDK-side validation (missing
795
+ * `id`, non-string `id`, empty `id`, malformed UUID `id`).
796
+ * **THROWN SYNCHRONOUSLY** (no fetch issued; not via the
797
+ * returned promise). Consumers using `.then(...)` without
798
+ * a surrounding try/catch see this surface as an uncaught
799
+ * synchronous throw — same caveat as `submit()`.
800
+ *
801
+ * **SDK-side validation** (synchronous `TypeError`, no fetch
802
+ * issued):
803
+ * - `id`: required; must be a non-empty string matching
804
+ * `UUID_REGEX` (RFC 4122 hyphenated, case-insensitive).
805
+ *
806
+ * **Response-shape validation** (P2 hardening — 11 fields, all
807
+ * always-present; symmetric defense on response side via the
808
+ * module-load `objectHasOwn` snapshot):
809
+ * - Rejects with `AttestryError` if the response isn't a non-
810
+ * null, non-array object.
811
+ * - Rejects if `id` / `jobType` / `status` / `createdAt` aren't
812
+ * strings.
813
+ * - Rejects if `totalSystems` / `processedSystems` /
814
+ * `failedSystems` aren't numbers.
815
+ * - Rejects if `results` isn't `null` OR an array.
816
+ * - Rejects if `config` isn't `null` OR a non-array object.
817
+ * - Rejects if `startedAt` / `completedAt` aren't `null` OR
818
+ * a string.
819
+ * - Per-row shape (open-spec `BatchSystemResult`) is faithful-
820
+ * courier — NOT validated.
821
+ * - `config.frameworks` shape is faithful-courier — NOT
822
+ * validated.
823
+ *
824
+ * **NO URIError defense on the `id` path segment** — the SDK
825
+ * pre-validates the UUID format (synchronous `TypeError`) BEFORE
826
+ * constructing the URL. A lone-surrogate or non-hex `id` is
827
+ * rejected before any `encodeURIComponent`-style call could fire.
828
+ * Hex-only UUIDs are guaranteed-safe for path concatenation.
829
+ *
830
+ * @example Poll a job's status
831
+ * ```ts
832
+ * const job = await client.batch.get("11111111-1111-1111-1111-111111111111");
833
+ * if (job.status === "completed") {
834
+ * console.log(`Processed ${job.processedSystems}/${job.totalSystems}`);
835
+ * } else if (job.status === "failed") {
836
+ * console.error("Batch failed entirely");
837
+ * } else {
838
+ * // "pending" / "processing" — still in flight
839
+ * console.log(`Job is ${job.status}`);
840
+ * }
841
+ * ```
842
+ */
843
+ get(id: string, options?: RequestOptions): Promise<BatchJobStatus>;
844
+ }
845
+ //# sourceMappingURL=batch.d.ts.map