Initial Commit
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
# `options` — Zod-validated options for `createStaticPrincipalResolver`
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
Owns the runtime contract between the test harness call site and the
|
||||
resolver factory. The schema validates both the outer options bag
|
||||
(`{ principal, nullForPaths?, applyTo? }`) and the nested `Principal` shape
|
||||
(non-empty `id`, readonly `scopes`, optional `tenantId`, default-`{}`
|
||||
`claims`). On failure it raises a typed `AuthStaticPrincipalError` carrying
|
||||
the originating Zod issues — splitting between `INVALID_OPTIONS` (anything
|
||||
outside `principal`) and `INVALID_PRINCIPAL` (anything inside it).
|
||||
|
||||
This module is the only place the package touches Zod at runtime. Keeping it
|
||||
isolated lets the resolver factory stay a thin three-line function and lets
|
||||
the conformance test target the resolver behaviour without invoking schema
|
||||
side-effects.
|
||||
|
||||
## Features
|
||||
|
||||
- Strict outer schema — unknown keys at the top level reject with
|
||||
`INVALID_OPTIONS`.
|
||||
- Discriminated error codes: `principal` issues map to `INVALID_PRINCIPAL`;
|
||||
everything else maps to `INVALID_OPTIONS`.
|
||||
- Pre-flight type check rejects non-object inputs with `INVALID_OPTIONS`
|
||||
before Zod sees them — a cleaner message than the Zod default for `null` /
|
||||
arrays.
|
||||
- `claims` defaults to `{}` so callers don't have to write
|
||||
`claims: {}` for the common case.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { parseStaticPrincipalResolverOptions } from "@suaveplan/api-auth-static-principal/resolver";
|
||||
|
||||
const opts = parseStaticPrincipalResolverOptions({
|
||||
principal: {
|
||||
id: "u_1",
|
||||
scopes: ["billing:write"],
|
||||
tenantId: "acme",
|
||||
claims: { email: "user@acme.test" },
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
Validate options that include both `applyTo` and `nullForPaths`:
|
||||
|
||||
```ts
|
||||
import { parseStaticPrincipalResolverOptions } from "@suaveplan/api-auth-static-principal/resolver";
|
||||
|
||||
const opts = parseStaticPrincipalResolverOptions({
|
||||
principal: { id: "u_1", scopes: [], claims: {} },
|
||||
nullForPaths: ["/webhooks/*", "/healthz"],
|
||||
applyTo: (req) => !req.headers.has("x-skip-auth"),
|
||||
});
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
| Symbol | Kind | Description |
|
||||
| -------------------------------------------- | -------- | ----------------------------------------------------------------- |
|
||||
| `StaticPrincipalResolverOptionsSchema` | Zod | Strict object schema for the outer bag. |
|
||||
| `parseStaticPrincipalResolverOptions(raw)` | function | Returns the validated options or throws `AuthStaticPrincipalError`. |
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The pre-flight `typeof`/`Array.isArray` check lets the function return a
|
||||
single canonical error for "you handed me something that isn't an object" —
|
||||
Zod's own behaviour on `null` is to emit
|
||||
`{ code: "invalid_type", expected: "object" }`, which is correct but verbose.
|
||||
Splitting into a pre-flight + Zod pass is one extra branch but keeps the
|
||||
caller-facing failure message stable.
|
||||
|
||||
`claims` is recorded as `z.record(z.unknown())` so any free-form JWT/claims
|
||||
payload validates. Coercing to readonly happens at the TypeScript boundary
|
||||
(`StaticPrincipalResolverOptions`), not in Zod — Zod's `.readonly()` is
|
||||
type-level only and would re-wrap arrays at runtime unnecessarily.
|
||||
Reference in New Issue
Block a user