Notify
Pluggable notification dispatcher. One contract — { name, send } — adapts any transport (Slack incoming-webhook, Discord, Microsoft Teams, PagerDuty, Twilio, FCM / APNs operator shim, plain developer log) and the dispatcher coordinates retry / timeout / circuit-breaker / observability / audit / PII redaction around it.
Composition over reinvention: every cross-cutting concern routes through an existing primitive — b.retry.withRetry for backoff + classification, b.safeAsync.withTimeout for per-call timeouts, b.retry.CircuitBreaker for per-channel breakers, b.observability. tap for span+counter wrapping, b.audit.safeEmit for audit rows (drop-silent on transport failure — observability sinks must not crash send), b.requestHelpers.extractActorContext for the 5 W's, b.safeUrl.parse + b.httpClient.request for HTTP I/O, b.redact.redact for default PII scrubbing of message contents before they hit the audit chain.
Built-in transports: httpJson (POST JSON / form to a URL — the workhorse for Slack / Discord / generic incoming-webhook integrations, with optional b.webhook.signer injection), log (fire-and-forget developer logger via b.log), test (captures sends to .sent[] for fixture inspection). Operators bring their own SDK shims for Twilio / FCM / APNs / Slack-API (the framework intentionally ships no vendor SDKs).
Out of scope by design: template rendering (use b.template), recipient preferences (operator concern), replacing b.mail (SMTP / MIME stays its own primitive), replacing b.websocketChannels (transient pub/sub vs retry-on-fail delivery).
b.notify.transports.httpJson(opts) #
{
url: string, // required
method: "POST" | "PUT" | "PATCH", // default "POST"
bodyFormat: "json" | "form", // default "json"
headers: { [k]: string },
signing: { sign(body) => headers | { headers } },
successStatus: function (status) => boolean,
allowHttp: boolean, // default false (HTTPS-only)
allowInternal: boolean,
httpClient: object, // override b.httpClient
name: string, // for audit + logs
}
Built-in transport that POSTs the message as JSON (or application/x-www-form-urlencoded) to a URL via b.httpClient. request. Validates the URL at create time so bad URLs surface at boot, not at first send. Optional signing slot accepts any object with a sign(body) → headers | { headers } function — drop a b.webhook.signer straight in for HMAC / PQC signed deliveries. The default success classifier accepts HTTP 2xx; non-success statuses throw a plain Error with statusCode set so b.retry.isRetryable classifies the response (429 / 503 / network errors retry; permanent rejections don't).
var b = require("@blamejs/core");
var slack = b.notify.transports.httpJson({
url: "https://hooks.slack.com/services/T0/B0/X",
name: "slack",
});
// → { name: "slack", send: async function (message, sendOpts) { ... } }
b.notify.create(opts) #
{
channels: { [name]: transport | { transport, retry?, breaker?, timeoutMs?, serialize? } },
audit: object, // b.audit handle
auditSuccess: boolean, // default true
auditFailures: boolean, // default true
redact: function (message) => any, // default b.redact.redact
defaultTimeoutMs: number, // default 30s, 0 disables
defaultRetry: object, // b.retry.withRetry opts
defaultBreaker: object, // b.retry.CircuitBreaker opts
queue: { enqueue(name, payload), registerHandler? },
clock: function () => number, // ms
}
Build a dispatcher bound to a set of named channels. Returns { send, sendBatch, queue, addChannel, channels, transport }: send delivers one message through one channel with the full retry / timeout / breaker / span+counter / audit stack; sendBatch settles each input independently so one channel down doesn't fail the rest; queue enqueues onto a b.queue handle for out-of-band delivery; addChannel registers a new channel post-construction; channels() lists registered names; transport(name) exposes the raw transport handle for diagnostics. Each channel entry is either a transport object directly ({ send, name? }) or a config wrapper ({ transport, retry?, breaker?, timeoutMs?, serialize? }) so operators tune retry / breaker / timeout / serialize per channel.
var b = require("@blamejs/core");
var notify = b.notify.create({
channels: {
slack: b.notify.transports.httpJson({ url: "https://hooks.slack.com/services/T0/B0/X" }),
log: b.notify.transports.log(),
},
});
// → { send, sendBatch, queue, addChannel, channels, transport }
Last updated 2026-08-08T16:39:49.652Z by seeder.