@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,1034 @@
1
+ import type { AttestryClient } from "../client.js";
2
+ import type { RequestOptions } from "../types.js";
3
+ /**
4
+ * Closed-enum of resources an ABAC policy can target. Runtime mirror
5
+ * of the kernel's `RESOURCES` const at `src/lib/auth.ts:29-40`.
6
+ * Object.freeze'd to prevent runtime mutation.
7
+ */
8
+ export declare const ABAC_POLICY_RESOURCES: readonly ["systems", "assessments", "documents", "attestations", "evidence", "users", "api_keys", "audit_log", "organization", "regulations"];
9
+ /**
10
+ * Closed-enum of actions an ABAC policy can gate. Runtime mirror of
11
+ * the kernel's `ACTIONS` const at `src/lib/auth.ts:42-48`.
12
+ */
13
+ export declare const ABAC_POLICY_ACTIONS: readonly ["create", "read", "update", "delete", "manage"];
14
+ /**
15
+ * Closed-enum of effects. Runtime mirror of the kernel's `Effect` type
16
+ * alias at `src/lib/auth/abac-policies.ts:77` + the Zod
17
+ * `z.enum(["allow", "deny"]).default("allow")` at
18
+ * `src/lib/auth/abac-policies.ts:756`.
19
+ */
20
+ export declare const ABAC_POLICY_EFFECTS: readonly ["allow", "deny"];
21
+ /**
22
+ * Stable enum of ABAC effects. Mirror of the kernel's `Effect` type
23
+ * alias at `src/lib/auth/abac-policies.ts:77`. **Closed-enum at the
24
+ * type level; runtime validation is `typeof === "string"` only**
25
+ * (faithful courier — mirror of `gate.evaluate`'s `gate: "pass" | "fail"`
26
+ * pattern). If a future kernel emits a new effect (unlikely — the
27
+ * NIST SP 800-162 decision algorithm is fundamentally allow/deny),
28
+ * the value round-trips at runtime.
29
+ */
30
+ export type AbacPolicyEffect = "allow" | "deny";
31
+ /**
32
+ * Stable enum of resources an ABAC policy can target. Mirror of the
33
+ * kernel's `Resource` type alias at `src/lib/auth.ts:5-15` AND the
34
+ * runtime `RESOURCES` const at `src/lib/auth.ts:29-40`. The SDK's
35
+ * mirrored runtime array (`ABAC_POLICY_RESOURCES`) ships in the
36
+ * `.create()` build round (session 22) when input pre-validation
37
+ * needs it; for `.list()` only the type alias is used.
38
+ *
39
+ * **Closed-enum at the type level; runtime is faithful-courier**
40
+ * (P2 validator checks `typeof === "string"` only). A kernel-side
41
+ * RESOURCES addition would surface in the drift suite (spec-diff
42
+ * round) before consumer regressions.
43
+ */
44
+ export type AbacPolicyResource = "systems" | "assessments" | "documents" | "attestations" | "evidence" | "users" | "api_keys" | "audit_log" | "organization" | "regulations";
45
+ /**
46
+ * Stable enum of actions an ABAC policy can gate. Mirror of the
47
+ * kernel's `Action` type alias at `src/lib/auth.ts:17` AND the runtime
48
+ * `ACTIONS` const at `src/lib/auth.ts:42-48`.
49
+ */
50
+ export type AbacPolicyAction = "create" | "read" | "update" | "delete" | "manage";
51
+ /**
52
+ * Root for attribute paths in a condition leaf. The kernel rejects
53
+ * paths not rooted at `principal.<...>` or `resource.<...>` via the
54
+ * `SAFE_PATH_RE` regex at `src/lib/auth/abac-policies.ts:143`.
55
+ */
56
+ export type AbacAttrRoot = "principal" | "resource";
57
+ /**
58
+ * Dotted attribute path like `principal.id` or `resource.ownerId`. The
59
+ * kernel's `SAFE_PATH_RE` requires `\.[A-Za-z_][A-Za-z0-9_]*` segments
60
+ * after the root and rejects `__proto__` / `constructor` / `prototype`
61
+ * via a separate `FORBIDDEN_KEYS` check. The SDK's TypeScript template-
62
+ * literal type only encodes the root prefix — segment-level shape is
63
+ * documented but not type-enforced (TS template-literal recursion
64
+ * costs aren't worth the small ergonomic win here).
65
+ */
66
+ export type AbacAttrPath = `${AbacAttrRoot}.${string}`;
67
+ /**
68
+ * A primitive value an attribute can equal / be-in. Strings, numbers,
69
+ * and booleans only. Mirror of the kernel's `AttrValue` at
70
+ * `src/lib/auth/abac-policies.ts:63`. `null` / `undefined` are NOT in
71
+ * the union — the evaluator treats missing attributes specially (see
72
+ * `evaluateCondition` at `src/lib/auth/abac-policies.ts:486-578`).
73
+ */
74
+ export type AbacAttrValue = string | number | boolean;
75
+ /**
76
+ * Leaf condition — one of 8 operator shapes. Mirror of the kernel's
77
+ * `LeafCondition` at `src/lib/auth/abac-policies.ts:65-69`. The
78
+ * canonical validator enforces per-op allowed-key sets server-side
79
+ * (`src/lib/auth/abac-policies.ts:220-232`) — admin typos like
80
+ * `valuee:` get rejected, not silently dropped.
81
+ */
82
+ export type AbacLeafCondition = {
83
+ op: "eq" | "ne";
84
+ attr: AbacAttrPath;
85
+ value: AbacAttrValue;
86
+ } | {
87
+ op: "in" | "notIn";
88
+ attr: AbacAttrPath;
89
+ values: AbacAttrValue[];
90
+ } | {
91
+ op: "exists" | "notExists";
92
+ attr: AbacAttrPath;
93
+ } | {
94
+ op: "attrEq" | "attrNe";
95
+ left: AbacAttrPath;
96
+ right: AbacAttrPath;
97
+ };
98
+ /**
99
+ * Compound condition — `and` / `or` / `not`. Mirror of the kernel's
100
+ * `CompoundCondition` at `src/lib/auth/abac-policies.ts:71-73`. The
101
+ * canonical validator enforces depth + clause budgets server-side
102
+ * (`MAX_DEPTH = 8`, `MAX_CLAUSES_PER_COMPOUND = 32`,
103
+ * `MAX_NODES_PER_EVALUATION = 1000`).
104
+ */
105
+ export type AbacCompoundCondition = {
106
+ op: "and" | "or";
107
+ clauses: AbacCondition[];
108
+ } | {
109
+ op: "not";
110
+ clause: AbacCondition;
111
+ };
112
+ /**
113
+ * Full condition AST — discriminated union of leaf + compound.
114
+ * Mirror of the kernel's `AbacCondition` at
115
+ * `src/lib/auth/abac-policies.ts:75`.
116
+ */
117
+ export type AbacCondition = AbacLeafCondition | AbacCompoundCondition;
118
+ /**
119
+ * An ABAC policy row as returned by `.list()` / `.retrieve()` /
120
+ * `.create()` / `.update()` / `.delete()`. Mirror of the kernel's
121
+ * `AbacPolicyRow` at `src/lib/auth/abac-policies.ts:88-98`.
122
+ *
123
+ * **Wire-shape note — Dates are ISO strings, not Date objects.** The
124
+ * kernel's TypeScript type declares `createdAt: Date` / `updatedAt:
125
+ * Date` (it's a Drizzle `timestamp` column inferred as `Date` post-
126
+ * fetch), but the response goes through `NextResponse.json(...)` which
127
+ * serializes Dates via `JSON.stringify(new Date(...))` → ISO-8601
128
+ * string. The SDK type reflects the wire reality (`string`), not the
129
+ * kernel's TypeScript intermediate.
130
+ *
131
+ * **`description`, `createdByUserId` — `string | null`** (NOT
132
+ * `string | undefined`). The kernel uses `null` for unset values via
133
+ * the `?? null` coalesce at `src/lib/auth/abac-policies.ts:706, 713`;
134
+ * the field is ALWAYS present on the wire, with value `null` when
135
+ * unset. Consumers comparing should use `policy.description !== null`
136
+ * (or truthy coercion, since null is falsy).
137
+ *
138
+ * **`condition` — recursive AST** mirroring the kernel grammar (8 leaf
139
+ * ops + 3 compound ops). Consumers can branch on `condition.op` to
140
+ * destructure. Server-side validation enforces depth / clause / value-
141
+ * list / total-node budgets; the SDK does NOT re-validate the AST
142
+ * after the kernel returns it (faithful courier).
143
+ */
144
+ export interface AbacPolicy {
145
+ /** UUID of the policy row. */
146
+ id: string;
147
+ /** UUID of the owning org. Always equals the auth caller's `orgId`. */
148
+ orgId: string;
149
+ /** Short identifier (1-128 chars). UNIQUE per `(orgId, name)` — */
150
+ name: string;
151
+ /**
152
+ * Optional human-readable description (max 2000 chars on the kernel's
153
+ * Zod schema). `null` when unset. **NOT `undefined`** — the kernel
154
+ * uses `?? null` coalesce server-side, so `description` is always an
155
+ * own-property on the wire.
156
+ */
157
+ description: string | null;
158
+ /** Resource the policy targets (closed-enum). */
159
+ resource: AbacPolicyResource;
160
+ /** Action the policy gates (closed-enum). */
161
+ action: AbacPolicyAction;
162
+ /** Effect — `allow` grants access, `deny` denies (NIST SP 800-162 §5.2). */
163
+ effect: AbacPolicyEffect;
164
+ /** Recursive condition AST evaluated against `{principal, resource}`. */
165
+ condition: AbacCondition;
166
+ /**
167
+ * Priority [0, 1000] used to order policies before evaluation (ASC
168
+ * — lower-priority policies are evaluated first, but `deny` short-
169
+ * circuits regardless of order). Default 100 server-side.
170
+ */
171
+ priority: number;
172
+ /** When `false`, the policy is excluded from the per-request fetch. */
173
+ enabled: boolean;
174
+ /**
175
+ * UUID of the user who created the policy. `null` when the policy
176
+ * was inserted directly via DB (e.g., migrations / fixtures), or
177
+ * when the creator's user row was deleted (ON DELETE SET NULL).
178
+ */
179
+ createdByUserId: string | null;
180
+ /** ISO-8601 timestamp of the insert. */
181
+ createdAt: string;
182
+ /** ISO-8601 timestamp of the most recent update (or insert if never updated). */
183
+ updatedAt: string;
184
+ }
185
+ /**
186
+ * Response shape returned by `.list()`. The kernel emits
187
+ * `{success: true, data: {items: AbacPolicy[], count: number}}`; the
188
+ * transport unwraps `data`, so consumers receive `{items, count}`.
189
+ *
190
+ * **No pagination** — `count` is `items.length` (NOT a total org
191
+ * count beyond the materialized page). Server-side cap is
192
+ * `MAX_POLICIES_PER_ORG_FETCH = 200`. Orgs with >200 policies see
193
+ * only the LOWEST 200 by priority ASC. Documented kernel surface
194
+ * gap — invariant #50.
195
+ */
196
+ export interface AbacPoliciesListResponse {
197
+ /** Up to 200 policies ordered by `priority` ASC, server-truncated. */
198
+ items: AbacPolicy[];
199
+ /** `items.length` — same as `items.length`; NOT a total org count. */
200
+ count: number;
201
+ }
202
+ /**
203
+ * Input shape for `.create()`. Mirror of the kernel's
204
+ * `createAbacPolicySchema` Zod at
205
+ * `src/lib/auth/abac-policies.ts:750-761`. The kernel applies
206
+ * **`.strict()`** — any extra fields are rejected with 422.
207
+ *
208
+ * **Required fields**: `name`, `resource`, `action`, `condition`.
209
+ *
210
+ * **Closed-spec defaults** (kernel applies if SDK omits):
211
+ * - `effect` defaults to `"allow"`.
212
+ * - `priority` defaults to `100`.
213
+ * - `enabled` defaults to `true`.
214
+ * Per invariant #52, the SDK OMITS the field from the body when the
215
+ * consumer omits it (so the kernel applies its default). Documenting
216
+ * each default prominently below.
217
+ *
218
+ * **`condition` is the recursive AST** (`AbacCondition`). The SDK
219
+ * does NOT pre-validate the AST grammar — the kernel's canonical
220
+ * validator runs server-side and rejects invalid shapes (depth >8,
221
+ * clauses >32 per compound, values >64 per list, total nodes >1000,
222
+ * unknown ops, malformed attr paths). **First SDK route with
223
+ * partial Zod pre-validation**: closed-spec fields are pre-validated
224
+ * SDK-side (UUID-style closed-enum + length bounds), but the
225
+ * recursive AST field defers entirely to server. Consumers see
226
+ * `AbacPolicyValidationError` as 422 with `details: { errors:
227
+ * string[] }` for AST violations; closed-spec rule violations
228
+ * surface as `BodyParseError` 422 with `details:
229
+ * Array<{path, message}>`.
230
+ *
231
+ * **Fifth SDK route to PRE-VALIDATE every Zod closed-spec rule
232
+ * synchronously** (after `check.run`, `gate.evaluate`,
233
+ * `batch.submit`, `shipGate.check`). **FIRST SDK route with PARTIAL
234
+ * pre-validation** — the `condition` field is an OPEN-spec rule
235
+ * (`z.record(z.string(), z.unknown())`) so AST grammar validation
236
+ * defers entirely to the server's canonical validator. Calibration:
237
+ * pre-validatable closed-spec rules are `name.min(1).max(128)`,
238
+ * `description.max(2000).optional().nullable()`,
239
+ * `resource`/`action`/`effect` closed-enums,
240
+ * `priority.int().min(0).max(1000)`, `enabled.boolean()`. The
241
+ * `condition` field is the only non-closed-spec rule on the schema.
242
+ */
243
+ export interface AbacPolicyCreateInput {
244
+ /**
245
+ * Short identifier (1-128 chars). UNIQUE per `(orgId, name)` on the
246
+ * `abac_policies` table — duplicates trip `AbacPolicyNameConflictError`
247
+ * which surfaces as HTTP 409.
248
+ */
249
+ name: string;
250
+ /**
251
+ * Optional description (max 2000 chars). Accepts `string`, `null`,
252
+ * or `undefined` (omitted). When omitted, the kernel persists `null`.
253
+ */
254
+ description?: string | null;
255
+ /** Resource the policy targets (closed-enum). */
256
+ resource: AbacPolicyResource;
257
+ /** Action the policy gates (closed-enum). */
258
+ action: AbacPolicyAction;
259
+ /**
260
+ * `"allow"` grants access, `"deny"` denies. Default `"allow"` —
261
+ * the SDK OMITS this field when consumer omits it; kernel applies
262
+ * `"allow"`. Per invariant #52.
263
+ */
264
+ effect?: AbacPolicyEffect;
265
+ /**
266
+ * Recursive condition AST evaluated against `{principal, resource}`.
267
+ * The SDK does NOT pre-validate the AST grammar — the kernel's
268
+ * canonical validator at `src/lib/auth/abac-policies.ts:161-174`
269
+ * handles depth / clause / value-list / total-node budgets +
270
+ * per-operator allowed keys. SDK-side check is only "is this an
271
+ * object" (rejects `null`, arrays, primitives).
272
+ */
273
+ condition: AbacCondition;
274
+ /**
275
+ * Integer [0, 1000]. Default `100` — the SDK OMITS this field when
276
+ * consumer omits it; kernel applies `100`. Per invariant #52.
277
+ * Lower values are evaluated FIRST (asc), but the deny-wins
278
+ * algorithm short-circuits regardless of order.
279
+ */
280
+ priority?: number;
281
+ /**
282
+ * Per-policy enable flag. Default `true` — the SDK OMITS this field
283
+ * when consumer omits it; kernel applies `true`. When `false`, the
284
+ * policy is excluded from the per-request fetch.
285
+ */
286
+ enabled?: boolean;
287
+ }
288
+ /**
289
+ * Input shape for `.update()`. Mirror of the kernel's
290
+ * `updateAbacPolicySchema` Zod at
291
+ * `src/lib/auth/abac-policies.ts:763-795`. The kernel applies
292
+ * **`.strict()`** — any extra fields are rejected with 422.
293
+ *
294
+ * **EVERY field is optional** — `.update()` is a PARTIAL update
295
+ * (PATCH semantics). Asymmetric with `AbacPolicyCreateInput`, whose
296
+ * `name` / `resource` / `action` / `condition` are required: the
297
+ * kernel's `updateAbacPolicySchema` carries `.optional()` on all 8
298
+ * fields. A consumer patches only the fields they want to change.
299
+ *
300
+ * **Empty-patch rejection** — the kernel schema ends in a `.refine()`
301
+ * rejecting a body with NO updatable field (`"PATCH body must
302
+ * include at least one updatable field"`). The SDK pre-rejects an
303
+ * empty patch — `update(id, {})`, an all-`undefined` patch, or a
304
+ * patch carrying ONLY unknown keys — synchronously with a
305
+ * `TypeError` BEFORE any fetch is issued.
306
+ *
307
+ * **`description` accepts `null`** — passing `description: null`
308
+ * CLEARS an existing description. `null` is a present field for the
309
+ * kernel's `.refine()` (`description !== undefined` is `true` when
310
+ * `description` is `null`), so `update(id, { description: null })`
311
+ * is a valid non-empty patch. An explicit `description: undefined`
312
+ * is treated as omission (symmetric with `.create()`).
313
+ *
314
+ * **`condition` is the recursive AST** (`AbacCondition`) — same as
315
+ * `.create()`. The SDK does NOT pre-validate the AST grammar; a
316
+ * present `condition` is pre-validated only as "is this a non-null
317
+ * object", and the recursive grammar defers to the kernel's
318
+ * canonical validator. The fields reuse `AbacPolicyResource` /
319
+ * `AbacPolicyAction` / `AbacPolicyEffect` / `AbacCondition` verbatim.
320
+ */
321
+ export interface AbacPolicyUpdateInput {
322
+ /**
323
+ * New short identifier (1-128 chars). UNIQUE per `(orgId, name)` on
324
+ * the `abac_policies` table — a collision trips
325
+ * `AbacPolicyNameConflictError` (HTTP 409).
326
+ */
327
+ name?: string;
328
+ /**
329
+ * New description (max 2000 chars). Accepts `string`, `null`, or
330
+ * `undefined` (omitted). Pass `null` to CLEAR an existing
331
+ * description — `null` counts as a present field (a non-empty
332
+ * patch); `undefined` is treated as omission.
333
+ */
334
+ description?: string | null;
335
+ /** New resource the policy targets (closed-enum). */
336
+ resource?: AbacPolicyResource;
337
+ /** New action the policy gates (closed-enum). */
338
+ action?: AbacPolicyAction;
339
+ /** New effect — `"allow"` grants access, `"deny"` denies (closed-enum). */
340
+ effect?: AbacPolicyEffect;
341
+ /**
342
+ * New recursive condition AST evaluated against `{principal,
343
+ * resource}`. The SDK pre-validates only that a present `condition`
344
+ * is a non-null object; the recursive AST grammar (depth / clause /
345
+ * value-list / total-node budgets, per-operator allowed keys) is
346
+ * validated server-side by the kernel's canonical validator.
347
+ */
348
+ condition?: AbacCondition;
349
+ /** New priority — integer [0, 1000]. Lower values are evaluated FIRST. */
350
+ priority?: number;
351
+ /** New per-policy enable flag. When `false`, the policy is excluded from the per-request fetch. */
352
+ enabled?: boolean;
353
+ }
354
+ /**
355
+ * `abacPolicies` resource — sibling to all 10 existing resource classes
356
+ * on the SDK. The class is the landing pad for the 5-method CRUD
357
+ * cluster; `.list()` is the first method to ship (session 21), with
358
+ * `.create()` / `.retrieve()` / `.update()` / `.delete()` arriving in
359
+ * session 22. Resource-class-per-kernel-resource convention,
360
+ * invariant #43.
361
+ */
362
+ export declare class AbacPoliciesResource {
363
+ private readonly client;
364
+ constructor(client: AttestryClient);
365
+ /**
366
+ * List ABAC policies for the caller's org. Returns up to 200 rows
367
+ * ordered by `priority` ASC. No pagination; the cap is a documented
368
+ * kernel surface gap.
369
+ *
370
+ * **Dual-auth admin scope** — the kernel route gates on
371
+ * `requireSessionOrApiKey(request, { sessionRoles: ["admin"],
372
+ * apiKeyPermissions: [API_KEY_PERMISSIONS.ADMIN] })`. The SDK's
373
+ * transport always sends `x-api-key`, so the api-key path is the
374
+ * only one reachable from SDK consumers. An api-key without the
375
+ * `ADMIN` permission returns 403 (NOT 401 — see status code
376
+ * surface below).
377
+ *
378
+ * **Status-code surface — 401 AND 403 distinguished** (verified
379
+ * by reading `src/lib/middleware/auth.ts:96-110` and
380
+ * `src/lib/middleware/permissions.ts:35-66`):
381
+ * - **HTTP 401**: no `x-api-key` header, empty `x-api-key`
382
+ * header (`""`), invalid key (no matching row), expired key.
383
+ * - **HTTP 403**: valid api-key in the org whose `permissions`
384
+ * column does NOT include `ADMIN`. Error message: `"API key
385
+ * lacks required permission. Required: admin. Key has: ..."`.
386
+ * `auditLog.export` shares this EXACT dual-auth surface — its
387
+ * kernel route uses the identical `requireSessionOrApiKey(...
388
+ * sessionRoles:["admin"], apiKeyPermissions:[ADMIN] ...)` gate, so
389
+ * it too returns 401 vs 403 distinctly. (The `audit-log.ts` JSDoc's
390
+ * prior "HTTP 401 for both" claim was a mis-read of the kernel
391
+ * test's mocked `AuthError(401)` — corrected in session-22 hostile
392
+ * review #2.)
393
+ *
394
+ * **No pagination** — `count` is `items.length`, NOT a total org
395
+ * count. Server-side cap is 200 rows by priority ASC. Orgs with
396
+ * >200 policies are silently truncated (documented invariant #50
397
+ * gap; the SDK does NOT auto-paginate this method because the
398
+ * kernel emits no cursor — there's no next-page anchor to follow).
399
+ *
400
+ * **No `writeAuditLog` side effect** — `.list()` is quiet
401
+ * (asymmetric with `gate.evaluate` / `batch.submit` /
402
+ * `shipGate.check` which all write entries).
403
+ *
404
+ * **Symmetric prototype-pollution defense — RESPONSE side only**:
405
+ * the P2 validator uses the module-load `objectHasOwn` snapshot on
406
+ * each response field read. Input side is N/A (`.list()` has no
407
+ * input fields). Mirror of `audit-log.verifyChain` /
408
+ * `regulatoryChanges.list` pattern.
409
+ *
410
+ * Errors — **happy-path precedence ordering** is rate-limit → auth
411
+ * → DB lookup → successResponse. **The 500-catchall is a SEPARATE
412
+ * DIMENSION** — any throwable not matched by the named `instanceof`
413
+ * arms (only `AuthError` here) falls to 500, regardless of where
414
+ * in the happy-path it fired.
415
+ * - `AttestryAPIError` (status 429) — rate limit FIRES FIRST
416
+ * (auto-retried by default — invariant #18; per-IP rate-limit
417
+ * key `abac-policies-list:${ip}` against the
418
+ * `assessmentLimiter` — 30 req / 1-min sliding window).
419
+ * - `AttestryAPIError` (status 401) — no API key OR invalid key
420
+ * OR expired key. Fires AFTER rate-limit.
421
+ * - `AttestryAPIError` (status 403) — valid api-key in the org
422
+ * whose permissions do NOT include `ADMIN`. Distinct branch
423
+ * from 401 — pin BOTH separately per the dual-auth status-
424
+ * code surface.
425
+ * - `AttestryAPIError` (status 500) — internal kernel error
426
+ * (scrubbed message via `internalErrorResponse`). **The 500
427
+ * surface is orthogonal to the precedence list above**: ANY
428
+ * throwable not matched by the route's single `instanceof
429
+ * AuthError` arm falls to 500.
430
+ * - `AttestryError` ("request aborted by caller") — caller-
431
+ * supplied `options.signal` fired.
432
+ * - `AttestryError` (P2 hardening) — kernel response failed
433
+ * SDK-side shape validation (not an object, `items` not an
434
+ * array, `count` not a number).
435
+ * - `AttestryAPIError` (P3 hardening) — kernel response had a
436
+ * wrong Content-Type (transport-level guard before body
437
+ * parsing).
438
+ *
439
+ * **Notably ABSENT**:
440
+ * - **No 400** — no input → nothing to validate.
441
+ * - **No 404** — `.list()` returns `{items: [], count: 0}` on
442
+ * empty result (NOT 404). 404 is only on `.retrieve()` /
443
+ * `.update()` / `.delete()` (session 22).
444
+ *
445
+ * **Response-shape validation** (P2 hardening — symmetric defense
446
+ * on response side per the module-load `objectHasOwn` snapshot;
447
+ * mirror of `regulatoryChanges.list` / `incidents.list` patterns):
448
+ * - Rejects with `AttestryError` if the kernel response isn't
449
+ * a non-null, non-array object.
450
+ * - Rejects if `items` isn't an array.
451
+ * - Rejects if `count` isn't a number.
452
+ * - Per-row item shape NOT validated (faithful courier — P4
453
+ * candidate; matches incidents.list / regulatoryChanges.list).
454
+ *
455
+ * **Transport-shape validation** (P3 hardening):
456
+ * - Rejects with `AttestryAPIError` if the kernel responds with
457
+ * a non-`application/json` Content-Type.
458
+ *
459
+ * @example List all ABAC policies for the caller's org
460
+ * ```ts
461
+ * const { items, count } = await client.abacPolicies.list();
462
+ * console.log(`${count} policies in this org:`);
463
+ * for (const policy of items) {
464
+ * console.log(` ${policy.priority} ${policy.effect} ${policy.action} ${policy.resource}: ${policy.name}`);
465
+ * }
466
+ * ```
467
+ *
468
+ * @example Inspect a policy's condition AST
469
+ * ```ts
470
+ * const { items } = await client.abacPolicies.list();
471
+ * const ownerOnly = items.find((p) => p.name === "owner-only");
472
+ * if (ownerOnly && ownerOnly.condition.op === "attrEq") {
473
+ * console.log(`Compares ${ownerOnly.condition.left} === ${ownerOnly.condition.right}`);
474
+ * }
475
+ * ```
476
+ */
477
+ list(options?: RequestOptions): Promise<AbacPoliciesListResponse>;
478
+ /**
479
+ * Create a new ABAC policy in the caller's org. Returns the
480
+ * inserted row on success (HTTP 201).
481
+ *
482
+ * **Dual-auth admin scope** — same as `.list()`: kernel uses
483
+ * `requireSessionOrApiKey(request, { sessionRoles: ["admin"],
484
+ * apiKeyPermissions: [API_KEY_PERMISSIONS.ADMIN] })`. The SDK's
485
+ * transport always sends `x-api-key`, so the api-key path is the
486
+ * only one reachable from SDK consumers. **HTTP 401** for no/
487
+ * invalid/expired key, **HTTP 403** for valid-key-without-ADMIN
488
+ * permission. Pin BOTH branches separately.
489
+ *
490
+ * **FIRST SDK route to return HTTP 201 on success** (NOT 200).
491
+ * The transport unwraps the `{success:true, data}` envelope and
492
+ * returns the body on any 2xx status — consumers receive the
493
+ * created row directly. To inspect the literal HTTP status,
494
+ * consumers must inspect via fetch-instrumented middleware
495
+ * (not exposed by the SDK today; P4 candidate).
496
+ *
497
+ * **FIRST SDK route with HTTP 409 Conflict surface**. The
498
+ * `(org_id, name)` unique constraint trips `AbacPolicyNameConflictError`
499
+ * at the DB layer; the kernel maps to 409 with error message
500
+ * `An ABAC policy named "<name>" already exists in this organization.`.
501
+ * Consumers should branch on `err.status === 409` to render a
502
+ * specific "name taken" UX.
503
+ *
504
+ * **Three-way 422 fan-out — distinct wire shapes per error class**:
505
+ * The kernel's POST handler catch block has THREE 422-mapping arms:
506
+ *
507
+ * 1. **`BodyParseError`** (most common — from `parseBody(request,
508
+ * schema)`) → `{ success: false, error: "Validation failed.",
509
+ * details: Array<{ path: string, message: string }> }`. Raised
510
+ * when Zod's `.strict()` schema rejects (e.g., extra field,
511
+ * wrong type, out-of-range value).
512
+ * 2. **`ZodError`** (DEFENSIVE — DEAD on happy path; `parseBody`
513
+ * catches Zod and converts to `BodyParseError`. The catch arm
514
+ * exists as defense-in-depth if some other code path throws
515
+ * raw `ZodError`) → `{ success: false, error: "Validation
516
+ * failed.", details: ZodIssue[] }` (richer than BodyParseError's
517
+ * mapped form — includes `code`, `expected`, `received`).
518
+ * 3. **`AbacPolicyValidationError`** (REACHABLE — from server-side
519
+ * canonical AST validation in `createAbacPolicy`) → `{ success:
520
+ * false, error: "ABAC policy validation failed: <messages>",
521
+ * details: { errors: string[] } }`. Raised when the condition
522
+ * AST violates depth / clause / value-list / total-node budgets,
523
+ * or has unknown ops / malformed attr paths.
524
+ *
525
+ * SDK surfaces all three uniformly as `AttestryAPIError(422)` —
526
+ * consumers inspect `err.details` to discriminate:
527
+ * - `Array.isArray(err.details)` → BodyParseError OR ZodError
528
+ * (per-field validation failure; iterate for `{path, message}`).
529
+ * - `err.details && Array.isArray(err.details.errors)` →
530
+ * AbacPolicyValidationError (AST violation; iterate `details.errors`
531
+ * for descriptive strings).
532
+ *
533
+ * Drift-pinned in spec-diff round (both wire shapes + the DEAD
534
+ * ZodError catch arm).
535
+ *
536
+ * **Fifth SDK route to PRE-VALIDATE every Zod closed-spec rule
537
+ * synchronously** (after `check.run`, `gate.evaluate`,
538
+ * `batch.submit`, `shipGate.check`). **FIRST SDK route with
539
+ * PARTIAL pre-validation** — the SDK pre-validates all 7 closed-
540
+ * spec fields synchronously (name length, description length-or-
541
+ * null, resource/action/effect closed-enums, priority int +
542
+ * bounds, enabled boolean) AND defers the recursive AST validation
543
+ * on `condition` to the server canonical validator. The condition
544
+ * field is `z.record(z.string(), z.unknown())` at the schema level
545
+ * (OPEN-spec, not pre-validatable without shipping the full
546
+ * recursive validator). Invariant #49 calibration: closed-spec
547
+ * rules ARE pre-validatable; recursive grammar rules are NOT
548
+ * (too expensive to mirror).
549
+ *
550
+ * **`writeAuditLog` side effect — every successful `.create()` call
551
+ * writes one audit entry** with `action: "abac_policy.create"` and
552
+ * `resourceType: "abac_policy"` (kernel route.ts:105-120; both
553
+ * strings drift-pinned). Properties:
554
+ * - Org-scoped, hash-chained.
555
+ * - **Time-blocking** but error-tolerant: kernel uses
556
+ * `await writeAuditLog(...)`; check response latency INCLUDES
557
+ * the audit-log write time.
558
+ * - Write FAILURE does NOT fail the request (try/catch swallows).
559
+ * - NOT counted against `decisionsPerMonth` quota.
560
+ * - **Audit log is NOT written on failed create** (Zod / canonical
561
+ * validation / name conflict all surface BEFORE writeAuditLog).
562
+ *
563
+ * **Kernel-side 30-second timeout** (`maxDuration = 30`). Same as
564
+ * `.list()` and `auditLog.export`; looser than `gate.evaluate` /
565
+ * `shipGate.check`'s 15s. ABAC policy creation does NO heavy
566
+ * computation — the 30s budget is for DB I/O headroom.
567
+ *
568
+ * **Default-applied fields**: `effect` defaults to `"allow"`,
569
+ * `priority` defaults to `100`, `enabled` defaults to `true`. The
570
+ * SDK OMITS these fields from the request body when the consumer
571
+ * omits them (so the kernel applies its default). Per invariant #52.
572
+ *
573
+ * Errors:
574
+ * - `AttestryAPIError` (429) — rate limit (auto-retried; per-IP
575
+ * key `abac-policies-create:${ip}` against `assessmentLimiter`).
576
+ * - `AttestryAPIError` (401) — no/invalid/expired api-key.
577
+ * - `AttestryAPIError` (403) — valid api-key without ADMIN permission.
578
+ * - `AttestryAPIError` (422) — Zod-schema validation OR canonical-
579
+ * validator AST failure. Discriminate via `err.details` shape
580
+ * (see "Three-way 422 fan-out" above).
581
+ * - `AttestryAPIError` (409) — `(org_id, name)` uniqueness
582
+ * conflict.
583
+ * - `AttestryAPIError` (500) — internal kernel error (scrubbed).
584
+ * - `AttestryError` ("request aborted by caller") — `options.signal`
585
+ * fired.
586
+ * - `AttestryError` (P2 hardening) — kernel response failed
587
+ * SDK-side shape validation. Pre-validated per-row shape:
588
+ * non-null object + all 13 fields present and correctly typed.
589
+ * - `AttestryAPIError` (P3 hardening) — wrong Content-Type on
590
+ * response.
591
+ * - `TypeError` (synchronous, no fetch issued) — SDK-side input
592
+ * validation: missing required field, wrong type, out-of-range
593
+ * value, unknown closed-enum value, malformed input.
594
+ *
595
+ * @example Create a simple "owner can edit own assessments" policy
596
+ * ```ts
597
+ * const policy = await client.abacPolicies.create({
598
+ * name: "owner-can-edit-own",
599
+ * description: "Owners can edit their own assessments.",
600
+ * resource: "assessments",
601
+ * action: "update",
602
+ * effect: "allow",
603
+ * condition: {
604
+ * op: "attrEq",
605
+ * left: "principal.id",
606
+ * right: "resource.ownerId",
607
+ * },
608
+ * priority: 100,
609
+ * enabled: true,
610
+ * });
611
+ * console.log(`Created policy ${policy.id}`);
612
+ * ```
613
+ *
614
+ * @example Catch name-conflict (HTTP 409)
615
+ * ```ts
616
+ * try {
617
+ * await client.abacPolicies.create({...});
618
+ * } catch (err) {
619
+ * if (err instanceof AttestryAPIError && err.status === 409) {
620
+ * // Show "name taken" UX
621
+ * }
622
+ * }
623
+ * ```
624
+ *
625
+ * @example Discriminate 422 wire-shape (Zod vs canonical-validator)
626
+ * ```ts
627
+ * try {
628
+ * await client.abacPolicies.create({...});
629
+ * } catch (err) {
630
+ * if (err instanceof AttestryAPIError && err.status === 422) {
631
+ * const details = err.details as unknown;
632
+ * if (Array.isArray(details)) {
633
+ * // Zod field-level failures: [{path, message}, ...]
634
+ * } else if (details && typeof details === "object" &&
635
+ * Array.isArray((details as {errors?: unknown}).errors)) {
636
+ * // Canonical-validator AST failures: {errors: string[]}
637
+ * }
638
+ * }
639
+ * }
640
+ * ```
641
+ */
642
+ create(input: AbacPolicyCreateInput, options?: RequestOptions): Promise<AbacPolicy>;
643
+ /**
644
+ * Retrieve one ABAC policy by id. Returns the policy row.
645
+ *
646
+ * **FIRST `abacPolicies` method with a UUID path segment** — `id`
647
+ * is interpolated into the request path
648
+ * (`/api/v1/abac-policies/<id>`). `.list()` / `.create()` hit the
649
+ * collection path with no segment; `.update()` / `.delete()` share
650
+ * this id-path shape.
651
+ *
652
+ * **Dual-auth admin scope** — same as `.list()` / `.create()`: the
653
+ * kernel route gates on `requireSessionOrApiKey(request, {
654
+ * sessionRoles: ["admin"], apiKeyPermissions:
655
+ * [API_KEY_PERMISSIONS.ADMIN] })`. The SDK transport always sends
656
+ * `x-api-key`, so the api-key path is the only one reachable from
657
+ * SDK consumers. **HTTP 401** for no/invalid/expired key, **HTTP
658
+ * 403** for a valid key whose permissions do NOT include `ADMIN`.
659
+ * Pin BOTH branches separately (asymmetric with carry-forward
660
+ * invariant #42's ADMIN-only 401-collapse).
661
+ *
662
+ * **UUID pre-validation** — the SDK pre-validates `id` against
663
+ * `UUID_REGEX` synchronously (`TypeError`, NO fetch issued) before
664
+ * constructing the URL. The kernel's own `badId` check would
665
+ * return HTTP 400 "Invalid policy id." on a malformed id, but the
666
+ * SDK pre-empts it — that 400 is reachable only via an `as any`
667
+ * cast or a kernel-side id-flavor change. Mirror of `batch.get`.
668
+ *
669
+ * **No `encodeURIComponent` / URIError defense on the path
670
+ * segment** — a string matching `UUID_REGEX` is ASCII hex digits +
671
+ * hyphens, so it is URL-safe verbatim and cannot trigger a
672
+ * `URIError`. The validated `id` is interpolated raw. Asymmetric
673
+ * with `decisions.retrieve` (free-form id → `encodePathSegment`
674
+ * with path-traversal + URIError defenses).
675
+ *
676
+ * **404 surface** — the kernel's `getAbacPolicyById(orgId, id)`
677
+ * returns `null` for a missing id OR a cross-org id (the
678
+ * `eq(orgId)` clause silently filters policies in other orgs), and
679
+ * the GET handler maps that to `errorResponse("ABAC policy not
680
+ * found.", 404)`. **Inline literal message** — distinct from
681
+ * `.update()` / `.delete()`'s 404, which is raised by
682
+ * `AbacPolicyNotFoundError` with the id-embedded message `"ABAC
683
+ * policy <id> not found in this organization."`.
684
+ *
685
+ * **No `writeAuditLog` side effect** — `.retrieve()` is a quiet
686
+ * read (same as `.list()`; asymmetric with `.create()` /
687
+ * `.update()` / `.delete()`, which each write an `abac_policy.*`
688
+ * audit-log entry).
689
+ *
690
+ * **Kernel-side 30-second timeout** (`maxDuration = 30`). Same as
691
+ * `.list()` / `.create()` / `auditLog.export`; looser than
692
+ * `gate.evaluate` / `shipGate.check`'s 15s.
693
+ *
694
+ * Errors — **happy-path precedence ordering**: UUID format (kernel
695
+ * `badId` — SDK-pre-empted) → rate-limit → auth → DB lookup →
696
+ * successResponse. **The 500-catchall is a SEPARATE DIMENSION** —
697
+ * any throwable not matched by the GET handler's single
698
+ * `instanceof AuthError` arm falls to 500.
699
+ * - `AttestryAPIError` (status 429) — rate limit FIRES FIRST
700
+ * among the network surfaces (auto-retried by default —
701
+ * invariant #18; per-IP key `abac-policies-get:${ip}` against
702
+ * `assessmentLimiter` — 30 req / 1-min sliding window).
703
+ * - `AttestryAPIError` (status 401) — no/invalid/expired api-key.
704
+ * - `AttestryAPIError` (status 403) — valid api-key whose
705
+ * permissions do NOT include `ADMIN`. Distinct branch from
706
+ * 401 — pin BOTH separately.
707
+ * - `AttestryAPIError` (status 404) — policy not found OR a
708
+ * cross-org id (kernel collapses both to "ABAC policy not
709
+ * found.").
710
+ * - `AttestryAPIError` (status 400) — kernel `badId` rejected
711
+ * the id. **SDK-pre-empted** — reachable from a consumer only
712
+ * via an `as any` cast or a kernel-side id-flavor change.
713
+ * - `AttestryAPIError` (status 500) — internal kernel error
714
+ * (scrubbed message via `internalErrorResponse`). **Orthogonal
715
+ * to the precedence list** — ANY throwable not matched by the
716
+ * route's single `instanceof AuthError` arm falls here.
717
+ * - `AttestryError` ("request aborted by caller") — caller-
718
+ * supplied `options.signal` fired.
719
+ * - `AttestryError` (P2 hardening) — kernel response failed
720
+ * SDK-side shape validation (non-object, or any of the 13
721
+ * `AbacPolicy` fields missing / wrong-typed).
722
+ * - `AttestryAPIError` (P3 hardening) — kernel response had a
723
+ * wrong Content-Type (transport-level guard before body
724
+ * parsing).
725
+ * - `TypeError` (synchronous, NO fetch issued) — `id` is missing,
726
+ * a non-string, an empty string, or not an RFC 4122 UUID.
727
+ *
728
+ * **SDK-side validation** (synchronous `TypeError`, no fetch
729
+ * issued):
730
+ * - `id`: required; must be a non-empty string matching
731
+ * `UUID_REGEX` (RFC 4122 hyphenated, case-insensitive).
732
+ *
733
+ * **Response-shape validation** (P2 hardening) — the shared
734
+ * `validateAbacPolicy` validator checks all 13 `AbacPolicy` fields
735
+ * via the module-load `objectHasOwn` snapshot (symmetric
736
+ * prototype-pollution defense). `condition` is validated as a
737
+ * non-null object only — the recursive AST is faithful-courier.
738
+ *
739
+ * **Transport-shape validation** (P3 hardening) — rejects with
740
+ * `AttestryAPIError` if the kernel responds with a
741
+ * non-`application/json` Content-Type.
742
+ *
743
+ * @example Retrieve a policy by id
744
+ * ```ts
745
+ * const policy = await client.abacPolicies.retrieve(
746
+ * "550e8400-e29b-41d4-a716-446655440000",
747
+ * );
748
+ * console.log(`${policy.effect} ${policy.action} ${policy.resource}`);
749
+ * ```
750
+ *
751
+ * @example Handle not-found (HTTP 404)
752
+ * ```ts
753
+ * try {
754
+ * return await client.abacPolicies.retrieve(id);
755
+ * } catch (err) {
756
+ * if (err instanceof AttestryAPIError && err.status === 404) {
757
+ * return null; // policy doesn't exist (or belongs to another org)
758
+ * }
759
+ * throw err;
760
+ * }
761
+ * ```
762
+ */
763
+ retrieve(id: string, options?: RequestOptions): Promise<AbacPolicy>;
764
+ /**
765
+ * Update one ABAC policy by id (PARTIAL update). Returns the
766
+ * **updated row** — the policy as it exists AFTER the patch is
767
+ * applied — on HTTP 200.
768
+ *
769
+ * **SECOND SDK method using the HTTP `PATCH` verb** (`incidents.update`
770
+ * is the first). The kernel route is `PATCH /api/v1/abac-policies/[id]`.
771
+ *
772
+ * **Partial update — every input field is optional.** A consumer
773
+ * patches only the fields they want to change; omitted fields keep
774
+ * their current value. The SDK builds the request body from the
775
+ * present-and-not-`undefined` fields only — an omitted field (or an
776
+ * explicit `field: undefined`) is left out of the body so the kernel
777
+ * leaves that column untouched.
778
+ *
779
+ * **Empty-patch pre-validation.** The kernel's `updateAbacPolicySchema`
780
+ * ends in a `.refine()` rejecting a body with NO updatable field
781
+ * (`"PATCH body must include at least one updatable field"`). The
782
+ * SDK pre-rejects an empty patch — `update(id, {})`, an
783
+ * all-`undefined` patch, or a patch carrying ONLY unknown keys —
784
+ * synchronously with a `TypeError` (NO fetch issued) so the consumer
785
+ * never burns a round-trip on a guaranteed 422.
786
+ *
787
+ * **Dual-auth admin scope** — same as `.list()` / `.create()` /
788
+ * `.retrieve()` / `.delete()`: `requireSessionOrApiKey(request, {
789
+ * sessionRoles: ["admin"], apiKeyPermissions:
790
+ * [API_KEY_PERMISSIONS.ADMIN] })`. **HTTP 401** for no/invalid/
791
+ * expired key, **HTTP 403** for a valid key whose permissions do NOT
792
+ * include `ADMIN`. Pin BOTH branches separately.
793
+ *
794
+ * **UUID pre-validation** — `id` is pre-validated against
795
+ * `UUID_REGEX` synchronously via the shared `assertValidPolicyId`
796
+ * helper (`TypeError`, NO fetch issued). The kernel `badId` 400
797
+ * ("Invalid policy id.") is SDK-pre-empted. **No `encodeURIComponent`
798
+ * / URIError defense** — a validated UUID is ASCII hex + hyphens and
799
+ * is interpolated into the path raw (mirror of `batch.get`).
800
+ *
801
+ * **Partial Zod pre-validation** — the closed-spec fields that ARE
802
+ * present are pre-validated synchronously (name length, description
803
+ * length-or-null, resource/action/effect closed-enums, priority
804
+ * int+bounds, enabled boolean); a present `condition` is checked
805
+ * only as a non-null object, deferring the recursive AST grammar to
806
+ * the kernel's canonical validator. Mirror of `.create()`'s partial
807
+ * pre-validation — but here EVERY field is optional.
808
+ *
809
+ * **`description: null` CLEARS the description.** Passing
810
+ * `description: null` is a valid non-empty patch — the kernel
811
+ * persists `null`. An explicit `description: undefined` is treated
812
+ * as omission (symmetric with `.create()`).
813
+ *
814
+ * **Three-way 422 fan-out — same distinct wire shapes as `.create()`:**
815
+ * 1. **`BodyParseError`** (Zod `.strict()` rejection via
816
+ * `parseBody`) → `details: Array<{ path, message }>`.
817
+ * 2. **`ZodError`** (DEFENSIVE — DEAD on the happy path;
818
+ * `parseBody` catches Zod and converts to `BodyParseError`) →
819
+ * `details: ZodIssue[]`.
820
+ * 3. **`AbacPolicyValidationError`** (server-side canonical AST
821
+ * validation) → `details: { errors: string[] }`.
822
+ * SDK surfaces all three uniformly as `AttestryAPIError(422)` —
823
+ * discriminate via `err.details` (see the `.create()` examples).
824
+ *
825
+ * **HTTP 409 Conflict** — patching `name` to a value already used
826
+ * by a sibling policy in the org trips the `(orgId, name)` unique
827
+ * constraint → `AbacPolicyNameConflictError` → 409.
828
+ *
829
+ * **HTTP 404** — the kernel's `updateAbacPolicy` throws
830
+ * `AbacPolicyNotFoundError` when the `(id, orgId)`-scoped lookup
831
+ * misses (a missing id OR a cross-org id). **The message is
832
+ * id-embedded** — `"ABAC policy <id> not found in this
833
+ * organization."` — same shape as `.delete()`'s 404 (distinct from
834
+ * `.retrieve()`'s INLINE `"ABAC policy not found."`).
835
+ *
836
+ * **6 named-error catch arms — the LARGEST on the SDK**, in order:
837
+ * `AuthError`, `BodyParseError`, `ZodError`,
838
+ * `AbacPolicyValidationError`, `AbacPolicyNameConflictError`,
839
+ * `AbacPolicyNotFoundError`. Everything else falls to the 500
840
+ * `internalErrorResponse` catchall.
841
+ *
842
+ * **`writeAuditLog` side effect** — every successful `.update()`
843
+ * writes one audit-log entry with `action: "abac_policy.update"`
844
+ * and `resourceType: "abac_policy"`; the entry's `details` records
845
+ * the changed field names plus a structured `before`/`after` diff.
846
+ * The write is org-scoped + hash-chained, `await`-ed (so `.update()`
847
+ * latency includes the audit write) but error-tolerant (a write
848
+ * failure does NOT fail the request) and is NOT counted against any
849
+ * quota. The audit log is NOT written on a failed update — 404 /
850
+ * 409 / 422 all surface BEFORE the `writeAuditLog` call.
851
+ *
852
+ * **Kernel-side 30-second timeout** (`maxDuration = 30`). Same as
853
+ * `.list()` / `.create()` / `.retrieve()` / `.delete()`.
854
+ *
855
+ * Errors — **happy-path precedence ordering**: UUID format (kernel
856
+ * `badId` — SDK-pre-empted) → rate-limit → auth → body parse → DB
857
+ * lookup/update → audit write → successResponse.
858
+ * - `AttestryAPIError` (429) — rate limit FIRES FIRST among the
859
+ * network surfaces (auto-retried; per-IP key
860
+ * `abac-policies-patch:${ip}` against `assessmentLimiter`).
861
+ * - `AttestryAPIError` (401) — no/invalid/expired api-key.
862
+ * - `AttestryAPIError` (403) — valid api-key without `ADMIN`.
863
+ * Distinct branch from 401 — pin BOTH separately.
864
+ * - `AttestryAPIError` (422) — Zod-schema validation OR canonical-
865
+ * validator AST failure. Discriminate via `err.details` shape.
866
+ * - `AttestryAPIError` (409) — `(orgId, name)` uniqueness conflict.
867
+ * - `AttestryAPIError` (404) — policy not found OR a cross-org id
868
+ * (`AbacPolicyNotFoundError`; id-embedded message).
869
+ * - `AttestryAPIError` (400) — kernel `badId` rejected the id.
870
+ * **SDK-pre-empted**.
871
+ * - `AttestryAPIError` (500) — internal kernel error (scrubbed).
872
+ * - `AttestryError` ("request aborted by caller") — `options.signal`
873
+ * fired.
874
+ * - `AttestryError` (P2 hardening) — the updated row failed
875
+ * SDK-side shape validation (non-object, or any of the 13
876
+ * `AbacPolicy` fields missing / wrong-typed).
877
+ * - `AttestryAPIError` (P3 hardening) — wrong Content-Type on the
878
+ * response.
879
+ * - `TypeError` (synchronous, NO fetch issued) — invalid `id`;
880
+ * `input` not a non-null object; a present field is the wrong
881
+ * type / out of range / an unknown closed-enum value; OR the
882
+ * patch is empty (no updatable field).
883
+ *
884
+ * @example Patch a single field (the rest of the policy is unchanged)
885
+ * ```ts
886
+ * const updated = await client.abacPolicies.update(
887
+ * "550e8400-e29b-41d4-a716-446655440000",
888
+ * { enabled: false },
889
+ * );
890
+ * console.log(`Policy "${updated.name}" is now ${updated.enabled ? "on" : "off"}`);
891
+ * ```
892
+ *
893
+ * @example Clear a description (pass null) and re-prioritize
894
+ * ```ts
895
+ * await client.abacPolicies.update(id, { description: null, priority: 10 });
896
+ * ```
897
+ *
898
+ * @example Catch a name-conflict (HTTP 409)
899
+ * ```ts
900
+ * try {
901
+ * await client.abacPolicies.update(id, { name: "taken-name" });
902
+ * } catch (err) {
903
+ * if (err instanceof AttestryAPIError && err.status === 409) {
904
+ * // another policy in the org already uses that name
905
+ * }
906
+ * }
907
+ * ```
908
+ */
909
+ update(id: string, input: AbacPolicyUpdateInput, options?: RequestOptions): Promise<AbacPolicy>;
910
+ /**
911
+ * Delete one ABAC policy by id. Returns the **deleted row** — the
912
+ * policy as it existed immediately before deletion — on HTTP 200.
913
+ *
914
+ * **Returns the deleted row, NOT `void`.** The kernel's DELETE
915
+ * handler emits `successResponse(row, 200)` carrying the
916
+ * just-deleted `AbacPolicy`, so a caller can log / audit / render
917
+ * an undo affordance with the full prior state. Consumers MUST NOT
918
+ * expect `Promise<void>` or a `{ deleted: true }` envelope — the
919
+ * resolved value is a complete `AbacPolicy`.
920
+ *
921
+ * **FIRST SDK method using the HTTP `DELETE` verb.** Every prior
922
+ * SDK route is GET / POST / PATCH. The transport's
923
+ * `InternalRequestArgs.method` union already includes `"DELETE"`,
924
+ * so no new transport primitive is needed.
925
+ *
926
+ * **Dual-auth admin scope** — same as `.list()` / `.create()` /
927
+ * `.retrieve()`: `requireSessionOrApiKey(request, { sessionRoles:
928
+ * ["admin"], apiKeyPermissions: [API_KEY_PERMISSIONS.ADMIN] })`.
929
+ * **HTTP 401** for no/invalid/expired key, **HTTP 403** for a valid
930
+ * key whose permissions do NOT include `ADMIN`. Pin BOTH branches.
931
+ *
932
+ * **UUID pre-validation** — `id` is pre-validated against
933
+ * `UUID_REGEX` synchronously (`TypeError`, NO fetch issued) via the
934
+ * shared `assertValidPolicyId` helper. The kernel `badId` 400
935
+ * ("Invalid policy id.") is SDK-pre-empted. **No `encodeURIComponent`
936
+ * / URIError defense** — a validated UUID is ASCII hex + hyphens and
937
+ * is interpolated into the path raw (see `UUID_REGEX`; mirror of
938
+ * `batch.get`).
939
+ *
940
+ * **404 surface** — the kernel's `deleteAbacPolicy(orgId, id)`
941
+ * throws `AbacPolicyNotFoundError` when the `(id, orgId)`-scoped
942
+ * delete matches zero rows (a missing id OR a cross-org id — the
943
+ * `eq(orgId)` clause scopes the delete). The DELETE handler maps it
944
+ * to `errorResponse(error.message, 404)`. **The message is
945
+ * id-embedded** — `"ABAC policy <id> not found in this
946
+ * organization."` — distinct from `.retrieve()`'s INLINE
947
+ * `"ABAC policy not found."`. (`.retrieve()` uses an inline string;
948
+ * `.update()` / `.delete()` raise `AbacPolicyNotFoundError`.)
949
+ *
950
+ * **`writeAuditLog` side effect — every successful `.delete()` call
951
+ * writes one audit-log entry** with `action: "abac_policy.delete"`
952
+ * and `resourceType: "abac_policy"`. The entry's `details` records
953
+ * the deleted policy's `name` / `resource` / `action` / `effect`
954
+ * for forensics. The write is org-scoped + hash-chained; it is
955
+ * `await`-ed (so `.delete()` latency includes the audit write) but
956
+ * error-tolerant (a write failure does NOT fail the request); it is
957
+ * NOT counted against any quota. The audit log is NOT written on a
958
+ * failed delete — a 404 surfaces BEFORE the `writeAuditLog` call.
959
+ *
960
+ * **Kernel-side 30-second timeout** (`maxDuration = 30`). Same as
961
+ * `.list()` / `.create()` / `.retrieve()`.
962
+ *
963
+ * Errors — **happy-path precedence ordering**: UUID format (kernel
964
+ * `badId` — SDK-pre-empted) → rate-limit → auth → DB delete → audit
965
+ * write → successResponse. **The 500-catchall is a SEPARATE
966
+ * DIMENSION** — any throwable not matched by the DELETE handler's 2
967
+ * `instanceof` arms (`AuthError`, `AbacPolicyNotFoundError`) falls
968
+ * to 500.
969
+ * - `AttestryAPIError` (status 429) — rate limit FIRES FIRST
970
+ * among the network surfaces (auto-retried by default —
971
+ * invariant #18; per-IP key `abac-policies-delete:${ip}`
972
+ * against `assessmentLimiter` — 30 req / 1-min sliding window).
973
+ * - `AttestryAPIError` (status 401) — no/invalid/expired api-key.
974
+ * - `AttestryAPIError` (status 403) — valid api-key without
975
+ * `ADMIN`. Distinct branch from 401 — pin BOTH separately.
976
+ * - `AttestryAPIError` (status 404) — policy not found OR a
977
+ * cross-org id (`AbacPolicyNotFoundError`; id-embedded message).
978
+ * - `AttestryAPIError` (status 400) — kernel `badId` rejected the
979
+ * id. **SDK-pre-empted** — reachable from a consumer only via
980
+ * an `as any` cast or a kernel-side id-flavor change.
981
+ * - `AttestryAPIError` (status 500) — internal kernel error
982
+ * (scrubbed message via `internalErrorResponse`). **Orthogonal
983
+ * to the precedence list** — ANY throwable not matched by the
984
+ * route's 2 `instanceof` arms falls here.
985
+ * - `AttestryError` ("request aborted by caller") — caller-
986
+ * supplied `options.signal` fired.
987
+ * - `AttestryError` (P2 hardening) — the deleted row failed
988
+ * SDK-side shape validation (non-object, or any of the 13
989
+ * `AbacPolicy` fields missing / wrong-typed).
990
+ * - `AttestryAPIError` (P3 hardening) — kernel response had a
991
+ * wrong Content-Type (transport-level guard before body
992
+ * parsing).
993
+ * - `TypeError` (synchronous, NO fetch issued) — `id` is missing,
994
+ * a non-string, an empty string, or not an RFC 4122 UUID.
995
+ *
996
+ * **SDK-side validation** (synchronous `TypeError`, no fetch
997
+ * issued):
998
+ * - `id`: required; must be a non-empty string matching
999
+ * `UUID_REGEX` (RFC 4122 hyphenated, case-insensitive).
1000
+ *
1001
+ * **Response-shape validation** (P2 hardening) — the shared
1002
+ * `validateAbacPolicy` validator checks all 13 `AbacPolicy` fields
1003
+ * of the deleted row via the module-load `objectHasOwn` snapshot.
1004
+ * `condition` is validated as a non-null object only — the
1005
+ * recursive AST is faithful-courier.
1006
+ *
1007
+ * **Transport-shape validation** (P3 hardening) — rejects with
1008
+ * `AttestryAPIError` if the kernel responds with a
1009
+ * non-`application/json` Content-Type.
1010
+ *
1011
+ * @example Delete a policy and log the prior state
1012
+ * ```ts
1013
+ * const deleted = await client.abacPolicies.delete(
1014
+ * "550e8400-e29b-41d4-a716-446655440000",
1015
+ * );
1016
+ * console.log(`Deleted "${deleted.name}" (${deleted.effect} ${deleted.action})`);
1017
+ * ```
1018
+ *
1019
+ * @example Treat a not-found delete as idempotent success
1020
+ * ```ts
1021
+ * try {
1022
+ * await client.abacPolicies.delete(id);
1023
+ * } catch (err) {
1024
+ * if (err instanceof AttestryAPIError && err.status === 404) {
1025
+ * // already gone — fine for an idempotent caller
1026
+ * } else {
1027
+ * throw err;
1028
+ * }
1029
+ * }
1030
+ * ```
1031
+ */
1032
+ delete(id: string, options?: RequestOptions): Promise<AbacPolicy>;
1033
+ }
1034
+ //# sourceMappingURL=abac-policies.d.ts.map