()
| 37 | /* Run `src`, streaming each raw stdout chunk to `onChunk`. `onPhase` reports 'runtime'/'worker' (cold start only) then 'running'. Resolves with the error text (empty on success) and elapsed ms. */ |
| 38 | export async function run(src, onChunk, onPhase) { |
| 39 | const exec = async () => { |
| 40 | // Only the run that triggers the cold start drives the load phases; warm runs go straight to 'running'. |
| 41 | const worker = await getWorker(workerReady ? undefined : onPhase) |
| 42 | onPhase?.('running') |
| 43 | activeSink = onChunk |
| 44 | let timer |
| 45 | try { |
| 46 | // Race against a hard timeout; terminate() kills the worker even mid-infinite-loop. |
| 47 | const runP = worker.run(src, { baseUrl: location.href }) |
| 48 | runP.catch(() => {}) // loser of the race; killWorker rejects it with nobody listening |
| 49 | const timeout = new Promise((_, reject) => { timer = setTimeout(() => reject(new Error(`Run exceeded ${RUN_TIMEOUT_MS / 1000}s — worker terminated`)), RUN_TIMEOUT_MS) }) |
| 50 | const { out, ms } = await Promise.race([runP, timeout]) |
| 51 | return { error: out || '', ms } |
| 52 | } catch (e) { |
| 53 | // Timeout or worker death: respawn so the queue isn't wedged forever. |
| 54 | await killWorker() |
| 55 | throw e |
| 56 | } finally { |
| 57 | clearTimeout(timer) |
| 58 | activeSink = null |
| 59 | } |
| 60 | } |
| 61 | // Queue behind any in-flight run (success or failure) so a second block never overwrites the first's activeSink mid-stream. |
| 62 | const result = runChain.then(exec, exec) |
| 63 | runChain = result.catch(() => {}) |
nothing calls this directly
no test coverage detected