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