beacon

A did:nostr social-graph indexer — it indexes Nostr profiles (kind 0), follows (kind 3, the social graph), and relay lists (kind 10002) for pubkeys into MongoDB, and serves them over a small read API.

Useful as the identity substrate for SSO: “sign in with did:nostr”, plus trust / discovery over the follow graph.

This is a clean reimplementation of nostr-labs/nostr-beacon, keeping the same Mongo schema to start (for regression). Per the RFC, DID-document generation will delegate to jss’s buildDidDocument rather than maintaining a second, divergent generator (the source of the bugs in nostr-labs/nostr-beacon#3).

Schema (matches the live nostr-beacon)

Each collection stores the raw Nostr event, keyed by pubkey, latest-wins by created_at:

data kind collection
profiles 0 beacon
follows (social graph) 3 follows
relay lists 10002 relay_lists

(Collection names are configurable via env so the same Mongo can be read/written interchangeably.)

Run

npm install
cp .env.example .env        # set MONGODB_URI and relays
npm start                   # indexer + read API
# or run separately:
npm run index               # indexer only
npm run serve               # read API only

# indexer flags (override the matching env var; see --help):
node index.js --hoses profiles --no-legacy   # run a single hose, no legacy fallback
node src/indexer.js --help

Read API

Status

v0 — MVP: indexer + read API + the regression-compatible schema, plus the DID-document resolution endpoint (/.well-known/did/nostr/:pubkey.json via jss’s buildDidDocument) and a /relays health directory.

The indexer is being reworked into composable hoses (src/hoses/), each owning a set of event kinds, all sharing one schnorr signature check (src/hoses/event.js) so a relay can’t inject forged data. Which hoses run is a switch — the HOSES env (comma list of names; default: all).

Every kind is now hose-owned; the legacy raw-upsert fallback is empty.

Separately, an active relay-health prober (node probe.js / npm run probe) keeps the relays directory fresh: it dials every known relay for reachability + latency, reads the NIP-11 info doc for auth/payment requirements, and rolls up uptime. It self-schedules (PROBE_INTERVAL, default hourly) or runs a single sweep with --once. It’s not a hose — it’s active, not a subscription.

License

MIT