import { AnsiUp } from 'ansi_up' import { Hono } from 'hono' import { serveStatic } from 'hono/bun' import { join, resolve } from 'path' import { wrapCode, ribbitGlobals } from './ribbit' import { Shrimp } from 'shrimp' export function startWeb(rootPath: string) { const root = resolve(rootPath) const app = new Hono() // console logging app.use('*', async (c, next) => { const start = Date.now() await next() const end = Date.now() console.log(`${c.res.status} ${c.req.method} ${c.req.url} (${end - start}ms)`) }) // static files get served out of pub/ app.use('/*', serveStatic({ root: join(root, 'pub') })) app.on(['GET', 'POST'], ['/', '/:page{.+}'], async (c) => { const page = c.req.param('page') || 'index' if (page === 'layout') return c.text('404 Not Found', 404) const params = c.req.query() const request = { method: c.req.method } if (c.req.method === 'POST') { const formData = await c.req.formData() for (const [key, value] of formData.entries()) { params[key] = value } } const path = join(root, `${page}.sh`) const file = Bun.file(path) const layoutPath = join(root, `layout.sh`) const layoutFile = Bun.file(layoutPath) let layoutCode = await layoutFile.exists() ? await layoutFile.text() : '' const vm = new Shrimp(Object.assign({}, ribbitGlobals, { params, request })) if (await file.exists()) { let content = '' try { const code = wrapCode(await file.text()) content = await vm.run(code) } catch (err) { return c.html(shrimpError(path, err), 500) } if (!layoutCode) return c.html(content) try { return c.html(await vm.run(wrapCode(layoutCode), { content })) } catch (err) { return c.html(shrimpError(layoutPath, err), 500) } } else { return c.text('404 Not Found', 404) } }) console.log('🫧 Server started at http://localhost:3000') return Bun.serve({ fetch: app.fetch, port: 3000, }) } function shrimpError(path: string, error: any): string { const ansiUp = new AnsiUp() const errorHtml = ansiUp.ansi_to_html(error?.message ?? String(error)) const blue = '#42A5F5' return `
${errorHtml}`
}