80 lines
2.5 KiB
JavaScript
80 lines
2.5 KiB
JavaScript
// 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 || 'nearle-admin-secret').trim()
|
|
const TARGET_LEGACY = 'https://api.workolik.com'
|
|
const TARGET_REST = 'https://jupiter.nearle.app'
|
|
|
|
if (!SECRET) {
|
|
console.warn('[xpress-docs] WARNING: HASURA_ADMIN_SECRET is not set. Proxied API calls will be sent without auth.')
|
|
}
|
|
|
|
const app = express()
|
|
|
|
const commonProxyOptions = {
|
|
changeOrigin: true,
|
|
secure: true,
|
|
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 }))
|
|
}
|
|
}
|
|
}
|
|
|
|
app.use('/api', createProxyMiddleware({
|
|
...commonProxyOptions,
|
|
target: TARGET_LEGACY,
|
|
pathRewrite: (p) => '/api' + p
|
|
}))
|
|
|
|
app.use('/live', createProxyMiddleware({
|
|
...commonProxyOptions,
|
|
target: TARGET_REST,
|
|
pathRewrite: (p) => '/live' + p
|
|
}))
|
|
|
|
app.use('/v1', createProxyMiddleware({
|
|
...commonProxyOptions,
|
|
target: TARGET_LEGACY,
|
|
pathRewrite: (p) => '/v1' + p
|
|
}))
|
|
|
|
// 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_LEGACY}/api/*`)
|
|
console.log(`[xpress-docs] proxying /live/* -> ${TARGET_REST}/live/*`)
|
|
console.log(`[xpress-docs] proxying /v1/* -> ${TARGET_LEGACY}/v1/*`)
|
|
console.log(`[xpress-docs] admin secret: ${SECRET ? 'loaded' : 'NOT SET'}`)
|
|
})
|