| 1 | // This is the main file for paperclover.net's server. |
| 2 | const app = new Hono(); |
| 3 | const console = log.scoped("http"); |
| 4 | |
| 5 | // Middleware |
| 6 | app.use(trimTrailingSlash()); |
| 7 | app.use(removeDuplicateSlashes); |
| 8 | app.use(logger((msg) => msg.startsWith("-->") && console.info(msg.slice(4)))); |
| 9 | app.use(admin.middleware); |
| 10 | |
| 11 | // Backends |
| 12 | app.route("", require("./blog/backend.ts").app); |
| 13 | app.route("", require("./q+a/backend.ts").app); |
| 14 | app.route("", require("./file-viewer/backend.ts").app); |
| 15 | app.route("", require("./friend-auth.ts").app); |
| 16 | app.route("", require("./backend-extra.ts").app); |
| 17 | |
| 18 | // Asset middleware has least precedence |
| 19 | app.use(assets.middleware); |
| 20 | |
| 21 | // Asset Aliases |
| 22 | app.get( |
| 23 | "/apple-touch-icon-precomposed.png", |
| 24 | (c) => assets.serveAsset(c, "/apple-touch-icon.png"), |
| 25 | ); |
| 26 | app.get( |
| 27 | "/apple-touch-icon-57x57.png", |
| 28 | (c) => assets.serveAsset(c, "/apple-touch-icon.png"), |
| 29 | ); |
| 30 | app.get( |
| 31 | "/apple-touch-icon-57x57-precomposed.png", |
| 32 | (c) => assets.serveAsset(c, "/apple-touch-icon.png"), |
| 33 | ); |
| 34 | |
| 35 | // Redirects |
| 36 | app.get( |
| 37 | "/hotewig-reanimated", |
| 38 | (c) => |
| 39 | c.redirect( |
| 40 | "https://docs.google.com/forms/d/e/1FAIpQLSdMdwotGKmrDYT8stYPm5uoOlmqZPLApYp8MuABDmcAwW6Fig/viewform?usp=header", |
| 41 | ), |
| 42 | ); |
| 43 | |
| 44 | // Handlers |
| 45 | app.notFound(assets.notFound); |
| 46 | |
| 47 | export default app; |
| 48 | |
| 49 | async function removeDuplicateSlashes(c: Context, next: Next) { |
| 50 | const path = c.req.path; |
| 51 | if (/\/\/+/.test(path)) { |
| 52 | const normalizedPath = path.replace(/\/\/+/g, "/"); |
| 53 | const query = c.req.query(); |
| 54 | const queryString = Object.keys(query).length > 0 |
| 55 | ? "?" + new URLSearchParams(query).toString() |
| 56 | : ""; |
| 57 | return c.redirect(normalizedPath + queryString, 301); |
| 58 | } |
| 59 | await next(); |
| 60 | } |
| 61 | |
| 62 | import * as assets from "#sitegen/assets"; |
| 63 | import * as log from "@clo/lib/log"; |
| 64 | import { type Context, Hono, type Next } from "hono"; |
| 65 | import { logger } from "hono/logger"; |
| 66 | import { trimTrailingSlash } from "hono/trailing-slash"; |
| 67 | import * as admin from "./admin.ts"; |
| 68 | import "./file-viewer/sync.ts"; |