diff --git a/plugins/EXTRACTING-A-PLUGIN.md b/plugins/EXTRACTING-A-PLUGIN.md index c92bf2a3..c64e3841 100644 --- a/plugins/EXTRACTING-A-PLUGIN.md +++ b/plugins/EXTRACTING-A-PLUGIN.md @@ -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.