mirror of
https://github.com/djdevin/recflare.git
synced 2026-10-25 23:18:51 -07:00
[econ] stub active consumable endpoint (?)
This commit is contained in:
@@ -43,6 +43,7 @@ missing/invalid). `~` = optional auth: served to anyone, personalised for a vali
|
||||
| POST | `/api/settings/v2/set` | ✓ | Persist settings (accept-and-ack) |
|
||||
| GET | `/api/consumables/v2/getUnlocked` | ✓ | Unlocked consumables |
|
||||
| POST | `/api/consumables/v1/consume` | ✓ | Consume an owned consumable |
|
||||
| POST | `/api/consumables/v1/updateActive` | ✓ | Mark a consumable active (stub, empty) |
|
||||
| GET | `/api/storefronts/v4/balance/:currencyType` | ✓ | Currency balance |
|
||||
| GET | `/api/storefronts/v3/giftdropstore/:id` | | Gift-drop storefront catalog |
|
||||
| POST | `/api/storefronts/v2/buyItem` | ✓ | Buy a storefront item |
|
||||
|
||||
@@ -149,6 +149,7 @@ import {
|
||||
UgcPurchasableBulkRequest,
|
||||
UgcPurchasableItemList,
|
||||
UNAUTHORIZED_RESPONSE,
|
||||
UpdateActiveConsumableRequest,
|
||||
UpdateObjectiveRequest,
|
||||
UpdateObjectiveResponse,
|
||||
UpdateRoomCurrencyRequest,
|
||||
@@ -4859,6 +4860,54 @@ const app = new Hono<App>({ strict: false })
|
||||
}
|
||||
)
|
||||
|
||||
// STUB. The client posts `{ Id, IsActive, ActivatedByRoomie }` when a consumable starts
|
||||
// or stops being used — `Id` is the consumable row id, as on `/consume`. Nothing is
|
||||
// stored: the body is read only to log it, and the client ignores the response entirely,
|
||||
// so none is sent.
|
||||
//
|
||||
// What this most likely means: the consumable is IN USE, and marking it so is what keeps
|
||||
// a player from reusing one before it is over (a second Confetti Cannon while the first
|
||||
// is still firing), and `ActivatedByRoomie` says a roommate set it off rather than its
|
||||
// owner. That is a guess from the field names, not observed behaviour, so no row flips
|
||||
// and `/consume` is unchanged. When the client's reading of it is known, this is where
|
||||
// an `is_active` flag on the consumable row (and a refusal on `/consume`) would go.
|
||||
.post(
|
||||
'/api/consumables/v1/updateActive',
|
||||
describeRoute({
|
||||
tags: ['Consumables'],
|
||||
summary: 'Mark a consumable active or inactive (stub)',
|
||||
description: [
|
||||
'STUB. Accepts `{ Id, IsActive, ActivatedByRoomie }` — the client posting that one',
|
||||
'of its consumables has started or stopped being used — and stores nothing. The',
|
||||
'client ignores the response entirely, so this answers an empty 200.',
|
||||
'',
|
||||
'Believed to mark the consumable as IN USE so it cannot be reused before it is over,',
|
||||
'with `ActivatedByRoomie` saying a roommate set it off; that is a guess from the field',
|
||||
'names, and nothing acts on it yet. `/consume` is unaffected.',
|
||||
].join(' '),
|
||||
security: AUTHED,
|
||||
requestBody: jsonBody(UpdateActiveConsumableRequest, 'The consumable and its new state'),
|
||||
responses: {
|
||||
200: { description: 'Empty body — the client ignores the response entirely' },
|
||||
401: UNAUTHORIZED_RESPONSE,
|
||||
},
|
||||
}),
|
||||
async (c) => {
|
||||
const id = await authedId(c)
|
||||
if (id === null) return unauthorized(c)
|
||||
const body = await c.req
|
||||
.json<Record<string, unknown>>()
|
||||
.catch(() => ({}) as Record<string, unknown>)
|
||||
logger.info('consumable updateActive (stub, not stored)', {
|
||||
accountId: id,
|
||||
consumableId: body.Id,
|
||||
isActive: body.IsActive,
|
||||
activatedByRoomie: body.ActivatedByRoomie,
|
||||
})
|
||||
return c.body(null, 200)
|
||||
}
|
||||
)
|
||||
|
||||
// Currency balance. [Authorize]. The trailing int is a CurrencyType — the client
|
||||
// fetches `/balance/2` (RecCenterTokens) on load. Backed by the `balance` table; a
|
||||
// player who has never been granted gets their starting balance on this first read.
|
||||
|
||||
@@ -1257,6 +1257,19 @@ export const ConsumeConsumableRequest = z.object({
|
||||
DeltaCount: z.int().optional().describe('How many to spend; defaults to 1'),
|
||||
})
|
||||
|
||||
/**
|
||||
* `POST /api/consumables/v1/updateActive` JSON body — the client marking one of its
|
||||
* consumables active or not. Accepted and NOT acted on yet; see the route.
|
||||
*/
|
||||
export const UpdateActiveConsumableRequest = z.object({
|
||||
Id: z.int().describe('The consumable row id'),
|
||||
IsActive: z.boolean().describe('Whether the consumable is now in use'),
|
||||
ActivatedByRoomie: z
|
||||
.boolean()
|
||||
.optional()
|
||||
.describe('Whether a roommate, rather than the owner, activated it'),
|
||||
})
|
||||
|
||||
/** `POST /api/avatar/v2/gifts/consume` form body (posted with a trailing slash). */
|
||||
export const ConsumeGiftRequest = z.object({
|
||||
Id: z.string().describe('The gift-box id to open'),
|
||||
|
||||
@@ -3578,6 +3578,30 @@ describe('econ endpoints', () => {
|
||||
expect(await res.json()).toEqual([])
|
||||
})
|
||||
|
||||
test('POST /api/consumables/v1/updateActive is a stub: auth-gated, stores nothing, answers nothing', async () => {
|
||||
const before = await env.DB.prepare('SELECT * FROM consumable ORDER BY id').all()
|
||||
const body = { Id: 7550, IsActive: true, ActivatedByRoomie: false }
|
||||
|
||||
const anon = await exports.default.fetch(`${ORIGIN}/api/consumables/v1/updateActive`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(body),
|
||||
})
|
||||
expect(anon.status).toBe(401)
|
||||
|
||||
const res = await exports.default.fetch(`${ORIGIN}/api/consumables/v1/updateActive`, {
|
||||
method: 'POST',
|
||||
headers: { ...(await bearer('314')), 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(body),
|
||||
})
|
||||
expect(res.status).toBe(200)
|
||||
// No body at all: the client ignores the response entirely.
|
||||
expect(await res.text()).toBe('')
|
||||
// Nothing is stored yet.
|
||||
const after = await env.DB.prepare('SELECT * FROM consumable ORDER BY id').all()
|
||||
expect(after.results).toEqual(before.results)
|
||||
})
|
||||
|
||||
test('POST /api/consumables/v1/consume reduces the count and deletes the row at zero', async () => {
|
||||
// Seed account 313 with two Supreme Pizza instances (counts 3 and 1).
|
||||
await grantConsumable(env.DB, 313, 'Supreme Pizza', 3)
|
||||
@@ -6991,6 +7015,7 @@ describe('econ endpoints', () => {
|
||||
'POST /api/checklist/v1/complete',
|
||||
'POST /api/checklist/v2/complete',
|
||||
'POST /api/consumables/v1/consume',
|
||||
'POST /api/consumables/v1/updateActive',
|
||||
'POST /api/equipment/v1/update',
|
||||
'POST /api/gamerewards/v1/request',
|
||||
'POST /api/itemWishlists/v1/isonwishlist/bulk',
|
||||
|
||||
Reference in New Issue
Block a user