HTTP APIs (Express)
Express is the most common thing to migrate, and it works. We tested Express 4.22.3 and 5.1.0 with a JSON endpoint:
const express = require("express");
const app = express();
app.get("/", (req, res) => res.json({ express: require("express/package.json").version }));
const s = app.listen(process.env.PORT || 3456, "127.0.0.1",
() => console.log("up", s.address().port));3va run server.js --allow-read=./node_modules --allow-net=127.0.0.1up 3456
$ curl 127.0.0.1:3456
{"express":"5.1.0"}Permissions an API usually needs
| Need | Grant |
|---|---|
Load express and its dependencies | --allow-read=./node_modules |
| Listen on a port | any --allow-net grant for loopback; 0.0.0.0 for every interface (see below) |
| Call another service | --allow-net=api.stripe.com (exact host) |
| Connect to the database | --allow-net=db.internal |
Read PORT, DATABASE_URL, secrets | --allow-env=PORT,DATABASE_URL |
| Serve static files, uploads | --allow-read=./public, --allow-write=./uploads |
Put them in package.json under "3va" so 3va run, 3va start and
3va test all share them (Permissions).
Things to keep in mind
-
Listening on loopback needs any network grant. Outbound calls are matched strictly against the host.
-
Every interface needs an explicit grant.
app.listen(3000)asks for0.0.0.0; unless--allow-netincludes0.0.0.0,::or*, 3va binds127.0.0.1instead and prints a note. In a container, where the server must be reachable from outside, add--allow-net=0.0.0.0. -
Without a grant the server doesn’t start, and the process still exits with code 0. The
EACCESgoes to the server’serrorevent. 3va now lists the refusal on exit:[!] 1 permission was denied during this run: bind a local server on 0.0.0.0 needs any --allow-net grant (e.g. --allow-net=127.0.0.1)Still add
server.on("error", …)so your own logs show it too. -
Ports in
--allow-netapply to every client.--allow-net=api.example.com:443limitsfetch, database drivers and othernet-based clients to that port, and a typo’d port matches nothing. Also,localhostand127.0.0.1are different grants. -
Env vars read as
undefinedwithout--allow-env, soprocess.env.PORT || 3000uses 3000. The denial summary lists the variable (read environment variable PORT).3va start --port 4000grantsPORTautomatically. Other variables need an explicit grant. -
Express 5 printed noise to stderr in 3va 2.9.0: one
[ERROR] [3va-requireFrom] node: spec=node:http …line for everyrequire("node:*"). It was a leftover debug log and is gone in 2.12.0. -
Production:
3va start server.js --name apisupervises and restarts the process, like pm2 (Process Manager).