runbook: record the hand-rolled-proxy bodyParser trap
Cost an afternoon on the vault extraction and presented as far as possible from
its cause: every POST through /api/vault answered "sidecar unreachable" while
bodyless GETs worked, so it read as an intermittently dead sidecar rather than
a consumed request stream.
bodyParser runs across the protected router and reads JSON and form bodies,
disturbing the stream; a catch-all that then forwards ctx.req.raw.body forwards
something already consumed, Bun's fetch throws, and the catch reports the
sidecar as down.
createSidecarProxy registers its prefix itself, so core sidecars and any plugin
using it never meet this. Vault proxies by hand and the extraction dropped the
registration. Found by the mobile dev, who went looking on the server side
after the app kept failing where the browser extension did not — the split was
the clue, since the extension's routes are mounted above the protected router
and never see bodyParser at all.
Verified before recording: registerProxiedPrefix and isProxiedPath do what the
fix assumes, bodyParser consults them, create-proxy.ts:83 registers for core,
no vault handler reads ctx.get('body') (all three call ctx.req.json()), and the
registered prefix covers every path the mobile app uses while still not
matching /api/vaultwarden.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -159,6 +159,16 @@ A normal refresh is enough; the shell is `no-store`. When the log's last line ap
|
||||
module cache holds it for the lifetime of the process — so editing a manifest while developing changes
|
||||
nothing until `pm2 restart officer`. Costs ten minutes the first time, because the plugins page keeps
|
||||
cheerfully showing the old values. `outdated` cannot notice a version bump without a restart either.
|
||||
- **A router that proxies BY HAND must call `registerProxiedPrefix`.** `bodyParser` runs on the whole
|
||||
protected router and reads JSON and form bodies, which DISTURBS the request stream — so a catch-all that
|
||||
then forwards `ctx.req.raw.body` forwards an already-consumed stream, Bun's fetch throws, and the proxy
|
||||
reports the sidecar as unreachable. Every bodyless GET keeps working, so it presents as "the sidecar is
|
||||
down" for POSTs only, which is a long way from the cause. `createSidecarProxy` registers the prefix
|
||||
itself, so core sidecars and any plugin using it never meet this; vault proxies by hand and its
|
||||
extraction dropped the registration on 2026-08-18, costing an afternoon. If your plugin hand-rolls a
|
||||
proxy: `registerProxiedPrefix(PREFIX)` beside the mount, and check no handler under it reads
|
||||
`ctx.get('body')`.
|
||||
|
||||
- **A plugin importing platform code is fine (`@@/…`); the reverse is not.** If something in `src/` imports
|
||||
from your feature and cannot move — a widget, a relay — that piece stays, and the boundary goes around
|
||||
it. Find those before you plan the split; they decide it for you.
|
||||
|
||||
Reference in New Issue
Block a user