# @suaveplan/network-trystero-server - Server-tier Trystero signaling daemon — hosts an MQTT broker shim or Nostr relay shim over plain WebSocket for browser-tier @suaveplan/network-discovery-trystero clients. Construction-time mode selection, injectable broker factory, AbortSignal lifecycle, health/ready/live endpoints, OTel observability, real-fake integration tests. ## Summary Server-tier Trystero signaling daemon. Hosts an MQTT-style or Nostr-style WebSocket broker shim plus standard `/health` / `/ready` / `/live` probes on a single Node `http.Server`. Browser-tier clients running `@suaveplan/network-discovery-trystero` connect to the daemon's published `relayUrl` for relay-backed P2P signaling. ## Documentation tree - [errors](./src/errors/errors.md) — _(no submodules)_ - [errors](./src/errors/errors.md) — _(no submodules)_ - [health](./src/health/health.md) — _(no submodules)_ - [health](./src/health/health.md) — _(no submodules)_ - [otel](./src/otel/otel.md) — _(no submodules)_ - [otel](./src/otel/otel.md) — _(no submodules)_ - [server](./src/server/server.md) — _(no submodules)_ - [broker-select](./src/server/broker-select.md) — The broker-select module resolves which broker factory the daemon hosts and bundles the matching mode-specific options… - [health-listener](./src/server/health-listener.md) — The health-listener helper extracts the `http.Server.listen` promise adapter out of the main daemon module so the daemo… - [peer-events](./src/server/peer-events.md) — The peer-events module owns the daemon-side wiring of broker lifecycle callbacks into the daemon's connection table, OT… - [server](./src/server/server.md) — _(no submodules)_ - [types](./src/types/types.md) — _(no submodules)_ - [types](./src/types/types.md) — _(no submodules)_ - [errors](./src/errors/errors.md) — _(no submodules)_- [health](./src/health/health.md) — _(no submodules)_- [health](./src/health/health.md) — _(no submodules)_- [otel](./src/otel/otel.md) — _(no submodules)_- [otel](./src/otel/otel.md) — _(no submodules)_- [server](./src/server/server.md) — _(no submodules)_- [broker-select](./src/server/broker-select.md) — The broker-select module resolves which broker factory the daemon hosts and bundles the matching mode-specific options… - [health-listener](./src/server/health-listener.md) — The health-listener helper extracts the `http.Server.listen` promise adapter out of the main daemon module so the daemo… - [peer-events](./src/server/peer-events.md) — The peer-events module owns the daemon-side wiring of broker lifecycle callbacks into the daemon's connection table, OT… - [server](./src/server/server.md) — _(no submodules)_- [types](./src/types/types.md) — _(no submodules)_- [types](./src/types/types.md) — _(no submodules)_- [errors](./src/errors/errors.md) — _(no submodules)_- [health](./src/health/health.md) — _(no submodules)_- [health](./src/health/health.md) — _(no submodules)_- [otel](./src/otel/otel.md) — _(no submodules)_- [otel](./src/otel/otel.md) — _(no submodules)_- [server](./src/server/server.md) — _(no submodules)_- [broker-select](./src/server/broker-select.md) — The broker-select module resolves which broker factory the daemon hosts and bundles the matching mode-specific options… - [health-listener](./src/server/health-listener.md) — The health-listener helper extracts the `http.Server.listen` promise adapter out of the main daemon module so the daemo… - [peer-events](./src/server/peer-events.md) — The peer-events module owns the daemon-side wiring of broker lifecycle callbacks into the daemon's connection table, OT… - [server](./src/server/server.md) — _(no submodules)_- [types](./src/types/types.md) — _(no submodules)_- [types](./src/types/types.md) — _(no submodules)_- [errors](./src/errors/errors.md) — _(no submodules)_- [health](./src/health/health.md) — _(no submodules)_- [health](./src/health/health.md) — _(no submodules)_- [otel](./src/otel/otel.md) — _(no submodules)_- [otel](./src/otel/otel.md) — _(no submodules)_- [server](./src/server/server.md) — _(no submodules)_- [broker-select](./src/server/broker-select.md) — The broker-select module resolves which broker factory the daemon hosts and bundles the matching mode-specific options… - [health-listener](./src/server/health-listener.md) — The health-listener helper extracts the `http.Server.listen` promise adapter out of the main daemon module so the daemo… - [peer-events](./src/server/peer-events.md) — The peer-events module owns the daemon-side wiring of broker lifecycle callbacks into the daemon's connection table, OT… - [server](./src/server/server.md) — _(no submodules)_- [types](./src/types/types.md) — _(no submodules)_- [types](./src/types/types.md) — _(no submodules)_- [errors](./src/errors/errors.md) — _(no submodules)_- [health](./src/health/health.md) — _(no submodules)_ - [health](./src/health/health.md) — _(no submodules)_- [otel](./src/otel/otel.md) — _(no submodules)_ - [otel](./src/otel/otel.md) — _(no submodules)_- [server](./src/server/server.md) — _(no submodules)_ - [broker-select](./src/server/broker-select.md) — The broker-select module resolves which broker factory the daemon hosts and bundles the matching mode-specific options… - [health-listener](./src/server/health-listener.md) — The health-listener helper extracts the `http.Server.listen` promise adapter out of the main daemon module so the daemo… - [peer-events](./src/server/peer-events.md) — The peer-events module owns the daemon-side wiring of broker lifecycle callbacks into the daemon's connection table, OT… - [server](./src/server/server.md) — _(no submodules)_- [types](./src/types/types.md) — _(no submodules)_ - [types](./src/types/types.md) — _(no submodules)_ ## Why this package - **One daemon, one mode.** Construction-time selection between `"mqtt"` and `"nostr"`. No runtime branching past the broker factory, so dashboards split cleanly by `mode` label. - **Defensive by default.** Malformed frames flow through `onMalformedFrame` and increment `trystero_server.messages_relayed_total{outcome="error"}` without ever crashing the relay. - **Injection-friendly.** The broker shim is a peer dependency on intent — production wires a real WebSocket broker, tests bind a deterministic in-memory `FakeBroker`. - **Lifecycle-correct.** `start({ signal? })` resolves with `{ address, port, mode, relayUrl }`. `stop()` is idempotent and drains in-flight peers. ## Run the daemon ```ts import { TrysteroServer, type BrokerFactory, } from "@suaveplan/network-trystero-server"; const mqttBrokerFactory: BrokerFactory = (deps) => { // attach to the daemon's http.Server, handle WS upgrade, etc. return { mode: deps.mode, activeConnections: 0, async start({ httpServer, callbacks }) { // real broker wiring }, async stop() { // drain sockets, close listeners }, }; }; const server = new TrysteroServer({ mode: "mqtt", port: 8765, host: "0.0.0.0", maxConnections: 256, mqttBrokerFactory, }); const { relayUrl } = await server.start(); console.log(`trystero relay listening on ${relayUrl}`); process.on("SIGTERM", async () => { await server.stop(); process.exit(0); }); ``` ## Modes | Mode | Wire path | Mode-specific options | |---------|------------|------------------------------------| | `mqtt` | `/mqtt` | `{ password? }` | | `nostr` | `/nostr` | `{ relayName? }` | Both modes follow the same wire-formatting contract from the browser-tier companion package [`@suaveplan/network-discovery-trystero`](../network-discovery-trystero) — the daemon publishes the matching `relayUrl` and the discovery client treats it as a relay endpoint. ## Configuration reference See [`src/types/types.md`](./src/types/types.md) for the full strict `TrysteroServerConfig`. The only required fields are `mode`, `port`, and the per-mode broker factory. Every other field is optional with a spec-documented default. ## Health endpoints | Verb | 200 OK when | 503 when | |----------|--------------------------------------|--------------------------------------| | `/live` | process alive (always, until stop) | after `stop()` | | `/ready` | started AND below `maxConnections` | starting, at-cap, or stopped | | `/health`| started AND below `maxConnections` | starting, at-cap, or stopped | See [`src/health/health.md`](./src/health/health.md). ## Observability OpenTelemetry instrument names emitted by the daemon: - `trystero_server.start` / `trystero_server.stop` — spans. - `trystero_server.connections_total{mode,outcome}` — counter. - `trystero_server.messages_relayed_total{mode,outcome}` — counter. - `trystero_server.active_connections{mode}` — up-down gauge. - `trystero_server.start_duration_ms{mode}` — histogram. See [`src/otel/otel.md`](./src/otel/otel.md). ## Companion package [`@suaveplan/network-discovery-trystero`](../network-discovery-trystero) is the browser-tier client this daemon serves.