first commit
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
# `error-codes`
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
Stable error-code registry for `@suaveplan/api-plugin-notifications`. The
|
||||
module exports a frozen `NOTIFICATIONS_PLUGIN_CODES` map produced by the
|
||||
`defineCodes("NOTIFICATIONS_PLUGIN", [...])` helper from `@suaveplan/error`,
|
||||
plus a concrete `NotificationsPluginError` class that extends
|
||||
`SuaveplanError<NotificationsPluginErrorCode>`. The namespace literal
|
||||
deliberately differs from `EVENTS` (owned by `@suaveplan/events`) and
|
||||
`EVENTS_PLUGIN` (owned by `@suaveplan/api-plugin-events`) so the global
|
||||
registry never silently shadows codes registered by sibling packages.
|
||||
|
||||
## Features
|
||||
|
||||
- Eighteen stable codes spanning configuration, lifecycle, repository,
|
||||
device-token, route, and APN-transport failure modes.
|
||||
- Type-level narrowing via `NotificationsPluginErrorCode` so any
|
||||
`instanceof NotificationsPluginError` check pins `error.code` to one
|
||||
of the declared literals.
|
||||
- Structured `context` and `cause` passthrough — the constructor
|
||||
forwards every `SuaveplanErrorOptions` field to the base class so
|
||||
Zod `ZodError`s, raw `Error`s, and arbitrary telemetry context all
|
||||
travel together.
|
||||
- A spec-conformance test reflects the registry at load time and
|
||||
greps the rest of `src/` to assert every code is referenced from a
|
||||
real `throw new NotificationsPluginError(...)` site.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import {
|
||||
NOTIFICATIONS_PLUGIN_CODES,
|
||||
NotificationsPluginError,
|
||||
} from "@suaveplan/api-plugin-notifications";
|
||||
|
||||
throw new NotificationsPluginError(
|
||||
NOTIFICATIONS_PLUGIN_CODES.NOTIFICATION_NOT_FOUND,
|
||||
"Notification not found",
|
||||
{ context: { id: "notification:abc" } }
|
||||
);
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
Catch handlers narrow `error.code` to the registered literals so
|
||||
branch-by-code routing stays type-safe without string literals leaking:
|
||||
|
||||
```ts
|
||||
try {
|
||||
await createNotification(...);
|
||||
} catch (err) {
|
||||
if (err instanceof NotificationsPluginError) {
|
||||
switch (err.code) {
|
||||
case NOTIFICATIONS_PLUGIN_CODES.APN_SEND_FAILED:
|
||||
case NOTIFICATIONS_PLUGIN_CODES.APN_SERVICE_UNAVAILABLE:
|
||||
return scheduleRetry(err);
|
||||
case NOTIFICATIONS_PLUGIN_CODES.UNAUTHENTICATED:
|
||||
case NOTIFICATIONS_PLUGIN_CODES.FORBIDDEN:
|
||||
return reject403(err);
|
||||
default:
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `NOTIFICATIONS_PLUGIN_CODES` — frozen record of literal codes
|
||||
(`{ INVALID_CONFIG: "NOTIFICATIONS_PLUGIN.INVALID_CONFIG", ... }`).
|
||||
- `NotificationsPluginErrorCode` — type alias of the value union.
|
||||
- `NotificationsPluginError(code, message, options?)` — concrete error
|
||||
class. Stores `code` on both the base `code` field and a redundant
|
||||
`notificationsPluginCode` field to keep type narrowing crisp when the
|
||||
base class is generic over the union.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
`defineCodes` accepts a namespace literal and a `readonly` tuple of
|
||||
suffix literals; the helper returns a frozen record keyed by the suffix
|
||||
with values `"<namespace>.<suffix>"`. Mutating the result is rejected
|
||||
at runtime by the `Object.freeze` step inside `@suaveplan/error`. The
|
||||
spec-conformance test depends on the constant identifier
|
||||
(`NOTIFICATIONS_PLUGIN_CODES.SOMETHING`) appearing literally in source
|
||||
files, so codes MUST be referenced by their constant name — not the
|
||||
string literal — at every throw site.
|
||||
Reference in New Issue
Block a user