summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rwxr-xr-xbun.lockbbin2386 -> 3923 bytes
-rw-r--r--package.json3
-rw-r--r--src/index.ts71
-rw-r--r--test/index.test.ts12
4 files changed, 72 insertions, 14 deletions
diff --git a/bun.lockb b/bun.lockb
index c8b2651..e8b79d3 100755
--- a/bun.lockb
+++ b/bun.lockb
Binary files differdiff --git a/package.json b/package.json
index 27f95e0..0eb65a3 100644
--- a/package.json
+++ b/package.json
@@ -2,6 +2,7 @@
   "name": "homestead",
   "module": "src/index.ts",
   "devDependencies": {
+    "@types/contains-path": "^1.0.2",
     "bun-html-live-reload": "^0.1.1",
     "bun-types": "latest"
   },
@@ -10,7 +11,7 @@
   },
   "type": "module",
   "dependencies": {
-    "serve-static-bun": "^0.5.3",
+    "contains-path": "^1.0.0",
     "toml": "^3.0.0"
   }
 }
\ No newline at end of file
diff --git a/src/index.ts b/src/index.ts
index d8c9bf1..ec1c296 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,16 +1,75 @@
 import path from "node:path";
+import fs, { Stats } from "node:fs";
+import fsp from "node:fs/promises";
+import util from "node:util";
+
 import { withHtmlLiveReload } from "bun-html-live-reload";
-import serveStatic from "serve-static-bun";
+import containsPath from "contains-path";
 
 import readConfig from "./config";
 
-const base = Bun.argv.length > 2 ? Bun.argv[Bun.argv.length - 1] : ".";
+const base = "../website/";
+const publicDir = path.resolve(base, "public") + path.sep;
 
 const config = readConfig(base);
+const defaultHeaders = config.extra.headers;
+
+function getFilename(name: string): string {
+  return path.join(publicDir, `${name}`);
+}
+
+let files: Map<string, any> = new Map();
+
+function registerFile(pathname: string, absPath: string, stat: Stats): void {
+  pathname = "/" + (pathname === "." || pathname === "./" ? "" : pathname);
+
+  if (files.get(pathname) !== undefined) {
+    console.warn("File already registered:", pathname);
+  }
+  files.set(pathname, {
+    filename: absPath,
+    size: stat.size,
+    mtime: stat.mtime.toUTCString(),
+  });
+}
+
+function walkDirectory(root: string, dir: string) {
+  const absDir = path.join(root, dir);
+  for (let pathname of fs.readdirSync(absDir)) {
+    const relPath = path.join(dir, pathname);
+    const absPath = path.join(absDir, pathname);
+    const stat = fs.statSync(absPath);
+    if (stat.isDirectory()) {
+      walkDirectory(root, relPath + path.sep);
+    } else if (stat.isFile()) {
+      if (pathname === "index.html") {
+        registerFile(path.dirname(relPath), absPath, stat);
+        registerFile(path.dirname(relPath) + path.sep, absPath, stat);
+      }
+      registerFile(relPath, absPath, stat);
+    }
+  }
+}
+
+walkDirectory(publicDir, "");
 
 export default withHtmlLiveReload({
-  fetch: serveStatic(path.join(base, "public"), {
-    headers: config.extra.headers,
-    dotfiles: "allow",
-  }),
+  fetch: async function (request) {
+    const pathname = new URL(request.url).pathname;
+    if (files.has(pathname)) {
+      const file = files.get(pathname);
+      console.info("filename", file.filename);
+      return new Response(Bun.file(file.filename), {
+        headers: defaultHeaders,
+        status: 200,
+      });
+    }
+    return new Response(Bun.file(getFilename("404.html")), {
+      headers: Object.assign({}, defaultHeaders, {
+        "cache-control": "max-age=5, no-cache",
+      }),
+      status: 404,
+      statusText: "Not Found",
+    });
+  },
 });
diff --git a/test/index.test.ts b/test/index.test.ts
index 234bd1e..c1f5f64 100644
--- a/test/index.test.ts
+++ b/test/index.test.ts
@@ -15,14 +15,12 @@ afterAll(function () {
   server.stop();
 });
 
-test("/status returns 200 OK", async function () {
-  const res = await fetch(new URL("/status", base));
+test("/ returns 200", async function () {
+  const res = await fetch(base);
   expect(res.status).toBe(200);
-  expect(await res.text()).toBe("OK");
 });
 
-test("/ returns 200 and says Hello world", async function () {
-  const res = await fetch(base);
-  expect(res.status).toBe(200);
-  expect(await res.text()).toBe("Hello world");
+test("/asdf returns 404", async function () {
+  const res = await fetch(`${base}asdf`);
+  expect(res.status).toBe(404);
 });