import { type IRequestStrict, Router } from 'itty-router'; import type { Database } from '../db/database.js'; import { buildGeneratorPage, buildResponsesPage, wrapPage } from './template.js'; import { CSS, JS } from './client.generated.js'; import type { HashedBundled } from '../../common/bundle.js'; import { getSourceMapFileName, SourceMapExtension, SourceMaps } from './sourcemaps.js'; import { collapseWhiteSpace } from 'collapse-white-space'; import { getQuerySingleton, takeLast } from '../request/query.js'; interface WebEnv { readonly BASE_URL: string, readonly CREDITS_URL: string, readonly DISCORD_APP_ID: string } export function webRouter(base: string) { function getSourceMappedJS(name: keyof typeof JS) { const { bundled, hash }: HashedBundled = JS[name]; return bundled + `\n//# sourceMappingURL=${getSourceMapFileName(name, hash, SourceMapExtension.JS)}`; } function getSourceMappedCSS(name: keyof typeof CSS) { const { bundled, hash }: HashedBundled = CSS[name]; return bundled + `\n/*# sourceMappingURL=${getSourceMapFileName(name, hash, SourceMapExtension.CSS)} */`; } async function handleMainPage(req: IRequestStrict, env: WebEnv, db: Database): Promise { const startAt = performance.now() const results = await db.getGeneratorPageForDiscordSet(getQuerySingleton(req.query['server'], takeLast)); const resultsAt = performance.now() const generator = buildGeneratorPage({ creditsUrl: env.CREDITS_URL, clientId: env.DISCORD_APP_ID, baseUrl: env.BASE_URL, results: results.rolled, selected: results.selected, includesResponses: true }) const generatorAt = performance.now() const responses = buildResponsesPage({ tables: Array.from(results.db.tables.values()), results: results.rolled, creditsUrl: env.CREDITS_URL, includesGenerator: true }) const responsesAt = performance.now() const wrapped = wrapPage({ title: 'Vore Scenario Generator', script: getSourceMappedJS('combinedGeneratorResponses'), styles: getSourceMappedCSS('combinedGeneratorResponses'), noscriptStyles: getSourceMappedCSS('noscript'), bodyContent: [generator, responses].join('') }) const wrappedAt = performance.now() const trimmed = collapseWhiteSpace(wrapped, {style: 'html'}) const trimmedAt = performance.now() console.log(`database: ${resultsAt - startAt}, generator: ${generatorAt - resultsAt}, responses: ${responsesAt - generatorAt}, wrapped: ${wrappedAt - responsesAt}, trimmed: ${trimmedAt - wrappedAt}`) return trimmed; } const router = Router({ base }) .get('/responses', async (req, _env, _db, _ctx) => { const url = new URL(req.url); url.pathname = base; url.hash = '#responses'; return Response.redirect(url.toString(), 303); }) .get('/generator', async (req, _env, _db, _ctx) => { const url = new URL(req.url); url.pathname = base; url.hash = '#generator'; return Response.redirect(url.toString(), 303); }) .get('/scenario', async (_req, _env, _db, _ctx) => { // TODO: implement me return new Response('Not yet supported', { status: 404 }); }) .get('/', handleMainPage) .post('/', handleMainPage); for (const [filename, contents] of SourceMaps) { router.get(`/${filename}`, () => contents); } return router; }