diff --git a/internal/dev-entrypoint/cloud-web-runtime.mjs b/internal/dev-entrypoint/cloud-web-runtime.mjs index 9e66b3b2..1449fee4 100644 --- a/internal/dev-entrypoint/cloud-web-runtime.mjs +++ b/internal/dev-entrypoint/cloud-web-runtime.mjs @@ -52,7 +52,7 @@ export function createCloudWebServer({ } const routePath = url.pathname.replace(/\/+$/u, "") || "/"; - const relativePath = routePath === "/" || routePath === "/gate" || routePath === "/diagnostics/gate" || routePath === "/help" || routePath === "/skills" + const relativePath = routePath === "/" || routePath === "/gate" || routePath === "/diagnostics/gate" || routePath === "/help" || routePath === "/skills" || routePath === "/access" ? "index.html" : url.pathname.slice(1); for (const root of roots) { diff --git a/internal/dev-entrypoint/cloud-web-runtime.test.mjs b/internal/dev-entrypoint/cloud-web-runtime.test.mjs index fd314723..e96b7e6e 100644 --- a/internal/dev-entrypoint/cloud-web-runtime.test.mjs +++ b/internal/dev-entrypoint/cloud-web-runtime.test.mjs @@ -1,5 +1,8 @@ import assert from "node:assert/strict"; +import { mkdtemp, rm, writeFile } from "node:fs/promises"; import { createServer } from "node:http"; +import os from "node:os"; +import path from "node:path"; import test from "node:test"; import { createCloudWebServer } from "./cloud-web-runtime.mjs"; @@ -43,6 +46,36 @@ test("cloud web auth requests are proxied once", async () => { } }); +test("cloud web serves access deep link through the React shell", async () => { + const root = await mkdtemp(path.join(os.tmpdir(), "hwlab-cloud-web-runtime-")); + await writeFile(path.join(root, "index.html"), "
\n", "utf8"); + const cloudWeb = createCloudWebServer({ + serviceId: "hwlab-cloud-web", + roots: [root], + cloudApiBaseUrl: "http://127.0.0.1:1", + healthPayload: () => ({ status: "ok" }), + sendJson(response, statusCode, body) { + const payload = JSON.stringify(body); + response.writeHead(statusCode, { + "content-type": "application/json", + "content-length": Buffer.byteLength(payload) + }); + response.end(payload); + } + }); + await listen(cloudWeb); + + try { + const response = await fetch(`${serverUrl(cloudWeb)}/access`); + assert.equal(response.status, 200); + assert.equal(response.headers.get("content-type"), "text/html; charset=utf-8"); + assert.equal(await response.text(), "
\n"); + } finally { + await close(cloudWeb); + await rm(root, { recursive: true, force: true }); + } +}); + function listen(server) { return new Promise((resolve, reject) => { server.once("error", reject); diff --git a/web/hwlab-cloud-web/scripts/dist-contract.ts b/web/hwlab-cloud-web/scripts/dist-contract.ts index aa4549da..63277644 100644 --- a/web/hwlab-cloud-web/scripts/dist-contract.ts +++ b/web/hwlab-cloud-web/scripts/dist-contract.ts @@ -10,7 +10,7 @@ export const cloudWebDistBuildCommand = "cd web/hwlab-cloud-web && bun run build export const cloudWebDistFreshnessCommand = cloudWebDistBuildCommand; export const cloudWebAppSourceFiles = Object.freeze(["src/main.tsx", "src/App.tsx"]); export const cloudWebDistRuntimeFiles = Object.freeze(["index.html", "app.js", "assets/index.css", "assets/favicon.svg", "help.md"]); -export const cloudWebDistAliasFiles = Object.freeze(["gate/index.html", "diagnostics/gate/index.html", "help/index.html", "skills/index.html"]); +export const cloudWebDistAliasFiles = Object.freeze(["gate/index.html", "diagnostics/gate/index.html", "help/index.html", "skills/index.html", "access/index.html"]); type FreshnessStatus = "pass" | "blocked";