Initial Commit
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
# error-codes
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
The `error-codes` module defines the seven stable `TENANT.*` failure codes
|
||||
shipped by `@suaveplan/api-tenant` and the concrete `TenantError`
|
||||
class that carries them. Every public failure path in the package —
|
||||
resolver lookups, middleware status gating, rate-limit enforcement,
|
||||
input validation, and lookup timeouts — raises a `TenantError` with
|
||||
one of these codes so consumers can `switch` on the string value
|
||||
without depending on a class-instanceof check.
|
||||
|
||||
The registry uses `defineCodes("TENANT", [...])` from
|
||||
`@suaveplan/error`, which freezes the object and produces
|
||||
`"TENANT.NOT_FOUND"`-style stable identifiers. Each code is sized to a
|
||||
specific operational outcome so log aggregators and on-call dashboards
|
||||
can group incidents accurately rather than collapsing every failure
|
||||
under a single bucket.
|
||||
|
||||
## Features
|
||||
|
||||
- Exactly seven `TENANT.*` codes: `NOT_FOUND`, `SUSPENDED`, `PENDING`,
|
||||
`RESOLUTION_FAILED`, `RATE_LIMITED`, `INVALID_INPUT`, `LOOKUP_TIMEOUT`.
|
||||
- Frozen registry — `Object.isFrozen(TENANT_CODES)` is `true`.
|
||||
- `TenantError extends SuaveplanError<TenantErrorCode>` — the generic
|
||||
parameter narrows `.code` from `string` to the discriminated union.
|
||||
- A duplicate `.tenantCode` field is exposed alongside `.code` so
|
||||
callers writing structural assertions (`error.tenantCode === ...`)
|
||||
do not have to widen the parent's type parameter.
|
||||
- `SuaveplanErrorOptions` flows through to support `cause`, `context`,
|
||||
redactable payloads, and OTel span-event adapter integration.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { TENANT_CODES, TenantError } from "@suaveplan/api-tenant";
|
||||
|
||||
throw new TenantError(TENANT_CODES.NOT_FOUND, "Tenant 'acme' not found");
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
Threading a cause and structured context for OTel ingestion:
|
||||
|
||||
```ts
|
||||
import { TENANT_CODES, TenantError } from "@suaveplan/api-tenant";
|
||||
|
||||
try {
|
||||
await db.query("SELECT * FROM tenants WHERE slug = $1", ["acme"]);
|
||||
} catch (cause) {
|
||||
throw new TenantError(
|
||||
TENANT_CODES.RESOLUTION_FAILED,
|
||||
"Tenant lookup failed",
|
||||
{
|
||||
cause: cause instanceof Error ? cause : new Error(String(cause)),
|
||||
context: { resolver: "subdomain", input: "acme" },
|
||||
}
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `TENANT_CODES` — frozen `Record<string, "TENANT.${string}">` mapping
|
||||
short keys (`NOT_FOUND` etc.) to dotted identifiers.
|
||||
- `TenantErrorCode` — discriminated string union over
|
||||
`(typeof TENANT_CODES)[keyof typeof TENANT_CODES]`.
|
||||
- `class TenantError extends SuaveplanError<TenantErrorCode>` —
|
||||
constructor `(code, message, options?)`. Public `.tenantCode` field
|
||||
mirrors `.code`.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The constructor widens visibility to `public` because
|
||||
`SuaveplanError`'s constructor is `protected` for the base class only.
|
||||
Every shipped subclass (`PluginError`, `TenantError`, etc.)
|
||||
follows the same shape so consumers can swap subclasses without
|
||||
adjusting call sites. The `tenantCode` mirror field avoids forcing
|
||||
callers to write `error.code as TenantErrorCode` when narrowing.
|
||||
Reference in New Issue
Block a user