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,61 @@
# `error-codes/error-codes.ts`
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
Owns the stable `SITE.*` error-code registry and the `SiteError` class used by every public API path in `@suaveplan/api-plugin-site`. Each code is a stable string that consumers can pattern-match without relying on message text — important for cross-version compatibility, log aggregation, alert routing, and HTTP-status mapping. Centralising the codes in one file makes the contract auditable in a single grep and prevents new code paths from inventing ad-hoc strings.
The registry is built with `defineCodes("SITE", [...])` from `@suaveplan/error`, which freezes the array into a readonly object whose values are namespaced `"SITE.<KEY>"`. `SiteError extends SuaveplanError<SiteErrorCode>` so `instanceof SiteError` narrows `error.code` to the literal-union `SiteErrorCode`.
## Features
- 14 canonical codes covering input validation, lifecycle wiring, site CRUD, domain CRUD, resolution failures, and bootstrap failures.
- `SiteError` constructor accepts `SuaveplanErrorOptions` so callers can attach `cause`, `context`, and structured fields.
- Stable string codes — `error.code === SITE_CODES.SITE_NOT_FOUND` survives minification and i18n.
- Per-code doc comment naming the HTTP status the route layer maps to.
- Zero runtime dependencies beyond `@suaveplan/error`.
## Usage: Basic
```ts
import { SITE_CODES, SiteError } from "@suaveplan/api-plugin-site/error-codes/error-codes";
if (site === null) {
throw new SiteError(SITE_CODES.SITE_NOT_FOUND, `site '${id}' not found`);
}
```
## Usage: Advanced
```ts
import { SITE_CODES, SiteError } from "@suaveplan/api-plugin-site/error-codes/error-codes";
try {
await db.query("SELECT * FROM site WHERE id = $p0", [id]);
} catch (cause) {
throw new SiteError(SITE_CODES.STORAGE_ERROR, "SurrealDB query failed", {
cause: cause instanceof Error ? cause : undefined,
context: { statusCode: 502, id },
});
}
// Discrimination at a boundary:
if (err instanceof SiteError && err.code === SITE_CODES.DOMAIN_ALREADY_CLAIMED) {
return c.json({ error: err.message }, 409);
}
```
## API Reference
- `SITE_CODES` — readonly object of 14 keys mapped to namespaced `"SITE.<KEY>"` literals.
- `SiteErrorCode` — string-literal union of every value in `SITE_CODES`.
- `class SiteError extends SuaveplanError<SiteErrorCode>` — constructor `(code, message, options?)`. Exposes `siteCode` as a typed alias of `code`.
## Implementation Notes
- The registry is the contract: deleting a code to satisfy a coverage gate is forbidden by `AGENTS.md §2c`. Every code MUST be thrown by at least one production path, asserted by `error-codes.test.ts`.
- HTTP statuses are documented per-code but the mapping is performed by the route layer (`routes/`) via `error.context.statusCode` — the registry itself is transport-agnostic.
- New codes require a registry edit, an OpenSpec change, and a test that drives the new throw path. There are no silent additions.