(options: SpawnDaemonChildOptions)
| 207 | } |
| 208 | |
| 209 | export function spawnDaemonChild(options: SpawnDaemonChildOptions): ChildProcess { |
| 210 | const program = resolveDaemonProgram(); |
| 211 | const logPath = daemonLogPath(); |
| 212 | const logDir = dirname(logPath); |
| 213 | mkdirSync(logDir, { recursive: true }); |
| 214 | const args = [ |
| 215 | 'server', |
| 216 | 'run', |
| 217 | '--daemon', |
| 218 | '--port', |
| 219 | String(options.port), |
| 220 | '--log-level', |
| 221 | options.logLevel, |
| 222 | ]; |
| 223 | if (options.host !== undefined) { |
| 224 | args.push('--host', options.host); |
| 225 | } |
| 226 | if (options.debugEndpoints === true) { |
| 227 | args.push('--debug-endpoints'); |
| 228 | } |
| 229 | if (options.insecureNoTls === true) { |
| 230 | args.push('--insecure-no-tls'); |
| 231 | } |
| 232 | if (options.allowRemoteShutdown === true) { |
| 233 | args.push('--allow-remote-shutdown'); |
| 234 | } |
| 235 | if (options.allowRemoteTerminals === true) { |
| 236 | args.push('--allow-remote-terminals'); |
| 237 | } |
| 238 | if (options.idleGraceMs !== undefined) { |
| 239 | args.push('--idle-grace-ms', String(options.idleGraceMs)); |
| 240 | } |
| 241 | if (options.allowedHosts !== undefined && options.allowedHosts.length > 0) { |
| 242 | args.push('--allowed-host', ...options.allowedHosts); |
| 243 | } |
| 244 | // On Windows `.mjs` files are not executable PE binaries, so we must run |
| 245 | // the script through the Node binary rather than spawning it directly. In |
| 246 | // SEA mode or when re-spawning from an already-running daemon, `program` is |
| 247 | // `process.execPath` itself, so no script argument is needed. |
| 248 | const execPath = process.execPath; |
| 249 | const spawnArgs = program === execPath ? args : [program, ...args]; |
| 250 | |
| 251 | const logFd = openSync(logPath, 'a'); |
| 252 | try { |
| 253 | const child = spawn(execPath, spawnArgs, { |
| 254 | detached: true, |
| 255 | // Run from the server log directory instead of inheriting the caller's |
| 256 | // cwd, so the long-lived daemon does not pin the directory it was |
| 257 | // launched from (notably blocking its deletion on Windows). |
| 258 | cwd: logDir, |
| 259 | stdio: ['ignore', logFd, logFd], |
| 260 | }); |
| 261 | child.once('error', (error) => { |
| 262 | // A spawn failure (e.g. ENOENT) surfaces asynchronously on the child, |
| 263 | // not as a thrown error. Without a listener Node would crash the parent |
| 264 | // with an unhandled 'error' event; record it instead and let the polling |
| 265 | // loop in `ensureDaemon` report the timeout. |
| 266 | try { |
no test coverage detected