@patchstack/connect 0.5.23 → 0.5.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/AGENT-INSTALL.md CHANGED
@@ -69,12 +69,12 @@ Every command at a glance — what it does, whether it reads your source, what i
69
69
  | Command | What it does | Reads your source? | Writes to your project | Sends over the network |
70
70
  |---|---|---|---|---|
71
71
  | `scan` | Provision (or reuse) the site and POST the dependency list for vulnerability matching. Also runs automatically via `setup` and the install/build hooks. | No source analysis — lockfile only; `node_modules/` is enumerated when no lockfile can be read (e.g. `bun.lockb`) or when the lockfiles present disagree. It also reads the `<title>` of the root `index.html` and the `name` in `package.json`, to report what the site is called. During `prebuild` only, it reads the scaffolded guard and its co-located rules JSON to remove a previous map stamp. | `.patchstackrc.json` (public: site UUID + settings); `.patchstackrc.local.json` (the API key, created owner-only) and a `.gitignore` entry for it — the CLI says so if it could not add one; during `prebuild`, removal of a previous `_patchstack.build_id` from the guard's own rules file so a later build cannot carry stale coordinates; the widget `<script>` tag in the root HTML shell — only after a successful post; the production marker in a code root shell — before the post, since it needs no site UUID | Package names + versions; this site's public address and name, where the project or build environment states them |
72
- | `setup` | One bounded command: `scan` → manage the widget → install + verify `protect` → wire the install/build scans. Never runs the project build. | No | Config, widget tag, production marker, guard files, `package.json` scripts | Package names + versions and the site's public address and name (via `scan`); a claim token as a request header, only when you pass one |
72
+ | `setup` | One bounded command: `scan` → manage the widget → install + verify `protect` → wire the install/build scans. Never runs the project build. | Local integration reads via `scan` and `protect` | Config, widget tag, production marker, guard/framework/route files, `package.json` scripts | Package names + versions and the site's public address and name (via `scan`); a claim token as a request header, only when you pass one |
73
73
  | `map` | Local attack-surface analysis (entry points → inputs → sinks → evidence-backed flows). Never run by another command. | **Yes** — via the app's own TypeScript; a pre-bundle `--upload` also locates the co-located rules file imported by the scaffolded guard | Only the file named by `--out`; during a pre-bundle `--upload`, `_patchstack.build_id` in that existing rules file | Nothing — **unless `--upload`**: structure only (routes, parameter names, the package behind each sink, file:line) plus a SHA-256 identity derived from its policy content. Never source code or env values |
74
- | `protect` | Install the always-on runtime guard; auto-wire known stacks, or scaffold a generic guard + print a wiring plan. `--check` verifies the guard is wired (exit 1 if not); `--demo` seeds a broad sample rule set. Runs automatically **only** via `setup` — never by `scan`, `guide`, `status`, or `mark-build`. | No — writes guard files, does not analyze your code | Guard/framework files (e.g. `middleware.ts`, `src/patchstack/`) | Nothing |
75
- | `demo node-serialize` | Production-backed walkthrough: confirm the vulnerable package is present, scan, wait for live rule `18843`, install + verify the guard, print test requests. Does not install the package or start/restart the app. | No | Same files as `scan` + `protect` | `scan` payload; polls the public Pulse rules endpoint (never the printed test requests) |
76
- | `demo-guide node-serialize` | Read-only companion: explains the prepare/run/prove/cleanup sequence and prints the next command. | No | Nothing | Nothing |
77
- | `guide` | Print this project's live setup status (done/missing, with tailored commands), then the full guide. `--full` prints it even when setup is complete. | No | Nothing | Nothing |
74
+ | `protect` | Install the always-on runtime guard; auto-wire known stacks, or scaffold a generic guard + print a wiring plan. `--check` verifies the guard is wired (exit 1 if not); `--demo` seeds a broad sample rule set. Runs automatically **only** via `setup` — never by `scan`, `guide`, `status`, or `mark-build`. | Reads local wiring/route source for integration; does not produce an attack-surface map | Guard/framework files (e.g. `middleware.ts`, `src/patchstack/`, supported Next App Router handlers) | Nothing |
75
+ | `demo node-serialize` | Production-backed walkthrough: confirm the vulnerable package is present, scan, wait for live rule `18843`, install + verify the guard, print test requests. Does not install the package or start/restart the app. | Local integration reads via `scan` and `protect` | Same files as `scan` + `protect` | `scan` payload; polls the public Pulse rules endpoint (never the printed test requests) |
76
+ | `demo-guide node-serialize` | Read-only companion: explains the prepare/run/prove/cleanup sequence and prints the next command. | Reads local protection wiring for verification | Nothing | Nothing |
77
+ | `guide` | Print this project's live setup status (done/missing, with tailored commands), then the full guide. `--full` prints it even when setup is complete. | Reads local protection wiring for verification | Nothing | Nothing |
78
78
  | `status` | Re-print the site UUID + dashboard URL and check whether the site still exists (active / removed / could not verify). | No | Nothing | Site-existence check |
79
79
  | `init <site-uuid>` | Optional: pre-seed `.patchstackrc.json` with an existing UUID. | No | `.patchstackrc.json` only | Nothing |
80
80
  | `mark-build` | Ensure the widget tag in built pages, and — **on a production build only** — stamp the live-site flag + build fingerprint. A local or preview build is stamped with neither, and has a stale marker removed; `--production` forces it for a build published by hand. Run as a `postbuild` step. | No | Build output only (`dist/ build/ out/ .output/public/ _site/`) — never source | The same manifest `scan` sent, plus one word for what it did with the marker — and only for a site already registered |
@@ -82,7 +82,7 @@ Every command at a glance — what it does, whether it reads your source, what i
82
82
  | `login` | Recover a lost credential for an existing site: print an owner-approval link and poll (10 min). Approving **rotates** the credential. Not usable in CI. | No | New credential into `.patchstackrc.local.json` on approval | Device-code request + approval poll |
83
83
  | `uninstall` | Signal Patchstack that the package is being removed: an unclaimed record is deleted, a claimed one is flagged. Does **not** touch local files. | No | Nothing local | Removal signal |
84
84
 
85
- Only `map` analyses your source, and only `map --upload` sends anything derived from it. `scan` additionally reads two declarations the project makes about itself — the `<title>` in the root `index.html` and the `name` in `package.json` — to report what the site is called; during `prebuild` it also reads the scaffolded guard and its co-located rules JSON solely to remove a previous map stamp. `scan` transmits package names + versions, plus the site's own public address and name where the project states them — never source code, file paths, git history, or any environment variable value other than the published URL of this site. `scan --install-paths` additionally sends where each package sits in the dependency tree; it is off unless you pass it.
85
+ Only `map` produces an attack-surface analysis, and only `map --upload` sends that description. `protect` reads and edits local source to integrate the guard; its verifier, also used by setup guides, reads the wiring without executing the app. These integration reads transmit nothing. `scan` additionally reads two declarations the project makes about itself — the `<title>` in the root `index.html` and the `name` in `package.json` — to report what the site is called; during `prebuild` it also reads the scaffolded guard and its co-located rules JSON solely to remove a previous map stamp. `scan` transmits package names + versions, plus the site's own public address and name where the project states them — never source code, file paths, git history, or any environment variable value other than the published URL of this site. `scan --install-paths` additionally sends where each package sits in the dependency tree; it is off unless you pass it.
86
86
 
87
87
  ## Package and command behavior
88
88
 
@@ -94,12 +94,12 @@ Only `map` analyses your source, and only `map --upload` sends anything derived
94
94
  - **Only `scan` looks for the address and the name.** They are resolved in the one code path that reports them, so `guide`, `status`, `login`, `uninstall`, `mark-build`, `init`, `protect`, `demo-guide` and `map` neither read the host's URL variables nor open `index.html` or `package.json` for this. `setup` and `demo` do, because both run `scan`.
95
95
  - **The address is the one your visitors use, and, apart from the tool's own `PATCHSTACK_*` settings, it is the only env var value read.** A site provisioned by a scan from a developer machine has no address, so the dashboard shows a placeholder and Patchstack cannot check that the published page still carries what was scanned. `scan` therefore sends `url` when — and only when — it can know it: `url` in `.patchstackrc.json` or `PATCHSTACK_SITE_URL` if you set one, otherwise the single variable a host publishes to name its own **production** URL (`VERCEL_PROJECT_PRODUCTION_URL` on a Vercel production deployment, Netlify's `URL` in the production context, `RENDER_EXTERNAL_URL`, `RAILWAY_PUBLIC_DOMAIN` in a production environment). Preview and branch deployments are excluded, as are hosts that publish no production signal. An address that is not how the public reaches a website is dropped: any IP address (in either family, however it is written), any single-label host such as `localhost` or `production`, and the reserved suffixes (`.local`, `.internal`, `.test`, `.invalid`, `.home.arpa`, …). A `url` you set explicitly that fails those checks is refused with an error rather than replaced by a guess. When nothing qualifies, `url` is omitted from the payload rather than guessed. Patchstack only ever applies it to a site that still has no address; it never re-points a site whose address is already real.
96
96
  - **The name is read from your project, never from the host environment.** `name` in `.patchstackrc.json` (or `PATCHSTACK_SITE_NAME`) if you set one; otherwise the `<title>` of the project's root `index.html` (`public/index.html` if there is no root one), read from the file as text — a title your app sets from script is not seen; otherwise the `name` in `package.json`, unless it is a template placeholder such as `vite_react_shadcn_ts`. It is omitted when nothing qualifies, and it only ever fills in a site that has no name yet — a name set in the dashboard is never replaced.
97
- - **Only `map` analyses source files.** It parses your server source to report your app's attack surface. It runs only when you invoke it and prints to stdout. It transmits nothing unless you explicitly pass `--upload`, which sends that description of your app's structure to your own site's Patchstack endpoint — never source code, and never without that flag. A `prebuild` scan reads the scaffolded guard and rules JSON only to identify and clear the reserved map stamp; it does not analyse them or transmit their contents.
97
+ - **Only `map` produces an attack-surface analysis.** It parses your server source to report your app's attack surface. It runs only when you invoke it and prints to stdout. It transmits nothing unless you explicitly pass `--upload`, which sends that description of your app's structure to your own site's Patchstack endpoint — never source code, and never without that flag. `protect` separately parses supported wiring and route files for local integration, without producing or uploading a map. A `prebuild` scan reads the scaffolded guard and rules JSON only to identify and clear the reserved map stamp; it does not analyse them or transmit their contents.
98
98
  - **`scan` makes up to three source edits:** the Patchstack Connector's `<script>` tag, the production marker, and — during `prebuild` only — removal of a previous `_patchstack.build_id` from the existing guard rules file. None runs on `--dry-run`; all are idempotent. `"widget": false` disables the first two, while stale-stamp removal is independent because it prevents old coordinates being attributed to a new build.
99
99
  - The **widget tag** goes in the root HTML shell — the first of `index.html`, `public/index.html`, or `src/app.html` that exists — and only after a successful post, because it carries the site UUID.
100
100
  - The **production marker** goes in a root shell that is JSX rather than HTML (e.g. `src/routes/__root.tsx`, `app/layout.tsx`), inside a `{/* #region patchstack */}` block placed above the widget tag. It is written *before* the post: it carries no site UUID and needs no network, and build scripts commonly chain `patchstack-connect scan || true`, where waiting on the server would mean an offline build silently ships without the flag. The marker is guarded by the framework's own production expression (`import.meta.env.PROD`, or `process.env.NODE_ENV === 'production'`), so it is inert in dev and preview builds. Without it a server-rendered site has no built HTML for `mark-build` to stamp, and the widget treats the published site as build mode. `mark-build` writes to build output only (`dist/`, `build/`, `out/`, `.output/public`), never to source. `guide`, `status`, and `init` write nothing except `init`'s own `.patchstackrc.json`.
101
101
  - **`setup` runs `scan`, then `protect`, then edits `package.json` scripts:** provisioning happens first so the runtime guard can bake the real site UUID. It verifies the resulting framework seam, preserves existing commands, adds `scan` after dependency installs and before builds, adds `mark-build` after builds, and uses a direct build chain for Bun. It never runs the project build. If the widget or runtime guard needs a framework-specific manual merge, it prints the exact remaining step instead of overwriting user code.
102
- - The package also exposes **`protect`** directly (runtime exploit guard; its templates live under `dist/protect/`). `setup` invokes it automatically; `scan`, `guide`, `status`, and `mark-build` do not. It writes only local files and auto-wires known stacks — **TanStack Start + Supabase** (patches the Supabase client + `src/start.ts`), **Next.js** (scaffolds `middleware.ts`), **SvelteKit** (`src/hooks.server.ts`), **Astro** (`src/middleware.ts`), **Nuxt** (`server/middleware/`), **NestJS** (`app.use(patchstackMiddleware)` in the bootstrap), **Fastify** (`app.register(patchstackFastify)`), and **Express** (`app.use(patchstackMiddleware)`). On **any other stack** it scaffolds a framework-agnostic guard under `src/patchstack/` and prints a wiring plan — then you finish the install by importing that guard into your server entry (`protectFetch(handler)` for a Web-Fetch server, or `app.use(patchstackMiddleware)` for Node/Express) and running `patchstack-connect protect --check` to confirm it is wired (exit 1 until it is). Passing `--demo` seeds a broad sample rule set (for demonstrations, not production).
102
+ - The package also exposes **`protect`** directly (runtime exploit guard; its templates live under `dist/protect/`). `setup` invokes it automatically; `scan`, `guide`, `status`, and `mark-build` do not. It writes only local files and auto-wires known stacks — **TanStack Start + Supabase** (patches the Supabase client + `src/start.ts`), **Next.js** (scaffolds or composes middleware and adds request/response checks to supported App Router handlers), **SvelteKit** (`src/hooks.server.ts`), **Astro** (`src/middleware.ts`), **Nuxt** (`server/middleware/`), **NestJS** (`app.use(patchstackMiddleware)` in the bootstrap), **Fastify** (`app.register(patchstackFastify)`), and **Express** (`app.use(patchstackMiddleware)`). On **any other stack** it scaffolds a framework-agnostic guard under `src/patchstack/` and prints a wiring plan — then you finish the install by importing that guard into your server entry (`protectFetch(handler)` for a Web-Fetch server, or `app.use(patchstackMiddleware)` for Node/Express) and running `patchstack-connect protect --check` to confirm it is wired (exit 1 until it is). Passing `--demo` seeds a broad sample rule set (for demonstrations, not production).
103
103
  - **`demo node-serialize` is an explicit production-backed walkthrough.** It requires `node-serialize@0.0.4` to already be present in the lockfile; it does not install the vulnerable dependency. It runs the same production `scan`, polls the configured site's public Pulse rules endpoint until rule `18843` is served, runs `protect`, verifies the generated guard, and prints exploit/benign test requests. It writes the same manifest/widget and guard files as those underlying commands. It does not start/restart the app and does not send the printed requests.
104
104
  - **`map` is local unless you pass `--upload`.** It walks the project's server source (skipping `node_modules`, build output and dot-directories; it does not follow symlinks out of the project unless you pass `--follow-symlinks`), parses it with the project's **own** `typescript`, and prints JSON describing the attack surface: entry points, the inputs each reads, the sinks they can reach (database / file system / process / outbound HTTP) with the npm package behind each, and evidence-backed input→sink flows, each labelled with how the link was established — from an exact read at the sink's own call site, through a transformed or cross-module link, down to the two being present together with no proven link. Static analysis is best-effort, so the output reports the *detected* surface with coverage counters — not a completeness guarantee. Without `--upload` it writes nothing except the file named by `--out`, and it is never invoked by `scan`, `setup`, `guide`, `protect`, or `mark-build`.
105
105
  - **`map --upload` is the only command that sends a description of your source.** (The runtime guard can also report rule detections, which carry route paths and parameter names — see "Runtime guard reporting" below.) It POSTs the same JSON document to `monitor/pulse/input-map/<your site uuid>` so Patchstack can pin protection rules to your app's own parameter names instead of guessing them. During a pre-bundle build hook it hashes the policy-relevant document (all fields except analyser timing and memory observations), writes the SHA-256 value as `_patchstack.build_id` in the existing rules file imported by the scaffolded guard, and sends the same value as `build_id`. Outside that lifecycle it sends no identity and changes no file, so any generated scoped rule remains detect-only. **No source code, no file contents, no environment variable values.** A map with no recognised entry points is still uploaded because its import inventory and coverage limits are evidence; a failure to reach Patchstack is reported and ignored rather than failing your build. Omit the flag and the command stays entirely local.
@@ -160,8 +160,15 @@ Only when the person asks you to publish the site. Two things decide whether Pat
160
160
  ```
161
161
 
162
162
  An app with a server needs this for runtime protection: the guard fetches its rules with the key. Without it the deploy is still recognised as long as the packages have not changed since the last scan, but nothing is protected. Never put the key in a committed file, in a public variable (`NEXT_PUBLIC_*`, `VITE_*`), or in your reply.
163
+ - **A host that builds the site itself but is not named under "How each environment is labelled"** — ChatGPT Sites (`*.chatgpt.site`, published from Codex) is one — gives Patchstack nothing that says "production", so its builds report `local` and the live site is never recognised as deployed. In that host's environment settings for the published site, set two variables: `PATCHSTACK_API_KEY`, read from `.patchstackrc.local.json` as above, and `PATCHSTACK_ENVIRONMENT=production`. Set the label only where the published build reads it, never in a committed file, and not in settings a preview or the local dev server also reads. Then publish again: the deployed site keeps serving the build from before setup until it is rebuilt.
164
+ - **Give Patchstack the live address when the host does not.** Patchstack confirms a deploy by reading the build marker off the live page, either when a visitor's browser loads the widget or through its own scheduled check of the site's address. A new site may get no visitors for days, so the scheduled check is often the only confirmation, and it can only read an address Patchstack has. Vercel, Netlify, Render and Railway production builds report their address themselves (see "Package and command behavior"). Anywhere else, including ChatGPT Sites, Lovable or Bolt, a custom domain, GitHub Pages, Cloudflare Pages or a folder uploaded by hand, take the public address from the deploy output or ask the person for it. Then:
165
+ 1. Add it to `.patchstackrc.json` as `"url": "https://your-app.example.com"`. Use the address visitors use, never a preview or a per-deployment URL. The address is public, so this file can be committed.
166
+ 2. Run `npx @patchstack/connect scan` once, so Patchstack learns it.
167
+
168
+ Patchstack applies the address only to a site that has no real address yet, meaning a placeholder or a builder preview. An address it already holds is never replaced, so if the dashboard shows a different one, the person changes it in the site's settings. A private site cannot be read this way; see the next item.
163
169
  - **Check the live site after deploying**, and tell the person what you found:
164
170
  - `curl -s <live url> | grep -ac __PATCHSTACK_PROD__` prints `1` or more. `0` means the build did not know it was production, and the widget will treat the live site as a preview.
171
+ - A site published privately answers `curl` with the host's sign-in page, so the check above prints `0` whatever was deployed — check the status code first (`curl -s -o /dev/null -w "%{http_code}" <live url>`). On a `401`, `403` or a redirect to a sign-in page, ask the person to open the live site while signed in and run `window.__PATCHSTACK_BUILD__` in the browser console: a short build ID means the marker is live, `undefined` means it is not. Patchstack cannot read a private page either, so its dashboard shows the deploy as reported, not confirmed, until a signed-in visit lets the widget report the build. Tell the person that, rather than describing the deploy as confirmed.
165
172
  - `curl -s -o /dev/null -w "%{http_code}" <live url>/.patchstackrc.local.json` is not `200`. A `200` means the API key was published: delete the deploy and tell the person.
166
173
  - The owner reaches their dashboard on the live site by adding `#patchstack` to the address, for example `https://example.com/#patchstack`. Visitors never see the owner panels there.
167
174
 
@@ -322,7 +329,20 @@ It is server-only. Never put it in the widget tag, client bundles, or public env
322
329
  npx @patchstack/connect protect --check
323
330
  ```
324
331
 
325
- `setup` performs both steps automatically. The explicit commands are for manual setup or repair. If verification reports a generic or existing framework seam, complete the printed source edit and re-run `--check`; do not report protection as active until it exits successfully.
332
+ `setup` performs both steps automatically. The explicit commands are for manual setup or repair. If verification reports a generic or existing framework seam, follow [Completing guard wiring](#completing-guard-wiring), complete the source edit and re-run `--check`; do not report protection as active until it exits successfully.
333
+
334
+ **Next.js:** `protect` uses the installed TypeScript parser to compose supported middleware while
335
+ preserving its original routing scope, and edits supported `app/**/route.ts`/`route.js` handlers to
336
+ check requests and filter returned responses. It writes a shared server-only `patchstack.next`
337
+ helper alongside `patchstack.rules.json`. Unsupported exports, complex matchers or handlers are
338
+ left unchanged and reported by `--check`; re-run `protect` after adding routes. An existing
339
+ `proxy.ts`/`proxy.js` requires manual integration: no competing middleware is scaffolded and
340
+ `--check` reports the gap. Middleware alone
341
+ cannot filter downstream page bodies. Rendered pages, Server Actions and Pages API response
342
+ filtering are not verified by this adapter. Keep Next.js patched: a framework middleware bypass
343
+ also bypasses a guard in middleware. Edge middleware needs `PATCHSTACK_API_KEY` in the server
344
+ environment; it cannot read `.patchstackrc.local.json`. Do not put credentials in public variables
345
+ or commit them. Source checks do not verify rule delivery or blocking in the running deployment.
326
346
 
327
347
  `--check` reads the app's source. It can establish that the guard is imported and called on a request
328
348
  path; it cannot establish that a request ever reaches it — an app can wire the guard onto one server
@@ -375,6 +395,96 @@ It is server-only. Never put it in the widget tag, client bundles, or public env
375
395
  2. **The dashboard link** the scan printed — open it in a browser and sign in.
376
396
  3. **`npx @patchstack/connect claim`** from the terminal, which prints a link to sign in with and then attaches the site.
377
397
 
398
+ ## Completing guard wiring
399
+
400
+ Use this procedure when scaffolding leaves a manual step, and review automatic edits against it too.
401
+ The printed entry candidates and framework names are hints. A generated guard or a successful source
402
+ check is not proof that every deployed route passes through it.
403
+
404
+ 1. **Find what actually serves requests.** Read the application's package, installed framework version,
405
+ start/build scripts, deployment adapter and existing server hooks. In a workspace, inspect each
406
+ deployed package separately. Trace the production entry to pages, APIs, loaders/actions, RPC and
407
+ server functions; include separately deployed functions and additional listeners. UI dependencies
408
+ and Vite alone do not establish a server or a static-only deployment. For a static export, establish
409
+ that no request handler is deployed before reporting runtime protection as not applicable.
410
+ 2. **Choose the shared request entry.** Prefer the framework's server hook or the deployed server's
411
+ outer handler over individual routes. Read the generated guard's exports and calling convention.
412
+ `protectFetch` wraps a handler receiving a Web `Request` and returning a `Response`; it is not a
413
+ wrapper for arbitrary framework contexts or response-writing callbacks. Preserve handler arguments,
414
+ runtime bindings and any required receiver. Do not pass Connect middleware directly to Koa, Hapi,
415
+ Adonis or other incompatible middleware APIs. If the conversion cannot be established, leave that
416
+ entry unwired and name the missing integration rather than inventing an API.
417
+ 3. **Compose a minimal edit.** Preserve authentication, redirects, rewrites, cookies, headers, errors
418
+ and existing matchers. Inspect matcher exclusions for skipped application routes. Keep the guard
419
+ server-only and return its blocking response before calling application code; call the original
420
+ handler once for an allowed request. The Express adapter's guard uses parsed `req.body` and belongs
421
+ **after** the body parser, before routes. The generic Node guard reads the stream and belongs
422
+ **before** body parsers. Preserve raw-body webhook verification and test uploads and streams before
423
+ claiming those paths work. Do not edit generated build output, replace an existing hook wholesale,
424
+ add a server to a static app, or rerun scaffolding over a manually adapted guard without reviewing
425
+ what it will write. Check the diff for duplicate registrations and unrelated changes.
426
+ 4. **Verify the integration and its limits.** Run `protect --check`, then the app's existing typecheck,
427
+ build and relevant request tests. In a local test environment, check an allowed request and a
428
+ controlled blocking case for each independent entry and representative page/API/action path;
429
+ verify the blocked request does not reach the handler. Include existing authentication, redirects,
430
+ body handling and error behavior. The opt-in `--runtime` check described above probes the guard
431
+ seam; it does not prove route coverage or rule effectiveness. Record an unsupported probe or an
432
+ unrecognized custom seam as unverified. Never add marker comments, dummy imports or unused calls
433
+ merely to make the source check pass.
434
+
435
+ ### Framework entry points to inspect
436
+
437
+ These are navigation hints for agent-assisted integration, not additional automatic adapters or a
438
+ compatibility guarantee. Confirm the installed version and deployment mode before choosing a hook.
439
+ The linked framework documentation describes its lifecycle; the generated Connect guard determines
440
+ which integration API is available.
441
+
442
+ | Framework or UI layer | Server entry and coverage question |
443
+ | --- | --- |
444
+ | [React](https://react.dev/learn/creating-a-react-app) | Find the hosting framework or custom server. A browser component or client router is not a request guard. |
445
+ | [Vue](https://vuejs.org/guide/scaling-up/ssr.html) | Inspect the SSR host or separate API; component setup and router navigation guards do not guard server requests. |
446
+ | [Angular](https://angular.dev/guide/ssr) | Distinguish browser/prerender output from the deployed SSR server; inspect `server.ts` and its HTTP adapter. |
447
+ | [Svelte](https://svelte.dev/docs/svelte/overview) | Determine whether this is a browser bundle, SvelteKit or a custom SSR host before choosing a server hook. |
448
+ | [Preact](https://preactjs.com/guide/v10/server-side-rendering/) | Guard the host invoking SSR or APIs; a render function alone is not the shared HTTP entry. |
449
+ | [Solid](https://docs.solidjs.com/quick-start) | Separate the UI library from SolidStart or a custom server; keep protection out of client components. |
450
+ | [Qwik](https://qwik.dev/docs/qwikcity/) | Inspect Qwik City and the deployment adapter; component resumability does not identify the request entry. |
451
+ | [Ember](https://guides.emberjs.com/release/getting-started/quick-start/) | Inspect the deployed backend or SSR host separately; browser routes and the development server are not production coverage. |
452
+ | [Next.js](https://nextjs.org/docs/app/api-reference/file-conventions/proxy) | Inspect root or `src/` middleware/proxy, matchers, APIs and Server Actions. Next 16 renamed middleware to proxy; Connect scaffolds `middleware.ts`. Do not leave competing files or assume its source check validates `proxy.ts`. |
453
+ | [Nuxt](https://nuxt.com/docs/4.x/directory-structure/server) | Inspect the configured server directory and Nitro server middleware, not client navigation middleware. Distinguish a server deployment from generated static output. |
454
+ | [SvelteKit](https://svelte.dev/docs/kit/hooks) | Compose the existing server `handle` hook; check endpoints, actions, prerendering and the deployed adapter. |
455
+ | [Astro](https://docs.astro.build/en/guides/middleware/) | Compose `onRequest` in server middleware; distinguish execution during prerendering from on-demand routes behind an adapter. |
456
+ | [Remix](https://v2.remix.run/docs/discussion/runtimes/) | Inspect the adapter around `createRequestHandler`; cover document requests, loaders, actions and resource routes, not only `entry.server` rendering. |
457
+ | [React Router](https://reactrouter.com/how-to/middleware) | Determine library versus framework/SSR mode. Inspect the server adapter and version-specific server middleware; client middleware cannot guard loaders/actions on the server. |
458
+ | [TanStack Start](https://tanstack.com/start/latest/docs/framework/react/guide/middleware) | Inspect the server entry and global request middleware, including server functions. The automatic TanStack/Supabase adapter matches a particular project layout, not every Start app. |
459
+ | [SolidStart](https://docs.solidjs.com/solid-start/v1/advanced/middleware) | Inspect configured server middleware and adapter; verify API and server action paths separately rather than assuming rendering middleware covers them. |
460
+ | [Qwik City](https://qwik.dev/docs/middleware/) | Inspect deployment entry and request middleware, including endpoints, loaders and actions. Confirm route/layout scope and static output. |
461
+ | [Gatsby](https://www.gatsbyjs.com/docs/reference/functions/) | Static pages need no request guard, but `src/api` functions and SSR deployments need their own server entry review. |
462
+ | [Docusaurus](https://docusaurus.io/docs/deployment) | Confirm static output; inspect any separately deployed API or custom server without adding a guard to browser code. |
463
+ | [Eleventy](https://www.11ty.dev/docs/) | Confirm static output; review accompanying functions or a custom server separately from build-time templates. |
464
+ | [Express](https://expressjs.com/en/guide/using-middleware/) | Register the generated Express guard after its body parser and before routers, for every app that actually serves traffic. |
465
+ | [NestJS](https://docs.nestjs.com/middleware) | Inspect `NestFactory.create` and the selected HTTP adapter. Express-style middleware is not proof of Fastify compatibility or microservice/WebSocket coverage. |
466
+ | [Fastify](https://fastify.dev/docs/latest/Reference/Hooks/) | Register the generated plugin in the root scope before route plugins; inspect encapsulation and every server instance. |
467
+ | [Hono](https://hono.dev/docs/api/hono) | Inspect the deployed Fetch entry and preserve environment/context arguments; check mounted apps and any other exported handlers. |
468
+ | [Koa](https://koajs.com/) | Inspect the Node server around `app.callback()` or use a verified Koa integration; `(ctx, next)` is not Connect's `(req, res, next)`. |
469
+ | [Elysia](https://elysiajs.com/integrations/cheat-sheet) | Inspect the actual Bun/Node/Fetch deployment entry and plugin scope; a local hook need not cover sibling routes. |
470
+ | [AdonisJS](https://docs.adonisjs.com/guides/basics/middleware) | Inspect the server middleware stack in `start/kernel.ts`; named route middleware alone leaves other routes outside its scope. |
471
+ | [Hapi](https://hapi.dev/api/21.x.x) | Inspect server lifecycle extensions and payload timing; adapt request/response semantics instead of passing Express middleware to `server.ext`. |
472
+ | [Nitro](https://nitro.build/docs/migration) | Inspect installed major, configured server directories, middleware and deployment preset; directory scanning conventions differ across versions. |
473
+ | [Strapi](https://docs.strapi.io/cms/backend-customization/middlewares) | Inspect configured global Koa middleware; route middleware and Document Service middleware do not establish whole-server HTTP coverage. |
474
+
475
+ ### When wiring cannot be completed
476
+
477
+ Return a short handoff in the current conversation for the person or their coding agent: framework
478
+ and version, deployment mode, project-relative server entries, files changed, exact failing check,
479
+ the remaining edit, and the routes or services whose coverage is unknown. Include commands actually
480
+ run and their results; omit credentials and environment values. If no server entry can be established,
481
+ say so and identify the missing deployment information. Do not invent one to clear a checklist.
482
+
483
+ Keep automatic scaffolding, source verification, local request verification and deployed coverage
484
+ separate in the report. HTTP middleware does not establish coverage of jobs, queues, WebSocket messages
485
+ or services deployed elsewhere. Connect prints a local plan; it does not automatically contact another
486
+ AI model. A framework or hosting upgrade requires this review again.
487
+
378
488
  ## Rules
379
489
 
380
490
  - Never invent or guess a UUID — the scan provisions it, the widget silently no-ops on a fake one.
package/README.md CHANGED
@@ -200,6 +200,36 @@ Options (for demo and demo-guide):
200
200
  (default: http://localhost:3000/api/tasks)
201
201
  ```
202
202
 
203
+ ### Next.js request and response protection
204
+
205
+ `protect` composes straightforward existing middleware instead of replacing its authentication or
206
+ redirect logic. The request guard gets a catch-all matcher; the application's middleware still runs
207
+ only within its original scope. Automatic composition accepts directly exported handlers and literal
208
+ path matchers (including a terminal `/:path*`). Complex matchers, re-exports and custom URL routing
209
+ are left untouched with an integration message. Source-aware edits use the application's installed
210
+ `typescript` parser; configuration files are never executed.
211
+
212
+ Apps with an existing `proxy.ts`/`proxy.js` (including under `src/`) require manual integration.
213
+ The installer leaves them unchanged and `protect --check` reports the gap. It never adds middleware
214
+ alongside a proxy, since Next.js does not allow both.
215
+
216
+ For App Router `app/**/route.ts` or `route.js` files, it also adds request checks and screens each
217
+ returned response. The shared server-only `patchstack.next` helper initializes one policy per module
218
+ instance, retries a failed initialization, and imports the same fallback rules file as middleware.
219
+ Supported handlers are directly exported async functions or block-bodied async arrows without an
220
+ explicit return type. Re-run `protect` after adding routes. Unsupported handlers remain unchanged;
221
+ `protect --check` lists the gaps instead of reporting complete route coverage.
222
+
223
+ Middleware cannot inspect the body that a downstream page returns. This setup does **not** establish
224
+ response filtering for rendered pages, Server Actions or Pages Router API handlers. Those need their
225
+ own server-side response boundary. It also cannot repair a vulnerability that bypasses Next.js
226
+ middleware itself: keep Next.js patched or filter such requests before they reach Next.js.
227
+
228
+ Set `PATCHSTACK_API_KEY` in the server environment for live rule delivery. Edge middleware cannot read
229
+ the local credential file. Never expose it as a `NEXT_PUBLIC_*` variable. A passing source check is not
230
+ proof of live protection: the running guard's `ruleSource`, `mode`, and coverage determine what it
231
+ actually received and screened.
232
+
203
233
  ### Verifying the guard at runtime (opt-in)
204
234
 
205
235
  `protect --check` reads the app's source. That establishes the guard is imported and called on a