4.2 KiB
4.2 KiB
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<X509ErrorCode>); 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'sdefineCodes("X509", [...]). X509ErrorCodeliteral-union derived directly from the registry — no manual duplication.X509Errorconcrete subclass ofSuaveplanError<X509ErrorCode>carrying optionalcause,context, andmessageKey.- 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
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
import { X509_CODES, X509Error, type X509ErrorCode } from "@suaveplan/x509/errors";
const HUMAN_READABLE: Record<X509ErrorCode, string> = {
[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.<NAME>"literal string.type X509ErrorCode— discriminated literal union, exactly 20 members.class X509Error extends SuaveplanError<X509ErrorCode>— concrete error class.constructor(code: X509ErrorCode, messageKey: string, options?: SuaveplanErrorOptions)—optionsmay carrycause,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. defineCodesnamespaces codes under"X509"; the raw string form is"X509.<NAME>"(e.g."X509.CERT_EXPIRED").messageKeyis an i18n key; the human-readable mapping above is illustrative — production consumers wire it through@suaveplan/i18n.