export function buildProcessSessionFixtureSource({ readyPrefix, echoPrefix, stoppedMarker, }) { for (const [name, value] of Object.entries({ readyPrefix, echoPrefix, stoppedMarker, })) { if ( typeof value !== 'string' || value.length === 0 || /[\r\n]/u.test(value) ) { throw new Error(`invalid process fixture marker: ${name}`); } } return [ "import { randomBytes } from 'node:crypto';", '', `const readyPrefix = ${JSON.stringify(readyPrefix)};`, `const echoPrefix = ${JSON.stringify(echoPrefix)};`, `const stoppedMarker = ${JSON.stringify(stoppedMarker)};`, "const challenge = randomBytes(18).toString('hex');", 'let echoed = false;', 'let stopping = false;', '', 'function stop() {', ' if (stopping) return;', ' stopping = true;', ' console.log(stoppedMarker);', ' process.exit(0);', '}', "for (const signal of ['SIGINT', 'SIGTERM', 'SIGHUP']) process.on(signal, stop);", "console.log(readyPrefix + ' challenge=' + challenge);", '', "process.stdin.setEncoding('utf8');", "let buffered = '';", "process.stdin.on('data', (chunk) => {", ' buffered += chunk;', ' const lines = buffered.split(/\\r?\\n/u);', " buffered = lines.pop() ?? '';", ' for (const line of lines) {', ' if (!echoed && line === challenge) {', ' echoed = true;', " console.log(echoPrefix + ' ' + challenge);", " } else if (line === challenge + ':stop') {", ' stop();', ' }', ' }', '});', 'process.stdin.resume();', '', ].join('\n'); }