3.6 KiB
error-codes
(no submodules)
Purpose
The error-codes module owns the canonical SMS.* registry for
@suaveplan/sms. Every error surfaced by the package — invalid
phone number, missing provider, exhausted retries, opted-out
recipient, rate limit, scheduled-message cancellation, abort —
carries one of the thirteen stable codes registered here. This
keeps downstream consumers (loggers, problem+json responders,
retry wrappers, dashboards) free from re-implementing the
classifier.
The thirteen codes are declared with the
defineCodes("SMS", [...]) helper, which produces a frozen
Namespace.Reason string union. Each code has a dedicated
leaf-error class extending the package-local abstract
BaseSmsError (itself a thin SuaveplanError<SmsCode>
subclass), so consumers can instanceof the class as well as
match on .code.
Features
- Thirteen
SMS.*codes:INVALID_NUMBER,INVALID_CONFIG,PROVIDER_NOT_CONFIGURED,PROVIDER_ERROR,SEND_FAILED,TEMPLATE_NOT_FOUND,RECIPIENT_OPTED_OUT,RATE_LIMITED,FORBIDDEN,CONFIG_MISSING,SCHEDULE_CANCELLED,ABORTED,RECEIPT_NOT_FOUND. - One leaf class per code, all extending
BaseSmsError. BaseOpts-typed constructors that acceptmessage,context,cause,traceId, withpickOptsstripping undefined keys so theexactOptionalPropertyTypescontract holds.SmsInvalidConfigErrormerges Zod issues intocontext.issues.
Usage: Basic
import {
SMS_CODES,
SmsRateLimitedError,
} from "@suaveplan/sms/error-codes";
try {
throw new SmsRateLimitedError({
context: { phoneNumber: "+15551234567" },
});
} catch (err) {
if (err instanceof SmsRateLimitedError) {
console.log(err.code === SMS_CODES.RATE_LIMITED);
}
}
Usage: Advanced
import {
BaseSmsError,
SmsInvalidConfigError,
} from "@suaveplan/sms/error-codes";
function classifyAndLog(err: unknown): void {
if (err instanceof SmsInvalidConfigError) {
for (const issue of (err.context?.issues ?? []) as ReadonlyArray<
Record<string, unknown>
>) {
console.error("zod issue", issue);
}
return;
}
if (err instanceof BaseSmsError) {
console.error(`${err.code}: ${err.message}`, err.context ?? {});
}
}
API Reference
SMS_CODES: Readonly<Record<Reason, "SMS.Reason">>— frozen registry returned fromdefineCodes("SMS", [...]).SmsCode = (typeof SMS_CODES)[keyof typeof SMS_CODES]— union of every fully-qualified code.abstract class BaseSmsError extends SuaveplanError<SmsCode>— base class for every typed leaf error.- Leaf classes (each takes a
BaseOptsargument and forwards a default messageKey for the i18n resolver):SmsInvalidNumberError,SmsInvalidConfigError,SmsProviderNotConfiguredError,SmsProviderError,SmsSendFailedError,SmsTemplateNotFoundError,SmsRecipientOptedOutError,SmsRateLimitedError,SmsForbiddenError,SmsConfigMissingError,SmsScheduleCancelledError,SmsAbortedError,SmsReceiptNotFoundError.
Implementation Notes
The leaf-class pattern (one class per code) was chosen over a
single generic class so callers can instanceof Xxx to discriminate
without inspecting .code. The pickOpts helper guards against
the exactOptionalPropertyTypes contract — copying a
cause: undefined into the super options table would fail to
typecheck against SuaveplanErrorOptions. Codes are reserved at
module load via defineCodes (which returns a frozen object) so
the registry cannot drift across module reloads.