From c3e10559c70b39e8977cf43a393364ded7e63096 Mon Sep 17 00:00:00 2001 From: Chris Wanstrath <2+defunkt@users.noreply.github.com> Date: Mon, 15 Sep 2025 14:03:07 -0700 Subject: [PATCH] webapp basics --- nose/app/hello.ts | 2 ++ nose/app/ping.ts | 2 ++ nose/bin/hello.ts | 3 +++ nose/global.d.ts | 6 ++++++ src/config.ts | 6 ++++++ src/js/.gitignore | 0 src/server.ts | 14 ++++++++++++-- src/webapp.ts | 25 +++++++++++++++++++++++++ 8 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 nose/app/hello.ts create mode 100644 nose/app/ping.ts create mode 100644 nose/bin/hello.ts create mode 100644 nose/global.d.ts create mode 100644 src/config.ts create mode 100644 src/js/.gitignore create mode 100644 src/webapp.ts diff --git a/nose/app/hello.ts b/nose/app/hello.ts new file mode 100644 index 0000000..b0eca04 --- /dev/null +++ b/nose/app/hello.ts @@ -0,0 +1,2 @@ +export default (c: Context) => + c.text("Hello, world!") \ No newline at end of file diff --git a/nose/app/ping.ts b/nose/app/ping.ts new file mode 100644 index 0000000..f6946da --- /dev/null +++ b/nose/app/ping.ts @@ -0,0 +1,2 @@ +export default (c: Context) => + c.text("pong") \ No newline at end of file diff --git a/nose/bin/hello.ts b/nose/bin/hello.ts new file mode 100644 index 0000000..b02821f --- /dev/null +++ b/nose/bin/hello.ts @@ -0,0 +1,3 @@ +export default function (): string { + return "Hello, world!" +} \ No newline at end of file diff --git a/nose/global.d.ts b/nose/global.d.ts new file mode 100644 index 0000000..8f530a9 --- /dev/null +++ b/nose/global.d.ts @@ -0,0 +1,6 @@ +// src/global.d.ts +import type { Context as HonoContext } from "hono" + +declare global { + type Context = HonoContext +} \ No newline at end of file diff --git a/src/config.ts b/src/config.ts new file mode 100644 index 0000000..1ad059a --- /dev/null +++ b/src/config.ts @@ -0,0 +1,6 @@ +import { resolve, join } from "node:path" + +export const NOSE_ICON = ` ͡° ͜ʖ ͡°` +export const NOSE_DIR = resolve("./nose") +export const NOSE_BIN = resolve(join(NOSE_DIR, "bin")) +export const NOSE_APP = resolve(join(NOSE_DIR, "app")) \ No newline at end of file diff --git a/src/js/.gitignore b/src/js/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/src/server.ts b/src/server.ts index ad20a6f..2edb094 100644 --- a/src/server.ts +++ b/src/server.ts @@ -3,9 +3,9 @@ import { serveStatic } from "hono/bun" import { prettyJSON } from "hono/pretty-json" import color from "kleur" +import { NOSE_ICON, NOSE_DIR, NOSE_BIN, NOSE_APP } from "./config" import { transpile, isFile } from "./utils" - -export const NOSE_ICON = ` ͡° ͜ʖ ͡°` +import { serveApp } from "./webapp" // // Hono setup @@ -43,7 +43,13 @@ app.get("/js/:path{.+}", async c => { // app routes // +app.get("*", async c => { + const url = new URL(c.req.url) + const domains = url.hostname.split(".") + const subdomain = domains.length > 1 ? domains[0]! : "none" + return await serveApp(c, subdomain) +}) // // server shutdown @@ -70,9 +76,13 @@ for (const sig of ["SIGINT", "SIGTERM"] as const) { // console.log(color.cyan(NOSE_ICON)) +console.log(color.blue("NOSE_DIR:"), color.yellow(NOSE_DIR)) +console.log(color.blue("NOSE_BIN:"), color.yellow(NOSE_BIN)) +console.log(color.blue("NOSE_APP:"), color.yellow(NOSE_APP)) export default { port: process.env.PORT || 3000, + hostname: "0.0.0.0", fetch: app.fetch, idleTimeout: 0, } \ No newline at end of file diff --git a/src/webapp.ts b/src/webapp.ts new file mode 100644 index 0000000..20ba8e2 --- /dev/null +++ b/src/webapp.ts @@ -0,0 +1,25 @@ +import type { Context } from "hono" +import { join } from "node:path" +import { NOSE_APP } from "./config" +import { isFile } from "./utils" + +export async function serveApp(c: Context, subdomain: string): Promise { + const app = await findApp(subdomain) + + if (app) + return app(c) + + return c.text(`App Not Found: ${subdomain}`, 404) +} + +async function findApp(name: string): Promise<((r: Context) => Response) | undefined> { + const path = join(NOSE_APP, `${name}.ts`) + + if (isFile(path)) { + const mod = await import(path + `?t=${Date.now()}`) + if (mod?.default) + return mod.default as (r: Context) => Response + } + + console.error("can't find app:", name) +}