Bridges third-party status pages into Webex spaces via RSS polling and inbound webhooks (Statuspage / Status.io / Uptime Kuma / generic). Includes an interactive Webex bot (websocket transport) that lets space members register sources with an Adaptive Card instead of hand-editing config/feeds.json: help, add, list, webhook <key>, remove <key>. Ships with an atomic JSON store (per-file mutex, tmp+rename), parallel RSS polling, and unit tests via node:test. All secrets are sourced from environment variables (see .env.example); no credentials in the repo. Co-authored-by: Cursor <cursoragent@cursor.com>
4 KiB
aeStatusPage
Small Node.js service that bridges third-party status pages into Webex spaces. It can consume:
- RSS / Atom feeds (polled every 5 minutes)
- Inbound webhooks in Atlassian Statuspage, Status.io, or Uptime Kuma format
- Anything else you point at it (raw dump)
It also runs a Webex bot so you can register new sources from inside a space
with a card-based UI instead of hand-editing config/feeds.json.
Configure
Copy .env.example to .env and set the values, at minimum:
| Variable | Purpose |
|---|---|
WEBEX_BOT_TOKEN |
Bearer token for the Webex bot user (required) |
PUBLIC_BASE_URL |
Public https URL where this service is reachable; used to show users the correct webhook URL |
SERVER_PORT |
Override the port from config/config.json (default 1449) |
SERVER_NAME |
Cosmetic name used in log lines |
BOT_ENABLED |
Set to false to disable the interactive chat bot |
config/config.json should now only contain non-secret configuration.
Run
Node version. The Docker image runs on Node 20 (node:20). For local
development, use Node 20.x — Node 21+ breaks webex-node-bot-framework's
transitive webex dep, which tries to write to the now read-only global
navigator. The app will still start on newer Node hosts, but the interactive
chat bot will be disabled with a warning logged. Set BOT_ENABLED=false to
suppress the warning if you don't want the bot in dev.
npm install
npm start
or Docker:
docker build -t aestatuspage .
docker run --env-file .env -p 1449:1449 \
-v $(pwd)/config:/usr/src/app/config \
-v $(pwd)/logs:/usr/src/app/logs \
aestatuspage
Register a source from Webex
- Invite the bot user to the space.
- Type
help— you'll see the available commands. - Type
add— the bot posts an Adaptive Card. Fill in:- a short key (used as the webhook URL slug)
- a friendly name
- source type:
RSS,Webhook, orBoth - the RSS URL and/or the webhook payload format
- On submit the bot saves the entry to
config/feeds.jsonatomically and posts back the exact webhook URL you should configure in your upstream status provider (Statuspage, Status.io, Uptime Kuma, ...).
Other commands:
list— show sources currently posting to this spacewebhook <key>— echo back the inbound webhook URL for a providerremove <key>— stop posting a provider to this space
The bot uses Webex's websocket transport, so it does not require an inbound
webhook URL to work as a chat bot. PUBLIC_BASE_URL is only used to show
users the correct URL for status page webhooks.
HTTP endpoints
| Method + path | Purpose |
|---|---|
GET /healthCheck |
Liveness probe |
GET /feeds |
Dumps the current feeds.json |
GET /webhookEvents |
Dumps recent webhook events (in-memory) |
GET /refreshFeeds |
Re-reads feeds.json from disk without restarting |
GET /checkRSSFeed?site=<url> |
Debug: fetch + parse a feed and return it |
GET /cleanOldFiles |
Manually trigger old-log cleanup |
GET /:provider/go |
Redirect to the provider's siteUrl |
POST /:provider |
Inbound status webhook (Statuspage / Status.io / Uptime Kuma / generic) |
POST /rssTest?provider=<key> |
Debug: send a fake RSS item as if it had come through the feed |
Tests
npm test
Runs node --test against test/**/*.test.js. No test framework
dependencies — everything is Node built-ins.
Layout
index.js HTTP server, cron loop, webhook processors
src/atomicJson.js Atomic JSON read/write with per-file mutex
src/providerStore.js Typed wrapper around feeds.json (add/remove/list)
src/cards.js Adaptive Card templates used by the bot
src/webexBot.js webex-node-bot-framework wiring (websocket mode)
config/config.json Non-secret configuration
config/feeds.json Registered providers (mutated at runtime)
config/rssFeedCache.json Dedup cache for RSS items already posted
logs/ Rolling per-day log files
test/ Unit tests