first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,86 @@
# `TENANT_PROVIDER_CODES` — stable error registry
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
`@suaveplan/api-tenant-provider` raises every failure through a single
`SuaveplanError` subclass — `TenantProviderError` — and every instance
carries a code from the frozen `TENANT_PROVIDER_CODES` registry. The
registry exists so consumers can branch on a stable string literal
(`error.code === "TENANT_PROVIDER.INVALID_CURSOR"`) without coupling
to the package's class hierarchy or sniffing message text.
Because tenant enumeration is consumed by very different concerns
(per-tenant cron fan-out, admin dashboards, background reconciliation,
cache warmers), a small set of well-named codes is more useful than a
large catalogue: callers either retry on `SOURCE_UNAVAILABLE`, fix
caller bugs on `INVALID_CURSOR`, or treat the absent record as expected
on `TENANT_NOT_FOUND`.
## Features
- `defineCodes("TENANT_PROVIDER", [...])` produces a frozen registry; new entries are an OpenSpec change.
- `TenantProviderError extends SuaveplanError<TenantProviderErrorCode>` so `instanceof TenantProviderError` narrows the `code` field.
- Three codes: `TENANT_NOT_FOUND`, `SOURCE_UNAVAILABLE`, `INVALID_CURSOR`.
- Inherits cause-chain, redaction, OTel span-event adapter from `@suaveplan/error`.
## Usage: Basic
```ts
import {
TENANT_PROVIDER_CODES,
TenantProviderError,
} from "@suaveplan/api-tenant-provider/error-codes";
throw new TenantProviderError(
TENANT_PROVIDER_CODES.TENANT_NOT_FOUND,
"tenant t-42 is not registered",
);
```
## Usage: Advanced
```ts
import {
TenantProviderError,
TENANT_PROVIDER_CODES,
} from "@suaveplan/api-tenant-provider/error-codes";
try {
for await (const t of provider.list({ cursor })) {
// ...
}
} catch (err) {
if (
err instanceof TenantProviderError &&
err.code === TENANT_PROVIDER_CODES.INVALID_CURSOR
) {
// The caller passed a cursor not produced by `list()` — reset
// and start a fresh iteration instead of crashing the job.
for await (const t of provider.list()) {
// ...
}
} else {
throw err;
}
}
```
## API Reference
- `TENANT_PROVIDER_CODES`: `Readonly<{ TENANT_NOT_FOUND: "TENANT_PROVIDER.TENANT_NOT_FOUND"; SOURCE_UNAVAILABLE: "TENANT_PROVIDER.SOURCE_UNAVAILABLE"; INVALID_CURSOR: "TENANT_PROVIDER.INVALID_CURSOR" }>`.
- `TenantProviderErrorCode`: the union of those three string literals.
- `class TenantProviderError extends SuaveplanError<TenantProviderErrorCode>` with `constructor(code, message, options?)` and public `readonly tenantProviderCode`.
## Implementation Notes
The codes are defined via `defineCodes("TENANT_PROVIDER", [...] as const)`
so the `TENANT_PROVIDER.` prefix is forwarded by the registry helper —
the array entries are bare names. The resulting object is frozen at
construction and the type is widened to the union of every namespaced
literal. The `tenantProviderCode` field on the error mirrors `code`
for ergonomic narrowing in consumer code that already imports the
class but not the code union.