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,78 @@
# `errors/error-codes` — typed error registry
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## 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`'s `defineCodes("X509", [...])`.
- `X509ErrorCode` literal-union derived directly from the registry — no manual duplication.
- `X509Error` concrete subclass of `SuaveplanError<X509ErrorCode>` 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<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)` — `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.<NAME>"` (e.g. `"X509.CERT_EXPIRED"`).
- `messageKey` is an i18n key; the human-readable mapping above is illustrative — production consumers wire it through `@suaveplan/i18n`.