| 142 | } |
| 143 | |
| 144 | export function createDashboardDevConfig({ apiTarget, host, port }) { |
| 145 | return { |
| 146 | root: dashboardRoot, |
| 147 | source: { |
| 148 | entry: { index: "./dev/main.tsx" }, |
| 149 | }, |
| 150 | html: { |
| 151 | template: "./dev/index.html", |
| 152 | title: "tracedecay dashboard (dev)", |
| 153 | }, |
| 154 | server: { |
| 155 | host, |
| 156 | port, |
| 157 | proxy: { |
| 158 | "/api": { |
| 159 | target: apiTarget, |
| 160 | changeOrigin: true, |
| 161 | // Long-running backend calls (e.g. graph scans) can exceed the |
| 162 | // default proxy timeout; raise both the upstream connect/idle |
| 163 | // timeout and the response timeout so they aren't cut short. |
| 164 | proxyTimeout: 120000, |
| 165 | timeout: 120000, |
| 166 | // Surface upstream failures instead of letting them surface as an |
| 167 | // opaque 504. `res` is a ServerResponse for HTTP and a Socket for |
| 168 | // upgrade/websocket failures, so handle both shapes. |
| 169 | on: { |
| 170 | error(err, _req, res) { |
| 171 | console.error( |
| 172 | `tracedecay dev /api proxy error -> ${apiTarget}: ${err.message}`, |
| 173 | ); |
| 174 | if (res && typeof res.writeHead === "function") { |
| 175 | if (!res.headersSent) { |
| 176 | res.writeHead(502, { "Content-Type": "application/json" }); |
| 177 | res.end( |
| 178 | JSON.stringify({ |
| 179 | error: `dev proxy failed to reach ${apiTarget}`, |
| 180 | detail: err.message, |
| 181 | }), |
| 182 | ); |
| 183 | } |
| 184 | } else if (res && typeof res.destroy === "function") { |
| 185 | res.destroy(err); |
| 186 | } |
| 187 | }, |
| 188 | }, |
| 189 | }, |
| 190 | }, |
| 191 | }, |
| 192 | plugins: [pluginReact(), pluginTypeCheck()], |
| 193 | }; |
| 194 | } |
| 195 | |
| 196 | export async function runRsbuildConfig(rsbuildConfig) { |
| 197 | const rsbuild = await createRsbuild({ cwd: dashboardRoot, rsbuildConfig }); |