Skip to content

five-on-it / apps/api/src/app

apps/api/src/app ​

The platform API's routes (TECHNICAL_SPECS §9.6), built from its dependencies so the tests run it with fakes. Requests and answers are JSON; a signed-in caller sends Authorization: Bearer <session token>; a creation job's session (an OAuth grant scoped job:<id>, creations.ts) takes the few routes its job needs, on its own draft only, and is refused (403) on every other, before any route runs. Every answer may be read by a page of any origin (CORS: Access-Control-Allow-Origin: *, a preflight answered 204): the desktop app's pages come from file://, and the sessions are bearer tokens, never cookies, so no origin gains anything a script without a token would not have. A route asks a level of its caller (need: session, player, creator), whose meaning the platform's entitlement sets (entitlement.ts): with FOI_ENTITLEMENT=steam a player has a copy of the game on Steam and a creator one of their own.

RouteWhoWhat
GET /healthanyoneThe API's state.
GET /infoanyoneWhat a client checks before playing online: the platform's release, its protocol version, where the cities' rooms are joined (game, a WebSocket address), how one signs in (signIn: guest, email, steam), whether it is for the game's owners (entitlement), whether its game servers ask for a join token (join), and the game's store page (store).
POST /auth/guest, POST /auth/loginanyone (not with FOI_ENTITLEMENT=steam: 403)A guest (a device) or a creator (an e-mail) signs in.
POST /auth/steam, /auth/steam/openid/…, POST /auth/steam/exchange, POST /auth/steam/linkanyone; an e-mail accountSigning in through Steam: the desktop app's ticket, a browser's OpenID round trip and its one-time code, an e-mail account linking a Steam account (steam-routes.ts).
/.well-known/oauth-authorization-server, /oauth/…anyoneOAuth 2.1 for the MCP server: the metadata, client registration, the sign-in page, tokens, revocation (oauth.ts).
GET /mesigned inThe account, whether it is a moderator's and an admin's, its limits a day (an admin's override first, else the defaults), what it used of them today and what is left, its Steam account (steam: its copy as Steam last said) and what it may do (access: play, create); its creations left today and when they start again, and whether creation is open to it now (creation: off, the account, the budget and when it resumes; consistent with access.create).
GET /levels, GET /levels/:name, GET /levels/:name/gameanyoneThe bundled levels; one level's roads, spawns and its bundled game's places and zones; its bundled game whole, an example that passes every check.
GET /guides, GET /guides/:name?section=anyoneThe guides a game is written from (guides.ts: missions, tiles, the city spec, the tone) with their sections; one guide, or one of its ## sections.
GET /openapi.jsonanyoneThis API described in OpenAPI 3.1 (openapi.ts).
GET /schemas, GET /schemas?template=anyoneThe JSON Schemas of a game document, a mission and a level spec; or one level spec template's alone (grid-town, region, city).
GET /catalogue, GET /catalogue?q=words&limit=n, GET /catalogue/:idanyoneThe catalogue (@foi/catalogue): every entry, the entries words find (the first limit of them, and their total), one entry.
GET /catalogue/cities?query=&offset=&limit=, GET /catalogue/cities/:idanyoneThe curated cities a creation remixes (@foi/catalogue/cities): a page of those the words find (24 by default, 100 at most, with their total; each its id, title, blurb, level and preview picture beside the web client's page), and one city with its city spec.
POST /drafts, GET /drafts, GET /drafts/:idcreatorStart a game on a bundled level or a level spec; list one's drafts (each with its last build's state and its playtest rooms still open: Your games) and read one (with the last build's places). A new draft's spec is a city (400 "cities only" for a grid-town or a region, but for an admin or with FOI_DEBUG); a creation's city is large (its size raised to 1000).
PUT /drafts/:id/gamecreatorReplace a draft's game document (its id and level stay the draft's).
PUT /drafts/:id/missions/:missionId, DELETE /drafts/:id/missions/:missionIdcreatorAdd or replace one mission, the places and zones it needs merged into the game's (201 when added); remove one, its places and zones kept.
PUT /drafts/:id/speccreatorReplace a draft's level spec: its level is then generated, named after the draft; the answer says its template (kind), and a region or a city is solved at once: its map in text, a city's plan and the solver's warnings, or its issues; a spec that matches its schema is saved with its issues (a layer deleted on the way to another), built once none is left. A draft keeps its own template; one that has none takes a city (as POST /drafts).
POST /drafts/:id/build, GET /builds/:id?wait=creatorQueue a build (it outlives an API restart, queue.ts; refused, reason: spec-issues, while the level spec has issues): generate the level of a spec, check the draft and store its artifact; read how it went, its place in the queue (position, 1 next) while it waits, or with wait (seconds, 60 at most) once it has ended.

Every write on a draft (its game, a mission, its spec) takes ifRevision, the revision it is meant for (in the body; a DELETE's in the query): a draft at another revision refuses it (409, with the draft as it is), so the creator chat, the studio and Claude Code never lose each other's writes. The writes on one draft run one at a time.

RouteWhoWhat
POST /drafts/:id/playtestcreatorOpen a private room on the draft's last good build; with a mission, a playtest run of that mission alone (runs.ts: its minimum of players relaxed, counting for nothing).
POST /drafts/:id/publishcreatorPublish the last good build, by link or publicly (public games are moderated, and so is a game the platform's model wrote, by link too); a game its creator deleted is back with it.
DELETE /drafts/:idits owner, an adminDeletes a draft: the draft and its builds' records go (their artifacts stay, content-addressed), its creations under way are cancelled and its queued builds with them. A game published from it is left as it is (DELETE /games/:id takes that away); a mission of a published game goes by removing it from the draft (DELETE /drafts/:id/missions/:missionId) and publishing again.
/games…, /rooms/:id/join, /previews/:hash.pnganyone, signed inThe published games and the curated ones: search and sort them, a game's page, versions, preview and rooms, ratings, reports, remixes, a mission's run (games.ts).
GET /runs/:id, POST /runs/:id/rejoin, POST /runs/:id/resultits players; its game server with the run's tokenA run: its state and roster, a fresh join URL to one's seat, its result reported once (runs.ts); open runs no result reached are swept as lost.
/lobbies…, POST /lobbies/quickanyone, signed inLobbies: opened for a multiplayer mission, joined, ready, teams, the host's start and kick, the vote on the next mission after a run, invitations; Quick play by playlist, into a lobby or a seat of a run under way (lobby-routes.ts, lobbies.ts, matchmaking.ts).
GET /missions?mode=&players=&level=anyoneThe listed games' missions, with how they are played and their public lobbies (missions-index.ts).
GET /playlistsanyoneThe playlists (Co-op, Versus, Races, Any): each one's missions in its rotation across levels and its public lobbies (playlists.ts).
/me/standing…, /players/:id/standing, /leaderboard, /runs/:id/standing, /runs/:id/endorse, /runs/:id/ratinganyone, signed inRespect: a player's own (their conduct's band), another's, the season's leaderboard, what a run paid, endorsements, a mission's rating; the admins' and moderators' conduct, upheld reports (respect-routes.ts, respect.ts).
/moderation/…moderatorThe reports, takedowns, the featured flag, the audit log (takedowns.ts); a creation's transcript (creations.ts, admins too).
/admin/…adminThe accounts' daily limits: search the accounts, set or reset one's override, every override, the audit of their changes (admin.ts); the platform's creations and the model's budget (creations.ts).
POST /jobs, GET /jobs, GET /jobs/:id, POST /jobs/:id/cancelcreatorCreations: a brief the platform's own model makes a game from, queued and cancelled, its result (creations.ts; 503 with FOI_CREATOR=off).
/creator/…the creator runners' secret, directThe runners claim creations, renew their leases and end them (creations.ts).
/social/…, /players/:id/reports, POST /moderation/chatsigned in; the room secretFriends, presence, parties, messages, mutes, the feed, reports of players; a public room's chat checked (social-routes.ts).
GET /artifacts/:hashanyoneA built game (the game servers fetch it), immutable: cached for a year, its ETag the hash.
GET /play?level=<name>anyone; a player with FOI_ENTITLEMENT=steam or FOI_JOIN=tokenWhere a city that ships is played ({url}): the fullest of its rooms with a place left, else the game server with the most room; for a player (one signed in on an open platform too: an open server reads its debug alone), with a join token of the level's room.
GET /metricsthe private networkPrometheus's metrics: the requests, the fleet, the process (metrics.ts); never through the proxy.
/fleet…the fleet's secret, the private networkThe game servers that joined on their own, their heartbeats, Prometheus's targets (fleet-routes.ts).

Interfaces ​

Functions ​