# `errors/error-codes` — typed error registry _(no submodules)_ ## Purpose Defines the frozen registry of typed error codes raised by `@suaveplan/x509`. Every public surface in the package throws `X509Error` (a subclass of `@suaveplan/error`'s `SuaveplanError`); consumers switch on `error.code` to map RFC 5280 §6.1.4 abort conditions, ASN.1/PEM parser failures, and internal-boundary refusals into actionable handling. The literal union is pinned by `expectTypeOf` in the test suite so accidental additions or removals fail typecheck before they ship. ## Features - 20-code frozen registry constructed via `@suaveplan/error`'s `defineCodes("X509", [...])`. - `X509ErrorCode` literal-union derived directly from the registry — no manual duplication. - `X509Error` concrete subclass of `SuaveplanError` carrying optional `cause`, `context`, and `messageKey`. - Every code is thrown by at least one production code path (verified by `error-codes.test.ts::"every code in the registry is thrown by at least one production path"`). ## Usage: Basic Example ```ts import { X509_CODES, X509Error } from "@suaveplan/x509/errors"; try { // ... call into @suaveplan/x509 ... } catch (err) { if (err instanceof X509Error) { if (err.code === X509_CODES.CERT_EXPIRED) { // present user-facing renewal prompt } } } ``` ## Usage: Advanced Example ```ts import { X509_CODES, X509Error, type X509ErrorCode } from "@suaveplan/x509/errors"; const HUMAN_READABLE: Record = { [X509_CODES.PEM_MALFORMED]: "The PEM block is malformed.", [X509_CODES.ASN1_MALFORMED]: "The ASN.1 encoding is malformed.", [X509_CODES.CERTIFICATE_MALFORMED]: "The certificate body is malformed.", [X509_CODES.UNSUPPORTED_VERSION]: "Certificate version is unsupported.", [X509_CODES.EXTENSION_MALFORMED]: "An extension value is malformed.", [X509_CODES.CRITICAL_EXTENSION_UNRECOGNIZED]: "Critical extension is unrecognised.", [X509_CODES.SIGNATURE_ALG_UNSUPPORTED]: "Signature algorithm is unsupported.", [X509_CODES.SIGNATURE_INVALID]: "Signature did not verify.", [X509_CODES.CERT_EXPIRED]: "Certificate has expired.", [X509_CODES.CERT_NOT_YET_VALID]: "Certificate is not yet valid.", [X509_CODES.NAME_CHAIN_BROKEN]: "Issuer/subject name chaining broken.", [X509_CODES.NAME_CONSTRAINT_VIOLATION]: "Name constraint violated.", [X509_CODES.ISSUER_NOT_CA]: "Issuer is not a CA.", [X509_CODES.KEY_USAGE_INVALID]: "Issuer lacks keyCertSign.", [X509_CODES.EXTENDED_KEY_USAGE_INVALID]: "Required EKU absent.", [X509_CODES.CHAIN_TOO_DEEP]: "Chain depth exceeds bound.", [X509_CODES.SELF_SIGNED_LEAF]: "Self-signed leaf without explicit trust.", [X509_CODES.TRUST_ANCHOR_NOT_FOUND]: "No trust anchor matched.", [X509_CODES.OCSP_REVOKED]: "Certificate is OCSP-revoked.", [X509_CODES.ABORTED]: "Validation was aborted.", }; throw new X509Error(X509_CODES.CERT_EXPIRED, "error.x509.cert-expired", { context: { notAfter: 1700000000000, now: 1800000000000 }, }); ``` ## API Reference - `X509_CODES` — frozen object mapping each code identifier to its `"X509."` literal string. - `type X509ErrorCode` — discriminated literal union, exactly 20 members. - `class X509Error extends SuaveplanError` — concrete error class. - `constructor(code: X509ErrorCode, messageKey: string, options?: SuaveplanErrorOptions)` — `options` may carry `cause`, `context`, and i18n params per `@suaveplan/error`. ## Implementation Notes - Codes were chosen to map 1:1 onto RFC 5280 §6.1.4 abort conditions plus parser-boundary failures. There is no aggregate "validation failed" code — every failure path names the precise condition so callers can route programmatically. - The registry MUST stay frozen; adding a code is a breaking change because consumers may switch exhaustively on `X509ErrorCode`. - `defineCodes` namespaces codes under `"X509"`; the raw string form is `"X509."` (e.g. `"X509.CERT_EXPIRED"`). - `messageKey` is an i18n key; the human-readable mapping above is illustrative — production consumers wire it through `@suaveplan/i18n`.