Skip to content

Commit cb856ec

Browse files
mariojgtclaude
andauthored
Give the agent one recipe for wiring any Node.js app (#448)
Setup wires the frameworks it recognises and leaves a generic guard for everything else. The guide described the procedure in general terms, and agents filled the gap by writing their own createProtection guard, which has no read-only rules credential and cannot fetch rule updates. AGENT-INSTALL.md now has a short recipe under "Completing guard wiring": use the guard file setup wrote (never write your own or copy the .patchstack cache), wrap the app's one request entry with the export that fits its shape (Fetch handler, Node (req, res), Express/Connect, Fastify), run setup again so the guard's rules file gets the site's rules and the credential, then check with protect --check and --runtime. Also corrects the refresh interval it states: 5 minutes, plus a background re-check every 30 seconds while serving, not 45 minutes. Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1 parent 36fb0d8 commit cb856ec

1 file changed

Lines changed: 31 additions & 1 deletion

File tree

‎AGENT-INSTALL.md‎

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -496,7 +496,7 @@ It is server-only. Never put it in the widget tag, client bundles, or public env
496496
services and separately deployed functions are not protected by guarding the frontend server;
497497
keep backend authorization/RLS and install a guard at each independently exposed backend.
498498

499-
Generated guards refresh live rules every 45 minutes (15 seconds in an explicit sandbox). `PATCHSTACK_RULES_REFRESH_SECONDS`, set to a positive number in the app's environment, overrides that interval (minimum 5 seconds).
499+
Generated guards refresh live rules every 5 minutes (15 seconds in an explicit sandbox), and while serving traffic also re-check them in the background every 30 seconds. `PATCHSTACK_RULES_REFRESH_SECONDS`, set to a positive number in the app's environment, overrides that interval (minimum 5 seconds).
500500
Express/Node guards enable bounded response filtering; Fastify filters buffered `onSend` output,
501501
leaving streams and bodyless replies untouched. Unmodified recognized helpers can be upgraded;
502502
customized helpers are preserved and flagged for manual review. Wiring checks inspect executable
@@ -591,6 +591,36 @@ check is not proof that every deployed route passes through it.
591591
unrecognized custom seam as unverified. Never add marker comments, dummy imports or unused calls
592592
merely to make the source check pass.
593593

594+
### Wiring any Node.js app
595+
596+
`setup` wires the frameworks it recognises by itself. For any other server-side JavaScript app it writes
597+
a generic guard file and lists the wiring under `To do`. This finishes it for any of them:
598+
599+
1. **Use the guard file `setup` wrote.** `npx @patchstack/connect protect --check` names it. Import from
600+
that file; do not call `createProtection` yourself, do not copy the `.patchstack/` folder (it is the
601+
running guard's cache, not its rules), and do not move or rename the guard's rules file. That file
602+
carries the site and the read-only rules credential, which let the deployed app fetch rule updates
603+
and report attacks without the site key.
604+
2. **Find the one function that answers every request** in the deployed app (step 1 above), and wrap it
605+
with the export that matches its shape:
606+
607+
| The request entry is | Use | For example |
608+
| --- | --- | --- |
609+
| `fetch(request, …)` returning a `Response`: Cloudflare Workers, Bun, Deno, Hono, an `export default { fetch }` module | `protectFetch` | `export default { fetch: protectFetch(app.fetch.bind(app)) }` |
610+
| `(req, res)` on Node's `http` server, including what Koa's `app.callback()` returns | `patchstackMiddleware`, before anything reads the body | `http.createServer((req, res) => patchstackMiddleware(req, res, () => handler(req, res)))` |
611+
| Express or Connect | `patchstackMiddleware`, registered first, before body parsers and routes | `app.use(patchstackMiddleware)` |
612+
| Fastify | the plugin `protect` writes for it | run `npx @patchstack/connect protect` |
613+
614+
Keep any extra arguments the host passes (`env`, `ctx`) flowing through to the handler. The wrapped
615+
handler is called once for an allowed request; a blocked one gets the guard's response instead.
616+
3. **Run `npx @patchstack/connect setup` again.** It writes the site's current rules and the read-only
617+
credential into the guard's rules file. Then `npx @patchstack/connect protect --check` must exit 0.
618+
4. **Check that a request reaches it:** `protect --check --runtime` when the entry runs under plain
619+
`node`, otherwise the local request test in step 4 above.
620+
621+
If the entry matches none of these shapes, do not invent an adapter or write a guard of your own: leave
622+
it unwired and hand off as described in "When wiring cannot be completed".
623+
594624
### Framework entry points to inspect
595625

596626
These are navigation hints for agent-assisted integration, not additional automatic adapters or a

0 commit comments

Comments
 (0)