From 9a8fc1cab5abcdaf3c01af4ebb80d42ac0e454e9 Mon Sep 17 00:00:00 2001 From: Devin Zuczek Date: Tue, 8 Sep 2026 23:52:36 -0400 Subject: [PATCH] [rooms] add showcase stub --- apps/rooms/src/openapi.ts | 8 +++++++ apps/rooms/src/rooms.app.ts | 24 +++++++++++++++++++++ apps/rooms/src/test/integration/api.test.ts | 18 ++++++++++++++++ 3 files changed, 50 insertions(+) diff --git a/apps/rooms/src/openapi.ts b/apps/rooms/src/openapi.ts index 10a8487..9426ecb 100644 --- a/apps/rooms/src/openapi.ts +++ b/apps/rooms/src/openapi.ts @@ -874,6 +874,14 @@ export const RoomExperiencePlayer = z .array(z.unknown()) .describe('Always empty — no per-room experience is tracked') +/** + * `GET /showcase/{playerId}` — the rooms a player showcases on their profile. Stubbed + * empty; nothing stores a showcase, so the element shape is unknown until something does. + */ +export const ShowcasedRooms = z + .array(z.unknown()) + .describe('Always empty — no room showcase is stored') + /** * `GET /rooms/curated_playlists` — the curated room playlists the discovery pages' * playlist sections draw from. Nothing curates one on this server, so the list is always diff --git a/apps/rooms/src/rooms.app.ts b/apps/rooms/src/rooms.app.ts index 8922568..32c4a25 100644 --- a/apps/rooms/src/rooms.app.ts +++ b/apps/rooms/src/rooms.app.ts @@ -123,6 +123,7 @@ import { SaveSubRoomDataRequest, SearchSuggestions, ServiceStatus, + ShowcasedRooms, stringQuery, SubRoomAccessibilityRequest, SubRoomDataSaveResponseDto, @@ -1282,6 +1283,29 @@ const app = new Hono() c.json(await getPublicRoomsByCreator(c.env.DB, Number.parseInt(c.req.param('accountId'), 10))) ) + // A player's showcased rooms — the hand-picked rail the client draws on a profile, + // separate from `ownedby/{accountId}` (which is everything public they own). Stub → + // empty list: nothing stores a showcase yet, and an empty rail is what a player who + // has picked nothing looks like, where a 404 leaves the profile half-drawn. No auth, + // matching the profile list it sits beside — a showcase is public by definition. + .get( + '/showcase/:playerId{[0-9]+}', + describeRoute({ + tags: ['Rooms'], + summary: 'A player’s showcased rooms', + description: [ + 'The rooms a player has showcased on their profile, as a bare array. Nothing stores a', + 'showcase yet, so this is a stub serving an empty list — which the client reads as', + '“nothing showcased”, the same as a player who has picked none. Unlike', + '`ownedby/{accountId}`, which lists everything public the account owns, a showcase is', + 'a chosen subset. No auth: a profile is public.', + ].join(' '), + parameters: [playerIdParam], + responses: { 200: json(ShowcasedRooms, 'An empty list') }, + }), + (c) => c.json([]) + ) + // Rooms the caller has favorited (from the interaction table). Auth-gated. // Paginated via skip/take (take defaults to 100). Returns a bare array, like the // other room-source `*by/me` lists the client loads. diff --git a/apps/rooms/src/test/integration/api.test.ts b/apps/rooms/src/test/integration/api.test.ts index bea98a4..aeaaa32 100644 --- a/apps/rooms/src/test/integration/api.test.ts +++ b/apps/rooms/src/test/integration/api.test.ts @@ -195,6 +195,23 @@ describe('rooms endpoints', () => { expect(await res.json()).toEqual([]) }) + // Stub, same reasoning: the profile asks for a showcase for any player, and an + // unregistered path leaves the profile half-drawn. No auth, and no such player is + // still [] rather than a 404. + it('GET /showcase/:playerId returns [] for any player', async () => { + const res = await SELF.fetch(`${ORIGIN}/showcase/205`) + expect(res.status).toBe(200) + expect(await res.json()).toEqual([]) + + const unknown = await SELF.fetch(`${ORIGIN}/showcase/99999`) + expect(unknown.status).toBe(200) + expect(await unknown.json()).toEqual([]) + }) + + it('GET /showcase/:playerId 404s on a non-numeric id', async () => { + expect((await SELF.fetch(`${ORIGIN}/showcase/abc`)).status).toBe(404) + }) + it('GET /rooms/:id 404s for a room not in D1', async () => { const res = await SELF.fetch(`${ORIGIN}/rooms/99999`) expect(res.status).toBe(404) @@ -4088,6 +4105,7 @@ describe('rooms endpoints', () => { 'GET /rooms/{roomId}/subrooms/{subRoomId}/saves/no_unity_assets', 'GET /rooms/{roomId}/subrooms/{subRoomId}/saves/{saveId}', 'GET /roomserver/rooms/createdby/me', + 'GET /showcase/{playerId}', 'POST /rooms/bulk', 'POST /rooms/{roomId}/bans', 'POST /rooms/{roomId}/clone',