npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@growth-labs/notify

v0.2.0

Published

Worker-compatible human notification delivery for Slack and email with severity routing, retry, and caller-supplied dedup hooks.

Readme

@growth-labs/notify

Worker-compatible human notification delivery for Slack and email.

Use this package when a Worker needs to alert people about operational events: daily digest completion/failure, auth monitor incidents, Tail Worker error capture, or migration status updates.

It is deliberately small:

  • Slack incoming webhooks
  • Cloudflare Send Email binding
  • Resend REST API fallback
  • fixed severity routing
  • caller-supplied dedup and audit hooks
  • no D1, KV, queues, or background work

Install

pnpm add @growth-labs/notify

Basic Usage

import { notify } from '@growth-labs/notify'

const result = await notify(env, {
	channels: ['slack', 'email'],
	severity: 'critical',
	title: 'Auth surface down',
	body: '/login/ returning 503 for 12 minutes. Last good: 09:32 UTC.',
	dedupKey: 'auth-monitor:fronts.co:login:down',
	dedupFn: async (key) => {
		// Caller-owned persistence, for example D1 or KV.
		return false
	},
	onSent: async (record) => {
		// Caller-owned audit log.
		console.log(record)
	},
})

if (result.failed.length > 0) {
	console.warn('Notification delivery failed', result.failed)
}

Severity Routing

The caller always provides the requested channel list. Severity filters that list:

| Severity | Slack | Email | | --- | --- | --- | | info | yes | no | | warning | yes | no | | critical | yes | yes |

Example: channels: ['email'] with severity: 'info' sends nothing and returns:

{
	attempted: ['email'],
	sent: [],
	skipped: [{ channel: 'email', reason: 'severity-routing' }],
	failed: [],
}

Routing is not configurable in v0.1. If an event should reach email, it should be critical.

Environment

interface NotifyEnv {
	NOTIFY_SLACK_WEBHOOK?: string
	SLACK_WEBHOOK_URL?: string
	SEND_EMAIL?: { send(message: unknown): Promise<unknown> }
	RESEND_API_KEY?: string
	NOTIFY_EMAIL_TO?: string
	NOTIFY_EMAIL_FROM?: string
}

| Channel | Required values | | --- | --- | | Slack | NOTIFY_SLACK_WEBHOOK (SLACK_WEBHOOK_URL accepted as a legacy fallback) | | Email via Cloudflare | SEND_EMAIL, NOTIFY_EMAIL_TO, NOTIFY_EMAIL_FROM | | Email via Resend | RESEND_API_KEY, NOTIFY_EMAIL_TO, NOTIFY_EMAIL_FROM |

If a requested and severity-allowed channel is missing required values, notify() skips that channel with reason missing-binding. It does not throw.

Cloudflare Email

Cloudflare is the default email provider:

await notify(env, {
	channels: ['email'],
	severity: 'critical',
	title: 'Digest failed',
	body: 'The 2026-05-18 digest job failed.',
})

Configure the Worker binding:

[[send_email]]
name = "SEND_EMAIL"

Cloudflare Email requires the destination address to be verified through Email Routing or Email Service setup before sends are accepted. If the binding rejects with a destination-verification error, notify records that provider error in result.failed[]; the package does not attempt verification.

Resend Fallback

Use Resend when the incident being reported could affect Cloudflare delivery itself:

await notify(env, {
	channels: ['slack', 'email'],
	severity: 'critical',
	title: 'Cloudflare auth worker unavailable',
	body: 'The monitor cannot reach the auth worker from two regions.',
	emailProvider: 'resend',
})

Resend sends a POST to https://api.resend.com/emails with bearer auth from RESEND_API_KEY.

Slack Blocks

Slack payloads always include text: title as the fallback. If you do not pass blocks, notify sends:

[
	{
		type: 'section',
		text: { type: 'mrkdwn', text: `*${title}*\n${body}` },
	},
]

Pass blocks when the caller owns richer formatting. Email ignores blocks.

Dedup And Audit Hooks

Dedup is caller-owned:

await notify(env, {
	channels: ['slack'],
	severity: 'warning',
	title: 'Queue backlog',
	body: 'Email queue has been above threshold for 10 minutes.',
	dedupKey: 'mailer:queue-backlog',
	dedupFn: async (key) => alreadySentRecently(key),
})

dedupFn is called per channel before dispatch. If it returns true, the channel is skipped with reason deduped. If it throws, notify warns and sends anyway. Over-delivery is safer than silently dropping an alert.

onSent runs once per successful adapter dispatch:

await notify(env, {
	channels: ['slack', 'email'],
	severity: 'critical',
	title: 'Monitor failed',
	body: 'The auth monitor detected a production outage.',
	onSent: async (record) => writeAuditRecord(record),
})

Errors from onSent are caught and logged with console.warn; a successful send is not reversed by an audit failure.

Result Shape

interface NotifyResult {
	attempted: Channel[]
	sent: Channel[]
	skipped: {
		channel: Channel
		reason: 'deduped' | 'missing-binding' | 'severity-routing'
	}[]
	failed: { channel: Channel; error: string }[]
}

Input validation can throw for an invalid shape: empty channels, missing title, missing body, unsupported severity, unsupported channel, or unsupported email provider.

Adapter delivery failures never throw from notify(). They are captured in failed[] and logged with console.warn.

Exports

export { notify } from '@growth-labs/notify'
export type {
	Channel,
	EmailProvider,
	NotifyEnv,
	NotifyInput,
	NotifyResult,
	SendEmailBinding,
	SentRecord,
	Severity,
	SlackBlock,
} from '@growth-labs/notify'