# `AlgorithmRegistry` ## Purpose In-package mapping from `alg` identifier to the concrete `AlgorithmImpl` that knows how to verify and (optionally) sign. The registry is seeded at module load with the 13 built-in algorithms required by RFC 7518 §3 and RFC 8037 (`HS256/384/512`, `RS256/384/512`, `PS256/384/512`, `ES256/384/512`, `EdDSA`, `none`). Downstream packages register experimental algorithms (e.g. ML-DSA, secp256k1) via `AlgorithmRegistry.register` without forking this package. ## Features - `defaultRegistry` — the package-wide seeded registry consumed by the verify/sign pipelines. - `register(alg, impl)` — add an algorithm; duplicate registration throws `JWS.ALG_UNSUPPORTED`. - `lookup(alg)` — returns the impl or `undefined`. - `lookupOrThrow(alg)` — returns the impl or throws `JWS.ALG_UNSUPPORTED`. - `has(alg)` / `algorithms()` — introspection helpers. ## Usage: Basic Example ```ts import { defaultRegistry } from "@suaveplan/jws"; defaultRegistry.has("RS256"); // true defaultRegistry.has("ML-DSA-44"); // false ``` ## Usage: Advanced Example ```ts import { AlgorithmRegistry, type AlgorithmImpl, defaultRegistry, } from "@suaveplan/jws"; const mlDsa44: AlgorithmImpl = { alg: "ML-DSA-44", verify: async (signingInput, sig, pub) => myMlDsaImpl.verify(pub, sig, signingInput), sign: async (signingInput, priv) => myMlDsaImpl.sign(priv, signingInput), }; defaultRegistry.register("ML-DSA-44", mlDsa44); // Or build an isolated registry for an integration test: const isolated = new AlgorithmRegistry(); isolated.register("HS256", myHsImpl); ``` ## API Reference - `class AlgorithmRegistry` - `register(alg: string, impl: AlgorithmImpl): void` - `lookup(alg: string): AlgorithmImpl | undefined` - `lookupOrThrow(alg: string): AlgorithmImpl` - `has(alg: string): boolean` - `algorithms(): readonly string[]` - `const defaultRegistry: AlgorithmRegistry` - `interface AlgorithmImpl { alg: string; verify(signingInput, signature, key: K): Promise; sign?(signingInput, key: K): Promise }` - `seedBuiltinAlgorithms(): void` — idempotent seeding (already invoked at module load). ## Implementation Notes Built-ins are seeded by the side-effect import `import "./builtin.js"` at the root of `algorithms/index.ts` AND `src/index.ts`. Idempotent via a module-scoped boolean so the registry survives test reload cycles. Registering an algorithm twice throws rather than silently overwriting, because silent overwrite would be an algorithm-confusion vector — a malicious downstream package could redefine `RS256` to delegate to an attacker-controlled impl. The registry is mutable but only via `register`; there is no `unregister` for the same reason.