mirror of
https://github.com/djdevin/recflare.git
synced 2026-09-08 14:41:28 -07:00
[event] fixup even listing, eliminate some misc log errors
This commit is contained in:
@@ -8,6 +8,7 @@ import { logger } from '@repo/hono-helpers'
|
||||
import { NotificationType } from '../../../notify/src/notification-types'
|
||||
import {
|
||||
createEvent,
|
||||
getEventAttendees,
|
||||
getEventById,
|
||||
getEventsByClubs,
|
||||
getEventsByCreator,
|
||||
@@ -18,6 +19,8 @@ import {
|
||||
parseEventBody,
|
||||
searchEvents,
|
||||
setEventResponse,
|
||||
toEventListing,
|
||||
toEventResponse,
|
||||
toEventNotification,
|
||||
toEventResult,
|
||||
updateEvent,
|
||||
@@ -31,8 +34,10 @@ import {
|
||||
jsonBody,
|
||||
pageParams,
|
||||
PlayerEventDto,
|
||||
PlayerEventListingDto,
|
||||
PlayerEventRequest,
|
||||
PlayerEventRespondRequest,
|
||||
PlayerEventResponseDto,
|
||||
PlayerEventResultDto,
|
||||
PlayerEventsAll,
|
||||
PlayerEventsPage,
|
||||
@@ -83,6 +88,33 @@ async function notifyEventCreated(c: Context<App>, event: PlayerEvent): Promise<
|
||||
* if they're unified.
|
||||
*/
|
||||
export const eventRoutes = new Hono<App>({ strict: false })
|
||||
// The player-events browse feed — everything upcoming or running, soonest first. Same
|
||||
// query `/search` runs with no text, but its own projection: this feed drops `State`
|
||||
// and carries a `BroadcastingRoomInstanceId`, so it goes through `toEventListing`.
|
||||
.get(
|
||||
'/api/playerevents/v1',
|
||||
describeRoute({
|
||||
tags: ['Events'],
|
||||
summary: 'The player-events browse feed',
|
||||
description:
|
||||
'The default feed on the player-events screen: every event that has not finished ' +
|
||||
'yet — upcoming and running — soonest first, paginated via skip/take. A bare ' +
|
||||
'array.\n\n' +
|
||||
'Each entry is the browse LISTING, not the stored record the by-id, bulk and ' +
|
||||
'search reads serve: it drops `State` and carries ' +
|
||||
'`BroadcastingRoomInstanceId` (always null — nothing broadcasts an event yet). ' +
|
||||
'That is the shape observed on this endpoint; keep the two projections apart.',
|
||||
parameters: pageParams(50),
|
||||
responses: { 200: json(PlayerEventListingDto.array(), 'The events that have not ended') },
|
||||
}),
|
||||
async (c) => {
|
||||
const skip = Number.parseInt(c.req.query('skip') ?? '', 10) || 0
|
||||
const take = Number.parseInt(c.req.query('take') ?? '', 10) || 50
|
||||
const events = await searchEvents(c.env.DB, '', skip, take)
|
||||
return c.json(events.map(toEventListing))
|
||||
}
|
||||
)
|
||||
|
||||
.get(
|
||||
'/api/playerevents/v1/all',
|
||||
describeRoute({
|
||||
@@ -390,6 +422,29 @@ export const eventRoutes = new Hono<App>({ strict: false })
|
||||
}
|
||||
)
|
||||
|
||||
// An event's guest list — every RSVP row, whatever the answer.
|
||||
.get(
|
||||
'/api/playerevents/v1/:eventId{[0-9]+}/responses',
|
||||
describeRoute({
|
||||
tags: ['Events'],
|
||||
summary: 'An event’s RSVPs',
|
||||
description:
|
||||
'Every answer given to an event, in the order they were given — declines and ' +
|
||||
'maybes included, not just the Going rows `AttendeeCount` counts. One entry per ' +
|
||||
'player: a player who changed their mind has one row carrying the answer that ' +
|
||||
'stands, and `CreatedAt` moves with it.\n\n' +
|
||||
'A bare array, and an unknown event is an empty one rather than a 404 — like the ' +
|
||||
'other list reads here. An event always has at least its creator’s Going row.',
|
||||
parameters: [idParam('eventId', 'Event id')],
|
||||
responses: { 200: json(PlayerEventResponseDto.array(), 'The event’s RSVPs') },
|
||||
}),
|
||||
async (c) => {
|
||||
const eventId = Number.parseInt(c.req.param('eventId'), 10)
|
||||
const attendees = await getEventAttendees(c.env.DB, eventId)
|
||||
return c.json(attendees.map(toEventResponse))
|
||||
}
|
||||
)
|
||||
|
||||
// A single event. Registered last so the literal `/bulk` and `/search` paths above
|
||||
// are matched first; the `[0-9]+` constraint keeps them apart regardless.
|
||||
.get(
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
JsonArray,
|
||||
jsonBody,
|
||||
JsonObject,
|
||||
KeepsakeCategories,
|
||||
KeepsakeConfig,
|
||||
SanitizeRequest,
|
||||
stringParam,
|
||||
@@ -97,15 +98,25 @@ export const gameplayRoutes = new Hono<App>({ strict: false })
|
||||
}),
|
||||
(c) => c.body(null, 204)
|
||||
)
|
||||
// A counted result set, NOT the bare list the stubs around it serve: the client parses
|
||||
// this one as an object and an array fails it outright — "expected:'{', actual:'[', at
|
||||
// offset:0", logged as "Failed to get keepsake categories" — which takes the keepsake
|
||||
// load down with it. `TotalResults` is the length of `Results`, not a total behind a
|
||||
// page; the reference returns `results.Length`.
|
||||
.get(
|
||||
'/api/keepsakes/categories',
|
||||
describeRoute({
|
||||
tags: ['Gameplay'],
|
||||
summary: 'Keepsake categories',
|
||||
description: 'No keepsake catalog yet, so this is an empty list.',
|
||||
responses: { 200: json(JsonArray, 'An empty list') },
|
||||
description:
|
||||
'No keepsake catalog yet, so the result set is empty — but it IS a result set ' +
|
||||
'(`{ Results, TotalResults }`), not the empty list the stubs around it serve. ' +
|
||||
'The client parses this one as an object and fails on an array ("expected \'{\', ' +
|
||||
'actual \'[\'"), taking the keepsake load down with it. `TotalResults` counts ' +
|
||||
'`Results` itself — there is no paging here.',
|
||||
responses: { 200: json(KeepsakeCategories, 'An empty result set') },
|
||||
}),
|
||||
(c) => c.json([])
|
||||
(c) => c.json({ Results: [], TotalResults: 0 })
|
||||
)
|
||||
|
||||
// ---- Objectives / events / rewards ---------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user