first commit
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
# `error-codes`
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
This module owns the stable `SECRETS_BUN.*` code registry and the
|
||||
`SecretsBunError` subclass thrown by every failure path inside the
|
||||
`Bun.secrets`-backed adapter. Splitting these codes from the upstream
|
||||
`SECRETS.*` namespace gives operators a one-glance distinction between
|
||||
the abstract secrets contract (`@suaveplan/api-secrets`), the
|
||||
environment-variable adapter (`SECRETS_ENV.*`), and the OS-keystore
|
||||
adapter (`SECRETS_BUN.*`).
|
||||
|
||||
The registry is frozen at module-load time so no consumer can mutate the
|
||||
codes that downstream telemetry already aggregates on. `SecretsBunError`
|
||||
pins `error.name` to a single canonical string so structured loggers can
|
||||
group rolled-up failure rates across every concrete code.
|
||||
|
||||
## Features
|
||||
|
||||
- Six codes — `NOT_FOUND`, `NOT_ALLOWED`, `KEYSTORE_UNAVAILABLE`,
|
||||
`KEYSTORE_LOCKED`, `WRITE_FAILED`, `INVALID_OPTIONS`.
|
||||
- Frozen registry via `defineCodes` so the surface cannot drift between
|
||||
runs in the same process.
|
||||
- Single `SecretsBunError` subclass for every throwable.
|
||||
- Carries `cause` chains so the underlying `Bun.secrets` error survives
|
||||
the wrap.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import {
|
||||
SECRETS_BUN_CODES,
|
||||
SecretsBunError,
|
||||
} from "@suaveplan/api-secrets-bun/error-codes";
|
||||
|
||||
throw new SecretsBunError(
|
||||
SECRETS_BUN_CODES.NOT_ALLOWED,
|
||||
"error.secrets_bun.not_allowed",
|
||||
{ context: { name: "AWS_SECRET_KEY" } }
|
||||
);
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
Catch and route on `code`:
|
||||
|
||||
```ts
|
||||
import {
|
||||
SECRETS_BUN_CODES,
|
||||
SecretsBunError,
|
||||
} from "@suaveplan/api-secrets-bun/error-codes";
|
||||
|
||||
try {
|
||||
await secrets.require("STRIPE");
|
||||
} catch (err) {
|
||||
if (err instanceof SecretsBunError) {
|
||||
if (err.code === SECRETS_BUN_CODES.KEYSTORE_LOCKED) {
|
||||
// Prompt the operator to unlock the OS keystore.
|
||||
} else if (err.code === SECRETS_BUN_CODES.NOT_FOUND) {
|
||||
// Surface a manifest-mismatch installer hint.
|
||||
}
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `SECRETS_BUN_CODES` — frozen `{ [name]: "SECRETS_BUN.<name>" }`.
|
||||
- `SecretsBunCode` — TypeScript union of every fully-qualified code.
|
||||
- `SECRETS_BUN_ERROR_NAME` — `"SecretsBunError"`.
|
||||
- `SecretsBunError extends SuaveplanError<SecretsBunCode>` — concrete
|
||||
subclass with `code` typed to `SecretsBunCode`.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
Codes follow the project convention `<NAMESPACE>.<CASE>` so the dotted
|
||||
prefix is a stable telemetry key for grouping at the metric backend.
|
||||
The `SecretsBunError` constructor sets `this.name` AFTER `super` because
|
||||
`SuaveplanError`'s base assigns its own default name; overriding it
|
||||
unconditionally is the only way to guarantee the canonical name survives
|
||||
inheritance.
|
||||
Reference in New Issue
Block a user