import { Hono } from 'hono'; import { isAbsolute, resolve } from 'node:path'; import { mkdirSync } from 'node:fs'; import { addRedirectHandler, deleteDocument, deleteDocumentPost, deleteRedirect, deleteUpload, editPage, functionContextHandler, loginPage, loginPost, logoutPost, notFoundPage, previewRender, renderEditorPage, searchDocuments, signupStateMiddleware, updateFromArchive, updateUploadHandler, uploadFile, whoami, } from "./routes/edit.js"; import { documents } from "./routes/documents.js"; import { readUpload } from "./routes/readUpload.js"; import { git } from "./routes/git.js"; import { assets } from "./routes/assets.js"; import { authorize } from "./middleware/authorize.js"; import { requireQuery } from "./middleware/requireQuery.js"; import { withDb } from "./middleware/withDb.js"; import { establishAuth } from "./middleware/establishAuth.js"; import { log } from "./middleware/log.js"; import { requirePathMatch } from "./middleware/requirePathMatch.js"; import { seedIfEmpty } from "../operations/seedIfEmpty.js"; export async function createApp(pool, options) { if (options?.seed !== false) { try { const client = await pool.connect(); try { await seedIfEmpty(client); } finally { client.release(); } } catch (err) { console.error('Seed check failed (non-fatal):', err); } } const uploadsRaw = process.env.UPLOADS_PATH || 'uploads'; const uploadsPath = isAbsolute(uploadsRaw) ? uploadsRaw : resolve(process.cwd(), uploadsRaw); try { mkdirSync(uploadsPath, { recursive: true }); } catch (err) { console.error(`Warning: could not create uploads directory "${uploadsPath}":`, err); } const gitReposRaw = process.env.GIT_REPOS_PATH || '.git-repos'; const gitReposPath = isAbsolute(gitReposRaw) ? gitReposRaw : resolve(process.cwd(), gitReposRaw); try { mkdirSync(gitReposPath, { recursive: true }); } catch (err) { console.error(`Warning: could not create git repos directory "${gitReposPath}":`, err); } const app = new Hono(); app.use('/*', async (c, next) => { c.set('uploadsPath', uploadsPath); c.set('gitReposPath', gitReposPath); await next(); }); app.use('/*', withDb(pool), establishAuth(), log()); app.all('/*', requirePathMatch(/^(.*)\.git(\/.*)?$/, authorize('Git Access'), git)); // GET: Document / Render editor page app.get('/*', documents, requirePathMatch(/^(.*)\/uploads\/([^/]+)$/, readUpload), editPage, requireQuery('style', assets), requireQuery('script', assets), notFoundPage, signupStateMiddleware, loginPage, authorize('Secure Area'), renderEditorPage); // POST: Handle file upload, redirect addition, document deletion, or preview rendering app.post('/*', editPage, signupStateMiddleware, requireQuery('login', loginPost), authorize('Secure Area'), requireQuery('logout', logoutPost), requireQuery('query', searchDocuments), requireQuery('update', updateFromArchive), requireQuery('fn', functionContextHandler), requireQuery('upload', uploadFile), requireQuery('redirect', addRedirectHandler), requireQuery('remove', deleteDocumentPost), requireQuery('whoami', whoami), previewRender); // DELETE: Handle upload, redirect, or document deletion app.delete('/*', editPage, authorize('Secure Area'), deleteUpload, deleteRedirect, deleteDocument); // PATCH: Handle upload updates (rename, toggle hidden) app.patch('/*', editPage, authorize('Secure Area'), requireQuery('uploadId', updateUploadHandler)); // 404 handler app.notFound(c => { return c.html('