Summary
When running the SDK standalone via npm run serve (single-process mode), the
editor surfaces [initFromShare] Failed: Error: Invalid share token and the
document area stays blank after the display-name dialog. Two underlying issues
contribute:
-
The COLLAB_EMBEDDED_WS=1 environment variable is required for correct
websocket URL generation in single-process deployments, but this isn't
documented in the README and isn't the default. Without it, the client
constructs a websocket URL for a port that nothing is listening on, the
WS handshake fails, the collab runtime can't establish, and the UI surfaces
this as "Invalid share token" — which sent me on an extended journey
debugging token validation that had nothing to do with the problem.
-
The server serves public/ as static content but not dist/, so
/assets/editor.js 404s after npm run build. The HTML loads, references
an absent bundle, and renders "Loading editor..." indefinitely. The
server/share-web-routes.ts handler does a dev-friendly "Editor not
built. Run: npm run build" error when it can't find dist/index.html,
but once the build exists, the companion static route for assets is
missing. I believe this is a gap from the open-source extraction from
your hosted product, where a CDN or reverse proxy presumably serves
/assets/* separately.
Environment
- macOS 26.4.1, Node v25.8.1, fresh
npm install on commit
fb2578758f1c62776301209131181643c5f4a19a
- Single-machine deployment, no reverse proxy, no separate collab process
Suggested resolutions
For (1): either default COLLAB_EMBEDDED_WS to 1 when no external
collab host is configured (auto-detect mode), or document the requirement
prominently in the README's self-host section. The error surface could also
distinguish "websocket handshake failed" from "token rejected" in the UI —
the current generic "Invalid share token" message is misleading when the
actual issue is networking.
For (2): add app.use(express.static(path.join(__dirname, '..', 'dist')))
alongside the existing public/ static mount in server/index.ts. Single
line change.
Related ergonomic note
server/index.ts currently calls server.listen(PORT) with no host argument
and logs [proof-sdk] listening on http://127.0.0.1:${PORT}. Per the Node
docs, omitting the host binds to :: (all interfaces) on dual-stack systems,
not loopback. Self-hosters wanting to restrict the bind have no supported
knob, and the log message doesn't match reality. Adding a HOST env var
parallel to the existing PORT pattern would address both. I have this
change in my fork and am happy to PR it alongside a fix for (2) if useful.
Local fork with patches
laurencenorton-tc-markets@8083282
Single commit addressing issue (2) and the bind host ergonomic note. Not
addressing issue (1) yet — that one has a design question about whether to
change the default or document the flag, and I'd value your take first.
Summary
When running the SDK standalone via
npm run serve(single-process mode), theeditor surfaces
[initFromShare] Failed: Error: Invalid share tokenand thedocument area stays blank after the display-name dialog. Two underlying issues
contribute:
The
COLLAB_EMBEDDED_WS=1environment variable is required for correctwebsocket URL generation in single-process deployments, but this isn't
documented in the README and isn't the default. Without it, the client
constructs a websocket URL for a port that nothing is listening on, the
WS handshake fails, the collab runtime can't establish, and the UI surfaces
this as "Invalid share token" — which sent me on an extended journey
debugging token validation that had nothing to do with the problem.
The server serves
public/as static content but notdist/, so/assets/editor.js404s afternpm run build. The HTML loads, referencesan absent bundle, and renders "Loading editor..." indefinitely. The
server/share-web-routes.tshandler does a dev-friendly "Editor notbuilt. Run: npm run build" error when it can't find
dist/index.html,but once the build exists, the companion static route for assets is
missing. I believe this is a gap from the open-source extraction from
your hosted product, where a CDN or reverse proxy presumably serves
/assets/*separately.Environment
npm installon commitfb2578758f1c62776301209131181643c5f4a19aSuggested resolutions
For (1): either default
COLLAB_EMBEDDED_WSto1when no externalcollab host is configured (auto-detect mode), or document the requirement
prominently in the README's self-host section. The error surface could also
distinguish "websocket handshake failed" from "token rejected" in the UI —
the current generic "Invalid share token" message is misleading when the
actual issue is networking.
For (2): add
app.use(express.static(path.join(__dirname, '..', 'dist')))alongside the existing
public/static mount inserver/index.ts. Singleline change.
Related ergonomic note
server/index.tscurrently callsserver.listen(PORT)with no host argumentand logs
[proof-sdk] listening on http://127.0.0.1:${PORT}. Per the Nodedocs, omitting the host binds to
::(all interfaces) on dual-stack systems,not loopback. Self-hosters wanting to restrict the bind have no supported
knob, and the log message doesn't match reality. Adding a
HOSTenv varparallel to the existing
PORTpattern would address both. I have thischange in my fork and am happy to PR it alongside a fix for (2) if useful.
Local fork with patches
laurencenorton-tc-markets@8083282
Single commit addressing issue (2) and the bind host ergonomic note. Not
addressing issue (1) yet — that one has a design question about whether to
change the default or document the flag, and I'd value your take first.