GenosDB Fallback Server (GenosSRV)
GenosDB is designed to run without servers. The Fallback Server is an optional superpeer you can add to a room when you want guarantees no browser can give: being always on. It ships as a single file with zero dependencies —genossrv.min.js, published with the GenosDB dist — and runs anywhere Bun runs.
What it does
The server behaves as just another peer in the network: it discovers and connects through the same Nostr relays as everyone else (or through its own — see Your own signaling), and every operation it emits is verified by every browser like anyone else’s. It does not centralize anything — it only adds the one guarantee no browser can offer, being always on.
Quick start
./data.sqlite.
CLI reference
Match the transport to your app. A room where browsers use
rtc: { cells: … } speaks over per-cell channels; start the server with --cells or it cannot receive browser writes (it will print a one-line warning telling you exactly this).
As a module
Options mirrorgdb(name, options) — same names, same shapes:
db.map with every operator, realtime subscriptions, middleware via db.use) — identical to the browser’s.
Governance: an always-on superadmin
In the browser, the governance engine runs only while a superadmin keeps a tab open. The fallback server removes that limitation: give it a signing identity and it becomes the room’s 24/7 governance authority — promotions, demotions and role expirations no longer depend on anyone being connected.How authority works
🛡️ SM: signing as 0x… — add that address to your application’s sm.superAdmins list (see the Security Manager documentation), and every peer verifies the server’s operations like any superadmin’s: same signatures, same machinery. Revoking it is as simple as removing the address from that list.
How rules work
The server must carry the same rules your application declares — one room, one policy: the server is simply its always-on executor. Each rule’sif is a plain GenosDB query, evaluated every few seconds against the synced graph with last-match-wins resolution: order rules easy→hard, and the last matching rule decides the role. Losing a condition auto-demotes; superadmins are immune by construction. See the Governance documentation for the rule model.
Key custody
The signing key lives on your server — treat it accordingly: use a dedicated governance identity (not your personal superadmin key), inject it through the environment or a secret manager, and never commit it. If the server is ever compromised, removing its address from your clients’superAdmins revokes it entirely.
Your own signaling
By default peers discover each other through public Nostr relays — those carry only encrypted handshakes, never your data. To own that layer too, the server embeds a signaling relay:$PORT — nothing is ever stored, every event is schnorr-verified before retransmission, and GET / on the same port answers a JSON health status.
With the relay on, the server signals through its own relay (plus anything you list in GDB_RELAY_URLS). Point your application at it and the whole stack — signaling, persistence, governance — runs on your infrastructure:
GDB_RELAY_URLS="wss://…,wss://…") if you want resilience through them as well.
ws:// vs wss://: use ws://host:port for local/LAN testing (browsers exempt localhost from mixed-content rules); production pages require wss://, whose TLS is terminated by your platform or proxy — on Heroku, wss://your-app.herokuapp.com works out of the box — while the relay itself always speaks plain WebSocket behind it.
Deployment
Anywhere Bun runs. The artifact is self-contained, so deployment is: fetch one file, run one command. VPS / bare metalsystemd, pm2, …) for restarts.
Docker
🚀 Deploy to Heroku in one click
Every option — room, transport, identity, governance rules — is an environment variable, so the deploy form configures the whole server:$PORT, so run it as the web process (heroku ps:scale web=1 worker=0) — the app’s URL then becomes your signaling endpoint (wss://your-app.herokuapp.com) and its root serves the relay’s health status.
Verification
The logs are the server’s interface — every state it goes through has a line. A healthy boot:GET http://host:$PORT/ returns {"relay":…,"connections":N,"events":N,"dropped":N} — dropped counts events rejected by signature verification.
And in operation, the signals that prove it is doing its job:
End-to-end check: open your application, write something, close every client, reopen — the data coming back can only have been served by the fallback server.