Since 19b5316 ("Require Node.js 22"), every supported Node version ships a native global WebSocket client, which makes both remaining uses of the ws package redundant: the DevTools probe in src/devtools.ts:12-34 (socket.on/socket.terminate maps to addEventListener/close), and customGlobal.WebSocket ||= ws in src/devtools-window-polyfill.ts:11, which never assigns anymore because the global already exists — so react-devtools-core connections already run over the native client today. Removing those two imports lets ws and @types/ws come out of package.json entirely; ws is a regular dependency, so every ink install currently pulls it in for this DEV-only path.
I verified a native-WebSocket rewrite of isDevToolsReachable on Node 22.22.2 and 26.1.0: the open, unreachable, and timeout paths all resolve correctly and the process exits cleanly (the concern behind 156bb75 / #648). One caveat worth knowing: the error handler must not call close() on the failed socket — on Node 22's bundled undici that re-fires error recursively until a stack overflow; the connection is already dead there, so the call is simply omitted.
Happy to send a small PR.
Since 19b5316 ("Require Node.js 22"), every supported Node version ships a native global
WebSocketclient, which makes both remaining uses of thewspackage redundant: the DevTools probe insrc/devtools.ts:12-34(socket.on/socket.terminatemaps toaddEventListener/close), andcustomGlobal.WebSocket ||= wsinsrc/devtools-window-polyfill.ts:11, which never assigns anymore because the global already exists — soreact-devtools-coreconnections already run over the native client today. Removing those two imports letswsand@types/wscome out of package.json entirely;wsis a regular dependency, so everyinkinstall currently pulls it in for this DEV-only path.I verified a native-
WebSocketrewrite ofisDevToolsReachableon Node 22.22.2 and 26.1.0: the open, unreachable, and timeout paths all resolve correctly and the process exits cleanly (the concern behind 156bb75 / #648). One caveat worth knowing: theerrorhandler must not callclose()on the failed socket — on Node 22's bundled undici that re-fireserrorrecursively until a stack overflow; the connection is already dead there, so the call is simply omitted.Happy to send a small PR.