'use strict'; const http = require('node:http'), path = require('node:path'), { spawn } = require('node:child_process'), { once } = require('node:events'); async function freePort() { const server = http.createServer(); await new Promise(resolve => server.listen(0, '127.0.0.1', resolve)); const port = server.address().port; await new Promise(resolve => server.close(resolve)); return port; } async function start({ mode = 'rednote', dataRoot, port, publicBase, delay = 0 }) { const child = spawn(process.execPath, [path.join(__dirname, '../scripts/fixture-server.cjs')], { env: { ...process.env, JUZI_ENTRY_MODE: mode, JUZI_DATA_ROOT: dataRoot, PORT: String(port), PUBLIC_BASE_URL: publicBase, FIXTURE_DELAY_MS: String(delay) }, stdio: ['ignore', 'pipe', 'pipe'] }); await new Promise((resolve, reject) => { const timer = setTimeout(() => { child.kill(); reject(Error('startup timeout')); }, 15000); let error = ''; child.stderr.on('data', bytes => { error += bytes; }); child.stdout.on('data', bytes => { if (String(bytes).includes('已启动')) { clearTimeout(timer); resolve(); } }); child.once('exit', code => { clearTimeout(timer); reject(Error('backend exited ' + code + ': ' + error)); }); }); return child; } async function stop(child) { if (child && child.exitCode == null) { const exited = once(child, 'exit'); child.kill(); await exited; } } module.exports = { freePort, start, stop };