Machines that cannot install Node 22 had no way to run the agent at all, which
left them stuck on direct mode — and direct mode only works when the hub can
route to the VNC port, which it often cannot.
agent.js now resolves the two Node 22 globals it uses through fallbacks: `ws`
for the control and tunnel sockets, and http/https for the single enrolment
POST. Node 22 loads neither, since `globalThis.WebSocket || require('ws')`
short-circuits. The require and the http/https references are static so the
bundler can follow them.
A new Docker stage bundles that file with a Node 12 runtime — the last line
supporting Windows 7 and Server 2008 R2 — into one self-contained .exe, served
from /download/agent.exe and linked from the enrolment page. The route answers
503 rather than 404 in a dev checkout, where the build has not run.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
express.json() raising a parse error was falling through to the generic
500 handler, which reads as a server fault for what is a bad request.
Also maps the body-size limit to 413.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Browser-based remote control (noVNC) with invite links, per-user access
control, garagedoor SSO and a persisted client list.
The hub proxies RFB rather than pointing the browser at a VNC server. That
is what lets it authenticate upstream with a stored password the browser
never sees, and enforce view-only by dropping input messages on the
client->server stream instead of hiding buttons.
Machines are reachable two ways: direct TCP for LAN hosts, or an outbound
agent tunnel for anything behind NAT. Node 22's global WebSocket keeps the
agent dependency-free, and node:sqlite keeps the image free of native
builds.
Ships with an end-to-end suite that boots the real server against a fake
VNC server and a fake auth service (72 assertions), plus Gitea Actions
CI/CD to Portainer.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>