spb/zyquo-cloud-web Public MIT
Zyquo Cloud Web — every cloud model, one beautiful chat, entirely in your browser.
TypeScript 81.9%
CSS 8.9%
JavaScript 7.5%
Shell 1.1%
HTML 0.6%
1/*2 * server.mjs3 * Zyquo Cloud Web4 *5 * Author: Simon-Pierre Boucher6 * Mail: contact@spboucher.ai7 *8 * Production static server (zero dependencies): serves the dist/ bundle with9 * security headers (CSP mirroring index.html, HSTS, nosniff, referrer10 * policy), immutable caching for hashed assets, no-cache for the HTML shell,11 * SPA fallback, and a /healthz endpoint. Run: node server.mjs [port] [dir]12 */1314import { createServer } from 'node:http'15import { createReadStream, existsSync, statSync } from 'node:fs'16import { extname, join, normalize, resolve } from 'node:path'1718const PORT = Number(process.argv[2] ?? process.env.PORT ?? 8080)19const ROOT = resolve(process.argv[3] ?? join(process.cwd(), 'dist'))2021const CSP = [22 "default-src 'self'",23 "script-src 'self'",24 "style-src 'self' 'unsafe-inline'",25 "img-src 'self' data: blob:",26 "font-src 'self' data:",27 "connect-src 'self' https://api.openai.com https://api.anthropic.com https://api.x.ai https://api.mistral.ai https://generativelanguage.googleapis.com https://dashscope-intl.aliyuncs.com https://api.deepseek.com https://api.moonshot.ai https://api.perplexity.ai https://api.together.xyz https://api.deepinfra.com https://api.cerebras.ai http://localhost:* http://127.0.0.1:*",28 "worker-src 'self'",29 "object-src 'none'",30 "base-uri 'self'",31 "form-action 'none'",32 "frame-ancestors 'none'",33].join('; ')3435const MIME = {36 '.html': 'text/html; charset=utf-8',37 '.js': 'text/javascript; charset=utf-8',38 '.css': 'text/css; charset=utf-8',39 '.json': 'application/json',40 '.svg': 'image/svg+xml',41 '.png': 'image/png',42 '.ico': 'image/x-icon',43 '.woff2': 'font/woff2',44 '.woff': 'font/woff',45 '.webmanifest': 'application/manifest+json',46 '.txt': 'text/plain; charset=utf-8',47 '.map': 'application/json',48}4950const server = createServer((req, res) => {51 const url = new URL(req.url ?? '/', 'http://localhost')52 let pathname = decodeURIComponent(url.pathname)5354 if (pathname === '/healthz') {55 res.writeHead(200, { 'Content-Type': 'text/plain' })56 res.end('ok')57 return58 }5960 // Resolve inside ROOT only (no traversal).61 let filePath = normalize(join(ROOT, pathname))62 if (!filePath.startsWith(ROOT)) {63 res.writeHead(403).end()64 return65 }66 if (!existsSync(filePath) || statSync(filePath).isDirectory()) {67 filePath = join(ROOT, 'index.html') // SPA fallback (also serves /)68 }6970 const ext = extname(filePath)71 const hashed = /\/assets\//.test(filePath) || /-\w{8,}\./.test(filePath)72 const headers = {73 'Content-Type': MIME[ext] ?? 'application/octet-stream',74 'Content-Security-Policy': CSP,75 'Strict-Transport-Security': 'max-age=63072000; includeSubDomains; preload',76 'X-Content-Type-Options': 'nosniff',77 'Referrer-Policy': 'no-referrer',78 'Permissions-Policy': 'camera=(), geolocation=(), payment=()',79 'Cache-Control':80 ext === '.html'81 ? 'no-cache'82 : hashed83 ? 'public, max-age=31536000, immutable'84 : 'public, max-age=3600',85 }86 res.writeHead(200, headers)87 createReadStream(filePath).pipe(res)88})8990server.listen(PORT, '0.0.0.0', () => {91 console.log(`Zyquo Cloud Web serving ${ROOT} on :${PORT}`)92})93