# Error codes ## Purpose This module defines the stable, namespaced error-code registry for `@suaveplan/api-plugin-banking`. Every failure path in the plugin throws a `BankingError` carrying one of fourteen `BANKING.*` codes, so callers can branch on `error.code` without parsing free-form messages and the HTTP layer can map a code → status with a one-line lookup. ## Features - 14 typed string-literal codes registered via `defineCodes("BANKING", ...)` - `BankingError` class extending `SuaveplanError`, generic over the code literal type so `instanceof` narrows the `code` field - Stable JSDoc with HTTP-status mapping for each code - Re-exported under the package's `./error-codes/error-codes` subpath ## Usage: Basic ```ts import { BankingError, BANKING_CODES } from "@suaveplan/api-plugin-banking"; throw new BankingError( BANKING_CODES.ACCOUNT_NOT_FOUND, `Account ${id} not found` ); ``` ## Usage: Advanced Codes carry no behaviour — they are documentation. The expected pattern is to catch at the route boundary, narrow on `instanceof BankingError`, and map `error.code` to an HTTP status: ```ts import { BankingError, BANKING_CODES, type BankingErrorCode, } from "@suaveplan/api-plugin-banking"; const STATUS: Record = { INVALID_OPTIONS: 500, SERVICE_NOT_AVAILABLE: 500, BANK_NOT_FOUND: 404, BANK_NAME_TAKEN: 400, BANK_HAS_ACTIVE_ACCOUNTS: 400, ACCOUNT_NOT_FOUND: 404, ACCOUNT_LIMIT_REACHED: 400, INSUFFICIENT_FUNDS: 400, INVALID_AMOUNT: 400, INVALID_FIELD_NAME: 500, INVALID_ACCOUNT_NUMBER: 400, INVALID_SORT_CODE: 400, TENANT_CLEANUP_FAILED: 500, DATABASE_ERROR: 500, }; try { await service.transferFunds(from, to, amount); } catch (err) { if (err instanceof BankingError) { const status = STATUS[err.code]; return { status, body: { error: err.message, code: err.code } }; } throw err; } ``` ## API Reference ### `BANKING_CODES` `const BANKING_CODES: { readonly INVALID_OPTIONS: "BANKING.INVALID_OPTIONS" } & {...}` Frozen, namespaced map of every code in the registry. Indexing it yields the canonical `"BANKING.XYZ"` string passed to `BankingError`. ### `BankingErrorCode` `type BankingErrorCode = (typeof BANKING_CODES)[keyof typeof BANKING_CODES]` Discriminated union of all literal code values. ### `class BankingError extends SuaveplanError` `constructor(code: BankingErrorCode, message: string, options?: SuaveplanErrorOptions)` `error.code: BankingErrorCode` — the literal code string. `error.bankingCode: BankingErrorCode` — alias for ergonomic exhaustive switches without re-typing the union annotation. `error.cause`, `error.context`, `error.toJSON()` — inherited from `SuaveplanError`. ## Implementation Notes The registry is intentionally exhaustive: every error code that appears here is thrown by at least one production code path inside the package. The pre-archive checklist (AGENTS.md §13) gates this — codes registered but never thrown are removed before the change ships, so the list reflects the real fault surface a caller can branch on. `BankingError` keeps the `bankingCode` alias so consumers writing exhaustive switches do not need to re-type the union annotation: `switch (err.bankingCode) { case "BANKING.ACCOUNT_NOT_FOUND": ... }` type-checks against `BankingErrorCode` directly. When throwing from a SurrealDB call site, always set `{ cause: originalError, context: { ... } }` — the wire-format JSON adapter (`SuaveplanError.toJSON`) preserves both. `DATABASE_ERROR` is the catch-all wrapper used by repositories when SurrealDB rejects a query for a reason outside the typed code list.