import { Hono } from 'hono' import { csrf } from 'hono/csrf' import { HTTPException } from 'hono/http-exception' import { secureHeaders } from 'hono/secure-headers' import { loadSession } from './auth/middleware.ts' import type { Config } from './config.ts' import type { Db } from './db/client.ts' import type { AppEnv } from './lib/http.ts' import type { Notifier } from './notifications.ts' import { actionRoutes } from './routes/actions.ts' import { attachmentRoutes } from './routes/attachments.ts' import { authRoutes } from './routes/auth.ts' import { incidentRoutes } from './routes/incidents.ts' import { kioskAdminRoutes, kioskPublicRoutes } from './routes/kiosks.ts' import { rootCauseRoutes } from './routes/root-causes.ts' import { setupRoutes } from './routes/setup.ts' import { areaRoutes, siteRoutes } from './routes/sites.ts' import { statsRoutes } from './routes/stats.ts' import { userRoutes } from './routes/users.ts' import type { FileStorage } from './storage.ts' export interface AppDeps { db: Db config: Config notifier: Notifier storage: FileStorage } export function createApp({ db, config, notifier, storage }: AppDeps) { const app = new Hono() app.use('*', secureHeaders()) const publicOrigin = new URL(config.publicUrl).origin // Form/multipart posts must come from our own pages. JSON requests are already protected by CORS preflight. const sameSite = csrf({ origin: (origin, c) => origin === publicOrigin || origin === new URL(c.req.url).origin }) app.use('/api/*', sameSite, async (c, next) => { c.set('db', db) c.set('config', config) c.set('notifier', notifier) c.set('storage', storage) c.header('Cache-Control', 'no-store') await next() }) app.use('/api/*', loadSession) app.get('/api/health', (c) => c.json({ ok: true })) app.route('/api/setup', setupRoutes) app.route('/api/auth', authRoutes()) app.route('/api/users', userRoutes) app.route('/api/sites', siteRoutes) app.route('/api/areas', areaRoutes) app.route('/api/incidents', incidentRoutes) app.route('/api/root-causes', rootCauseRoutes) app.route('/api/actions', actionRoutes) app.route('/api/attachments', attachmentRoutes) app.route('/api/stats', statsRoutes) app.route('/api/kiosks', kioskAdminRoutes) app.route('/api/kiosk', kioskPublicRoutes()) app.all('/api/*', (c) => c.json({ error: 'Not found' }, 404)) app.onError((error, c) => { if (error instanceof HTTPException) return c.json({ error: error.message }, error.status) console.error(error) return c.json({ error: 'Internal server error' }, 500) }) return app } export type App = ReturnType