8.6 KiB
8.6 KiB
@suaveplan/sms-providers - Universal SMS provider implementations for @suaveplan/sms. Real HTTP clients for Twilio (Basic auth + form-encoded + X-Twilio-Signature HMAC-SHA1), Vonage (HMAC-SHA256 webhook), MessageBird (AccessKey + JWT HS256 webhook), Plivo (Basic auth + X-Plivo-Signature-V3 HMAC-SHA256), and AWS SNS (inline SigV4 + RSA-SHA1 SNS notification verifier). Ships ProviderRegistry, httpRequest over injectable FetchLike, composeAbortSignal, SMS_PROVIDERS_CODES + SmsProvidersError, per-provider mapStatus, parseInbound, parseOptOutKeyword, and five OTel instruments. No provider SDK deps; every HTTP call flows through an injectable FetchLike seam.
Real provider clients for
@suaveplan/sms— Twilio, Vonage, MessageBird, Plivo, AWS SNS. Universal (Bun, Node, browsers, Workers, Deno) over an injectableFetchLikeseam; no provider SDKs in the dep tree.
Documentation tree
- aws-sns — Real AWS SNS SMS provider implementing
SmsProviderfrom@suaveplan/sms. POSTsAction=Publishform bodies to the r… - crypto — Owns the package's default
HmacSignimplementation (routed throughglobalThis.crypto.subtle) and the small set of u…- default-hmac — Owns the package's default
HmacSignimplementation (routed throughglobalThis.crypto.subtle) and the small set of u…
- default-hmac — Owns the package's default
- error-codes — Defines the stable, namespaced error-code registry
SMS_PROVIDERS_CODESand theSmsProvidersErrordiscriminated subc…- error-codes — Defines the stable, namespaced error-code registry
SMS_PROVIDERS_CODESand theSmsProvidersErrordiscriminated subc…
- error-codes — Defines the stable, namespaced error-code registry
- http — Universal HTTP helper that every concrete provider client routes through. Wraps an injectable
FetchLikeseam, se…- http — Universal HTTP helper that every concrete provider client routes through. Wraps an injectable
FetchLikeseam, se…
- http — Universal HTTP helper that every concrete provider client routes through. Wraps an injectable
- keywords — Universal classifier mapping an inbound SMS body to the canonical
OptOutActionenum used by@suaveplan/sms's `OptOu…- keywords — Universal classifier mapping an inbound SMS body to the canonical
OptOutActionenum used by@suaveplan/sms's `OptOu…
- keywords — Universal classifier mapping an inbound SMS body to the canonical
- messagebird — Real MessageBird SMS provider implementing
SmsProviderfrom@suaveplan/sms. POSTs to/messageswith `Authorizatio…- messagebird — Real MessageBird SMS provider implementing
SmsProviderfrom@suaveplan/sms. POSTs to/messageswith `Authorizatio…
- messagebird — Real MessageBird SMS provider implementing
- otel — Owns the package's OpenTelemetry instrument set. Five instruments cover the public-surface operations every provider cl…
- otel — Owns the package's OpenTelemetry instrument set. Five instruments cover the public-surface operations every provider cl…
- plivo — Real Plivo SMS provider implementing
SmsProviderfrom@suaveplan/sms. POSTs to/v1/Account/{AuthId}/Message/auth…- plivo — Real Plivo SMS provider implementing
SmsProviderfrom@suaveplan/sms. POSTs to/v1/Account/{AuthId}/Message/auth…
- plivo — Real Plivo SMS provider implementing
- registry —
ProviderRegistryis a process-local, synchronous index ofSmsProviderinstances keyed byprovider.name. Sibling p…- registry —
ProviderRegistryis a process-local, synchronous index ofSmsProviderinstances keyed byprovider.name. Sibling p…
- registry —
- twilio — Real Twilio SMS provider implementing the
SmsProvidercontract from@suaveplan/sms. Issues authenticated, form-enco…- twilio — Real Twilio SMS provider implementing the
SmsProvidercontract from@suaveplan/sms. Issues authenticated, form-enco…
- twilio — Real Twilio SMS provider implementing the
- types — Defines the shared structural types every concrete provider class consumes:
FetchLike(the injectable HTTP seam), `Hm…- provider — Defines the shared structural types every concrete provider class consumes:
FetchLike(the injectable HTTP seam), `Hm…
- provider — Defines the shared structural types every concrete provider class consumes:
- vonage — Real Vonage (formerly Nexmo) SMS provider implementing
SmsProviderfrom@suaveplan/sms. POSTs to/sms/jsonwith `…- vonage — Real Vonage (formerly Nexmo) SMS provider implementing
SmsProviderfrom@suaveplan/sms. POSTs to/sms/jsonwith `…
- vonage — Real Vonage (formerly Nexmo) SMS provider implementing
Highlights
- Five real provider clients, every one implementing the
SmsProvidercontract from@suaveplan/sms:TwilioProvider—POST /Messages.json, HTTP Basic auth, MMSMediaUrl[], X-Twilio-Signature HMAC-SHA1 webhook verifier.VonageProvider—POST /sms/json, body auth, autotype=unicode, HMAC-SHA256 webhook verifier.MessageBirdProvider—AccessKeyauth, JSON body, JWT HS256 webhook verifier withiat/exp/nbfenforcement + optionalpayload_hashbinding.PlivoProvider— Basic auth, JSON body, X-Plivo-Signature-V3 HMAC-SHA256 verifier.AwsSnsProvider— inline AWS SigV4-signedAction=Publish, RSA-SHA1 SNS notification verifier with injectable callback.
ProviderRegistryindexes provider instances by name; strict register/lookup, frozenlist()snapshot.SmsProvidersErrordiscriminated subclass ofSuaveplanErrorwith eight namespaced codes (SMS_PROVIDERS.HTTP_ERROR,TIMEOUT,PARSE_ERROR,CONFIG_MISSING,SIGNATURE_INVALID,INVALID_NUMBER,PROVIDER_NOT_REGISTERED,PROVIDER_ALREADY_REGISTERED).parseOptOutKeyworduniversal CTIA/TCPA opt-in/opt-out/help keyword classifier.- Five OTel instruments —
send_total,webhook_total,signature_failures_total,send_duration_ms,webhook_verify_duration_ms. - Real
node:httpround-trip tests per provider — no mocks; tests bind a server on a random port and inject aFetchLikepointing at it.
Quick start
import {
AwsSnsProvider,
MessageBirdProvider,
PlivoProvider,
ProviderRegistry,
TwilioProvider,
VonageProvider,
} from "@suaveplan/sms-providers";
const registry = new ProviderRegistry();
registry.register(new TwilioProvider({ accountSid: "AC…", authToken: "…" }));
registry.register(new VonageProvider({ apiKey: "k", apiSecret: "s" }));
registry.register(new MessageBirdProvider({ accessKey: "K" }));
registry.register(new PlivoProvider({ authId: "A", authToken: "T" }));
registry.register(
new AwsSnsProvider({
region: "us-east-1",
accessKeyId: "AKIA…",
secretAccessKey: "…",
})
);
const twilio = registry.get("twilio");
const report = await twilio.send({
to: "+15551234567",
from: "+15550000000",
body: "Hello",
});
console.log(report.messageId, report.status);
Webhook verification
Every provider exposes a signature verifier matching its documented scheme:
// Twilio HMAC-SHA1 over url + sorted form
await twilio.verifyWebhookSignature(callbackUrl, params, signature);
// Vonage HMAC-SHA256 hex over sorted &key=value (excluding sig)
await vonage.verifyWebhookSignature(params, sigHex, signatureSecret);
// MessageBird JWT HS256 with iat/exp/nbf window + payload_hash binding
await mb.verifyWebhookSignature(jwt, signingKey, { nowMs, bodyHashHex });
// Plivo HMAC-SHA256 base64 over url + nonce + sorted key=value,...
await plivo.verifyWebhookSignature(url, nonce, params, signature);
// AWS SNS RSA-SHA1 — pass an injectable verifier callback
await sns.verifyNotification(payload, async (pem, msg, sigB64) => {
/* createVerify("RSA-SHA1")…verify(...) */
return true;
});
Tier
src/ ships zero node:* / bun:* / platform imports. Every HTTP call routes through an injectable FetchLike; every HMAC routes through an injectable HmacSign (defaulting to globalThis.crypto.subtle). Tests use real node:http + node:crypto from under tests/setup/ and inside *.test.ts files only.
Pre-publish gate
bunx turbo lint typecheck test build --filter=@suaveplan/sms-providers
bunx turbo test:coverage --filter=@suaveplan/sms-providers # 100/100/100/100