(
targetPort: number,
projectCwd?: string,
isFresh?: () => boolean,
getComparisonPhase?: () => ComparisonPhase | null
)
| 28 | * and injects the Awel host script into HTML responses. |
| 29 | */ |
| 30 | export function createProxyMiddleware( |
| 31 | targetPort: number, |
| 32 | projectCwd?: string, |
| 33 | isFresh?: () => boolean, |
| 34 | getComparisonPhase?: () => ComparisonPhase | null |
| 35 | ) { |
| 36 | return async (c: any, _next: () => Promise<void>) => { |
| 37 | const url = new URL(c.req.url); |
| 38 | const comparisonPhase = getComparisonPhase?.(); |
| 39 | |
| 40 | // Serve creation mode dashboard when fresh AND not in comparing phase. |
| 41 | // In comparing phase, show the actual app with the comparison overlay instead. |
| 42 | if (isFresh?.() && comparisonPhase !== 'comparing') { |
| 43 | const accept = c.req.header('accept') || ''; |
| 44 | const isNavigation = accept.includes('text/html'); |
| 45 | if (isNavigation) { |
| 46 | const html = getCreationModeHtml(); |
| 47 | if (html) { |
| 48 | return new Response(html, { |
| 49 | status: 200, |
| 50 | headers: { 'Content-Type': 'text/html; charset=utf-8' }, |
| 51 | }); |
| 52 | } |
| 53 | } |
| 54 | } |
| 55 | |
| 56 | const targetUrl = `http://localhost:${targetPort}${url.pathname}${url.search}`; |
| 57 | |
| 58 | try { |
| 59 | // Clone headers and remove Accept-Encoding to get uncompressed response |
| 60 | const headers = new Headers(c.req.raw.headers); |
| 61 | headers.delete('accept-encoding'); |
| 62 | |
| 63 | const response = await fetch(targetUrl, { |
| 64 | method: c.req.method, |
| 65 | headers, |
| 66 | body: c.req.method !== 'GET' && c.req.method !== 'HEAD' |
| 67 | ? await c.req.raw.arrayBuffer() |
| 68 | : undefined, |
| 69 | }); |
| 70 | |
| 71 | // Handle null body status codes (204, 304, etc.) - pass through without body |
| 72 | const nullBodyStatuses = [101, 204, 205, 304]; |
| 73 | if (nullBodyStatuses.includes(response.status)) { |
| 74 | return new Response(null, { |
| 75 | status: response.status, |
| 76 | headers: response.headers, |
| 77 | }); |
| 78 | } |
| 79 | |
| 80 | const contentType = response.headers.get('content-type') || ''; |
| 81 | |
| 82 | // If it's HTML, inject the Awel host script |
| 83 | if (contentType.includes('text/html')) { |
| 84 | let html = await response.text(); |
| 85 | |
| 86 | // Inject project CWD (for source-map resolution) and the host script |
| 87 | const cwdScript = projectCwd |
no test coverage detected