3.0 KiB
error-codes/error-codes.ts
(no submodules)
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.
SiteErrorconstructor acceptsSuaveplanErrorOptionsso callers can attachcause,context, and structured fields.- Stable string codes —
error.code === SITE_CODES.SITE_NOT_FOUNDsurvives minification and i18n. - Per-code doc comment naming the HTTP status the route layer maps to.
- Zero runtime dependencies beyond
@suaveplan/error.
Usage: Basic
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
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 inSITE_CODES.class SiteError extends SuaveplanError<SiteErrorCode>— constructor(code, message, options?). ExposessiteCodeas a typed alias ofcode.
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 byerror-codes.test.ts. - HTTP statuses are documented per-code but the mapping is performed by the route layer (
routes/) viaerror.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.