mirror of
https://github.com/wahyd4/heygo.git
synced 2026-08-09 05:15:52 +10:00
164 lines
6.4 KiB
TypeScript
164 lines
6.4 KiB
TypeScript
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<Response | null> {
|
|
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<Response> {
|
|
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<Env>;
|