Initial Commit

This commit is contained in:
2026-05-27 23:29:53 +01:00
commit fbc70f96e6
10000 changed files with 1102152 additions and 0 deletions

View File

@@ -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.