first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,63 @@
# `sms-channel` — SMS delivery channel
## Purpose
`sms-channel.ts` ships the `SmsChannel` `DeliveryChannel` implementation. Like the email channel, it is provider-neutral: a caller-supplied `sendFn(message)` performs the actual API call into Twilio, MessageBird, Vonage, Sinch, or any in-house SMSC. The channel keeps the responsibility surface tiny — recipient validation (E.164 `+` prefix), payload shaping, and error swallowing — so the router can stay decoupled from any specific carrier.
## Features
- Provider-neutral via injectable `sendFn`.
- `canSend` rejects recipients that do not start with `+` (E.164 prefix); avoids hitting upstream providers with formats they will reject.
- Propagates `metadata` to the provider message for correlation IDs and segmentation.
- Injectable `Clock` for deterministic `timestamp` fields in tests.
- Returns `DeliveryResult` even on provider failure — never throws to the router.
## Usage: Basic
```ts
import { SmsChannel } from "@suaveplan/notification-channel";
const channel = new SmsChannel({
from: "+15559999999",
sendFn: async (msg) => ({
messageId: await twilio.messages.create({
from: "+15559999999",
to: msg.to,
body: msg.body,
}).sid,
}),
});
```
## Usage: Advanced
```ts
import { SmsChannel } from "@suaveplan/notification-channel";
const channel = new SmsChannel({
from: "+15559999999",
sendFn: async (msg) => {
const { sid } = await provider.send({
from: "+15559999999",
to: msg.to,
body: msg.body,
...(msg.metadata?.["statusCallback"] !== undefined
? { statusCallback: msg.metadata["statusCallback"] }
: {}),
});
return { messageId: sid };
},
clock: () => testNow,
});
```
## API Reference
- `SmsChannel(config: SmsChannelConfig)` — constructor.
- `SmsChannelConfig` — `{ from, sendFn, clock? }`.
- `SmsMessage` — `{ to, body, metadata? }` passed to `sendFn`.
- `canSend(n): boolean`, `send(n): Promise<DeliveryResult>` — `DeliveryChannel` impl.
## Implementation Notes
The `+` prefix check is intentionally conservative — it does not validate the full E.164 country/area format because providers do that anyway and over-validating client-side breaks edge cases like short-code dispatch. Tests cover both `Error` and non-`Error` throws inside `sendFn` to lock in the `String(err)` coercion. The injected `clock` only affects the `DeliveryResult.timestamp` field; provider-recorded send time remains authoritative.