[api] add xp boost stub endpoint

This commit is contained in:
Devin Zuczek
2026-10-15 15:01:21 -04:00
parent e225a8a2f1
commit 972432d4d3
3 changed files with 50 additions and 0 deletions
+18
View File
@@ -326,6 +326,24 @@ export const ProgressionEventRecordDto = z.object({
LimitedRewardCollectionState: z.int(), LimitedRewardCollectionState: z.int(),
}) })
/**
* One XP boost a player bought and has running, as `GET /api/purchasableXpBoosts/activations`
* lists it. Documented from the reference shape; nothing here sells or stores boosts yet.
*/
export const XpBoostActivationDto = z.object({
PurchasableXpBoostLedgerEntryId: z.int().describe('The purchase this activation came from'),
PurchasableXpBoostId: z.string().describe('GUID of the boost product bought'),
XpMultiplier: z.number().describe('XP is multiplied by this while the boost runs, e.g. 2.0'),
StartTime: z.string().describe('ISO-8601 UTC'),
EndTime: z.string().describe('ISO-8601 UTC'),
})
/** `GET /api/purchasableXpBoosts/activations` — a paged list of the caller's active boosts. */
export const XpBoostActivationsResponse = z.object({
Results: XpBoostActivationDto.array(),
TotalResults: z.int().describe('The number of entries in `Results`'),
})
/** /**
* The form body of `POST /api/PlayerCheer/v1/create`. Nothing here is stored beyond the * The form body of `POST /api/PlayerCheer/v1/create`. Nothing here is stored beyond the
* counter the cheer increments: `Anonymous` is spent on the notification it triggers and * counter the cheer increments: `Anonymous` is spent on the notification it triggers and
+25
View File
@@ -45,6 +45,7 @@ import {
ReputationDto, ReputationDto,
SetSelectedCheerRequest, SetSelectedCheerRequest,
UNAUTHORIZED_RESPONSE, UNAUTHORIZED_RESPONSE,
XpBoostActivationsResponse,
} from '../openapi' } from '../openapi'
import { import {
addCheer, addCheer,
@@ -672,3 +673,27 @@ export const progressionRoutes = new Hono<App>({ strict: false })
}) })
} }
) )
// The XP boosts the caller has bought and has running — the client multiplies the XP it
// shows by them and draws a timer for each.
//
// STUB: always the empty page. Nothing sells boosts yet, so nobody has one running. No
// auth while the answer is the same for everybody, like `xpEarnedToday` above; it will
// need the caller once it is real, since the path names no player.
.get(
'/api/purchasableXpBoosts/activations',
describeRoute({
tags: ['Progression'],
summary: 'The caller’s active XP boosts (stub)',
description:
'The XP boosts the caller has running, as `{ Results, TotalResults }`. Always the ' +
'empty page (`{ "Results": [], "TotalResults": 0 }`) — nothing on this server sells ' +
'boosts yet. Each entry, once there are any, names the purchase ' +
'(`PurchasableXpBoostLedgerEntryId`), the boost bought (`PurchasableXpBoostId`), its ' +
'`XpMultiplier`, and when it runs (`StartTime`/`EndTime`, ISO-8601 UTC).',
responses: {
200: json(XpBoostActivationsResponse, 'Always `{ "Results": [], "TotalResults": 0 }`'),
},
}),
(c) => c.json({ Results: [], TotalResults: 0 })
)
@@ -2144,6 +2144,12 @@ describe('public endpoints', () => {
expect(await other.json()).toMatchObject({ ProgressionEventId: 7 }) expect(await other.json()).toMatchObject({ ProgressionEventId: 7 })
}) })
test('GET /api/purchasableXpBoosts/activations is the empty page', async () => {
const res = await exports.default.fetch(`${ORIGIN}/api/purchasableXpBoosts/activations`)
expect(res.status).toBe(200)
expect(await res.json()).toStrictEqual({ Results: [], TotalResults: 0 })
})
test('GET /api/rooms/v1/filters returns an object with filter arrays', async () => { test('GET /api/rooms/v1/filters returns an object with filter arrays', async () => {
const res = await exports.default.fetch(`${ORIGIN}/api/rooms/v1/filters`) const res = await exports.default.fetch(`${ORIGIN}/api/rooms/v1/filters`)
expect(res.status).toBe(200) expect(res.status).toBe(200)
@@ -10247,6 +10253,7 @@ describe('openapi', () => {
'GET /api/progressionEvents/active', 'GET /api/progressionEvents/active',
'GET /api/progressionEvents/event/{id}', 'GET /api/progressionEvents/event/{id}',
'GET /api/progressionEvents/record/{id}', 'GET /api/progressionEvents/record/{id}',
'GET /api/purchasableXpBoosts/activations',
'GET /api/quickPlay/v1/getandclear', 'GET /api/quickPlay/v1/getandclear',
'GET /api/referee/files', 'GET /api/referee/files',
'GET /api/relationships/mutualfriends', 'GET /api/relationships/mutualfriends',