// server/cloudflare-site-bridge/src/index.ts // d3ro.chanpaca.net 한 도메인 아래 세 서비스를 잇는 브리지. // // /app, /app/* → 도메인 원본(Cloudflare Tunnel kd-nas) → NAS 웹앱(3002) // /api/*, /health → 도메인 원본(Cloudflare Tunnel kd-nas) → NAS API 서버(5050) // 그 밖 → 랜딩 사이트(site/, Cloudflare Pages) // // 경로 규칙의 정본은 packages/core/src/web-urls.ts 다. 터널 ingress가 path로 웹앱과 API를 나눈다. // 워커 안에서 같은 요청을 그대로 fetch 하면 워커를 다시 거치지 않고 도메인 원본(터널)으로 간다. // Pages 커스텀 도메인은 존 DNS에 CNAME을 요구해 d3ro 레코드(터널)와 충돌하므로, 이 워커가 // 랜딩을 Pages에서 가져온다. import { API_PATH_PREFIXES, WEB_APP_BASE_PATH } from '../../../packages/core/src/web-urls' const PAGES_ORIGIN = 'https://d3ro.pages.dev' const ORIGIN_PATH_PREFIXES: readonly string[] = [WEB_APP_BASE_PATH, ...API_PATH_PREFIXES] function servedByOrigin(pathname: string): boolean { return ORIGIN_PATH_PREFIXES.some((prefix) => pathname === prefix || pathname.startsWith(`${prefix}/`)) } async function fromPages(request: Request): Promise { const target = new URL(request.url) target.protocol = 'https:' target.hostname = new URL(PAGES_ORIGIN).hostname target.port = '' const headers = new Headers(request.headers) headers.delete('host') const hasBody = request.method !== 'GET' && request.method !== 'HEAD' return fetch(target.toString(), { method: request.method, headers, body: hasBody ? request.body : undefined, redirect: 'manual', }) } export default { async fetch(request: Request): Promise { const { pathname } = new URL(request.url) if (servedByOrigin(pathname)) return fetch(request) return fromPages(request) }, }