Phase 4 of the firehose rework. Adds the active relay-health prober — the piece that refreshes the relays directory the /relays page renders (data is currently a frozen 2025-11 snapshot). Unlike the subscription hoses it is active (dials each relay) and kind-less, so it is not a hose — it's its own self-scheduling module/process.
Design (confirmed)
- Process model:
src/prober.js — sweeps on an interval by default, runnable standalone or under pm2 (probe.js entry, mirroring serve.js), with --once / RUN_ONCE for a single sweep.
- Check depth: WebSocket connect (
online, responseTime, uptime rollup, lastChecked, lastError) plus a NIP-11 HTTP GET (Accept: application/nostr+json) for requiresAuth / requiresPayment. acceptsEvents stays untouched (publish-test is a later pass; the page already renders missing as "—").
- Relay universe: the
relays collection itself — continuously self-fed by the phase 2/3 harvesting.
- Consistent rollup: aggregation-pipeline
updateOne so uptime = checksOnline/checksTotal*100 is computed from the freshly $inc'd running totals.
- Scale knobs (env, CLI-overridable):
PROBE_INTERVAL (default 1h), PROBE_CONCURRENCY (25), PROBE_TIMEOUT (7s).
- No new deps — Node's global
WebSocket / fetch.
Scope
src/prober.js: pure helpers (proberConfig, nip11Flags, relayInfoUrl, arg parsing) + checkRelay, fetchNip11, probeRelay, sweepOnce, runProber.
probe.js: pm2/standalone entry; npm run probe.
.env.example + README: document the prober and its env/flags.
- Tests: pure helpers (config/flags, NIP-11 flag extraction, ws→http URL, scalar handling).
Out of scope
Publish-test (acceptsEvents) — a later pass · deploy/cut-over on nostr.social — phase 5.
Acceptance
node probe.js --once sweeps the relays collection and updates online/responseTime/uptime/lastChecked (+ requiresAuth/requiresPayment from NIP-11) without clobbering unrelated fields.
- Self-schedules by default;
--once exits after one sweep.
npm test green incl. new prober unit tests.
Phase 4 of the firehose rework. Adds the active relay-health prober — the piece that refreshes the
relaysdirectory the/relayspage renders (data is currently a frozen 2025-11 snapshot). Unlike the subscription hoses it is active (dials each relay) and kind-less, so it is not a hose — it's its own self-scheduling module/process.Design (confirmed)
src/prober.js— sweeps on an interval by default, runnable standalone or under pm2 (probe.jsentry, mirroringserve.js), with--once/RUN_ONCEfor a single sweep.online,responseTime,uptimerollup,lastChecked,lastError) plus a NIP-11 HTTP GET (Accept: application/nostr+json) forrequiresAuth/requiresPayment.acceptsEventsstays untouched (publish-test is a later pass; the page already renders missing as "—").relayscollection itself — continuously self-fed by the phase 2/3 harvesting.updateOnesouptime = checksOnline/checksTotal*100is computed from the freshly$inc'd running totals.PROBE_INTERVAL(default 1h),PROBE_CONCURRENCY(25),PROBE_TIMEOUT(7s).WebSocket/fetch.Scope
src/prober.js: pure helpers (proberConfig,nip11Flags,relayInfoUrl, arg parsing) +checkRelay,fetchNip11,probeRelay,sweepOnce,runProber.probe.js: pm2/standalone entry;npm run probe..env.example+ README: document the prober and its env/flags.Out of scope
Publish-test (
acceptsEvents) — a later pass · deploy/cut-over on nostr.social — phase 5.Acceptance
node probe.js --oncesweeps therelayscollection and updatesonline/responseTime/uptime/lastChecked(+requiresAuth/requiresPaymentfrom NIP-11) without clobbering unrelated fields.--onceexits after one sweep.npm testgreen incl. new prober unit tests.