first commit
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
# `error-codes`
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
Frozen registry of `SECRETS_VAULT.*` error codes thrown by the
|
||||
vault-backed `SecretsLike` adapter and its watcher / allow-list
|
||||
helpers. Kept distinct from upstream `SECRETS.*` (owned by
|
||||
`@suaveplan/api-secrets`) and `SECRETS_ENV.*` (the env adapter) so a
|
||||
single log line is enough for operators to identify whether the
|
||||
failure originated in vault-locked state, allow-list rejection,
|
||||
backend I/O failure, or write-path mutation. Built on
|
||||
`defineCodes` + `SuaveplanError` so the throwable carries the
|
||||
canonical `code` field and structured-logger `name` attribute.
|
||||
|
||||
## Features
|
||||
|
||||
- `SECRETS_VAULT_CODES` — frozen object literal with six entries:
|
||||
`NOT_FOUND`, `NOT_ALLOWED`, `VAULT_LOCKED`, `VAULT_UNAVAILABLE`,
|
||||
`WRITE_FAILED`, `INVALID_OPTIONS`.
|
||||
- `SecretsVaultCode` — string-literal union of the six codes.
|
||||
- `SecretsVaultError` — `SuaveplanError<SecretsVaultCode>` subclass
|
||||
with `error.name === "SecretsVaultError"`.
|
||||
- `SECRETS_VAULT_ERROR_NAME` — exported constant for cross-package
|
||||
`name`-equality checks.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import {
|
||||
SECRETS_VAULT_CODES,
|
||||
SecretsVaultError,
|
||||
} from "@suaveplan/api-secrets-vault/error-codes";
|
||||
|
||||
throw new SecretsVaultError(
|
||||
SECRETS_VAULT_CODES.NOT_ALLOWED,
|
||||
"error.secrets_vault.not_allowed",
|
||||
{ context: { name: "AWS" } }
|
||||
);
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
Cause-chained surfacing from a backend I/O failure:
|
||||
|
||||
```ts
|
||||
import {
|
||||
SECRETS_VAULT_CODES,
|
||||
SecretsVaultError,
|
||||
} from "@suaveplan/api-secrets-vault/error-codes";
|
||||
|
||||
try {
|
||||
await backend.get("STRIPE");
|
||||
} catch (cause) {
|
||||
throw new SecretsVaultError(
|
||||
SECRETS_VAULT_CODES.VAULT_UNAVAILABLE,
|
||||
"error.secrets_vault.vault_unavailable",
|
||||
{ cause, context: { name: "STRIPE" } }
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `SECRETS_VAULT_CODES: Readonly<{ NOT_FOUND, NOT_ALLOWED, VAULT_LOCKED,
|
||||
VAULT_UNAVAILABLE, WRITE_FAILED, INVALID_OPTIONS }>`
|
||||
- `type SecretsVaultCode = (typeof SECRETS_VAULT_CODES)[…]`
|
||||
- `const SECRETS_VAULT_ERROR_NAME = "SecretsVaultError"`
|
||||
- `class SecretsVaultError extends SuaveplanError<SecretsVaultCode>`
|
||||
- `constructor(code, messageKey, options?: SuaveplanErrorOptions)`
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The codes register at module load via the package's root barrel
|
||||
side-effect-importing this file. That guarantees subpath consumers
|
||||
who import `@suaveplan/api-secrets-vault/adapter` directly still get
|
||||
the registry populated for cross-package code lookups. The throwable
|
||||
attaches the original error on `cause` per WHATWG semantics, which
|
||||
the `error.cause`-chain redactor in `@suaveplan/error` walks during
|
||||
log emission.
|
||||
|
||||
`VAULT_LOCKED` is intentionally raised eagerly rather than letting
|
||||
the backend's own locked-state error bubble up — this preserves the
|
||||
package's strict-mode invariant (no plaintext fallback on a locked
|
||||
vault) and lets the adapter throw a consistent code regardless of
|
||||
which `@suaveplan/vault` version is in scope.
|
||||
Reference in New Issue
Block a user