at least we are in the dorm now

This commit is contained in:
Devin Zuczek
2026-06-14 21:32:37 -04:00
parent 768ca2a0a3
commit 2f70eab186
14 changed files with 310 additions and 28 deletions
+12 -1
View File
@@ -3,6 +3,7 @@ import { useWorkersLogger } from 'workers-tagged-logger'
import { withNotFound, withOnError } from '@repo/hono-helpers'
import defaultAvatar from '../static/default-avatar.json'
import defaultAvatarItems from '../static/default-avatar-items.json'
import myProgress from '../static/my-progress.json'
import storefrontGiftDrop3 from '../static/storefronts-v3-giftdropstore-3.json'
@@ -87,7 +88,17 @@ const app = new Hono<App>()
const id = await authedId(c)
if (id === null) return unauthorized(c)
// TODO: load/create the PlayerAvatar for `id` once a DB binding exists.
return c.json({ OutfitSelections: '', FaceFeatures: '{}', SkinColor: '', HairColor: '' })
// Must return a populated outfit — the client's parser NREs on an empty
// OutfitSelections (real RecNet never returns one), so serve a valid default.
return c.json(defaultAvatar)
})
// NUX checklist — the client fetches this on the econ host during load. []
// with no DB. A 404 here can abort the load orchestration before matchmake.
.get('/api/checklist/v1/current', async (c) => {
const id = await authedId(c)
if (id === null) return unauthorized(c)
return c.json([])
})
// The player's saved outfits. [Authorize]; empty without a DB binding.
+16 -7
View File
@@ -72,15 +72,14 @@ describe('econ endpoints', () => {
expect(res.status).toBe(401)
})
test('GET /api/avatar/v2 returns the default avatar with a valid token', async () => {
test('GET /api/avatar/v2 returns a populated default avatar with a valid token', async () => {
const res = await exports.default.fetch(`${ORIGIN}/api/avatar/v2`, { headers: await bearer() })
expect(res.status).toBe(200)
expect(await res.json()).toEqual({
OutfitSelections: '',
FaceFeatures: '{}',
SkinColor: '',
HairColor: '',
})
const body = (await res.json()) as { OutfitSelections: string; FaceFeatures: string }
// Must be non-empty — the client's outfit parser NREs on an empty string.
expect(body.OutfitSelections.length).toBeGreaterThan(0)
expect(body.OutfitSelections).toContain(';')
expect(body.FaceFeatures).toContain('eyeId')
})
test('GET /econ/customAvatarItems/v1/owned returns { items: [] } (no auth)', async () => {
@@ -97,6 +96,16 @@ describe('econ endpoints', () => {
expect(Array.isArray(body.ObjectiveGroups)).toBe(true)
})
test('GET /api/checklist/v1/current 401s without a token, returns [] with one', async () => {
const anon = await exports.default.fetch(`${ORIGIN}/api/checklist/v1/current`)
expect(anon.status).toBe(401)
const res = await exports.default.fetch(`${ORIGIN}/api/checklist/v1/current`, {
headers: await bearer(),
})
expect(res.status).toBe(200)
expect(await res.json()).toEqual([])
})
test('GET /api/avatar/v3/saved 401s without a token, returns [] with one', async () => {
const anon = await exports.default.fetch(`${ORIGIN}/api/avatar/v3/saved`)
expect(anon.status).toBe(401)