Files
2026-10-24 01:16:49 -04:00

120 lines
7.6 KiB
Markdown

# studio
The RecFlare Studio host (`https://studio.<domain>`).
Device login stays on Auth, `GET /account/me` stays on Accounts, and the approval
page is WWW `/device`. This worker queues cloud builds, accepts completed bundles,
and serves build status and co-owner presence. Rooms exposes playable bundles in
`CurrentSave.UnitySubAssets`; their bytes are served by the CDN at `/room/{filename}`.
The Rooms `GET /rooms/{roomId}/subrooms/{subRoomId}/unityasset` route separately
returns the editable source manifest and available build metadata.
| Method | Path | Purpose |
| ------ | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `GET` | `/cloud-builds/for-room` | Cloud builds for that room and subroom, newest first (`results`, `totalResults`). Query: `roomId`, `subRoomId`, `skip`, `take`. A bad query is an empty page. |
| `GET` | `/cloud-builds/get-build-count-for-user` | Authenticated user's Studio build totals for the current UTC-hour rate-limit window. |
| `POST` | `/cloud-builds/from-editor` | Multipart Windows bundle (`windows`) and Android bundle (`android`), optional `windowsStripped` and `androidStripped`. Stores a finished build on the subroom's current published save and sets `BecameRRStudioRoomAt` the first time. Bearer required, and the token must include `betastudio`. Caller must be the creator or a co-owner. |
| `GET` | `/collaboration/owners-in-room` | Account ids of the room's co-owners (creator, or a Creator/CoOwner role) whose live presence is in that `roomId` and `subRoomId`. Body: `{ success: true, error: null, value: number[] }`. Bearer required. |
## Development
### Run in dev mode
```sh
pnpm dev
```
### Run tests
```sh
pnpm test
```
### Deploy
```sh
pnpm turbo deploy
```
### Migrate
This worker owns `studio_cloud_build` on the shared `recflare` database (`migrations/`,
tracked in its own `d1_migrations_studio` table). The bundles themselves are rows of the
rooms worker's `unity_asset` (one per platform and kind: target 0 Windows / 2 Android,
`studio/<roomId>/<name>.assetbundle` as `filename` — the bytes sit at `room/<filename>` in
the bucket, the prefix the client adds — base64 SHA-256 as `hash`), so a stored build needs
the rooms migrations too. Deploying does not apply either.
```sh
just migrate -F studio # remote
just migrate -F studio -- --local # dev db
```
## Launcher template distribution
Set `STUDIO_DISTRIBUTION_MANIFEST` to an R2 catalog key to enable the optional
PatchKit-compatible `/1/apps/:secret/*` routes. The catalog and ZIP parts are
generated by `studio-patch-2026/build_distribution.py`; upload all parts through
the existing CDN before publishing the catalog. No template bytes or operator
configuration belong in this repository.
The catalog names the template application's SHA-256 identifier, latest release,
HTTPS multipart content URL, file hashes, and download-chunk hashes. Optional
legacy summaries supply comparison hashes without making old templates
downloadable. The application identifier scopes requests; it is not an access
credential. Missing or disabled catalogs return 404. Invalid catalogs or catalogs
larger than 8 MiB return 503; responses use `Cache-Control: no-store` so a corrected
publication can be retried immediately.
## Editor build limits
`GET /cloud-builds/get-rate-limit-config` returns the editor's
`CloudBuildRateLimitConfigDTO` directly: `buildThrottleIntervalHours` (1),
`warnAfterBuildsPerInterval` (90), and `maxBuildsPerInterval` (100). These names
matter: unknown keys leave the DTO's maximum at zero and block even a first build.
The authenticated `get-build-count-for-user` route provides the user's counts.
## Queued Studio builds
`POST /cloud-builds/create` accepts the SDK's room, subroom, save, auto-publish,
and optional target fields. It requires Studio authorization and room management
rights, validates the uploaded source manifest, and returns a numeric string
build ID with a null completion time. Repeated requests for an in-progress save
reuse its job. `GET /cloud-builds?cloudBuildId=...` reads the status;
`PUT /cloud-builds/cancel` cancels a queued or running job.
Apply migration `0003_studio_cloud_build_job.sql`. Create the private
`CLOUD_BUILD_KEY` in the shared Secrets Store (the one `JWT_SECRET` lives in — see
`.env.example`) and run the outbound worker from `recflare/cloud-building` with the
same value as its `STUDIO_WORKER_KEY`. The binding must exist for the worker to
deploy; a value of `off` disables cloud building, and creation then returns an
explicit unavailable response. `CLOUD_BUILD_TARGETS` defaults to `0,2` (Windows and
Android), and `CLOUD_BUILD_TEMPLATE_VERSION` defaults to 169 — the cloud-building
worker claims only jobs for its own configured template version (171 by default),
so set this to match or jobs queue and are never claimed. Match installed editor
modules to the enabled targets.
The private `/internal/cloud-builds/claim`, `/:id/heartbeat`, and `/:id/finish`
routes lease jobs to that worker. Only validated UnityFS artifacts for the
allocated asset IDs and requested platforms are accepted. SDK bundle version 5
is retained. Completion links the submitted save; auto-publish does not replace
a newer draft. Failed, cancelled, or expired jobs never become successful builds.
Claims include a signed, short-lived SDK validation token with no account subject
or roles. Bulk component-text validation and job-scoped grant reads accept this
credential. It cannot authenticate as an account or publish a room.
## Avatar Studio and consumable validation
Avatar authoring uses per-account Studio grants, source revisions, and the managed
cloud queue. Apply `migrations/0004_avatar_studio.sql` to the shared database before
enabling these routes. The API owns creator saves and explicit publication; the
Studio service queues prefab builds and returns per-platform main/stripped bundles
at version 5 and material bundles at version 6. Image badges publish directly.
Changed body/configuration inputs receive distinct output IDs, and automatic
publication cannot replace a newer revision. Deploy the paired cloud-building
worker for prefab support; restricted validation credentials grant no account role.
The SDK's access override reads the target account's entitlement. Build-validation
credentials can inspect only the current owners of their active job's room; peers
can inspect grants only while they currently manage the same room.