first commit
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
# error-codes
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
Defines the stable, machine-readable error namespace for `@suaveplan/campaigns`. Every failure path in the package — from invalid options at construction time, through state-machine violations during a send, to missing records and store contract breaches — produces a `CampaignsError` whose `code` is drawn from the `CAMPAIGNS_CODES` registry.
|
||||
|
||||
Centralising the registry here keeps the error namespace decoupled from any one feature module. Downstream consumers can pattern-match on the code constants instead of importing concrete error classes, which keeps deserialised errors (over the wire, across worker boundaries) just as switchable as in-process ones.
|
||||
|
||||
## Features
|
||||
|
||||
- `CAMPAIGNS_CODES` literal map produced by `defineCodes("CAMPAIGNS", [...])`.
|
||||
- `CampaignsCode` discriminating union literal type derived from the registry.
|
||||
- `CampaignsError extends SuaveplanError<CampaignsCode>` with an explicit public constructor so `new CampaignsError(...)` is allowed at any call site.
|
||||
- Eight initial codes covering construction, input validation, state transitions, missing records, store breaches, batch + throttle config validation, and workflow failures.
|
||||
- Codes are namespaced under the `CAMPAIGNS.` prefix so they never clash with codes from sibling packages.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { CAMPAIGNS_CODES, CampaignsError } from "@suaveplan/campaigns";
|
||||
|
||||
throw new CampaignsError(
|
||||
CAMPAIGNS_CODES.CAMPAIGN_NOT_FOUND,
|
||||
"Campaign not found: c-42",
|
||||
{ context: { id: "c-42" } }
|
||||
);
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
Discriminating in consumer code without an `instanceof` chain:
|
||||
|
||||
```ts
|
||||
import { CAMPAIGNS_CODES, CampaignsError } from "@suaveplan/campaigns";
|
||||
|
||||
try {
|
||||
await engine.send(id);
|
||||
} catch (err) {
|
||||
if (!(err instanceof CampaignsError)) throw err;
|
||||
switch (err.code) {
|
||||
case CAMPAIGNS_CODES.CAMPAIGN_NOT_FOUND:
|
||||
return { kind: "not-found" as const };
|
||||
case CAMPAIGNS_CODES.INVALID_TRANSITION:
|
||||
return { kind: "conflict" as const };
|
||||
default:
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `CAMPAIGNS_CODES` — readonly literal map of `KEY -> "CAMPAIGNS.KEY"` strings.
|
||||
- `CampaignsCode` — `typeof CAMPAIGNS_CODES[keyof typeof CAMPAIGNS_CODES]`.
|
||||
- `CampaignsError(code, message, options?)` — public constructor delegating to `SuaveplanError`. `options.cause` chains an underlying error; `options.context` attaches a structured payload.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
`SuaveplanError`'s base constructor is protected, so without the explicit `public constructor` here, `new CampaignsError(...)` would fail with TS2674. The constructor sets `this.name = "CampaignsError"` so stack traces are self-describing. The `code` field narrows against `CampaignsCode`, which means consumers get exhaustiveness checking on `switch` statements with `noFallthroughCasesInSwitch` enabled.
|
||||
Reference in New Issue
Block a user