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

@agentine/herald

v0.1.0

Published

Cross-platform desktop notifications for Node.js — drop-in replacement for node-notifier

Downloads

64

Readme

@agentine/herald

npm version npm downloads CI License: MIT Node.js TypeScript

Cross-platform desktop notifications for Node.js — drop-in replacement for node-notifier.

Zero dependencies. Pure TypeScript. No bundled binaries.

Installation

npm install @agentine/herald

Quick Start

import { notify } from '@agentine/herald';

await notify({
  title: 'Build Complete',
  message: 'All tests passed',
});

API Reference

notify(options): Promise<NotificationResult>

Send a notification using the auto-detected platform provider.

import { notify } from '@agentine/herald';

const result = await notify({
  title: 'Deployment',
  message: 'Production deploy succeeded',
  icon: './icon.png',
  sound: true,
  timeout: 10,
});

console.log(result.success); // true or false

NotifyOptions

| Field | Type | Platform | Description | |-------|------|----------|-------------| | title | string | All | Notification title (required) | | message | string | All | Notification body (required) | | subtitle | string | macOS | Secondary line below the title | | icon | string | Windows, Linux | Path to icon image | | sound | boolean \| string | macOS, Windows | Play sound (true for default; on macOS pass a named sound e.g. "Ping") | | timeout | number | Linux | Auto-dismiss after N seconds (passed as milliseconds to notify-send) | | actions | string[] | Linux | Action button labels (requires a compatible notification daemon) | | wait | boolean | — | Reserved for future use | | appId | string | Windows | Application identifier shown in notification centre (defaults to "herald") | | urgency | "low" \| "normal" \| "critical" | Linux | Maps to --urgency flag of notify-send |

NotificationResult

| Field | Type | Description | |-------|------|-------------| | success | boolean | Whether the notification was sent | | action | string? | Action taken by the user | | error | Error? | Error if notification failed |

Platform-Specific Providers

import { NotificationCenter, WindowsBalloon, NotifySend } from '@agentine/herald';

// macOS
const nc = new NotificationCenter();
await nc.notify({ title: 'macOS', message: 'via osascript', sound: 'Ping' });

// Windows
const wb = new WindowsBalloon();
await wb.notify({ title: 'Windows', message: 'via PowerShell', appId: 'com.myapp' });

// Linux
const ns = new NotifySend();
await ns.notify({ title: 'Linux', message: 'via notify-send', urgency: 'critical' });

FallbackChain

Try multiple notification strategies in order, returning the first success:

import { FallbackChain, NotificationCenter, NotifySend } from '@agentine/herald';

const chain = new FallbackChain([
  new NotificationCenter(),
  new NotifySend(),
]);

await chain.notify({ title: 'Fallback', message: 'Tries each in order' });

Migration from node-notifier

Step 1: Install

npm uninstall node-notifier
npm install @agentine/herald

Step 2: Update imports

Callback style (node-notifier API):

// Before
const notifier = require('node-notifier');
notifier.notify({ title: 'Hello', message: 'World' });

// After
import notifier from '@agentine/herald';
notifier.notify({ title: 'Hello', message: 'World' });

Promise style (recommended):

// Before
const notifier = require('node-notifier');
notifier.notify({ title: 'Hello', message: 'World' }, (err) => { ... });

// After
import { notify } from '@agentine/herald';
const result = await notify({ title: 'Hello', message: 'World' });

Step 3: Event listeners (optional)

import notifier from '@agentine/herald';

notifier.on('click', (result) => console.log('Clicked'));
notifier.on('timeout', (result) => console.log('Dismissed'));

notifier.notify({ title: 'Hello', message: 'World' });

Platform Requirements

| Platform | Tool | Notes | |----------|------|-------| | macOS | osascript | Built-in on all macOS versions | | Windows | PowerShell 5+ | Built-in on Windows 10+. Optionally install BurntToast for richer notifications | | Linux | notify-send | Install via sudo apt install libnotify-bin (Debian/Ubuntu) or sudo dnf install libnotify (Fedora). Falls back to D-Bus via gdbus |

Comparison with node-notifier

| Feature | node-notifier | @agentine/herald | |---------|--------------|-----------------| | Bundled binaries | Yes (terminal-notifier, snoreToast) | No | | Runtime dependencies | 7 | 0 | | TypeScript | Partial (@types) | Native | | Module format | CJS only | ESM + CJS | | macOS | terminal-notifier binary | osascript (built-in) | | Windows | snoreToast binary | PowerShell + BurntToast/WinRT | | Linux | notify-send | notify-send + D-Bus fallback | | API style | Callback | Promise + callback compat | | Maintained | Last commit Jan 2023 | Active |

Security

Herald escapes all user-supplied strings before passing them to OS notification tools.

| Platform | Mechanism | What is escaped | |----------|-----------|-----------------| | macOS | JXA via osascript -e | Backslashes, double quotes, newlines, carriage returns inside the JavaScript string literal | | Windows (WinRT) | XML template embedded in PowerShell | &, <, > XML entities in the toast XML body | | Windows (PowerShell args) | PowerShell double-quoted strings | Backticks, double quotes, $, newlines, carriage returns | | Linux | execFile argument array | OS handles argument isolation — no shell interpolation |

Windows WinRT XML injection — title and message values are XML-escaped (&amp;, &lt;, &gt;) before insertion into the WinRT toast template. Unescaped < or & characters in input would otherwise break the XML document and could be abused to inject arbitrary toast XML elements.

General recommendations:

  • Validate and sanitise notification content before passing user-controlled strings to notify().
  • Avoid embedding raw user input in notification titles/messages in security-sensitive contexts without additional sanitisation.

License

MIT