first pass analytics redo

This commit is contained in:
George Powell committed 2026-09-22 12:15:56 -04:00
1 parent b656fd04c0
commit 45ffa39f2a
69 files changed
+6400 -1138

No files matched your search

+52
View File
@@ -0,0 +1,52 @@
import { json } from '@sveltejs/kit';
import type { RequestHandler } from './$types';
import { isEventName, recordEvent, encodeMetadata } from '$lib/server/stats/events';
const DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
/**
* Fire-and-forget client analytics sink.
*
* Body: `{ name, anonymousId?, date?, metadata? }`.
* `userId` is resolved server-side from the session — never trusted from the client.
* Always returns 204, even for invalid input, so gameplay is never blocked.
*/
export const POST: RequestHandler = async ({ request, locals }) => {
let body: any;
try {
body = await request.json();
} catch {
return new Response(null, { status: 204 });
}
const name = typeof body?.name === 'string' ? body.name : '';
if (!isEventName(name)) {
return new Response(null, { status: 204 });
}
const anonymousId =
typeof body?.anonymousId === 'string' && body.anonymousId.length > 0
? body.anonymousId.slice(0, 128)
: null;
const date =
typeof body?.date === 'string' && DATE_RE.test(body.date) ? body.date : null;
const metadata =
body?.metadata && typeof body.metadata === 'object' && !Array.isArray(body.metadata)
? (body.metadata as Record<string, unknown>)
: null;
// Ensure metadata is always serializable/capped before it reaches the DB.
void encodeMetadata(metadata);
await recordEvent({
name,
anonymousId,
userId: locals.user?.id ?? null,
date,
metadata
});
return new Response(null, { status: 204 });
};