Edge runtime
Olympia has no origin servers. Two Workers carry the whole platform: olympia-api-hono (Hono, game APIs, WebSockets) and olympia-ui-nuxt (Nuxt 4 SSR + static assets). Everything below them is a Cloudflare primitive.
The API worker
| Binding | Type | Purpose |
|---|---|---|
DB | D1 | Rooms, guest sessions, replay index, banned IP hashes |
RATE_LIMIT | KV | Per-IP / per-session rate limiting |
REPLAYS | R2 | Recorded game replay binaries (30-day TTL) |
ANALYTICS | Analytics Engine | Request + game-event telemetry |
MATCHMAKING_DO | Durable Object | Quickmatch queue + lobby coordination |
CHESS_GAME_DO / POOL_GAME_DO / POKER_GAME_DO / SNAKE_ARENA_DO | Durable Objects | One instance per active room — authoritative game state |
Smart placement is enabled, so the Worker migrates toward its D1 database rather than pinning to the visitor's colo — reads stay fast without manual region pinning.
Why Durable Objects
A multiplayer game room is a tiny stateful server: it owns the canonical game state, orders incoming moves, and broadcasts to every connected socket. That is exactly the DO contract. Each room code maps to one DO instance (idFromName(roomCode)), so two players joining AB12CD always land on the same object, anywhere in the world. WebSocket upgrades terminate directly on the DO — no fan-out layer, no pub/sub.
The snake arena DO additionally runs an authoritative tick loop, which is why snake multiplayer feels server-driven rather than peer-trusted.
Scheduled work
Two crons keep the platform tidy without any job queue:
*/5 * * * *— sweep: marks expired rooms, deletes stale guest sessions, purges expired replay rows and their R2 objects in FK-safe order.0 * * * *— hourly analytics rollup into Analytics Engine.
The UI worker
Nuxt 4 on the cloudflare_module Nitro preset. Static assets (including the vendored matter.js physics bundle) are served by the Workers assets layer with immutable caching; SSR HTML is rendered at the edge with cache-control: no-cache so deploys are visible immediately. These docs are themselves served from a dedicated D1 database (olympia-docs) — Nuxt Content v3 queries run against D1 at the edge.
Operational surface
GET /health— process liveness, no I/O.GET /ready— proves a live D1 round-trip.- Secrets (
JWT_SECRET,IP_HASH_KEY) are validated at startup; the API refuses to boot with placeholder values.
Cold starts are single-digit milliseconds (the API worker reports ~12 ms startup), so there is no warm-pool to manage — the platform scales to zero between games and back up on the next visitor.