more endpoints

This commit is contained in:
Devin Zuczek
2026-07-05 19:23:06 -04:00
parent 8f61adff1b
commit 7cf380a401
14 changed files with 179 additions and 33 deletions
+6 -5
View File
@@ -223,7 +223,7 @@ export class NotificationsHub extends DurableObject<Env> {
*/
async notifyPlayer(
playerId: number,
notificationType: number,
notificationType: string | number,
data?: Record<string, unknown>
): Promise<{ delivered: number; queued: boolean }> {
const payload = this.buildNotificationPayload(notificationType, data)
@@ -257,7 +257,7 @@ export class NotificationsHub extends DurableObject<Env> {
/** Broadcast a notification to every connected (handshaken) client. */
async broadcast(
notificationType: number,
notificationType: string | number,
data?: Record<string, unknown>
): Promise<{ delivered: number }> {
const payload = this.buildNotificationPayload(notificationType, data)
@@ -275,10 +275,11 @@ export class NotificationsHub extends DurableObject<Env> {
/**
* Build the `Notification` argument: a JSON string `{ Id, Msg }`
* (null values are dropped from `Msg`).
* (null values are dropped from `Msg`). `Id` is a client-defined tag — a
* string name (e.g. "AccountUpdate") or a numeric code.
*/
private buildNotificationPayload(
notificationType: number,
notificationType: string | number,
data?: Record<string, unknown>
): string {
const msg: Record<string, unknown> = {}
@@ -288,7 +289,7 @@ export class NotificationsHub extends DurableObject<Env> {
msg[key] = value
}
}
return JSON.stringify({ Id: notificationType ?? 0, Msg: msg })
return JSON.stringify({ Id: notificationType ?? '', Msg: msg })
}
private invocation(target: string, args: unknown[]): string {
+17 -5
View File
@@ -18,6 +18,14 @@ import type { App } from './context'
/** The hub state is global → one DO instance. */
const HUB_INSTANCE = 'global'
/**
* A valid notification `Id` — a client-defined string tag (e.g. "AccountUpdate")
* or a numeric code. An empty string is treated as missing.
*/
function isNotificationType(value: unknown): value is string | number {
return (typeof value === 'string' && value !== '') || typeof value === 'number'
}
const app = new Hono<App>()
.use(
'*',
@@ -48,7 +56,7 @@ const app = new Hono<App>()
})
// The hub WebSocket. Upgrade requests are forwarded to the Durable Object.
.get('/hub/v1', (c) => {
.get('/hub/v1', async (c) => {
if ((c.req.header('upgrade') ?? '').toLowerCase() !== 'websocket') {
return c.json({ error: 'Expected a WebSocket upgrade request' }, 426)
}
@@ -60,9 +68,13 @@ const app = new Hono<App>()
// TODO: protect these before production.
.post('/internal/notify', async (c) => {
const body = await c.req
.json<{ playerId?: number; notificationType?: number; data?: Record<string, unknown> }>()
.json<{
playerId?: number
notificationType?: string | number
data?: Record<string, unknown>
}>()
.catch(() => null)
if (!body || typeof body.playerId !== 'number' || typeof body.notificationType !== 'number') {
if (!body || typeof body.playerId !== 'number' || !isNotificationType(body.notificationType)) {
return c.json({ error: 'playerId and notificationType are required' }, 400)
}
const result = await c.env.RECFLARE_NOTIFICATIONS_HUB.getByName(HUB_INSTANCE).notifyPlayer(
@@ -75,9 +87,9 @@ const app = new Hono<App>()
.post('/internal/broadcast', async (c) => {
const body = await c.req
.json<{ notificationType?: number; data?: Record<string, unknown> }>()
.json<{ notificationType?: string | number; data?: Record<string, unknown> }>()
.catch(() => null)
if (!body || typeof body.notificationType !== 'number') {
if (!body || !isNotificationType(body.notificationType)) {
return c.json({ error: 'notificationType is required' }, 400)
}
const result = await c.env.RECFLARE_NOTIFICATIONS_HUB.getByName(HUB_INSTANCE).broadcast(