3.7 KiB
error-codes
(no submodules)
Purpose
The error-codes module owns the stable AUTH.* code registry and the
AuthError class used by every production failure path inside
@suaveplan/api-plugin-auth. Consumers branch on the namespaced string
literal (e.g. error.code === "AUTH.UNAUTHENTICATED") — the registry
exists so the strings never drift across the plugin, its consumers, and
the OpenAPI error responses surfaced by @suaveplan/api.
Features
- 10 namespaced
AUTH.*codes built via@suaveplan/error'sdefineCodes("AUTH", […])— type-safe at compile time and stable at runtime. AuthErrorextendsSuaveplanError<AuthErrorCode>soinstanceof AuthErrornarrowserror.codeto the union.- Codes carry HTTP status via
context.statusCode— the@suaveplan/apierror-handler reads that field and translates to the matching response code (401 / 403 / 500 / 503).
Usage: Basic
import { AUTH_CODES, AuthError } from "@suaveplan/api-plugin-auth/error-codes/error-codes";
throw new AuthError(AUTH_CODES.UNAUTHENTICATED, "Login required", {
context: { statusCode: 401 },
});
Usage: Advanced
Pass context.required on a role-check failure so callers and the
OpenAPI 403 response can show which roles satisfy the gate. Carry the
underlying ZodError as cause on input-validation failures so the
toJSON pipeline preserves it on the wire:
import { AUTH_CODES, AuthError } from "@suaveplan/api-plugin-auth/error-codes/error-codes";
import z from "zod";
const parsed = z.object({ email: z.string().email() }).safeParse(input);
if (!parsed.success) {
throw new AuthError(AUTH_CODES.INVALID_INPUT, "Invalid sign-up body", {
cause: parsed.error,
context: { statusCode: 400, issues: parsed.error.issues },
});
}
const principal = c.get("user");
if (!principal) {
throw new AuthError(AUTH_CODES.UNAUTHENTICATED, "Login required", {
context: { statusCode: 401 },
});
}
const required = ["admin", "owner"] as const;
if (!principal.roles.some((r) => required.includes(r as never))) {
throw new AuthError(AUTH_CODES.INSUFFICIENT_ROLE, "Forbidden", {
context: { statusCode: 403, required: [...required] },
});
}
API Reference
AUTH_CODES
Record<AuthCodeKey, "AUTH.<KEY>"> — frozen mapping built with
defineCodes. Keys: UNAUTHENTICATED, INSUFFICIENT_ROLE,
EMAIL_NOT_VERIFIED, SESSION_RESOLVE_FAILED,
PRINCIPAL_MAPPING_FAILED, BETTER_AUTH_INIT_FAILED, INVALID_INPUT,
ROUTE_PREFIX_COLLISION, SCHEMA_APPLY_FAILED, SERVICE_NOT_AVAILABLE.
AuthErrorCode
Discriminated string union, "AUTH.UNAUTHENTICATED" | … — the type of
AUTH_CODES[key].
class AuthError extends SuaveplanError<AuthErrorCode>
new AuthError(code, message, options?)—codeis anAuthErrorCode;optionsis theSuaveplanErrorOptionsshape ({ context?, cause?, traceId?, clock? }). The constructor ispublicso any plugin module may throw directly.error.authCode— convenience field that narrows toAuthErrorCodeeven when the value is treated as a plainSuaveplanError.
Implementation Notes
- The full code list lives in this file. Adding a new code requires authoring a new OpenSpec change so the spec delta, registry, and call sites move together.
context.statusCodeis non-normative onSuaveplanError(the field is read by@suaveplan/api's error-handler); the auth plugin always attaches it for codes that map cleanly to an HTTP response so the served error matches the route's OpenAPI schema.SERVICE_NOT_AVAILABLElists missing service names incontext.missingso operators reading logs / span events can see exactly whichctx.getService(...)call returnedundefined.