Files
devin 178d3b5b0e support for 202507 endpoints (#37)
* [auth][api] accept the 20250424.01 client

* [2025] unstable

* 20250718.0

* correct one this time

* stubs

* more stubs

* more stubs

* [lists] add worker

* [ai] route stubs

* [api] player photo setting

* [econ] add roomEconConfig route

* [infra] update worker generators

* [worker] add cards/moderation/platformnotification workers

* [lists] updates to some endpoints

* [clubs] stub out announcement endpoint, for now

* [econ] stub out season endpoints for now

* [chat] apps/chat stub out party endpoint not sure the shape yet

* [api] stub out statsig and lockeditems

* [doc] new services

* [lists] stub the bulk endpoint

* [datacollection] add placeholder service until we can kill it

* [api] set gifting to lvl5

* update lock

* [cdn] enable cache

* [match] matchmake v2

* [lists] stub some lists

* [ai] stubs

* [rooms] new subroom save endpoint

* [econ] add bulk purchase endpoint

* [discovery] update featured creator to 1 for fun

* [api] add photo settings flag

* [chat] fixup chat permissions (sorta)

* [auth] restrictions endpoint

* [rooms] contributed endpoint

* [api] fix outfit endpoint

* [discovery] attempt to fix store

* [chat] privacy endpoints

* [api] cheered images

* [rooms] add xp endpoint (disbaled)

* [rooms] add xp endpoint (disabled)

* update images-db for cheers

* [rooms] add autocomplete endpoint

* [cdn/img] increase cache ttl for statics

* [api] bulk route for images

* [accounts] add banner image

* [api] add misc missing endpoints

* [discovery] remove AI tab

* [platformnotifications] stub some endpoints

* [lists] add some more lists

* [rooms] additional endpoints

* [chat] stub a few privacy endpoints

* [econ] stub some endpoints

* misc db fixes

* [api] tweak shape for images v6

* [rooms] dont show trending RROs
2026-08-21 15:15:55 -04:00
..
2026-08-21 15:15:55 -04:00
2026-06-09 00:49:11 -04:00
2026-07-20 16:20:54 -04:00
2026-07-20 16:20:54 -04:00
2026-06-09 00:49:11 -04:00
2026-06-30 23:57:29 -04:00
2026-07-13 18:24:00 -04:00

accounts

Accounts Worker served on the accounts subdomain (accounts.recflare.net) — a Hono app for account reads, profile mutations and lookups. Accounts live in the shared recflare D1 database, whose account schema and migrations are owned by the auth worker; this worker binds it read/write.

Routes

Method Path Auth Description
GET / Health check
GET /account/me The caller's own account (private self DTO)
GET /account/search?name= Prefix-search accounts by username
GET /account/bulk?id=1&id=2,3 Look up many accounts by id
GET /account/:id A single public account
GET /account/:id/bio A player's bio
POST /account/create Create an account → { success, value }
GET /parentalcontrol/me The caller's parental-control flags
GET /accountprivacysettings/:id An account's privacy settings
PUT /account/me/displayname Set display name
PUT /account/me/username Change username (unique + change remaining)
POST /account/me/email Set email
POST /account/me/phone Set phone number
PUT /account/me/identityflags Set identity flags bitmask
PUT /account/me/personalpronouns Set personal pronouns (posted as pronounFlags)
PUT /account/me/bio Set bio
PUT /account/me/profileimage Set avatar object key
GET /openapi.json Generated OpenAPI 3.1 spec (see below)

Auth-gated routes validate the Bearer JWT issued by the auth worker and return an empty-body 401 when it's missing or invalid.

API documentation

GET /openapi.json serves a spec generated from describeRoute blocks that sit alongside each handler, with the schemas in src/openapi.ts.

The spec is descriptive, not enforced. Nothing validates requests against it — same rationale as the auth worker: this serves a protocol reverse-engineered from the Rec Room client, the handlers are lenient (form fields are read as typeof value === 'string' ? value : ''), and reads fall back to a synthesized default account rather than 404. Read a "required" field as the client always sends it, not the server rejects it if absent.

A test asserts that every route the worker serves appears in the spec, so adding a route without documenting it fails rather than silently shipping an incomplete spec.

Account shapes

Two DTOs, both camelCase:

  • Public (toAccountDto) — returned for any account. Excludes private fields.
  • Self (toSelfAccountDto, the /account/me shape) — the public DTO plus owner-only email, birthday and availableUsernameChanges.

Two client-deserializer quirks are load-bearing and deliberate:

  • juniorState / parentAccountId are omitted entirely when unset — emitting null makes the client's enum parser throw. email / birthday aren't enums, so they're kept as null.
  • GET /accountprivacysettings/:id never returns a bare {} — that fails the client's deserializer ("Deserialization returned null"), so the id is echoed back with recent history reported visible. Nothing stores per-player privacy yet.

Missing rows fall back to defaults

Account reads (/account/me, /account/:id, /account/bulk) never 404 on an unknown id — they synthesize a default account (defaultAccount) so every requested id is present in the response. bulk in particular guarantees one entry per requested id.

Notifications

Profile mutations persist to the account row and then push through the shared notifications hub (a single global Durable Object owned by the notify worker): the owner receives SelfAccountUpdate + AccountUpdate, and every connected client receives an AccountUpdate broadcast. Hub failures are logged and swallowed — the write has already committed, so a hub hiccup must not fail the request.

This matters most for the mutations whose HTTP response carries no account body (personalpronouns, identityflags): the client only learns the new value from the pushed update, and since those fields are in the public DTO, every other client needs the broadcast too. email and phone are private, so they persist without a push.

Bindings

Binding Type Notes
DB D1 Shared recflare database; account schema owned by auth
JWT_SECRET Secrets Store Shared HS256 signing key (see the auth README)
RECFLARE_NOTIFICATIONS_HUB Durable Object Cross-worker RPC to the notify worker's hub

This worker has no migrations of its own — the account table is created and migrated by auth (apps/auth/migrations/).

Known gaps

  • POST /account/create parses platformId but doesn't yet persist it, and doesn't create the dorm Room/SubRoom a new account should get.