← All @molecule/* packages · App templates

@molecule/api-notifications

Core interface · notifications · API (Node) · v1.0.1 · Apache-2.0

Multi-channel notification delivery

npm install @molecule/api-notifications

npm · Source on GitHub

How it works

@molecule/api-notifications is the notifications core interface on the API (Node) side: the API your app calls, with no vendor inside.

Choose the implementation by bonding one of its 2 providers: @molecule/api-notifications-slack, @molecule/api-notifications-webhook.

import { setProvider, notifyAll } from '@molecule/api-notifications'
import { provider as webhook } from '@molecule/api-notifications-webhook'

setProvider('webhook', webhook)

await notifyAll({
  subject: 'Service Down',
  body: 'API is not responding',
})

Providers (2): @molecule/api-notifications-slack, @molecule/api-notifications-webhook

Works with: @molecule/api-bond, @molecule/api-i18n

Reference

Auto-generated, AI-first package reference for the molecule.dev ecosystem. It is written to be read by coding agents as much as by people, and is generated from this package's source — edit src/index.ts JSDoc, not this file.

Notifications interface for molecule.dev.

Supports multiple notification channels (webhook, Slack, email, etc.) through named bonds. Use notifyAll() to broadcast to all channels.

Quick Start

import { setProvider, notifyAll } from '@molecule/api-notifications'
import { provider as webhook } from '@molecule/api-notifications-webhook'

setProvider('webhook', webhook)

await notifyAll({
  subject: 'Service Down',
  body: 'API is not responding',
})

Type

core

Installation

npm install @molecule/api-notifications @molecule/api-bond @molecule/api-i18n

API

Interfaces

Notification

A notification to send through a notification channel.

interface Notification {
  /** Subject or title of the notification. */
  subject: string
  /** Body text of the notification (may contain markdown). */
  body: string
  /** Optional metadata for provider-specific features. */
  metadata?: Record<string, unknown>
}

NotificationResult

Result of a notification send attempt.

interface NotificationResult {
  /** Whether the notification was sent successfully. */
  success: boolean
  /** Error message if the send failed. */
  error?: string
  /** Channel name this result came from (populated by notifyAll). */
  channel?: string
  /** ISO 8601 timestamp of the send attempt (populated by notifyAll). */
  sentAt?: string
}

NotificationsProvider

Notifications provider interface. Providers implement specific channels (webhook, Slack, email, etc.).

Bonded as named providers: bond('notifications', 'webhook', provider)

interface NotificationsProvider {
  /** The channel name (e.g. 'webhook', 'slack', 'email'). */
  readonly name: string

  /**
   * Sends a notification through this channel.
   *
   * @param notification - The notification to send.
   * @returns The result of the send attempt.
   */
  send(notification: Notification): Promise<NotificationResult>
}

Functions

getAllProviders()

Returns all bonded notification providers.

function getAllProviders(): Map<string, NotificationsProvider>

Returns: Map of channel name to provider.

getProvider(name)

Retrieves a specific notifications provider by channel name.

function getProvider(name: string): NotificationsProvider | null
  • name — The channel name.

Returns: The provider, or null if not bonded.

hasProvider()

Checks whether any notifications provider is bonded.

Notification channels are NAMED bonds (bond('notifications', name, provider)), so this checks the named-provider map. (isBonded('notifications') alone checks the singleton map and would always report false here — a channel registered via {@link setProvider} never appears there.)

function hasProvider(): boolean

Returns: true if at least one provider is bonded.

notifyAll(notification)

Sends a notification through ALL bonded channels CONCURRENTLY (via Promise.allSettled), so one slow/hanging channel cannot delay every other channel behind it. Failures in one channel do not prevent other channels from being tried. Errors are logged, not thrown. Results are reassembled in registration (Map insertion) order regardless of which channel settles first.

function notifyAll(notification: Notification): Promise<NotificationResult[]>
  • notification — The notification to send.

Returns: Array of results, one per channel, in registration order.

setProvider(name, provider)

Registers a notifications provider under its channel name.

function setProvider(name: string, provider: NotificationsProvider): void
  • name — The channel name (e.g. 'webhook', 'slack').
  • provider — The provider implementation.

Available Providers

ProviderPackage
Slack@molecule/api-notifications-slack
Webhook@molecule/api-notifications-webhook

Injection Notes

Requirements

Peer dependencies:

  • @molecule/api-bond ^1.0.1
  • @molecule/api-i18n ^1.0.1

Runtime Dependencies

  • @molecule/api-bond
  • @molecule/api-i18n

notifyAll() fans out to every bonded channel CONCURRENTLY (Promise.allSettled), not serially — a slow or hanging channel does not delay the delivery of any other channel behind it. Per-channel failures (rejected result or thrown error) are isolated and logged; results are always returned in the channels' registration order, regardless of which settles first.

E2E Tests

Integration checklist — drive the real flow (no mocks), adapt each item to this app's actual events/triggers, and check every box off one by one. A box you can't check is an integration bug to fix — not a skip:

  • Each ops/event trigger the app defines (service down, new signup, a threshold crossed) actually calls notifyAll() and the message reaches every bonded channel. The sandbox CAPTURES outbound notifications instead of sending — read them with the read_activity tool and confirm the subject+body match the event that fired. Never mock the flow or modify production code to expose it.
  • MULTI-CHANNEL: with >1 channel bonded, notifyAll() returns one NotificationResult per channel and a single channel failing (success: false) does not swallow the others — every other channel still captured, its own result still success: true.
  • The body carries the real event data (no undefined placeholders) and nothing that must not leave the system — no secrets, tokens, or PII that an external channel (Slack/webhook) should never receive.
  • Triggers are not end-user SPAMMABLE — no public endpoint lets a caller fire unbounded notifications; the trigger is internal (an ops/system event) or rate-limited.

Translations

Translation strings are provided by @molecule/api-locales-notifications.