first commit
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
# `error-codes`
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
Defines the stable error-code registry for
|
||||
`@suaveplan/api-tenant-resolver-header`. Every public failure path raises a
|
||||
{@link HeaderTenantResolverError} carrying one of the namespaced
|
||||
`TENANT_HEADER.*` codes so consumers branch on a string value rather than a
|
||||
brittle `instanceof` check on a third-party concrete error class.
|
||||
|
||||
The registry is the single source of truth for the resolver's wire-level
|
||||
failure modes. Strict-mode hosts map the codes to HTTP responses (`INVALID`,
|
||||
`NOT_FOUND_IN_REGISTRY`, `UNTRUSTED_SOURCE` all surface as HTTP 400 unless
|
||||
the host overrides the mapping); non-strict-mode hosts swallow the codes by
|
||||
returning `null` from the resolver so the chain advances.
|
||||
|
||||
## Features
|
||||
|
||||
- Frozen four-entry registry: `INVALID`, `NOT_FOUND_IN_REGISTRY`,
|
||||
`UNTRUSTED_SOURCE`, `INVALID_OPTIONS`.
|
||||
- Namespaced `TENANT_HEADER.*` codes built via `defineCodes` from
|
||||
`@suaveplan/error`.
|
||||
- `HeaderTenantResolverError` subclass narrows `code` for downstream
|
||||
pattern-matching and carries a `headerTenantResolverCode` mirror field for
|
||||
ergonomic switch statements.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import {
|
||||
HeaderTenantResolverError,
|
||||
TENANT_HEADER_CODES,
|
||||
} from "@suaveplan/api-tenant-resolver-header/error-codes";
|
||||
|
||||
throw new HeaderTenantResolverError(
|
||||
TENANT_HEADER_CODES.INVALID,
|
||||
"X-Tenant-Id 'Acme!' does not match ^[a-z0-9-]{1,64}$"
|
||||
);
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import {
|
||||
HeaderTenantResolverError,
|
||||
TENANT_HEADER_CODES,
|
||||
} from "@suaveplan/api-tenant-resolver-header/error-codes";
|
||||
|
||||
function toHttpStatus(error: HeaderTenantResolverError): number {
|
||||
switch (error.code) {
|
||||
case TENANT_HEADER_CODES.INVALID:
|
||||
case TENANT_HEADER_CODES.NOT_FOUND_IN_REGISTRY:
|
||||
case TENANT_HEADER_CODES.UNTRUSTED_SOURCE:
|
||||
return 400;
|
||||
case TENANT_HEADER_CODES.INVALID_OPTIONS:
|
||||
return 500;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `TENANT_HEADER_CODES` — frozen registry with keys `INVALID`,
|
||||
`NOT_FOUND_IN_REGISTRY`, `UNTRUSTED_SOURCE`, `INVALID_OPTIONS`.
|
||||
- `type HeaderTenantResolverErrorCode` — string union of the four code
|
||||
values, e.g. `"TENANT_HEADER.INVALID"`.
|
||||
- `class HeaderTenantResolverError extends SuaveplanError<HeaderTenantResolverErrorCode>`
|
||||
— accepts `(code, message, { cause? })` and exposes
|
||||
`headerTenantResolverCode` alongside the inherited `code` field.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The registry is intentionally minimal — four codes covering the resolver's
|
||||
four distinct outcomes. Adding a code requires a spec delta because the codes
|
||||
are part of the package's wire contract. Hosts that need finer-grained
|
||||
diagnostics attach detail via `error.cause`; the codes themselves stay coarse
|
||||
so consumers' switch statements don't proliferate when new validators are
|
||||
plugged in.
|
||||
|
||||
`defineCodes` freezes the returned object so accidental mutation of the
|
||||
registry at runtime is impossible — the four `TENANT_HEADER.*` strings are
|
||||
the only values that will ever flow through the public surface.
|
||||
Reference in New Issue
Block a user