4.5 KiB
Error codes — @suaveplan/sms-providers
(no submodules)
Purpose
Defines the stable, namespaced error-code registry SMS_PROVIDERS_CODES and the SmsProvidersError discriminated subclass used by every public surface of @suaveplan/sms-providers. Every failure path the package can take — a non-2xx HTTP response from a provider, an upstream request timeout, a JSON parse failure on a response body, a missing configuration value, a webhook signature mismatch, an invalid E.164 number, a registry name collision, a missing registry lookup — raises one of these eight codes so downstream loggers, problem+json responders, retry wrappers, and analytics pipelines see a consistent shape.
Codes are minted through @suaveplan/error's defineCodes("SMS_PROVIDERS", […]) so they sit in a non-colliding namespace (SMS_PROVIDERS.*) distinct from @suaveplan/sms's SMS.* codes. The SmsProvidersError class extends SuaveplanError<SmsProvidersErrorCode> so instanceof SmsProvidersError narrows error.code to the union; optional provider, httpStatus, url, and bodyExcerpt discriminants are carried so consumers can branch without re-parsing the message.
Features
- Eight codes covering every public-surface failure path.
- Six factory helpers (
httpError,timeoutError,parseError,configMissing,signatureInvalid,invalidNumber,providerNotRegistered,providerAlreadyRegistered). - Response bodies are truncated to 256 chars on the
bodyExcerptdiscriminant — bounded log volume regardless of payload size. causeis preserved for any wrapped exception (timeout, parse failure) so root-cause traversal still works.
Usage: Basic
import {
SmsProvidersError,
SMS_PROVIDERS_CODES,
httpError,
} from "@suaveplan/sms-providers";
try {
/* call provider */
} catch (err) {
if (
err instanceof SmsProvidersError &&
err.code === SMS_PROVIDERS_CODES.HTTP_ERROR
) {
console.warn(`HTTP ${err.httpStatus} from ${err.provider}`);
}
}
const e = httpError("twilio", 422, "https://api.twilio.com/x", "{}", "invalid");
Usage: Advanced
import {
SmsProvidersError,
SMS_PROVIDERS_CODES,
signatureInvalid,
} from "@suaveplan/sms-providers";
// A custom webhook router that maps `SMS_PROVIDERS.SIGNATURE_INVALID` to a 401.
export function verifyOrThrow(
provider: string,
ok: boolean,
reason: string
): void {
if (!ok) {
throw signatureInvalid(provider, reason);
}
}
// Branch on every code for a problem+json renderer.
function statusFor(err: SmsProvidersError): number {
switch (err.code) {
case SMS_PROVIDERS_CODES.SIGNATURE_INVALID:
return 401;
case SMS_PROVIDERS_CODES.CONFIG_MISSING:
return 500;
case SMS_PROVIDERS_CODES.INVALID_NUMBER:
return 400;
case SMS_PROVIDERS_CODES.PROVIDER_NOT_REGISTERED:
return 404;
case SMS_PROVIDERS_CODES.PROVIDER_ALREADY_REGISTERED:
return 409;
case SMS_PROVIDERS_CODES.TIMEOUT:
case SMS_PROVIDERS_CODES.HTTP_ERROR:
case SMS_PROVIDERS_CODES.PARSE_ERROR:
return err.httpStatus ?? 502;
default:
return 500;
}
}
API Reference
| Symbol | Kind | Notes |
|---|---|---|
SMS_PROVIDERS_CODES |
const record | Frozen map produced by defineCodes("SMS_PROVIDERS", […]) |
SmsProvidersErrorCode |
type | Union of every code value |
SmsProvidersError |
class | Extends SuaveplanError with optional provider / httpStatus / url / bodyExcerpt |
httpError(provider, status, url, body, message?) |
factory | HTTP_ERROR |
timeoutError(provider, url, timeoutMs, cause?) |
factory | TIMEOUT |
parseError(provider, url, body, cause) |
factory | PARSE_ERROR |
configMissing(provider, key) |
factory | CONFIG_MISSING |
signatureInvalid(provider, reason) |
factory | SIGNATURE_INVALID |
invalidNumber(provider, number) |
factory | INVALID_NUMBER |
providerNotRegistered(name) |
factory | PROVIDER_NOT_REGISTERED |
providerAlreadyRegistered(name) |
factory | PROVIDER_ALREADY_REGISTERED |
Implementation Notes
bodyExcerpt truncation keeps the elision sentinel … (U+2026) — distinguishable from a literal three-dot ASCII triplet so log scrapers can tell when truncation fired. The factories never construct errors from raw Error; they always go through new SmsProvidersError(...) so the prototype chain stays intact under transpiler-emitted __extends shims.