first commit
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
# `error-codes`
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
Stable error-code registry for `@suaveplan/api-auth-rolled`. Every code is
|
||||
namespaced under `AUTH_ROLLED.*` so cross-package consumers (the host's audit
|
||||
log, the OpenAPI emitter, the conformance harness) can identify the package
|
||||
that raised the failure without string-matching on free-form messages.
|
||||
|
||||
The milestone ships the session-resolver half only; the registry
|
||||
is correspondingly minimal — four operator-actionable infrastructure codes,
|
||||
all of which are thrown synchronously from production code paths and
|
||||
covered by the conformance test. Per-request soft failures (missing token,
|
||||
bad signature, expired) collapse to `null` per `SessionResolver` chain
|
||||
semantics and are therefore NOT codes. Account-lifecycle codes
|
||||
(`USER_NOT_FOUND`, `INVALID_CREDENTIALS`, `PASSWORD_BREACHED`, …) belong to
|
||||
the deferred provider half and will be added by a successor change.
|
||||
|
||||
## Features
|
||||
|
||||
- Tagged with `defineCodes("AUTH_ROLLED", [...])` from `@suaveplan/error`,
|
||||
so all codes share a single namespace prefix.
|
||||
- `AuthRolledError` extends `SuaveplanError` so `instanceof AuthRolledError`
|
||||
narrows `.code` to `AuthRolledErrorCode`.
|
||||
- Four codes: `SIGNING_KEY_NOT_CONFIGURED` (options validation),
|
||||
`KEY_ROTATION_FAILED` (`TokenRotator.setKeys`),
|
||||
`DATABASE_REQUIRED` (missing `store`), `PRINCIPAL_PROJECTION_FAILED`
|
||||
(malformed user row).
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { AUTH_ROLLED_CODES, AuthRolledError } from "@suaveplan/api-auth-rolled";
|
||||
|
||||
throw new AuthRolledError(
|
||||
AUTH_ROLLED_CODES.DATABASE_REQUIRED,
|
||||
"host did not inject a store"
|
||||
);
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import { AUTH_ROLLED_CODES, AuthRolledError } from "@suaveplan/api-auth-rolled";
|
||||
|
||||
try {
|
||||
/* ... */
|
||||
} catch (err) {
|
||||
if (err instanceof AuthRolledError) {
|
||||
// .rolledCode is typed as AuthRolledErrorCode — no narrowing cast.
|
||||
if (err.rolledCode === AUTH_ROLLED_CODES.KEY_ROTATION_FAILED) {
|
||||
log.fatal({ err }, "operator key-rotation contract violated");
|
||||
}
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `AUTH_ROLLED_CODES` — frozen `Record<Name, "AUTH_ROLLED.NAME">`.
|
||||
- `AuthRolledErrorCode` — string-literal union of every code value.
|
||||
- `AuthRolledError extends SuaveplanError<AuthRolledErrorCode>` — has a
|
||||
`rolledCode: AuthRolledErrorCode` convenience accessor.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The set of 20 codes is fixed by the OpenSpec spec delta. The conformance
|
||||
test enumerates `AUTH_ROLLED_CODES` and asserts every code has a named
|
||||
production trigger; if a code is added without a trigger, the test fails
|
||||
loudly. Cross-package codes (e.g. `HIBP.*` propagated from
|
||||
`@suaveplan/hibp` when the breach lookup fails) are NOT re-encoded — they
|
||||
surface to the caller intact through `SuaveplanError`'s `cause` chain so
|
||||
operators can attribute failures to the originating layer.
|
||||
Reference in New Issue
Block a user