mirror of
https://github.com/djdevin/recflare.git
synced 2026-09-08 14:41:28 -07:00
add api/objectives/v1/updateobjective endpoint even though it does not work right now
This commit is contained in:
@@ -69,6 +69,8 @@ import {
|
||||
SaveOutfitV4Response,
|
||||
SubscriptionResponse,
|
||||
UNAUTHORIZED_RESPONSE,
|
||||
UpdateObjectiveRequest,
|
||||
UpdateObjectiveResponse,
|
||||
} from './openapi'
|
||||
import { getOutfits, setOutfit } from './outfit-db'
|
||||
|
||||
@@ -500,6 +502,37 @@ const app = new Hono<App>({ strict: false })
|
||||
(c) => c.json([])
|
||||
)
|
||||
|
||||
// Report one objective's progress. The client posts the whole objective as it now
|
||||
// sees it (Index/Group identify it within `myprogress`) and reads back the state of
|
||||
// the GROUP that objective belongs to — camelCase here, unlike the PascalCase body it
|
||||
// posted. Stubbed: with no objectives store yet we persist nothing, echo the group
|
||||
// back and never complete it, so the reward-claim flow isn't triggered. `clearedAt`
|
||||
// is the clear time, which for a group we didn't clear is just now.
|
||||
.post(
|
||||
'/api/objectives/v1/updateobjective',
|
||||
describeRoute({
|
||||
tags: ['Econ'],
|
||||
summary: 'Report objective progress',
|
||||
description: [
|
||||
'Stubbed: with no objectives store we persist nothing and never complete a group.',
|
||||
'Echoes `Group` back as camelCase `group` with `isCompleted: false` so the client',
|
||||
'gets a well-formed body.',
|
||||
].join(' '),
|
||||
requestBody: jsonBody(UpdateObjectiveRequest, 'The objective as the client now sees it'),
|
||||
responses: { 200: json(UpdateObjectiveResponse, 'The echoed group, never completed') },
|
||||
}),
|
||||
async (c) => {
|
||||
const body = await c.req
|
||||
.json<{ Group?: string | number }>()
|
||||
.catch(() => ({}) as Record<string, never>)
|
||||
return c.json({
|
||||
group: Number(body.Group) || 0,
|
||||
isCompleted: false,
|
||||
clearedAt: new Date().toISOString(),
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
// The player's avatar, stored as a JSON blob on their account row. Falls back
|
||||
// to the default outfit when they haven't saved one — the client's parser NREs
|
||||
// on an empty OutfitSelections (real RecNet never returns one).
|
||||
|
||||
@@ -112,6 +112,17 @@ export const ChallengeProgressResponse = z.object({
|
||||
Complete: z.boolean().describe('Always false — no challenge-progress store yet'),
|
||||
})
|
||||
|
||||
/**
|
||||
* `POST /api/objectives/v1/updateobjective` — the group the objective belongs to, after
|
||||
* the update. camelCase, unlike the PascalCase body the client posts and the PascalCase
|
||||
* `ObjectiveGroups` entries `myprogress` serves — three spellings of the same group.
|
||||
*/
|
||||
export const UpdateObjectiveResponse = z.object({
|
||||
group: z.int().describe('Echoed back from the request'),
|
||||
isCompleted: z.boolean().describe('Always false — no objectives store yet'),
|
||||
clearedAt: z.string().describe('When the group was cleared — now, since nothing persists'),
|
||||
})
|
||||
|
||||
/**
|
||||
* `POST /api/storefronts/v2/buyItem` — the purchase result. `Balance` is the CHANGE
|
||||
* applied (the negated price), not the resulting total; the client reads its new total
|
||||
@@ -198,6 +209,20 @@ export const ChallengeProgressRequest = z.object({
|
||||
Config: z.string().optional().describe('The client-evaluated rule tree'),
|
||||
})
|
||||
|
||||
/**
|
||||
* `POST /api/objectives/v1/updateobjective` JSON body — one objective's state as the
|
||||
* client now sees it. `Index`/`Group` identify it within `myprogress`; the rest is the
|
||||
* progress it wants persisted.
|
||||
*/
|
||||
export const UpdateObjectiveRequest = z.object({
|
||||
Index: z.int().describe('Which objective within the group'),
|
||||
Group: z.int().describe('Which objective group'),
|
||||
Progress: z.int().optional(),
|
||||
VisualProgress: z.int().optional().describe('What the client animates towards'),
|
||||
IsCompleted: z.boolean().optional(),
|
||||
HasClaimedReward: z.boolean().optional(),
|
||||
})
|
||||
|
||||
/** `POST /api/avatar/v3/saved/set` JSON body — an outfit with a target `Slot`. */
|
||||
export const SaveOutfitRequest = z
|
||||
.object({ Slot: z.int().describe('Which slot to overwrite; a non-integer is 400') })
|
||||
|
||||
@@ -342,6 +342,37 @@ describe('econ endpoints', () => {
|
||||
}
|
||||
})
|
||||
|
||||
test('POST /api/objectives/v1/updateobjective echoes the group, never completed', async () => {
|
||||
const res = await exports.default.fetch(`${ORIGIN}/api/objectives/v1/updateobjective`, {
|
||||
method: 'POST',
|
||||
headers: { 'content-type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
Index: 2,
|
||||
Group: 3,
|
||||
Progress: 1,
|
||||
VisualProgress: 0,
|
||||
IsCompleted: true,
|
||||
HasClaimedReward: false,
|
||||
}),
|
||||
})
|
||||
expect(res.status).toBe(200)
|
||||
const body = (await res.json()) as { group: number; isCompleted: boolean; clearedAt: string }
|
||||
expect(body.group).toBe(3)
|
||||
expect(body.isCompleted).toBe(false)
|
||||
expect(Number.isNaN(Date.parse(body.clearedAt))).toBe(false)
|
||||
})
|
||||
|
||||
test('POST /api/objectives/v1/updateobjective tolerates a non-JSON body', async () => {
|
||||
const res = await exports.default.fetch(`${ORIGIN}/api/objectives/v1/updateobjective`, {
|
||||
method: 'POST',
|
||||
body: 'not json',
|
||||
})
|
||||
expect(res.status).toBe(200)
|
||||
const body = (await res.json()) as { group: number; isCompleted: boolean }
|
||||
expect(body.group).toBe(0)
|
||||
expect(body.isCompleted).toBe(false)
|
||||
})
|
||||
|
||||
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)
|
||||
@@ -1425,6 +1456,7 @@ describe('econ endpoints', () => {
|
||||
'POST /api/consumables/v1/consume',
|
||||
'POST /api/gamerewards/v1/request',
|
||||
'POST /api/objectives/v1/cleargroup',
|
||||
'POST /api/objectives/v1/updateobjective',
|
||||
'POST /api/storefronts/v2/buyItem',
|
||||
'PUT /api/equipment/v1/update',
|
||||
])
|
||||
|
||||
Reference in New Issue
Block a user