[rooms] fix cloud variables

This commit is contained in:
Devin Zuczek
2026-10-03 21:53:23 -04:00
parent ec423b2eb9
commit f7167358d8
6 changed files with 74 additions and 21 deletions
+13 -3
View File
@@ -255,7 +255,10 @@ export const SubRoomDto = z.object({
'The latest room save — where the client finds the scene blob. Null until first save'
),
DataBlob: z.string().optional().describe('Legacy flat key; the client reads `CurrentSave`'),
RoomDataBlob: z.string().optional().describe('Uploaded room-data key; absent until first save'),
RoomDataBlob: z
.string()
.optional()
.describe('Legacy; the room-level blob is the ROOM’s `DataBlob`. Not a key the client knows'),
DataSavedAt: z.string().optional().describe('ISO timestamp of the last save'),
PersistenceVersion: z.int().optional(),
InventionUsage: z.string().optional().describe('Recorded by a room save; absent until then'),
@@ -304,6 +307,11 @@ export const RoomDto = z.object({
PublishedAt: z.string(),
BecameRRStudioRoomAt: z.string().nullable(),
Stats: RoomStatsDto,
DataBlob: z
.string()
.optional()
.describe('The room-level metadata blob a room save uploads as `RoomData`; absent until one'),
DataBlobHash: z.string().nullable().optional().describe('`RoomData.Hash` from that save'),
BoostCount: z
.int()
.describe('Boosts on the room. Nothing grants boosts here, so always 0 — but present'),
@@ -877,9 +885,11 @@ export const SaveSubRoomDataRequest = z.object({
.optional()
.describe('The uploaded scene-data blob — becomes the subroom’s `CurrentSave.DataBlob`'),
RoomData: z
.object({ Filename: z.string() })
.object({ Filename: z.string(), Hash: z.string().nullable().optional() })
.optional()
.describe('The uploaded room-level data blob — becomes `RoomDataBlob`'),
.describe(
'The uploaded room-level metadata blob — becomes the ROOM’s `DataBlob`/`DataBlobHash`'
),
Description: z
.string()
.optional()
+5 -3
View File
@@ -3606,10 +3606,11 @@ const app = new Hono<App>()
if (!canManageRoom(room, accountId)) return c.body(null, 403)
// The client uploads BOTH blobs to `storage` first and sends their keys here:
// `SubRoomData` is the scene blob (what the loader downloads), `RoomData` the
// metadata blob. `OwnershipProof` is accepted and ignored.
// `SubRoomData` is the scene blob (what the loader downloads, onto the subroom's
// save), `RoomData` the room-level metadata blob (onto the ROOM, as `DataBlob`).
// `OwnershipProof` is accepted and ignored.
const body = (await c.req.json().catch(() => ({}))) as {
RoomData?: { Filename?: string }
RoomData?: { Filename?: string; Hash?: string | null }
SubRoomData?: { Filename?: string; Hash?: string | null }
UnityAssetId?: string | null
Description?: string
@@ -3623,6 +3624,7 @@ const app = new Hono<App>()
subRoomDataHash:
typeof body.SubRoomData?.Hash === 'string' ? body.SubRoomData.Hash : undefined,
roomDataFilename: body.RoomData?.Filename,
roomDataHash: typeof body.RoomData?.Hash === 'string' ? body.RoomData.Hash : undefined,
unityAssetId: typeof body.UnityAssetId === 'string' ? body.UnityAssetId : undefined,
autoPublish: body.AutoPublish === true,
description: typeof body.Description === 'string' ? body.Description : undefined,
+11 -1
View File
@@ -3552,10 +3552,20 @@ describe('rooms endpoints', () => {
(s) => s.SubRoomId === 2
)!
expect(savedSub).toMatchObject({
RoomDataBlob: '5c618c920f6247efb8327e327d0b4417',
CreatorAccountId: 1,
PersistenceVersion: 41,
})
// `RoomData` is the ROOM-level metadata blob: it lands on the room as `DataBlob`, which
// is where the client reads it — not on the subroom, which has no field for it.
expect(savedSub).not.toHaveProperty('RoomDataBlob')
expect(saved.value.room).toMatchObject({
DataBlob: '5c618c920f6247efb8327e327d0b4417',
DataBlobHash: null,
})
expect(await (await SELF.fetch(`${ORIGIN}/rooms/2`)).json()).toMatchObject({
DataBlob: '5c618c920f6247efb8327e327d0b4417',
DataBlobHash: null,
})
expect(savedSub.CurrentSave).toMatchObject({
DataBlob: 'a84167b16796452ab70ee8a6a5b1dc5f',
})