6.1 KiB
Enterprise migration — @suaveplan/sms-providers
Why
@suaveplan/sms shipped a clean send/receive/template/scheduler/opt-out core with InMemorySmsProvider as the canonical test double. Production deployments need real provider clients — Twilio, Vonage, MessageBird, Plivo, AWS SNS — each speaking its own REST dialect, authenticating with its own scheme, returning its own status vocabulary, and signing its own webhooks. Upstream packages/universal/sms-providers shipped simulated providers (random IDs, no network IO, no signature verification) — not enterprise grade.
This change ports the package fresh under packages/communication/messaging/sms-providers/ (per assignment.yml), replacing every simulated implementation with real HTTP clients over an injectable FetchLike seam, real HMAC/signature verifiers for each provider's inbound webhook contract, and a typed SMS_PROVIDERS.* error registry. Tests bind a real node:http server on a random port for end-to-end flows; no mocks.
What changes
- ADDED Package
@suaveplan/sms-providersatpackages/communication/messaging/sms-providers/, version0.1.0, universal-tiersrc/(zero hard browser/node deps; injectablefetch+ injectable HMAC seam). - ADDED
SMS_PROVIDERS.*namespaced error code registry viadefineCodes("SMS_PROVIDERS", […])with eight codes:HTTP_ERROR,TIMEOUT,PARSE_ERROR,CONFIG_MISSING,SIGNATURE_INVALID,INVALID_NUMBER,PROVIDER_NOT_REGISTERED,PROVIDER_ALREADY_REGISTERED. - ADDED
SmsProvidersErrordiscriminated subclass ofSuaveplanErrorcarryingprovider,httpStatus,url,bodyExcerptdiscriminants; factory helpers per code. - ADDED Slim foundation:
httpRequestoverFetchLikewith composedAbortSignal+ per-call timeout + JSON parse + typed error translation;composeAbortSignalhelper. - ADDED
ProviderRegistryindexingSmsProviderinstances by name (insertion-ordered, strict register/lookup, frozenlist()). - ADDED Five real provider clients implementing
SmsProviderfrom@suaveplan/sms:TwilioProvider—POST /2010-04-01/Accounts/{AccountSid}/Messages.json, HTTP Basic auth (AccountSid:AuthToken), form-encoded body, MMSMediaUrlpass-through, status URL → polled, X-Twilio-Signature HMAC-SHA1 webhook verifier.VonageProvider—POST /sms/json,api_key+api_secretbody params, alphanumeric / short-code / long-codefrom, HMAC-SHA256 webhook signature verifier honouringsig/timestamp.MessageBirdProvider—POST /messages,AccessKey <key>auth header, JSON body,Messagebird-Signature-JwtJWT (HS256) webhook verifier with timestamp freshness window.PlivoProvider—POST /v1/Account/{AuthId}/Message/, HTTP Basic auth (AuthId:AuthToken), JSON body,X-Plivo-Signature-V3HMAC-SHA256 webhook verifier (canonical-string of URL+nonce+body).AwsSnsProvider—POST /tosns.{region}.amazonaws.comwith AWS SigV4 signing (computed inline; no aws-sdk dep),Action=Publishform body, message-attribute mapped sender +SMSType(Transactional/Promotional); SNS webhook verifier accepts subscription confirmation, notification, and unsubscribe-confirmation payloads with PEM-cert injectable resolver.
- ADDED Per-provider raw-status →
SmsDeliveryStatusmap; injectableClock+IdGeneratorper provider for deterministic message-id fallbacks (when the provider does not return one synchronously). - ADDED Inbound webhook router pipeline per provider: signature verify → header timestamp freshness check → discriminated
InboundSmsEvent(message_received|delivery_receipt|opt_out|opt_in) — opt-in/opt-out keywords (STOP/UNSTOP/HELP family) recognised from inbound body. - ADDED OTel instruments (5):
- counter
sms_providers.send_total{provider,outcome} - counter
sms_providers.webhook_total{provider,event,outcome} - counter
sms_providers.signature_failures_total{provider} - histogram
sms_providers.send_duration_ms{provider} - histogram
sms_providers.webhook_verify_duration_ms{provider}
- counter
- ADDED Real
node:httpround-trip integration tests per provider (test binds an HTTP server on a random port, captures the request, returns a canned response, asserts URL/method/headers/body) and real-node:crypto-driven webhook signature suites (accept + reject paths). - ADDED Co-located
.mdper.ts(six required sections, ≥200 words excl. code) and a rootREADME.md. - MODIFIED STATUS.md row for
@suaveplan/sms-providersflipped–→✅.
Parity Checklist
| Capability | Upstream | Migrated | Notes |
|---|---|---|---|
TwilioProvider simulated send |
✅ | ⬆️ | Replaced: real HTTP Basic + form-encoded POST + MMS MediaUrl + status poll + X-Twilio-Signature HMAC-SHA1 verifier. |
VonageProvider simulated send |
✅ | ⬆️ | Replaced: real POST + alpha/short/long sender parsing + HMAC-SHA256 webhook verifier. |
MessageBirdProvider simulated send |
✅ | ⬆️ | Replaced: real AccessKey POST + JWT (HS256) webhook verifier with timestamp freshness. |
AwsSnsProvider simulated send |
✅ | ⬆️ | Replaced: real SigV4-signed POST to sns.<region>.amazonaws.com + PEM-cert injectable SNS verifier. |
PlivoProvider |
🚫 | ✅ | ADDED — orchestrator scope explicitly names Plivo. |
httpRequest helper |
✅ | ⬆️ | Re-implemented over injectable FetchLike + composed AbortSignal + SMS_PROVIDERS.* codes. |
SMS_PROVIDER_* codes on shared ErrorCodes |
✅ | ⬆️ | Migrated to genesis-native defineCodes("SMS_PROVIDERS", […]). |
mapStatus(raw) per provider |
✅ | ✅ | Preserved on every provider class. |
| Webhook signature verification | 🚫 | ✅ | ADDED — production requirement. |
| Provider registry | 🚫 | ✅ | ADDED — multiplexing by name (mirrors @suaveplan/payment-providers). |
| OTel instrumentation | 🚫 | ✅ | ADDED — production requirement. |
node:http round-trip tests |
🚫 | ✅ | ADDED — orchestrator requirement; real in-process server, no mocks. |
| Inbound opt-in/opt-out keyword detection | 🚫 | ✅ | ADDED — required for compliance integration with @suaveplan/sms's OptOutRegistry. |