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

thelounge-plugin-apprise-push

v1.2.1

Published

TheLounge server plugin: push notifications via Apprise HTTP API

Readme

thelounge-plugin-apprise-push

npm version CI npm downloads license node

A TheLounge server plugin that forwards IRC highlights and private messages to Apprise, so you get a push notification on your phone, desktop, or any of Apprise's 100+ services (Telegram, Pushover, ntfy, Gotify, Slack, Discord, …) even when no browser tab is open.

It runs entirely server-side, has no runtime dependencies (Node.js built-ins only), and is configured with a single JSON file that is hot-reloaded on change.


Features

  • 🔔 Highlights & PMs out of the box — fully customisable via an ordered rule engine.
  • 🧩 Rule engine with glob matching on channel, network, sender nick; notify / suppress actions; first-match-wins ordering.
  • ✍️ Per-rule message templates — override the title/body for specific rules.
  • 🔐 Apprise authentication — bearer token or arbitrary custom headers.
  • 🔁 Retry with exponential backoff and a configurable request timeout.
  • 😴 Away-only mode, per-context cooldown, nick/network blacklists, and extra highlight words.
  • ♻️ Hot-reload — edit the config and changes apply within a second; no restart.
  • 🪶 Zero runtime dependencies, single small codebase, fully unit-tested.

Table of contents


Requirements

  • TheLounge ≥ 4.0
  • Node.js ≥ 18
  • A running Apprise API server with a persistent notification configuration pre-loaded under a key (e.g. chatnotifications)

Installation

  1. Install the plugin:

    thelounge install thelounge-plugin-apprise-push
  2. Create the config file at ~/.thelounge/apprise-push.json (see Configuration below). A starter file is shipped as apprise-push.example.json.

  3. Restart TheLounge once to load the plugin. After that, config changes are picked up automatically. No further restarts needed.


Configuration

All options go in $THELOUNGE_HOME/apprise-push.json (usually ~/.thelounge/apprise-push.json).

Apprise connection

| Key | Type | Description | | ------------- | ------ | --------------------------------------------------------------------------------------- | | apprise_url | string | Full Apprise API notify endpoint, e.g. "http://apprise:8000/notify/chatnotifications" |

The plugin POSTs { "title": "...", "body": "..." } to this URL. The notification destinations are configured server-side in Apprise under the given key.

Authentication

Optional. Use these when your Apprise API sits behind auth or a reverse proxy.

| Key | Type | Default | Description | | ----------------- | ------ | ------- | -------------------------------------------------------------------------- | | apprise_token | string | "" | Shorthand — sent as Authorization: Bearer <token>. | | apprise_headers | object | {} | Arbitrary extra HTTP headers. Overrides the bearer header on key conflict. |

"apprise_headers": { "Authorization": "Basic dXNlcjpwYXNz", "X-Source": "thelounge" }

Delivery tuning

| Key | Type | Default | Description | | ------------- | ------ | ------- | -------------------------------------------------------------------------------------------------- | | timeout | number | 10000 | Milliseconds before a single Apprise request is aborted. | | retries | number | 2 | Extra attempts after the first on transient failure (timeout, 5xx, network). 0 disables retries. | | retry_delay | number | 500 | Base backoff in ms; grows exponentially (500 → 1000 → 2000 …). |

Notification text

| Key | Default | Description | | ------------- | ------------------------------ | -------------------------------------------------------------- | | title_pm | "PM from {nick} [{network}]" | Title for private message notifications. | | title_chan | "[{network}] {channel}" | Title for channel notifications. | | body | "{nick}: {message}" | Notification body. | | body_length | 100 | Truncate {message} to this many characters. 0 = unlimited. |

Keyword expansion: these placeholders are replaced in title_pm, title_chan, body, and per-rule title/body overrides:

| Keyword | Value | | ----------- | ------------------------------------------------------------------ | | {channel} | Channel name or sender nick (for PMs) | | {nick} | Message sender | | {network} | IRC network name | | {mynick} | Your own nick on that network | | {time} | Local time the message was received | | {message} | Message text (IRC formatting stripped, truncated to body_length) |

Global pre-filters

These apply before any rule is evaluated. They are fast exits.

| Key | Default | Description | | ------------------- | ------- | ---------------------------------------------------------------------------------------------------- | | away_only | false | Only notify when no TheLounge browser tabs are connected. Equivalent to ZNC's away-only mode. | | cooldown | 0 | Minimum seconds between two notifications for the same context (channel or PM). 0 = disabled. | | nick_blacklist | [] | Glob patterns. Messages from matching nicks are silently dropped. E.g. ["*bot*", "ChanServ"]. | | network_blacklist | [] | Glob patterns. Messages from matching network names are silently dropped. | | highlight_words | [] | Extra words/patterns that count as a highlight in addition to your own nick. Glob patterns accepted. |

Rules

"rules": [ <rule>, <rule>, ... ]

Rules are evaluated in order; the first matching rule wins. If no rule matches, no notification is sent.

Each rule is a JSON object. All specified conditions must be true (AND logic). If a rule has no conditions it matches everything.

Rule conditions

| Key | Type | Description | | ----------- | ------------------ | ----------------------------------------------------------------------------------------------------------- | | channel | string | string[] | Glob pattern(s) for the channel name. If set, the rule only matches channel messages in a matching channel. | | pm | boolean | true → only match private messages. false → only match channel messages. Omit to match both. | | highlight | boolean | true → only match if the message contains your nick or a highlight_words entry. | | network | string | string[] | Glob pattern(s) for the network name. | | nick | string | string[] | Glob pattern(s) for the sender nick. |

Rule action & overrides

| Key | Default | Description | | -------- | ---------- | --------------------------------------------------------------------------------- | | action | "notify" | "notify" sends a notification. "suppress" blocks and stops evaluation. | | title | (global) | Override the title template for this rule. Falls back to title_pm/title_chan. | | body | (global) | Override the body template for this rule. Falls back to body. |

Glob patterns support * (any sequence) and ? (any single character), case-insensitive.


Examples

Default: highlights and PMs

"rules": [
  { "highlight": true },
  { "pm": true }
]

All messages in a channel

"rules": [
  { "channel": "#announcements" },
  { "highlight": true },
  { "pm": true }
]

Multiple channels: all messages

"rules": [
  { "channel": ["#announcements", "#alerts", "#ops"] },
  { "highlight": true },
  { "pm": true }
]

Highlights only in specific channels

"rules": [
  { "channel": "#dev", "highlight": true },
  { "channel": "#ops", "highlight": true },
  { "pm": true }
]

Custom message template for a rule

"rules": [
  { "channel": "#alerts", "title": "🚨 ALERT [{network}]", "body": "{nick}: {message}" },
  { "highlight": true },
  { "pm": true }
]

Suppress a noisy channel before a catch-all

"rules": [
  { "channel": "#random", "action": "suppress" },
  { "channel": "#*", "highlight": true },
  { "pm": true }
]

Suppress bots everywhere

"nick_blacklist": ["*bot*", "ChanServ", "NickServ"],
"rules": [
  { "highlight": true },
  { "pm": true }
]

nick_blacklist is a global pre-filter, so no rule can override it. If you need per-channel bot suppression, use a suppress rule instead.

Per-network rule

"rules": [
  { "network": "Libera", "channel": "#project", "highlight": true },
  { "network": "OFTC", "highlight": true },
  { "pm": true }
]

Extra highlight words

"highlight_words": ["myproject", "urgent", "prod*"],
"rules": [
  { "highlight": true },
  { "pm": true }
]

prod* will match "production", "prod-alert", etc.

Authenticated Apprise behind a proxy

"apprise_url": "https://apprise.example.com/notify/chatnotifications",
"apprise_token": "s3cr3t-bearer-token",
"timeout": 5000,
"retries": 3

Running Apprise API

The quickest way to run the Apprise API server:

docker run -p 8000:8000 caronc/apprise:latest

Load your notification URLs into Apprise under a key (e.g. chatnotifications) via the web UI or API, then set apprise_url to "http://apprise:8000/notify/chatnotifications".

See the Apprise wiki for the full list of supported services (Telegram, Pushover, Slack, Discord, Gotify, ntfy, and many more).


Debugging

Set "debug": true in the config. Each incoming message will log its evaluation result to TheLounge's stdout:

[apprise-push] chan "#dev" from "alice" hl=true → notify
[apprise-push] → "[Libera] #dev" / "alice: hey yourname, take a look"
[apprise-push] Apprise → HTTP 200

Unknown config keys and bad value types are also reported as warnings at load time.


Notes

  • /me actions (* nick does something) are included as triggers. The action text is prefixed with * nick in the notification body.
  • Cooldown is tracked independently per context (each channel and each PM thread has its own timer).
  • Retries apply to transient failures (timeouts, network errors, and non-2xx responses) with exponential backoff; the request is dropped after the last attempt and the error is logged.
  • Hot-reload: apprise-push.json is watched for changes. Edits take effect within a second; no TheLounge restart required. If the file is invalid JSON the previous config is kept and an error is logged.
  • Reconnects are handled automatically: the plugin re-attaches to a network's IRC connection on reconnection.
  • The plugin has no runtime npm dependencies beyond Node.js built-ins.

Development

npm install      # install dev tooling (ESLint, Prettier)
npm test         # run the node:test unit suite
npm run lint     # ESLint
npm run format   # Prettier --write

The codebase is split into small, individually-tested modules under lib/: config.js (defaults, glob compilation, validation), highlight.js, rules.js (rule engine), template.js (placeholder expansion), and apprise.js (HTTP delivery). index.js wires them into TheLounge.


Related

Part of a small family of TheLounge add-ons by @mbologna:


License

MIT © Michele Bologna