# error-codes _(no submodules)_ ## Purpose Declares the stable, namespaced error registry for `@suaveplan/cryptocurrency` and the typed `CryptocurrencyError` class that wraps every failure path. The registry uses `defineCodes("CRYPTOCURRENCY", [...])` to produce a frozen, literal-typed map (`{ readonly UNKNOWN_CHAIN: "CRYPTOCURRENCY.UNKNOWN_CHAIN", ... }`) so consumers can dispatch programmatically on `err.code === CRYPTOCURRENCY_CODES.UNKNOWN_CHAIN` with full TypeScript narrowing. Centralising the registry guarantees the error contract is single-sourced — every throw site in the package picks from the same five-code set, and the exposed `CryptocurrencyErrorCode` union travels with consumers' code so a future code addition triggers an exhaustiveness check at every switch site. ## Features - Five codes covering every distinct failure mode in the migrated surface: `UNKNOWN_CHAIN`, `UNKNOWN_CURRENCY`, `UNKNOWN_UNIT`, `INVALID_ADDRESS`, `INVALID_HASH`. - `CryptocurrencyError extends SuaveplanError` with optional `chainId` / `currency` / `unit` discriminants for diagnostics. - `CryptocurrencyErrorCode` literal union exported for consumer narrowing. - `CryptocurrencyErrorOptions` extends `SuaveplanErrorOptions` so `cause`, `context`, `traceId`, and `clock` are all available. - The registry is `Object.freeze`d so consumers cannot mutate the code map. ## Usage: Basic ```ts import { CRYPTOCURRENCY_CODES, CryptocurrencyError, } from "@suaveplan/cryptocurrency"; throw new CryptocurrencyError( CRYPTOCURRENCY_CODES.UNKNOWN_CHAIN, "Unknown chain: ethereum", { chainId: "ethereum" } ); ``` ## Usage: Advanced ```ts import { CRYPTOCURRENCY_CODES, CryptocurrencyError, type CryptocurrencyErrorCode, } from "@suaveplan/cryptocurrency"; function describeFailure(err: unknown): string { if (!(err instanceof CryptocurrencyError)) return "non-crypto error"; const code: CryptocurrencyErrorCode = err.code; switch (code) { case CRYPTOCURRENCY_CODES.UNKNOWN_CHAIN: return `unknown chain: ${err.chainId ?? ""}`; case CRYPTOCURRENCY_CODES.UNKNOWN_CURRENCY: return `unknown currency: ${err.currency ?? ""}`; case CRYPTOCURRENCY_CODES.UNKNOWN_UNIT: return `unknown unit '${err.unit}' for ${err.currency}`; case CRYPTOCURRENCY_CODES.INVALID_ADDRESS: return `invalid address${err.chainId ? ` for ${err.chainId}` : ""}`; case CRYPTOCURRENCY_CODES.INVALID_HASH: return `invalid hash${err.chainId ? ` for ${err.chainId}` : ""}`; } } try { // some package call } catch (err) { console.error(describeFailure(err)); } ``` The exhaustive switch above will fail to compile if a new code is added without a matching arm — that is the point of exporting `CryptocurrencyErrorCode`. ## API Reference | Export | Kind | Notes | |---|---|---| | `CRYPTOCURRENCY_CODES` | const | frozen `{ readonly : "CRYPTOCURRENCY." }` map | | `CryptocurrencyErrorCode` | type | union of every registered code's string literal | | `CryptocurrencyError` | class | `extends SuaveplanError`; constructor `(code, message, options?)` | | `CryptocurrencyErrorOptions` | interface | `extends SuaveplanErrorOptions`; adds optional `chainId`, `currency`, `unit` | ### `CryptocurrencyError` discriminants - `chainId?: ChainId` — set on `UNKNOWN_CHAIN`, `INVALID_ADDRESS`, `INVALID_HASH` raises. - `currency?: string` — set on `UNKNOWN_CURRENCY`, `UNKNOWN_UNIT` raises. - `unit?: string` — set on `UNKNOWN_UNIT` raises. All discriminants are read-only and `undefined` when not supplied — consumers should narrow with `if (err.chainId)` rather than asserting non-null. ## Implementation Notes - `INVALID_ADDRESS` and `INVALID_HASH` are exposed in the registry even though the package's own validators return structured `AddressValidation` / `TxHashValidation` records rather than throwing. The codes are there for application-tier consumers that want to wrap a failed validation in a typed throw. They are exercised by direct construction in `error-codes.test.ts`, satisfying the conformance rule (§13 step 4 in `AGENTS.md`) that every registered code must be reachable from a call site somewhere in `src/`. - `defineCodes` produces a `Object.freeze`d record — mutating `CRYPTOCURRENCY_CODES` throws in strict mode. Consumers must rely on the literal types, not runtime extension. - `CryptocurrencyError` extends `SuaveplanError` (rule §63 of `CLAUDE.md`) so every error in the package participates in cause-chain traversal, OTel span events, redaction, and i18n message resolution. - The error's `name` field is automatically set to `"CryptocurrencyError"` by `SuaveplanError`'s use of `new.target.name`. - The optional discriminants are assigned via `if (options.X !== undefined)` so the field stays `undefined` (and serialises away from JSON) when not provided.