# error-codes _(no submodules)_ ## Purpose The `@suaveplan/font-decompress` package centralises every failure mode it can produce behind a single registry built with `defineCodes("FONT_DECOMPRESS", [...])` from `@suaveplan/error`. The registry is the stable contract callers depend on: code strings are documented, frozen at module load, and never renamed without an explicit migration. This module exports the `FONT_DECOMPRESS_CODES` registry, the derived `FontDecompressErrorCode` literal-union type, and the `FontDecompressError` class that every public failure path raises. `FontDecompressError` extends `SuaveplanError` so `instanceof FontDecompressError` narrows `code` to the union of `FONT_DECOMPRESS.*` strings. The class threads `cause` straight through `SuaveplanError`, so primitive-layer exceptions (`RangeError` from `DataView`, `TypeError` from `TextDecoder`, `@suaveplan/font-convert` errors) remain inspectable through `error.cause`. ## Features - Frozen `FONT_DECOMPRESS_CODES` registry with two namespaced codes - `FontDecompressErrorCode` literal-union type derived from the registry - `FontDecompressError` class extending `SuaveplanError` - Full `cause`-chain preservation via `SuaveplanError` - Distinct from `FONT_COMPRESS.*` codes — different namespace, different class ## Usage: Basic ```ts import { FONT_DECOMPRESS_CODES, FontDecompressError, } from "@suaveplan/font-decompress"; if (data.byteLength < 1) { throw new FontDecompressError( FONT_DECOMPRESS_CODES.INVALID_DATA, "BTF buffer is empty", ); } ``` ## Usage: Advanced ```ts import { FONT_DECOMPRESS_CODES, FontDecompressError, } from "@suaveplan/font-decompress"; try { const font = unpacker.unpack(buffer); } catch (err) { if (err instanceof FontDecompressError) { if (err.code === FONT_DECOMPRESS_CODES.UNPACK_FAILED) { telemetry.increment("font.unpack.failure", { root: err.cause instanceof Error ? err.cause.name : "unknown", }); } } throw err; } ``` ## API Reference ### `FONT_DECOMPRESS_CODES` A frozen object literal of two namespaced codes: | Property | Value | | --------------- | -------------------------------- | | `UNPACK_FAILED` | `"FONT_DECOMPRESS.UNPACK_FAILED"` | | `INVALID_DATA` | `"FONT_DECOMPRESS.INVALID_DATA"` | ### `type FontDecompressErrorCode` The literal union of every value in `FONT_DECOMPRESS_CODES`. ### `class FontDecompressError extends SuaveplanError` | Member | Type | | ------------------ | ---------------------------------------------------------- | | `code` | `FontDecompressErrorCode` (narrowed) | | `cause?` | `unknown` (inherited) | | `timestamp` | `number` (inherited; `Date.now()` at construction) | | `constructor(...)` | `(code, message, options?: SuaveplanErrorOptions)` | ## Implementation Notes `defineCodes` returns a `Object.freeze`d record with `null` prototype, so the registry cannot be mutated, reassigned, or extended at runtime. The literal-type machinery preserves the exact `${Namespace}.${Reason}` string template across every consumer, so `switch (err.code)` enjoys exhaustive narrowing without runtime cost. The class's constructor passes `message` through to `SuaveplanError`'s `messageKey` parameter. The base class resolves the key via the i18n resolver if one has been registered with `setMessageResolver`, falling back to the raw string otherwise — so this package works without i18n wiring and lights up automatically when `@suaveplan/i18n` is present. The split from `@suaveplan/font-compress` preserves namespace distinctness: an `INVALID_DATA` raised by the packer is `FONT_COMPRESS.INVALID_DATA`; an `INVALID_DATA` raised by the unpacker is `FONT_DECOMPRESS.INVALID_DATA`. Consumers dispatching on either class plus its code get fully unambiguous error handling.