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,71 @@
# `errors`
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
This module hosts the stable error-code registry and the `SrpError` class for the `@suaveplan/srp` package. Every code listed here is thrown by at least one production path under `src/` — the audit test in `errors.test.ts` enforces that contract so dead codes cannot accumulate. Consumers branch on `error.code` (a literal-typed `SrpErrorCode`) rather than parsing `error.message`, which keeps error-handling resilient across releases.
## Features
- Frozen `SRP_CODES` registry via `defineCodes("SRP", […])`.
- Literal-typed `SrpErrorCode` union derived from the registry.
- `SrpError extends SuaveplanError<SrpErrorCode>` carrying the code on the instance.
- `srpError(code, message, options)` factory that prefixes the code into the message string so log scrapers and `expect(...).toThrow(/SRP\./)` matchers find a stable substring without inspecting `.code`.
- Each `SrpError` instance is `instanceof SuaveplanError`, so the global error-classification surface (OTel span events, structured logging) sees it without per-package wiring.
## Usage: Basic Example
```ts
import { SRP_CODES, SrpError, srpError } from "@suaveplan/srp/errors";
throw srpError(SRP_CODES.AUTH_FAILED, "client M1 did not match expected M1");
```
## Usage: Advanced Example
```ts
import { SrpError, SRP_CODES } from "@suaveplan/srp/errors";
try {
runSrpHandshake();
} catch (err) {
if (err instanceof SrpError && err.code === SRP_CODES.PUBLIC_KEY_INVALID) {
// RFC 5054 §2.5.4 — abort the session and rotate ephemeral keys.
return;
}
throw err;
}
```
## API Reference
### `SRP_CODES`
Frozen record mapping each reason to `"SRP.<REASON>"`. Six codes:
- `SRP.INVALID_PARAMS` — malformed `SrpParams`, oversized `PAD` input, or other structural validation failure.
- `SRP.PUBLIC_KEY_INVALID` — `A ≡ 0 mod N`, `B ≡ 0 mod N`, or `u ≡ 0 mod N`.
- `SRP.AUTH_FAILED` — server rejected the client's `M1`.
- `SRP.MUTUAL_AUTH_FAILED` — client rejected the server's `M2`.
- `SRP.GROUP_UNSUPPORTED` — group parameters fail structural validation.
- `SRP.HASH_UNSUPPORTED` — hash algorithm outside `{"SHA256", "SHA1"}`.
### `SrpErrorCode`
Literal-typed union of every value in `SRP_CODES`.
### `class SrpError extends SuaveplanError<SrpErrorCode>`
Carries `.code: SrpErrorCode`. Constructor accepts `(code, message, options?)`. The `options.cause` field, when an `Error`, threads through `SuaveplanError`'s cause-chain machinery.
### `srpError(code, message, options?)`
Factory returning an `SrpError`. Prefixes the message with `${code}:` for stable substring matching. `options.cause` accepts any `unknown` and is only attached when it is an `Error` instance.
## Implementation Notes
The registry is exhaustively audited at test time: `errors.test.ts` walks `SRP_CODES`, scans `src/` for a matching throw site for each code, and fails if any code is unreachable. This forces every new code to either ship with a real production path or be removed from the registry. The audit deliberately excludes `*.test.ts` files so test-only fixtures cannot satisfy the contract.
`srpError` prefixes the code into the message because `SuaveplanError`'s base constructor uses the `messageKey` argument for i18n resolution; in this package every code is internal and has a short English-only message, so prefixing keeps the substring stable while preserving the structured `.code` field. Callers that want a different presentation MAY construct `SrpError` directly.