import type { Env } from './env'; import { withPrivateNoStoreHeaders } from './lib/responses'; import { handleAuthApi } from './routes/api.auth'; import { handleDevAuth } from './routes/api.dev-auth'; import { handleLinksApi } from './routes/api.links'; import { handleNotificationsApi } from './routes/api.notifications'; import { handleOAuthApi } from './routes/api.oauth'; import { handleLinkGoRoute } from './routes/link-go'; import { handlePromotionsApi } from './routes/api.promotions'; import { handlePrivateShortlink, isHeygoPrivateHost } from './routes/private-redirect'; import { handlePublicShortlink, isHeygoPublicHost, isReservedPublicPath } from './routes/redirect'; export type { Env } from './env'; const jsonHeaders = { 'content-type': 'application/json; charset=utf-8', }; function json(body: unknown, init: ResponseInit = {}) { return Response.json(body, { ...init, headers: { ...jsonHeaders, ...init.headers, }, }); } function withPrivateHostNoStoreHeaders(url: URL, response: Response, privateHost: string): Response { return isHeygoPrivateHost(url.hostname, privateHost) ? withPrivateNoStoreHeaders(response) : response; } function isHtmlNavigationRequest(request: Request): boolean { const accept = request.headers.get('accept') ?? ''; const secFetchDest = request.headers.get('sec-fetch-dest') ?? ''; return accept.includes('text/html') || secFetchDest === 'document'; } function spaHashUrl(appBaseUrl: string, route: string): string { return `${appBaseUrl}/#${route}`; } function spaRedirectForAppPath(url: URL, appBaseUrl: string): Response | null { const pathname = url.pathname.replace(/\/+$/, '') || '/'; if (pathname === '/app') { return Response.redirect(spaHashUrl(appBaseUrl, '/'), 302); } if (pathname === '/app/private') { return Response.redirect(spaHashUrl(appBaseUrl, '/my-links'), 302); } if (pathname === '/app/login') { return Response.redirect(spaHashUrl(appBaseUrl, '/login'), 302); } if (pathname === '/app/dev-login') { return Response.redirect(spaHashUrl(appBaseUrl, '/dev-login'), 302); } if (pathname === '/app/admin') { return Response.redirect(spaHashUrl(appBaseUrl, '/admin'), 302); } if (pathname === '/app/profile') { return Response.redirect(spaHashUrl(appBaseUrl, '/profile'), 302); } if (pathname === '/app/settings') { return Response.redirect(spaHashUrl(appBaseUrl, '/settings'), 302); } return null; } async function serveSpaShell(request: Request, env: Env): Promise { if (!env.ASSETS) { return null; } const url = new URL(request.url); if (url.pathname.startsWith('/assets/')) { return env.ASSETS.fetch(request); } if (url.pathname !== '/' || !isHtmlNavigationRequest(request)) { return null; } const assetUrl = new URL('/index.html', url); return env.ASSETS.fetch(new Request(assetUrl, request)); } export default { async fetch(request, env, ctx): Promise { const url = new URL(request.url); const appPathRedirect = spaRedirectForAppPath(url, env.APP_BASE_URL); if (appPathRedirect) { return withPrivateHostNoStoreHeaders(url, appPathRedirect, env.PRIVATE_HOST); } const spaShellResponse = await serveSpaShell(request, env); if (spaShellResponse && isHeygoPublicHost(url.hostname, env.PUBLIC_HOST)) { return withPrivateHostNoStoreHeaders(url, spaShellResponse, env.PRIVATE_HOST); } if (url.pathname === '/api/health') { return withPrivateHostNoStoreHeaders(url, json({ ok: true, service: 'heygo-worker' }), env.PRIVATE_HOST); } if (url.pathname.startsWith('/api/')) { const oauthResponse = await handleOAuthApi(request, env); if (oauthResponse) { return withPrivateHostNoStoreHeaders(url, oauthResponse, env.PRIVATE_HOST); } const authResponse = await handleAuthApi(request, env); if (authResponse) { return withPrivateHostNoStoreHeaders(url, authResponse, env.PRIVATE_HOST); } const devAuthResponse = await handleDevAuth(request, env); if (devAuthResponse) { return withPrivateHostNoStoreHeaders(url, devAuthResponse, env.PRIVATE_HOST); } const apiResponse = await handleLinksApi(request, env); if (apiResponse) { return withPrivateHostNoStoreHeaders(url, apiResponse, env.PRIVATE_HOST); } const promotionsResponse = await handlePromotionsApi(request, env); if (promotionsResponse) { return withPrivateHostNoStoreHeaders(url, promotionsResponse, env.PRIVATE_HOST); } const notificationsResponse = await handleNotificationsApi(request, env); if (notificationsResponse) { return withPrivateHostNoStoreHeaders(url, notificationsResponse, env.PRIVATE_HOST); } return withPrivateHostNoStoreHeaders(url, json({ error: 'Not found' }, { status: 404 }), env.PRIVATE_HOST); } const linkGoResponse = await handleLinkGoRoute(request, env, ctx); if (linkGoResponse) { return withPrivateHostNoStoreHeaders(url, linkGoResponse, env.PRIVATE_HOST); } // In local dev (PUBLIC_HOST=*), public and private share the same host. // Try public first; if it returns 404 (alias not found), fall through to // private so authenticated users can resolve their personal shortlinks. // If private also returns 404, keep the original public 404 response. if (isHeygoPublicHost(url.hostname, env.PUBLIC_HOST) && !isReservedPublicPath(url.pathname)) { const publicResponse = await handlePublicShortlink(request, env, ctx); if (publicResponse.status !== 404) { return withPrivateHostNoStoreHeaders(url, publicResponse, env.PRIVATE_HOST); } // Public alias not found — try private route (for local dev with shared host) if (isHeygoPrivateHost(url.hostname, env.PRIVATE_HOST)) { const privateResponse = await handlePrivateShortlink(request, env, ctx); if (privateResponse.status !== 404) { return withPrivateHostNoStoreHeaders(url, privateResponse, env.PRIVATE_HOST); } } return withPrivateHostNoStoreHeaders(url, publicResponse, env.PRIVATE_HOST); } if (isHeygoPrivateHost(url.hostname, env.PRIVATE_HOST) && !isReservedPublicPath(url.pathname)) { return withPrivateHostNoStoreHeaders(url, await handlePrivateShortlink(request, env, ctx), env.PRIVATE_HOST); } return withPrivateHostNoStoreHeaders(url, json({ error: 'Not found' }, { status: 404 }), env.PRIVATE_HOST); }, } satisfies ExportedHandler;