Files
heygo/worker/lib/responses.ts
T
Hermes Agent e4fbbaec14 feat: add terraform IaC, dev/prod environments, and multi-host worker support
- Terraform configs for D1 databases, KV namespaces, Worker custom domains
- wrangler.dev.jsonc and wrangler.prod.jsonc for environment-specific deployments
- Worker code refactored to use env vars for host checking (PUBLIC_HOST, PRIVATE_HOST)
- Configurable app URLs and cookie domain via env vars
- Deploy and migrate npm scripts for dev/prod
- Updated all tests with new env fixtures
- Deployment guide in README
2026-06-20 14:26:56 +10:00

103 lines
3.5 KiB
TypeScript

export function htmlResponse(body: string, init: ResponseInit = {}): Response {
const headers = new Headers(init.headers);
if (!headers.has('content-type')) {
headers.set('content-type', 'text/html; charset=utf-8');
}
return new Response(body, {
...init,
headers,
});
}
function withCookieVary(headers: Headers): Headers {
const vary = headers.get('vary');
const varies = vary?.split(',').map((value) => value.trim().toLowerCase()) ?? [];
if (!varies.includes('cookie')) {
headers.set('vary', vary ? `${vary}, Cookie` : 'Cookie');
}
return headers;
}
function privateNoStoreHeaders(headersInit?: HeadersInit): Headers {
const headers = new Headers(headersInit);
headers.set('cache-control', 'no-store');
return withCookieVary(headers);
}
export function withPrivateNoStoreHeaders(response: Response): Response {
return new Response(response.body, {
status: response.status,
statusText: response.statusText,
headers: privateNoStoreHeaders(response.headers),
});
}
export function privateHtmlResponse(body: string, init: ResponseInit = {}): Response {
return htmlResponse(body, {
...init,
headers: privateNoStoreHeaders(init.headers),
});
}
export function privateRedirectResponse(location: string, status = 302): Response {
return new Response(null, {
status,
headers: privateNoStoreHeaders({ location }),
});
}
export function publicNotFoundResponse(): Response {
return htmlResponse(
'<!doctype html><html lang="en"><head><meta charset="utf-8"><title>Not found</title></head><body><h1>Not found</h1><p>This short link does not exist.</p></body></html>',
{ status: 404 },
);
}
export function publicBadRequestResponse(message = 'Invalid short link'): Response {
return htmlResponse(
`<!doctype html><html lang="en"><head><meta charset="utf-8"><title>Invalid short link</title></head><body><h1>Invalid short link</h1><p>${escapeHtml(message)}</p></body></html>`,
{ status: 400 },
);
}
/**
* Build the app login URL for a given environment's APP_BASE_URL.
* Kept as a function (not a constant) so each deployment's base URL is honored.
*/
export function privateLoginUrl(appBaseUrl: string): string {
return `${appBaseUrl}/app/login`;
}
/**
* Build the private links app URL for a given environment's APP_BASE_URL.
*/
export function privateAppUrl(appBaseUrl: string): string {
return `${appBaseUrl}/app/private`;
}
export function privateLoginRequiredResponse(appBaseUrl: string): Response {
const loginUrl = privateLoginUrl(appBaseUrl);
return privateHtmlResponse(
`<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>Login required</title></head><body><h1>Not found</h1><p><a href="${loginUrl}">Login to use your private links</a>.</p></body></html>`,
{ status: 404 },
);
}
export function privateAliasNotFoundResponse(appBaseUrl: string): Response {
const appUrl = privateAppUrl(appBaseUrl);
return privateHtmlResponse(
`<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>Not found</title></head><body><h1>Not found</h1><p>This private link does not exist.</p><p><a href="${appUrl}">Create this private link</a>.</p></body></html>`,
{ status: 404 },
);
}
export function escapeHtml(value: string): string {
return value
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;');
}