Files
skills/plugins/document-navigator/docs/communication/messaging/sms-providers/README.md
2026-06-09 21:06:27 +01:00

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 injectable FetchLike seam; no provider SDKs in the dep tree.

Documentation tree

  • aws-sns — Real AWS SNS SMS provider implementing SmsProvider from @suaveplan/sms. POSTs Action=Publish form bodies to the r…
    • aws-sns — Real AWS SNS SMS provider implementing SmsProvider from @suaveplan/sms. POSTs Action=Publish form bodies to the r…
    • sigv4 — Inline AWS Signature V4 signer used by AwsSnsProvider. Replaces the @aws-sdk/signature-v4 dependency tree (15+ MB)…
  • crypto — Owns the package's default HmacSign implementation (routed through globalThis.crypto.subtle) and the small set of u…
    • default-hmac — Owns the package's default HmacSign implementation (routed through globalThis.crypto.subtle) and the small set of u…
  • error-codes — Defines the stable, namespaced error-code registry SMS_PROVIDERS_CODES and the SmsProvidersError discriminated subc…
    • error-codes — Defines the stable, namespaced error-code registry SMS_PROVIDERS_CODES and the SmsProvidersError discriminated subc…
  • http — Universal HTTP helper that every concrete provider client routes through. Wraps an injectable FetchLike seam, se…
    • http — Universal HTTP helper that every concrete provider client routes through. Wraps an injectable FetchLike seam, se…
  • keywords — Universal classifier mapping an inbound SMS body to the canonical OptOutAction enum used by @suaveplan/sms's `OptOu…
    • keywords — Universal classifier mapping an inbound SMS body to the canonical OptOutAction enum used by @suaveplan/sms's `OptOu…
  • messagebird — Real MessageBird SMS provider implementing SmsProvider from @suaveplan/sms. POSTs to /messages with `Authorizatio…
    • messagebird — Real MessageBird SMS provider implementing SmsProvider from @suaveplan/sms. POSTs to /messages with `Authorizatio…
  • 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 SmsProvider from @suaveplan/sms. POSTs to /v1/Account/{AuthId}/Message/ auth…
    • plivo — Real Plivo SMS provider implementing SmsProvider from @suaveplan/sms. POSTs to /v1/Account/{AuthId}/Message/ auth…
  • registry — ProviderRegistry is a process-local, synchronous index of SmsProvider instances keyed by provider.name. Sibling p…
    • registry — ProviderRegistry is a process-local, synchronous index of SmsProvider instances keyed by provider.name. Sibling p…
  • twilio — Real Twilio SMS provider implementing the SmsProvider contract from @suaveplan/sms. Issues authenticated, form-enco…
    • twilio — Real Twilio SMS provider implementing the SmsProvider contract from @suaveplan/sms. Issues authenticated, form-enco…
  • 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…
  • vonage — Real Vonage (formerly Nexmo) SMS provider implementing SmsProvider from @suaveplan/sms. POSTs to /sms/json with `…
    • vonage — Real Vonage (formerly Nexmo) SMS provider implementing SmsProvider from @suaveplan/sms. POSTs to /sms/json with `…

Highlights

  • Five real provider clients, every one implementing the SmsProvider contract from @suaveplan/sms:
    • TwilioProvider — POST /Messages.json, HTTP Basic auth, MMS MediaUrl[], X-Twilio-Signature HMAC-SHA1 webhook verifier.
    • VonageProvider — POST /sms/json, body auth, auto type=unicode, HMAC-SHA256 webhook verifier.
    • MessageBirdProvider — AccessKey auth, JSON body, JWT HS256 webhook verifier with iat/exp/nbf enforcement + optional payload_hash binding.
    • PlivoProvider — Basic auth, JSON body, X-Plivo-Signature-V3 HMAC-SHA256 verifier.
    • AwsSnsProvider — inline AWS SigV4-signed Action=Publish, RSA-SHA1 SNS notification verifier with injectable callback.
  • ProviderRegistry indexes provider instances by name; strict register/lookup, frozen list() snapshot.
  • SmsProvidersError discriminated subclass of SuaveplanError with eight namespaced codes (SMS_PROVIDERS.HTTP_ERROR, TIMEOUT, PARSE_ERROR, CONFIG_MISSING, SIGNATURE_INVALID, INVALID_NUMBER, PROVIDER_NOT_REGISTERED, PROVIDER_ALREADY_REGISTERED).
  • parseOptOutKeyword universal 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:http round-trip tests per provider — no mocks; tests bind a server on a random port and inject a FetchLike pointing 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