Initial Commit

This commit is contained in:
2026-05-27 23:47:53 +01:00
parent fbc70f96e6
commit 9b28db724f
18103 changed files with 1600554 additions and 0 deletions

View File

@@ -0,0 +1,115 @@
# error-codes
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## 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<FontDecompressErrorCode>`
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<FontDecompressErrorCode>`
- 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<FontDecompressErrorCode>`
| 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.