more stubs

This commit is contained in:
Devin Zuczek
2026-08-14 01:01:19 -04:00
committed by devin
parent dda18b0d2c
commit 8ea0caa1e5
3 changed files with 74 additions and 0 deletions
+21
View File
@@ -683,3 +683,24 @@ export const PlayerDataDto = z.object({
export const RoomExperiencePlayer = z
.array(z.unknown())
.describe('Always empty — no per-room experience is tracked')
/**
* `GET /publishState/configs` — the limits the client enforces on republishing a room:
* how many updates are allowed in the rolling window, and the cooldown/expiry around
* them. Served as fixed values from the reference server.
*
* The envelope is NOT the `{ success, error, value }` one the room mutations use: `error`
* is null rather than `""`, and there's an extra `error_id`. Kept as-is — the client
* reads both keys.
*/
export const PublishStateConfigsEnvelope = z.object({
value: z.object({
UpdateMaxCount: z.int().describe('Updates allowed per rolling window'),
UpdateRollingWindowInDays: z.int().describe('Length of that window, in days'),
UpdateExpirationInDays: z.int().describe('Days before an update expires'),
UpdateCooldownInDays: z.int().describe('Days between updates'),
}),
success: z.literal(true),
error_id: z.null(),
error: z.null(),
})
+33
View File
@@ -91,6 +91,7 @@ import {
PlayerDataDto,
playerIdParam,
PublishSaveRequest,
PublishStateConfigsEnvelope,
RestrictionsRequest,
RoleRequest,
RoomBanEntryDto,
@@ -2682,6 +2683,38 @@ const app = new Hono<App>()
}
)
// The republish limits, verbatim from the reference server. Fixed values, no auth:
// the client reads them to render its publish UI, before any room is in play.
.get(
'/publishState/configs',
describeRoute({
tags: ['Rooms'],
summary: 'Room republish limits',
description: [
'The limits the client enforces around republishing a room — how many updates are',
'allowed per rolling window, and the cooldown and expiry around them. Fixed values',
'from the reference server; nothing here enforces them server-side yet, so this is',
'what the client shows and gates its own UI on.',
'',
'Note the envelope differs from the room mutations: `error` is null (not `""`) and',
'there is an extra `error_id`.',
].join(' '),
responses: { 200: json(PublishStateConfigsEnvelope, 'The republish limits') },
}),
(c) =>
c.json({
value: {
UpdateMaxCount: 3,
UpdateRollingWindowInDays: 365,
UpdateExpirationInDays: 30,
UpdateCooldownInDays: 45,
},
success: true,
error_id: null,
error: null,
})
)
// Photon access token + room permissions the client needs to spawn into a room.
.get(
'/photon_access_token',
@@ -141,6 +141,25 @@ describe('rooms endpoints', () => {
expect(body.SubRooms[0].UnitySceneId).toBe('76d98498-60a1-430c-ab76-b54a29b7a163')
})
// Pinned whole: these are the numbers the client's publish UI counts against, and
// `error: null` / `error_id` is a different envelope from the room mutations' — a
// "cleanup" that unified the two would break the client silently.
it('GET /publishState/configs returns the republish limits', async () => {
const res = await SELF.fetch(`${ORIGIN}/publishState/configs`)
expect(res.status).toBe(200)
expect(await res.json()).toEqual({
value: {
UpdateMaxCount: 3,
UpdateRollingWindowInDays: 365,
UpdateExpirationInDays: 30,
UpdateCooldownInDays: 45,
},
success: true,
error_id: null,
error: null,
})
})
// Stub. Registered (not 404) matters more than the body: the client asks for this on
// room entry, and an unregistered path stalls the load rather than erroring visibly.
it('GET /rooms/:id/experience/player returns [] for any room', async () => {
@@ -2966,6 +2985,7 @@ describe('rooms endpoints', () => {
'GET /XXXfeaturedrooms/current',
'GET /dormroom/me',
'GET /photon_access_token',
'GET /publishState/configs',
'GET /rooms',
'GET /rooms/base',
'GET /rooms/bulk',