# `errors/hibp-error.ts` ## Purpose `HibpError` is the structured error class every failure path inside `@suaveplan/hibp` throws. It carries one of the seven registered `HibpErrorCode` values plus optional cause / context / trace-id metadata, and ships a `toJSON()` form that strips sensitive payloads (API keys, emails, passwords, full SHA-1 hashes) before any logger touches it. ## Features - `code` field narrows on the seven-member registry, so callers can fan out on stable enumerated values rather than parse messages. - Inherits trace-id propagation and timestamp from `SuaveplanError`, keeping every error in the project wire-compatible. - `leakClass` field annotates errors thrown by `assert-no-leak.ts` with whether the offending value was a SHA-1, a password, or an email — without ever echoing the leaked bytes. - `toJSON()` scrubs any 40-char hex sequence and any address-shaped substring as a defence-in-depth filter, so even an unexpected interpolation cannot leak a hash or email. ## Usage: Basic Example ```ts import { HIBP_CODES, HibpError } from "@suaveplan/hibp"; try { /* ... */ } catch (err) { if (err instanceof HibpError && err.code === HIBP_CODES.RATE_LIMITED) { // back off } } ``` ## Usage: Advanced Example ```ts import { HibpError } from "@suaveplan/hibp"; function logSafely(err: unknown, logger: { error(s: string): void }): void { if (err instanceof HibpError) { logger.error(JSON.stringify(err.toJSON())); } else if (err instanceof Error) { logger.error(err.message); } } ``` ## API Reference - `new HibpError(code, message, options?)` — `options` accepts `cause`, `context`, `traceId`, `clock`, and `leakClass`. - `error.code: HibpErrorCode` — the namespaced code string. - `error.leakClass: "sha1" | "password" | "email" | undefined`. - `error.toJSON()` — returns a stable, redacted serialization safe to hand to any logger. ## Implementation Notes The `toJSON` redaction is intentionally regex-based — strings that happen to resemble a SHA-1 or an email get replaced with `[redacted]` even if they were never deliberate. False positives here cost almost nothing; false negatives would cost the privacy contract. The constructor uses a helper to build the super-options object so that `exactOptionalPropertyTypes: true` doesn't reject `undefined` values that the parent class doesn't accept.