Skip to content

v0.15.1

Latest

Choose a tag to compare

@jeffyaw jeffyaw released this 23 Aug 16:52
· 2 commits to main since this release

Fixed

  • The launcher no longer dies with a raw stack trace when spawn fails. Node throws synchronously rather than emitting error for some unexecutable targets — notably a .cmd/.bat on Windows — and the error listener is registered after the spawn call, so it could never observe that throw. Both failure modes now route through one handler.
  • Windows PATH discovery accepts oam.exe only, instead of walking every PATHEXT entry and returning an oam.cmd Node cannot execute. A skipped shim is still named in the diagnostic, so an npm-style install no longer reports as "no oam binary was found".
  • A failing in-process fallback no longer escapes as an unhandled rejection. void runInProcess() discarded the promise, replacing the launcher's own diagnostic with a raw stack trace.
  • Diagnostics that precede process.exit are written synchronously. stderr is async for TTYs and pipes on Windows, so the exit could truncate them. They route through one helper that also handles short writes and macOS EAGAIN on a non-blocking piped stderr.
  • Removed a literal backspace byte (U+0008) from the runtime-discovery comment, which made git treat the file as binary so its diff could not be reviewed.
  • An oam that cannot be run is no longer reported as an outdated one. The version probe returns null for several distinct causes — not executable, wrong architecture, a shim Node refuses, deleted since the stat, unparseable --version output — and every one produced "older than oam 0.9.0 … run oam self-update", pointing at the single cause it definitely was not. The two cases now carry separate wording and remedies, and the outdated message reports the version actually detected.
  • Windows: the launcher no longer hard-kills the server on the first Ctrl-C. There are no POSIX signals on Windows — child.kill(sig) ignores the name and calls TerminateProcess, an immediate hard kill (verified: a child with a SIGTERM handler never runs it and dies with code=null). The launcher forwarded anyway, on the stated assumption that this was a "no-op on Windows", so it aborted the graceful shutdown the console's own Ctrl-C had just started and skipped the server's process.on("exit") cleanup. The console already delivers the event to the whole process group, so on Windows the launcher now forwards nothing.
  • A wedged server no longer leaves the launcher hanging. Forwarding was gated on child.killed, which records only that kill() was called — never that the child is gone — so every signal after the first was swallowed and there was no escape hatch. Escalation is now armed by a timer on the first signal: one press is enough, and a child still alive after a 2s grace window is killed. Using a timer rather than counting signals also stops the ordinary supervisor sequence (SIGINT then SIGTERM milliseconds apart) from being misread as impatience.
  • The test suite is bounded by --test-timeout, so a hang cannot wedge a release. node:test has no default per-test timeout, so a test awaiting an event that never arrives runs forever -- and npm test runs unattended inside release.sh, which turns a wedged release rather than a failed one. 300000ms is deliberately generous (files measure ~7.5s worst case) and converts an infinite hang into a reported failure. Note the flag is per-FILE until Node 24, and requires Node >= 20.11.0.
  • engines.node now declares >=20.11.0, matching what the test tooling actually requires (--test-timeout landed in Node 20.11.0). The previous >=20 admitted 20.0-20.10, where the flag does not exist. README updated to match.