5.2 KiB
error-codes
(no submodules)
Purpose
The @suaveplan/seed package centralises every failure mode it can produce
behind a single registry built with defineCodes("SEED", [...]) 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 SEED_CODES
registry, the derived SeedErrorCode type, and the SeedError class that
every public failure path raises.
SeedError extends SuaveplanError<SeedErrorCode> so instanceof SeedError
narrows code to the exact union of SEED.* strings. It adds optional
seedName and dependency discriminants that diagnose which seed (or
which missing dependency) triggered the error, while leaving the base
context map free for caller-supplied structured data. The class threads
cause straight through SuaveplanError, so store-layer exceptions
wrapped by the runner remain inspectable through error.cause.
Features
- Frozen
SEED_CODESregistry with seven namespaced codes SeedErrorCodeliteral-union type derived from the registrySeedErrorclass extendingSuaveplanError<SeedErrorCode>- Optional
seedNameanddependencydiagnostic discriminants - Full
cause-chain preservation viaSuaveplanError - Compatible with the OTel span-event adapter shipped by
@suaveplan/error
Usage: Basic
import { SEED_CODES, SeedError } from "@suaveplan/seed";
if (registry.has(seed.name)) {
throw new SeedError(SEED_CODES.DUPLICATE_NAME, `seed "${seed.name}" already registered`, {
seedName: seed.name,
});
}
Usage: Advanced
import { SEED_CODES, SeedError } from "@suaveplan/seed";
import { SuaveplanError } from "@suaveplan/error";
try {
await store.insert(seed.table, batch);
} catch (cause) {
throw new SeedError(SEED_CODES.STORE_ERROR, `store rejected batch for ${seed.table}`, {
cause: cause instanceof Error ? cause : undefined,
seedName: seed.name,
context: { table: seed.table, batchSize: batch.length },
});
}
// Downstream:
catch (err) {
if (err instanceof SeedError && err.code === SEED_CODES.STORE_ERROR) {
logger.error("seed.store.failure", {
seedName: err.seedName,
rootMessage: err.cause instanceof Error ? err.cause.message : String(err.cause),
});
}
}
API Reference
SEED_CODES
A frozen object literal of seven namespaced codes:
| Property | Value |
|---|---|
DUPLICATE_NAME |
"SEED.DUPLICATE_NAME" |
UNREGISTERED_DEPENDENCY |
"SEED.UNREGISTERED_DEPENDENCY" |
CIRCULAR_DEPENDENCY |
"SEED.CIRCULAR_DEPENDENCY" |
DEPENDENCY_DEPTH_EXCEEDED |
"SEED.DEPENDENCY_DEPTH_EXCEEDED" |
INVALID_CONFIG |
"SEED.INVALID_CONFIG" |
STORE_ERROR |
"SEED.STORE_ERROR" |
ABORTED |
"SEED.ABORTED" |
type SeedErrorCode
The literal union of every value in SEED_CODES.
class SeedError extends SuaveplanError<SeedErrorCode>
| Member | Type |
|---|---|
code |
SeedErrorCode (narrowed) |
seedName? |
string |
dependency? |
string |
cause? |
unknown (inherited) |
timestamp |
number (inherited; Date.now() at construction) |
constructor(...) |
(code, message, options?: SeedErrorOptions) |
SeedErrorOptions extends SuaveplanErrorOptions (cause, context,
clock, traceId) with the additional optional seedName and
dependency fields.
Implementation Notes
defineCodes returns a Object.freezed record with null prototype, so
the registry cannot be mutated, reassigned, or extended at runtime — any
attempt fails in strict mode (which TypeScript modules enforce). The
literal type machinery preserves the exact ${Namespace}.${Reason}
string template across every consumer, so switch (err.code) enjoys
exhaustive narrowing without runtime cost.
SeedError's constructor passes message straight 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.
Optional seedName / dependency fields are stored on the error instance
directly (not on context) so they survive structured-cloning and
serialisation via the toJSON helper from @suaveplan/error. Consumers
that programmatically dispatch on a missing dependency can read
err.dependency without first parsing err.context.