Both workarounds existed because Five was missing two features that
just landed upstream:
Five 7629f95 (variadic PValue) makes FUNCTION foo(...) / PValue()
actually return the caller's variadic args instead of the caller's
first LOCAL slot. AP_RPUTS / AP_ECHO can go back to their `( ... )`
signature now.
Five f3e0ffe (file-local STATIC FUNCTION) gives each .prg its own
namespace for `STATIC FUNCTION name`, so the seven duplicate
`STATIC FUNCTION fn_HGet` definitions across labdb's api/*.prg
files no longer collide. The sed-renamed unique names can revert
to the upstream definitions.
Files
app/bridge/bridge_request.prg ← cp from fivenode/native/
app/api/{device-status,record-detail,records-list,session-detail,
session-stats,sessions-list,session-export}.prg
← cp from fivenode/labdb/api/
fivenode-upstream is now byte-identical to fivenode_go's app/ copy
of those files. No more "// fivenode_go patch" comments, no more
file-prefix renames.
Verified end-to-end against the same live postgres@16 cluster:
/api/admin-stats.prg -> {"active_sessions":1,"devices":2,...}
/api/sessions-list.prg -> 2 rows w/ full session data
/api/admin-devices.prg -> 2 devices w/ api_key, created_at
/api/hello.prg -> hello (unchanged)
/ -> 200 text/html (static)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Drop-in copy of labdb's API surface from
fivenode/labdb/api/*.prg into app/api/. Single fnode invocation builds
the whole thing (bridge_server + bridge/ + 22 api/*.prg) into one
24 MB Go binary — no Node.js, no FFI, no Apache.
End-to-end smoke test (server.js not running, ctx empty so defaults
fall back) hitting six endpoints all return well-formed JSON via the
bridge layer + path -> Main dispatcher:
GET /api/hello.prg -> {"msg":"hello from PRG","ok":true}
GET /api/admin-stats.prg -> {"active_sessions":0,...}
GET /api/admin-me.prg -> {"ok":true,"user":{...}}
GET /api/sessions-list.prg -> {"sessions":[],"total":0}
GET /api/records-list.prg -> {"records":[],"sessionId":"",...}
POST /api/devices-register -> {"deviceId":"","status":"pending",...}
One small upstream patch was needed: seven .prg files each define
their own STATIC FUNCTION fn_HGet, but Five doesn't yet honour
file-local STATIC scoping for top-level functions — all definitions
land in the same symbol table and collide. Renamed each duplicate to
<file>_fn_hget so they peacefully coexist; the call sites still
reference fn_HGet and Five resolves them against _helpers.prg's
public version (signature-compatible). TODO: revert once Five gains
file-local STATIC FUNCTION scoping.
What's deferred to 1a.4-4: ctx data injection (so endpoints return
real labdb data), static asset embedding (labdb/public/), and a live
LABDB_DSN round-trip to confirm pgrtl in the request path.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Lets app/api/foo.prg keep its idiomatic `FUNCTION Main()` shape while
multiple such files compile into one binary. fnode auto-renames each
library file's Main into a unique symbol derived from the basename:
app/api/hello.prg -> HELLO__MAIN
app/api/admin-stats.prg -> ADMIN_STATS__MAIN (hyphen -> underscore)
Three moving parts:
cmd/fnode/main.go
parseOne for every PRG, then rename Main on every file except
the first (the entry). crossFile map updated so the analyzer
treats the renamed symbol as declared.
hbrtl_ext/dispatch/dispatch.go
New HB_FUNC FNODE_CALL(cFuncName) that does VM.FindSymbol +
PushSymbol/Function dance and discards the return value. Same
pattern pgserver's callPRG helper uses internally.
app/bridge_server.prg
BridgeDispatch now derives the symbol name from hReq["path"]
( /api/foo[.prg] -> FOO__MAIN ), invokes FNODE_CALL, and
maps "not found" errors to HTTP 404 (other errors -> 500).
Hardcoded /api/hello and /api/echo handlers replaced by the
path-driven model.
Verified end-to-end with app/api/hello.prg and app/api/admin-stats.prg:
GET /api/hello.prg -> 200 + JSON from HELLO__MAIN
GET /api/hello -> 200 (extension optional)
GET /api/admin-stats.prg?from=2026 -> 200 from ADMIN_STATS__MAIN
with query string echoed
GET /api/nope -> 404 "function not found"
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>