diff --git a/index.html b/index.html
index 168c85b..f885722 100644
--- a/index.html
+++ b/index.html
@@ -31,6 +31,7 @@
+
Share HTML — upload one HTML file, get a sandboxed shareable link
Upload a single self-contained HTML file and get a public, sandboxed preview URL. No signup required; anonymous uploads are kept for 365 days.
@@ -39,6 +40,7 @@ Use it programmatically
# returns JSON: { "share": { "share_url", "preview_url", "slug", "id" }, "claimToken" }
Full API: /openapi.json · AI guide: /llms.txt · MCP: /mcp
+
`;
const html = await response.text();
- const injected = html.replace("", `${configScript}`);
+ const bodyAdjusted = routeFallbackHtml(html, request);
+ const injected = bodyAdjusted.replace("", `${configScript}`);
return new Response(injected, {
status: response.status,
statusText: response.statusText,
@@ -172,6 +173,37 @@ async function injectConfig(response: Response, env: Env): Promise {
});
}
+function routeFallbackHtml(html: string, request: Request): string {
+ const pathname = new URL(request.url).pathname;
+ if (!isShareRoute(pathname)) return html;
+ return replaceAppFallback(html, shareRouteFallback());
+}
+
+function isShareRoute(pathname: string): boolean {
+ return /^\/s\/[^/]+\/?$/.test(pathname);
+}
+
+function replaceAppFallback(html: string, replacement: string): string {
+ const startMarker = "";
+ const endMarker = "";
+ const start = html.indexOf(startMarker);
+ const end = html.indexOf(endMarker);
+ if (start === -1 || end === -1 || end < start) return html;
+
+ const contentStart = start + startMarker.length;
+ return `${html.slice(0, contentStart)}\n${replacement}\n ${html.slice(end)}`;
+}
+
+function shareRouteFallback(): string {
+ return [
+ ' ',
+ ' ',
+ ' Loading share...
',
+ " ",
+ " ",
+ ].join("\n");
+}
+
function discoveryRoute(request: Request, url: URL): Response | null {
if (request.method !== "GET" && request.method !== "HEAD") {
return null;
@@ -308,4 +340,3 @@ export type { AuthUser } from "./auth.ts";
export { cleanTitle, sanitizeShortText, looksLikeHtml, isUploadFile, getClientIp, sha256Hex, hashText, base64Url, numberEnv, formatBytes, escapeHtml, errorMessage, logBackgroundError } from "./utils.ts";
export { maxUploadBytes, appOrigin, previewOrigin } from "./config.ts";
export { createShare, createShareRecord, checkUploadRate, listMyShares, getPublicShare, reportShare, claimShare, deleteShare, listReports, moderateShare, previewShare, previewHeaders, previewMessage } from "./shares.ts";
-
diff --git a/tests/worker-index.test.ts b/tests/worker-index.test.ts
new file mode 100644
index 0000000..588f88b
--- /dev/null
+++ b/tests/worker-index.test.ts
@@ -0,0 +1,69 @@
+import assert from "node:assert/strict";
+import { test, vi } from "vitest";
+
+import worker from "../src/worker/index.ts";
+
+const INDEX_HTML = `
+
+
+ Share HTML
+
+
+
+
+
+ Share HTML — upload one HTML file, get a sandboxed shareable link
+
+
+
+
+
+`;
+
+function makeEnv() {
+ return {
+ SUPABASE_URL: "https://proj.supabase.co",
+ SUPABASE_PUBLISHABLE_KEY: "publishable-key",
+ ASSETS: {
+ fetch: vi.fn(async () => new Response(INDEX_HTML, {
+ headers: { "content-type": "text/html" },
+ })),
+ },
+ } as any;
+}
+
+function makeCtx() {
+ return { waitUntil: vi.fn() } as any;
+}
+
+test("worker fetch: share SPA fallback does not expose homepage copy before React renders", async () => {
+ const env = makeEnv();
+ const response = await worker.fetch(
+ new Request("https://sharehtml.zhenjia.dev/s/example"),
+ env,
+ makeCtx()
+ );
+
+ assert.equal(response.status, 200);
+ const html = await response.text();
+
+ assert.ok(html.includes("Loading share..."));
+ assert.ok(!html.includes("Share HTML — upload one HTML file"));
+ assert.ok(html.includes("window.__APP_CONFIG__"));
+});
+
+test("worker fetch: homepage SPA fallback keeps agent-readable static copy", async () => {
+ const env = makeEnv();
+ const response = await worker.fetch(
+ new Request("https://sharehtml.zhenjia.dev/"),
+ env,
+ makeCtx()
+ );
+
+ assert.equal(response.status, 200);
+ const html = await response.text();
+
+ assert.ok(html.includes("Share HTML — upload one HTML file"));
+ assert.ok(!html.includes("Loading share..."));
+ assert.ok(html.includes("window.__APP_CONFIG__"));
+});