7.6 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. 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.