/**
* Gateway-served one-time credential entry page.
*
* Velay-tunneled deployments have no SPA server behind the tunnel (Velay only
* proxies allowlisted paths to the gateway, and the gateway serves no web
* bundle), so the React entry page in `clients/web` is unreachable there.
* This route serves a SELF-CONTAINED static page instead — inline CSS/JS, no
* external assets — following the `oauth-callback.ts` static-page pattern.
* nginx-fronted deployments never hit this route: nginx serves the SPA for
* `/assistant/*` paths, so the React page wins there.
*
* SECURITY:
* - The single-use token rides the URL FRAGMENT (`#token=`), which browsers
* never send over HTTP — this handler never sees it. The inline script
* reads it, strips it from history, and sends it only in POST bodies to
* the peek/submit routes (which validate it server-side).
* - The page template is fully static: no request data is interpolated, and
* all dynamic content is rendered client-side via `textContent`.
*/
const PAGE_HTML = `
Provide a credential
One-time credential link
Checking this link…
Credential saved
The value is stored in the assistant's encrypted vault. This link has now been used and can't be opened again — you can close this tab.
Invalid link
This credential link isn't valid — it may have expired long ago, been replaced, or been copied incompletely when it was shared. Ask for a new link if a value still needs to be provided.
Link expired
This credential link has expired. Ask for a new one and use it within its validity window.
Link already used
Each link works exactly once. Ask for a new one if the value still needs to be provided.
Link no longer valid
The assistant could not store the credential, and for safety this one-time link cannot be reused. Ask for a new link and try again there.
`;
export function handleCredentialEntryPage(req: Request): Response {
if (req.method !== "GET") {
return new Response("method not allowed", {
status: 405,
headers: { Allow: "GET" },
});
}
return new Response(PAGE_HTML, {
headers: {
"Content-Type": "text/html; charset=utf-8",
"Cache-Control": "no-store",
"Referrer-Policy": "no-referrer",
"X-Content-Type-Options": "nosniff",
},
});
}