first commit
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
# error-codes/error-codes
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
The error-codes module defines the stable registry of programmatic
|
||||
failure codes raised by `@suaveplan/api-plugin-user`. Every code lives
|
||||
behind a `UserError` class extending the canonical `SuaveplanError`
|
||||
base, so callers can `instanceof UserError` to narrow `error.code` to
|
||||
the union of seven `USER.*` codes — never a free-form string. The
|
||||
registry is the contract: adding, removing, or renaming a code is a
|
||||
breaking change for consumers asserting on the value.
|
||||
|
||||
## Features
|
||||
|
||||
- Seven stable codes covering every plugin failure path: lookup misses,
|
||||
invalid factory options, disabled self-delete, profile-update
|
||||
failures, missing services, schema-apply failures, and route-prefix
|
||||
collisions.
|
||||
- `defineCodes("USER", [...])` registers the codes globally so the
|
||||
unified error registry can resolve them by string.
|
||||
- `UserError` carries `userCode` alongside the canonical `code` field
|
||||
so downstream code that does not import the base class can still
|
||||
branch on the discriminant.
|
||||
- Each thrown instance carries `context.statusCode` so the host's
|
||||
error-handler middleware maps the failure to the right HTTP status
|
||||
without per-route boilerplate.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { USER_CODES, UserError } from "@suaveplan/api-plugin-user/error-codes/error-codes";
|
||||
|
||||
if (!row) {
|
||||
throw new UserError(USER_CODES.NOT_FOUND, "user not found", {
|
||||
context: { statusCode: 404, userId: id },
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
Compose the registry with the `@suaveplan/error` `cause` chain so the
|
||||
original database error survives translation to HTTP without losing
|
||||
its stack:
|
||||
|
||||
```ts
|
||||
try {
|
||||
await db.execute(sql);
|
||||
} catch (cause) {
|
||||
throw new UserError(USER_CODES.PROFILE_UPDATE_FAILED, "patch failed", {
|
||||
cause,
|
||||
context: { statusCode: 500, userId, fields: Object.keys(patch) },
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `USER_CODES`
|
||||
|
||||
`Readonly<Record<"NOT_FOUND" | "INVALID_INPUT" | "SELF_DELETE_DISABLED" | "PROFILE_UPDATE_FAILED" | "SERVICE_NOT_AVAILABLE" | "SCHEMA_APPLY_FAILED" | "ROUTE_PREFIX_COLLISION", string>>`.
|
||||
Each value is the fully-qualified `"USER.<NAME>"` string used as the
|
||||
discriminant.
|
||||
|
||||
### `UserError`
|
||||
|
||||
`class UserError extends SuaveplanError<UserErrorCode>` — public
|
||||
constructor `(code, message, options?)` so callers can construct the
|
||||
error directly. `userCode` mirrors `code` for ergonomic narrowing.
|
||||
|
||||
### `UserErrorCode`
|
||||
|
||||
Union of all seven literal code values.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- `defineCodes` performs duplicate-detection at module-load time; a
|
||||
duplicate name throws synchronously so a stale build fails loudly.
|
||||
- The seven codes are intentionally cohesive — admin-side listings,
|
||||
avatar uploads, and GDPR export are scoped to follow-up plugins with
|
||||
their own registries.
|
||||
- `statusCode` is always carried on `context`, not as a top-level
|
||||
field, so the error registry remains transport-agnostic.
|
||||
Reference in New Issue
Block a user