CI / test (push) Successful in 6m38s
The realtime connection now carries the IMVU chats a client is in: the hub tells each proxy in a chat which other T5DE users are there and what community products they wear (adult products only to adult accounts), on joining and on every change. Rooms T5DE users enter are looked up on IMVU; those that are public, listed and whose owner turned on "List my public rooms" appear on the new Rooms page, with the T5DE users in them who show they're online. AP rooms are shown to adults only. Co-Authored-By: Claude Opus 5.5 <[email protected]>
75 lines
4.3 KiB
Markdown
75 lines
4.3 KiB
Markdown
# The hub's API
|
|
|
|
`apps/api` (Elysia on Bun). The route definitions in `apps/api/src/app.ts` are the reference: their schemas validate
|
|
requests and type the website's client (Eden). This is the overview.
|
|
|
|
- `/api/auth/*`: Better Auth (accounts, sessions, device sign-in, JWT keys).
|
|
- `/api/v1/*`: the hub's own routes.
|
|
|
|
The website reaches the API through its own origin (Next.js rewrites `/api` to it), so sessions are first-party
|
|
cookies. T5DE's proxy calls it directly with `Authorization: Bearer <session token>`.
|
|
|
|
Errors are `{"error": "<code>", "message": "<text for people>"}` with a 4xx/5xx status; `message` can be shown as
|
|
is. Codes: `invalid`, `signed_out`, `forbidden`, `not_found`, `no_such_imvu_account`, `already_linked`,
|
|
`code_missing`, `expired`, `link_cap`, `rate_limited`, `imvu_unavailable`.
|
|
|
|
## Accounts (Better Auth)
|
|
|
|
| | |
|
|
| --- | --- |
|
|
| `POST /api/auth/sign-up/email` | `{email, password, name, username}`. Usernames 3-32 of `A-Za-z0-9_`; passwords 10-256 characters. The first account is an admin. |
|
|
| `POST /api/auth/sign-in/username` | `{username, password}` |
|
|
| `POST /api/auth/sign-out` | |
|
|
| `GET /api/v1/me` | `{person}` |
|
|
|
|
## Proxies
|
|
|
|
| | |
|
|
| --- | --- |
|
|
| `POST /api/auth/device/code` | `{client_id: "t5de-proxy"}` → `{device_code, user_code, verification_uri, verification_uri_complete, interval, expires_in}` (RFC 8628). `verification_uri` is the website's `/device`. |
|
|
| `POST /api/auth/device/token` | `{grant_type: "urn:ietf:params:oauth:grant-type:device_code", device_code, client_id}` → `{access_token}` (a session token, used as a bearer token) or `{error: authorization_pending \| slow_down \| expired_token \| access_denied}` |
|
|
| `POST /api/v1/device/approve` | (website, signed in) `{code}`: signs the waiting proxy in as this person |
|
|
| `GET /api/v1/realtime` | WebSocket, bearer token: presence, outfits, and the room channel. Protocol in `apps/api/src/realtime.ts`. |
|
|
| `GET /.well-known/jwks.json` | the Ed25519 keys JWTs are signed with |
|
|
|
|
## Website routes (signed in unless noted)
|
|
|
|
| | |
|
|
| --- | --- |
|
|
| `GET /api/v1/home` | (anyone) `{onlineCount, links?}` |
|
|
| `GET /api/v1/online` | (anyone) `{online}`: accounts showing they're online (moderators see all, with `hidden`) |
|
|
| `GET /api/v1/online/events` | (anyone) server-sent events: `online` with `{online}` now and on each change |
|
|
| `GET /api/v1/rooms` | (anyone) `{rooms}`: listed IMVU rooms of T5DE users, with the T5DE users in each now (AP rooms for adults only) |
|
|
| `GET /api/v1/account` | `{person, links, challenges, computers, canLink}` |
|
|
| `POST /api/v1/account/links` | `{username}` → 201 `{challenge}` (the tagline code) |
|
|
| `POST /api/v1/account/links/:imvu/check` | `{link, moved}` |
|
|
| `DELETE /api/v1/account/challenges/:imvu` | cancel linking |
|
|
| `PATCH /api/v1/account/links/:imvu` | `{showBadge?, showPresence?, listRooms?}` → `{link}` |
|
|
| `POST /api/v1/account/links/:imvu/recheck` | `{link}` (age checked with IMVU again) |
|
|
| `DELETE /api/v1/account/links/:imvu` | unlink |
|
|
| `POST /api/v1/account/signout-computers` | signs T5DE out on all their computers |
|
|
|
|
## Age verification
|
|
|
|
Vendor-neutral (docs/design.md, "Age"): IMVU's answer is recorded when an account is linked or checked again;
|
|
person-level providers (phone wallets, document checks) are started here.
|
|
|
|
| | |
|
|
| --- | --- |
|
|
| `GET /api/v1/age` | `{providers: [{id, label, scope}], checks}`: the providers in use and the person's own checks |
|
|
| `POST /api/v1/age/:provider/start` | `{returnURL}` → `{kind: "done"}`, `{kind: "redirect", url, ref}` (send the person there) or `{kind: "browser", request, ref}` (hand `request` to the browser's Digital Credentials API) |
|
|
| `POST /api/v1/age/:provider/complete` | `{ref, response}`: the browser's answer, for wallet providers |
|
|
| `POST /api/v1/age/webhook/:provider` | the provider's webhook; the provider checks its signature |
|
|
|
|
## Console (moderators; roles: admins)
|
|
|
|
| | |
|
|
| --- | --- |
|
|
| `GET /api/v1/console` | `{counts, connections, online, audit}` |
|
|
| `GET /api/v1/console/people?q=` | `{people}` |
|
|
| `GET /api/v1/console/people/:id` | `{person, links, computers}` |
|
|
| `POST /api/v1/console/people/:id/link-cap` | `{linkCap}` (0-1000) |
|
|
| `POST /api/v1/console/people/:id/ban` | `{reason}`; only admins ban moderators |
|
|
| `POST /api/v1/console/people/:id/unban` | |
|
|
| `POST /api/v1/console/people/:id/role` | (admins) `{role}` |
|