diff --git a/README.md b/README.md index d02af57..7a2255f 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,8 @@ Every page on the site is a `.md` file in the root of this repository. There is ## How a page is served - `/` is `index.md`. `/manifesto` and `/manifesto.md` are both `manifesto.md`. A missing page is `404.md` with a 404 status. -- A browser (anything that sends `Accept: text/html`) gets `text/plain`, so the source displays inline instead of downloading. Everything else gets `text/markdown`. +- A browser (anything that sends `Accept: text/html`) gets the verbatim source in a `
`, with Markdown links and bare URLs made clickable, because plain text in a browser has no links. Nothing is rendered. Everything else gets raw `text/markdown`.
+- `/.html` redirects to the readm3.com render of that page.
 - Every response carries `Access-Control-Allow-Origin: *`, so a reader on any origin can fetch a page. That is what the **html** link at the bottom of each page relies on: it hands the file to [readm3.com](https://readm3.com), which renders it in the browser.
 - Only `.md` files are served. Dotfiles, the server, this README's neighbours in `.github`: none of it is reachable.
 - `www.` redirects to the apex.
diff --git a/index.md b/index.md
index dac4c32..4bde117 100644
--- a/index.md
+++ b/index.md
@@ -12,7 +12,7 @@ More documents land here as they get written.
 
 Every page is a Markdown file and nothing else. No HTML, no JavaScript, no build step.
 
-Read it here as text, fetch it with curl, pipe it through readm3, or click **html** at the bottom of any page to render it with readm3.com.
+In a browser you see the source as written, links included. Fetch it with curl, pipe it through readm3, or click **html** at the bottom of any page to render it with readm3.com. Swapping `.md` for `.html` in the address does the same.
 
     curl https://fleetsysops.com/manifesto.md
     curl -s https://fleetsysops.com/manifesto.md | npx @profullstack/readm3 --print
diff --git a/server.test.ts b/server.test.ts
index 082c675..94186b1 100644
--- a/server.test.ts
+++ b/server.test.ts
@@ -1,7 +1,7 @@
 import { describe, expect, test } from "bun:test";
 import { readdirSync, readFileSync, statSync } from "node:fs";
 import { join, relative } from "node:path";
-import { handle, resolve, root, SITE } from "./server.ts";
+import { browserPage, handle, resolve, root, SITE } from "./server.ts";
 
 const get = (path: string, init: RequestInit & { host?: string } = {}) => {
   const { host, ...rest } = init;
@@ -20,11 +20,30 @@ describe("the Markdown server", () => {
     expect(await response.text()).toStartWith("# Fleet SysOps");
   });
 
-  test("gives a browser text/plain so the source displays instead of downloading", async () => {
+  test("gives a browser the verbatim source in a 
 with the links clickable", async () => {
     const response = get("/manifesto.md", { headers: { accept: "text/html,application/xhtml+xml,*/*;q=0.8" } });
     expect(response.status).toBe(200);
-    expect(response.headers.get("content-type")).toBe("text/plain; charset=utf-8");
-    expect(await response.text()).toContain("We test in prod.");
+    expect(response.headers.get("content-type")).toBe("text/html; charset=utf-8");
+    const html = await response.text();
+    expect(html).toContain("
");
+    expect(html).toContain("- We test in prod.");
+    expect(html).toContain('[html](https://readm3.com/viewer?url=https://fleetsysops.com/manifesto.md)');
+    expect(html).toContain("manifesto.md · fleetsysops.com");
+  });
+
+  test("escapes the source in the browser view and links bare URLs", () => {
+    const html = browserPage("# T\n\n see https://example.com/a?b=1 and [x](/y.md).", "t.md");
+    expect(html).not.toContain("