Files
recflare/apps/studio/README.md
T

7.2 KiB

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

pnpm dev

Run tests

pnpm test

Deploy

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.

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. Configure a private CLOUD_BUILD_KEY and run the outbound worker from recflare/cloud-building with the matching credential. Without a key, creation returns an explicit unavailable response. CLOUD_BUILD_TARGETS defaults to 0,2 (Windows and Android), and CLOUD_BUILD_TEMPLATE_VERSION defaults to 169. 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.