// Production server for the Xpress developer docs. // // What this does: // 1. Reads HASURA_ADMIN_SECRET from .env.local (server-side, never bundled). // 2. Proxies /api/* requests to https://api.workolik.com/api/*, injecting // the x-hasura-admin-secret header on the way out. // 3. Serves the built React app from dist/ (SPA fallback to index.html). // // The browser never receives the secret. To run: // npm run build # builds dist/ // npm start # starts this server on PORT (default 3000) import express from 'express' import { createProxyMiddleware } from 'http-proxy-middleware' import { fileURLToPath } from 'node:url' import path from 'node:path' import 'dotenv/config' const __dirname = path.dirname(fileURLToPath(import.meta.url)) const PORT = Number(process.env.PORT) || 3000 const SECRET = (process.env.HASURA_ADMIN_SECRET || '').trim() const TARGET = 'https://api.workolik.com' if (!SECRET) { console.warn('[xpress-docs] WARNING: HASURA_ADMIN_SECRET is not set. Proxied API calls will be sent without auth.') } const app = express() app.use('/api', createProxyMiddleware({ target: TARGET, changeOrigin: true, secure: true, // The mount strips '/api' from req.url; add it back so the target URL // stays /api/rest/... pathRewrite: (p) => '/api' + p, on: { proxyReq: (proxyReq) => { if (SECRET) proxyReq.setHeader('x-hasura-admin-secret', SECRET) }, error: (err, _req, res) => { console.error('[xpress-docs] proxy error:', err.message) if (!res.headersSent) { res.writeHead(502, { 'Content-Type': 'application/json' }) } res.end(JSON.stringify({ error: 'proxy_error', message: err.message })) } } })) // Built React app const distDir = path.join(__dirname, 'dist') app.use(express.static(distDir)) app.get('*', (_req, res) => { res.sendFile(path.join(distDir, 'index.html')) }) app.listen(PORT, () => { console.log(`[xpress-docs] listening on http://localhost:${PORT}`) console.log(`[xpress-docs] proxying /api/* -> ${TARGET}/api/*`) console.log(`[xpress-docs] admin secret: ${SECRET ? 'loaded' : 'NOT SET'}`) })