Files
jayjennings 61c876edec
CI / Lint, typecheck, test, build (push) Canceled after 0s
CI / End-to-end tests (push) Canceled after 0s
Add OSHA Form 301 and Osha page components
- Implemented Form301 component for displaying OSHA Form 301 equivalent, including employee and case information.
- Created Osha component to manage OSHA recordkeeping, including tabs for 300 Log, 300A Summary, Hours & rates, and Submit to OSHA.
- Added functionality for printing and downloading CSV files for OSHA submissions.
- Integrated loading and error handling states for data fetching.
2026-10-06 13:09:57 -07:00

76 lines
2.8 KiB
TypeScript

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 { oshaRoutes } from './routes/osha.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 { viewRoutes } from './routes/views.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<AppEnv>()
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.route('/api/osha', oshaRoutes)
app.route('/api/views', viewRoutes)
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<typeof createApp>