import { createHash } from 'node:crypto'; import { error } from '@sveltejs/kit'; import { renderBuildSocialCardPng, type BuildSocialCardFact, type BuildSocialCardInput, } from '$lib/server/build-social-card'; import { publicOrigin } from '$lib/server/public-origin'; import { loadSharedBuildProjection } from '$lib/server/shared-build'; import type { RequestHandler } from './$types'; const number = new Intl.NumberFormat('en-US', { maximumFractionDigits: 2 }); const MAX_CACHE_BYTES = 16 * 1024 * 1024; const MAX_ACTIVE_REQUESTS = 4; const MAX_QUEUED_REQUESTS = 32; type CachedImage = { body: Buffer; etag: string }; const imageCache = new Map(); const pendingImages = new Map>(); const requestQueue: Array<(release: () => void) => void> = []; let cacheBytes = 0; let activeRequests = 0; function unitValue(value: number, unit: string | null | undefined) { const rendered = number.format(value); return unit === 'Shots' ? `${rendered} ${unit}` : `${rendered}${unit ?? ''}`; } export function _socialCardInput( projection: NonNullable< Awaited> >, directUrl: string, ): BuildSocialCardInput { const attribute = (id: string) => projection.attributes.find((item) => String(item.id) === id); const statByName = (name: string) => projection.summary.stats.find( (stat) => String(attribute(stat.id)?.name) === name, ); const statValue = (name: string) => { const stat = statByName(name); return stat ? unitValue(Number(stat.value), attribute(stat.id)?.unit) : '0'; }; const weaponName = (index: number) => { const selected = projection.loadout.weapons[index]; return ( projection.weapons.find((item) => String(item.id) === selected?.itemId) ?.name ?? 'Unassigned' ); }; const coreNames = new Set(['Firepower', 'Toughness', 'Engineering']); const supportingAttributes: BuildSocialCardFact[] = projection.summary.stats .filter((stat) => !coreNames.has(String(attribute(stat.id)?.name))) .slice(0, 3) .map((stat) => ({ label: String(attribute(stat.id)?.name ?? 'Attribute'), value: unitValue(Number(stat.value), attribute(stat.id)?.unit), })); return { title: projection.build.title, author: projection.build.author, primaryWeapon: String(weaponName(0)), secondaryWeapon: String(weaponName(1)), firepower: statValue('Firepower'), toughness: statValue('Toughness'), engineering: statValue('Engineering'), supportingAttributes, visibility: projection.build.visibility as 'public' | 'unlisted', directUrl, }; } function matchesEtag(request: Request, etag: string) { return request.headers .get('if-none-match') ?.split(',') .some((value) => value.trim() === etag); } function releaseRequest() { const next = requestQueue.shift(); if (next) { next(releaseRequest); return; } activeRequests -= 1; } function acquireRequest(): Promise<(() => void) | null> { if (activeRequests < MAX_ACTIVE_REQUESTS) { activeRequests += 1; return Promise.resolve(releaseRequest); } if (requestQueue.length >= MAX_QUEUED_REQUESTS) return Promise.resolve(null); return new Promise((resolve) => requestQueue.push(resolve)); } function storeImage(key: string, image: CachedImage) { imageCache.set(key, image); cacheBytes += image.body.byteLength; while (cacheBytes > MAX_CACHE_BYTES && imageCache.size > 1) { const oldestKey = imageCache.keys().next().value; if (!oldestKey) break; const oldest = imageCache.get(oldestKey); imageCache.delete(oldestKey); cacheBytes -= oldest?.body.byteLength ?? 0; } } async function loadImage(input: BuildSocialCardInput, inputKey: string) { const cached = imageCache.get(inputKey); if (cached) { imageCache.delete(inputKey); imageCache.set(inputKey, cached); return cached; } const pending = pendingImages.get(inputKey); if (pending) return pending; const request = renderBuildSocialCardPng(input).then((body) => { const image = { body, etag: `"${createHash('sha256').update(body).digest('base64url')}"`, }; storeImage(inputKey, image); return image; }); pendingImages.set(inputKey, request); try { return await request; } finally { pendingImages.delete(inputKey); } } export const GET: RequestHandler = async ({ params, request, url }) => { const release = await acquireRequest(); if (!release) error(503, 'Build preview capacity exceeded'); try { const projection = await loadSharedBuildProjection(params.slug, { kind: 'public-preview', }); if (!projection) error(404, 'Build preview not found'); const origin = publicOrigin(url.origin); const directUrl = new URL( `/builds/${encodeURIComponent(projection.build.slug)}`, origin, ).toString(); const input = _socialCardInput(projection, directUrl); const inputKey = createHash('sha256') .update(JSON.stringify({ version: 1, input })) .digest('base64url'); const image = await loadImage(input, inputKey); const cacheControl = 'public, max-age=0, must-revalidate'; if (matchesEtag(request, image.etag)) { return new Response(null, { status: 304, headers: { 'cache-control': cacheControl, etag: image.etag }, }); } return new Response(new Uint8Array(image.body), { headers: { 'cache-control': cacheControl, 'content-length': String(image.body.byteLength), 'content-type': 'image/png', 'cross-origin-resource-policy': 'same-origin', etag: image.etag, 'x-content-type-options': 'nosniff', ...(projection.build.visibility === 'unlisted' ? { 'x-robots-tag': 'noindex' } : {}), }, }); } finally { release(); } };