Spaces:
Running
Running
| import fs from 'node:fs/promises'; | |
| import path from 'node:path'; | |
| import { gzipSync } from 'node:zlib'; | |
| const mimeTypes = new Map([ | |
| ['.html', 'text/html; charset=utf-8'], | |
| ['.js', 'text/javascript; charset=utf-8'], | |
| ['.css', 'text/css; charset=utf-8'], | |
| ['.json', 'application/json; charset=utf-8'], | |
| ['.webmanifest', 'application/manifest+json; charset=utf-8'], | |
| ['.svg', 'image/svg+xml'], | |
| ['.png', 'image/png'], | |
| ['.jpg', 'image/jpeg'], | |
| ['.jpeg', 'image/jpeg'], | |
| ['.webp', 'image/webp'], | |
| ['.ico', 'image/x-icon'] | |
| ]); | |
| const compressibleExtensions = new Set(['.html', '.js', '.css', '.json', '.webmanifest', '.svg']); | |
| function sendText(res, status, text, headers = {}) { | |
| const body = Buffer.from(String(text || '')); | |
| res.writeHead(status, { | |
| 'content-type': 'text/plain; charset=utf-8', | |
| 'content-length': body.length, | |
| ...headers | |
| }); | |
| res.end(body); | |
| } | |
| function acceptsGzip(req) { | |
| return /\bgzip\b/i.test(req.headers['accept-encoding'] || ''); | |
| } | |
| function staticCacheControl(ext, filePath = '') { | |
| if (ext === '.html') { | |
| return 'no-store'; | |
| } | |
| return filePath.split(path.sep).join('/').includes('/assets/') | |
| ? 'public, max-age=31536000, immutable' | |
| : 'public, max-age=3600'; | |
| } | |
| function sendStaticContent(req, res, status, content, headers, ext) { | |
| let body = content; | |
| const nextHeaders = { ...headers }; | |
| if (content.length >= 1024 && compressibleExtensions.has(ext) && acceptsGzip(req)) { | |
| body = gzipSync(content); | |
| nextHeaders['content-encoding'] = 'gzip'; | |
| nextHeaders.vary = nextHeaders.vary ? `${nextHeaders.vary}, Accept-Encoding` : 'Accept-Encoding'; | |
| } | |
| nextHeaders['content-length'] = body.length; | |
| res.writeHead(status, nextHeaders); | |
| res.end(body); | |
| } | |
| export async function serveStatic(req, res, url, clientDist) { | |
| let requestedPath = ''; | |
| try { | |
| requestedPath = decodeURIComponent(url.pathname); | |
| } catch { | |
| sendText(res, 400, 'Bad request'); | |
| return; | |
| } | |
| if (requestedPath === '/') { | |
| requestedPath = '/index.html'; | |
| } | |
| const candidate = path.normalize(path.join(clientDist, requestedPath)); | |
| if (candidate !== clientDist && !candidate.startsWith(`${clientDist}${path.sep}`)) { | |
| sendText(res, 403, 'Forbidden'); | |
| return; | |
| } | |
| try { | |
| const stat = await fs.stat(candidate); | |
| const filePath = stat.isDirectory() ? path.join(candidate, 'index.html') : candidate; | |
| const ext = path.extname(filePath); | |
| const content = await fs.readFile(filePath); | |
| sendStaticContent(req, res, 200, content, { | |
| 'content-type': mimeTypes.get(ext) || 'application/octet-stream', | |
| 'cache-control': staticCacheControl(ext, filePath), | |
| 'x-content-type-options': 'nosniff' | |
| }, ext); | |
| } catch { | |
| await serveStaticFallback(req, res, clientDist); | |
| } | |
| } | |
| async function serveStaticFallback(req, res, clientDist) { | |
| const indexPath = path.join(clientDist, 'index.html'); | |
| try { | |
| const content = await fs.readFile(indexPath); | |
| sendStaticContent(req, res, 200, content, { | |
| 'content-type': 'text/html; charset=utf-8', | |
| 'cache-control': 'no-store', | |
| 'x-content-type-options': 'nosniff' | |
| }, '.html'); | |
| } catch { | |
| sendText(res, 200, 'CodexMobile relay is running. Build the PWA with: npm run build'); | |
| } | |
| } | |