import { packageContext } from 'kody:runtime' import { getSnapshot } from './getSnapshot' import { AQI_STANDARDS, type AqiStandard } from './getSnapshot' function appUrl(path: string): URL { if (!packageContext?.hostedUrl) { throw new Error('This module must run as a package app.') } const relative = path.replace(/^\/+/, '') const mount = packageContext.appBasePath.endsWith('/') ? packageContext.appBasePath : `${packageContext.appBasePath}/` return new URL(`${mount}${relative}`, packageContext.hostedUrl) } function renderPage(): Response { const apiPath = appUrl('api/getSnapshot').pathname const standards = Object.entries(AQI_STANDARDS) .map(([k, label]) => ``) .join('') const html = ` 空气质量快照

空气质量快照

Scrapes air-quality.com(同 HA air_quality_cn 字段):AQI / 污染物 / 花粉 / 天气。上游 HTML 可能变更。

—

Not medical advice. Primary: scraped air-quality.com. Fallback: Open-Meteo / 北京花粉监测平台.

` return new Response(html, { headers: { 'content-type': 'text/html; charset=utf-8', 'cache-control': 'no-store' }, }) } async function handleApi(request: Request): Promise { if (request.method !== 'POST') { return Response.json({ error: 'POST required' }, { status: 405 }) } let body: { location?: string place?: string standard?: AqiStandard fallback?: boolean } = {} try { body = (await request.json()) as typeof body } catch { return Response.json({ error: 'Invalid JSON body' }, { status: 400 }) } try { const result = await getSnapshot(body) return Response.json(result) } catch (e) { return Response.json( { error: e instanceof Error ? e.message : String(e) }, { status: 400 }, ) } } export default { async fetch(request: Request): Promise { const path = new URL(request.url).pathname if (path === '/' || path === '') return renderPage() if (path === '/api/getSnapshot') return handleApi(request) return new Response('Not found', { status: 404 }) }, }