5.5 KiB
Server Directory
Area: server-directory Status: Active Last updated: 2026-07-05
Overview
Server directory is the cross-context contract for which signaling servers exist, how clients health-check and route to them, and how public/private chat-servers are created, joined, updated, moderated, and discovered over REST. It spans the signaling server (server/src/routes/servers.ts, CQRS handlers) and the product client (server-directory domain + ServerDirectoryFacade).
Curated browse lists (featured/trending) are documented separately in server-discovery.md. WebSocket membership (join_server, presence) is in signaling.md.
Responsibilities
- Server: persist public server records, memberships, channels, roles, bans, invites, join requests; expose REST CRUD and access checks.
- Client: maintain configured endpoint list, health/compatibility probes, canonical endpoint dedup by
serverInstanceId, roomsourceId/sourceUrlaffinity, and HTTP orchestration for all server operations. - It does NOT own: P2P chat transport, voice WebRTC, or local Electron room/message persistence (except mirroring server metadata into local DB after join).
Key concepts
- ServerEndpoint: configured signaling base URL with health status, latency, and version compatibility.
- ServerInfo: public server card shape returned by search/discovery/GET — includes
sourceId,sourceName,sourceUrlfilled by the client API layer. - Room signal affinity: each saved room records which endpoint registered it; reconnect prefers that URL before fallback endpoints.
- serverInstanceId: stable id from
GET /api/healthused to collapse alias URLs to one canonical endpoint.
Public REST (no bearer)
| Method | Path | Purpose |
|---|---|---|
| GET | /api/health |
Liveness, serverVersion, serverInstanceId, optional serverTag |
| GET | /api/servers |
Free-text search / public listing (q, limit) |
| GET | /api/servers/featured |
Curated popular list — server-discovery.md |
| GET | /api/servers/trending |
Curated active list — server-discovery.md |
| GET | /api/servers/:id |
Single server metadata |
Protected REST (bearer required)
All mutations derive the actor from the session token; body user ids are not trusted.
| Method | Path | Purpose |
|---|---|---|
| POST | /api/servers |
Register a new public server |
| PUT | /api/servers/:id |
Update name, description, channels, icon metadata, access settings |
| DELETE | /api/servers/:id |
Unregister server (owner) |
| POST | /api/servers/:id/join |
Join or request access (password, invite, public) |
| POST | /api/servers/:id/leave |
Leave membership |
| POST | /api/servers/:id/heartbeat |
Refresh lastSeen for trending ranking |
| POST | /api/servers/:id/invites |
Create invite link — invites-join-requests.md |
| GET | /api/servers/:id/requests |
List pending join requests (moderators) |
| POST | /api/servers/:id/moderation/kick |
Remove member |
| POST | /api/servers/:id/moderation/ban |
Ban member (optional expiry) |
| POST | /api/servers/:id/moderation/unban |
Lift ban |
Join-request approval: PUT /api/requests/:id — invites-join-requests.md.
Plugin metadata under /api/servers/:serverId/plugins — plugins.md.
Client endpoint lifecycle
- Load endpoints from
localStorage(metoyou_server_endpoints); reconcile with environment defaults. testAllServers()probesGET /api/health(5 s timeout); on failure falls back toGET /api/servers.- Mark incompatible when
serverVersionfails semantic compatibility check. resolveCanonicalEndpoint()collapses aliases sharing the sameserverInstanceId.- Cold-start room reconnect waits for the initial health sweep before opening WebSockets.
Multi-endpoint behavior
| Operation | Fan-out |
|---|---|
Search (searchServers with searchAllServers) |
All online endpoints, dedupe by server id |
| Discovery (featured/trending) | All online endpoints + 404→public list fallback |
| Room CRUD/join | Authoritative room sourceUrl first; temporary fallback to other compatible endpoints on outage |
Only status === 'incompatible' stops fallback with an update-required message. Network errors and Cloudflare 521/522 must continue to the next endpoint.
Server-owned channel metadata
PUT /api/servers/:id persists the server's channels array (text + voice). The client round-trips channel create/rename/delete through this API — local-only channel state is not authoritative. Server-side normalisation deduplicates names within each channel type.
WebSocket complement
After REST join, the client sends join_server on the room's signaling URL. Presence (server_users, user_joined, user_left) is room-scoped on the WebSocket — see signaling.md.
Related
- server-discovery.md — featured/trending ranking and browse UI
- authentication.md — bearer tokens for mutations
- invites-join-requests.md — invite links and approval workflow
- signal-server-tag.md —
serverTagon health + profile cards - Product-client domain README:
toju-app/src/app/domains/server-directory/README.md
Changelog
| Date | Change |
|---|---|
| 2026-07-05 | Initial cross-context server-directory REST contract |