# studio The RecFlare Studio host (`https://studio.`). 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//.assetbundle` as `filename` — the bytes sit at `room/` 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.