@patchstack/connect 0.5.27 → 0.5.32
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 +75 -25
- package/README.md +28 -14
- package/dist/{chunk-YG5C7HYB.js → chunk-52IV7LN7.js} +1 -1
- package/dist/{chunk-YG5C7HYB.js.map → chunk-52IV7LN7.js.map} +1 -1
- package/dist/cli.js +2749 -372
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +10 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +10 -6
- package/dist/index.js.map +1 -1
- package/dist/protect/templates/astro-middleware.ts +5 -4
- package/dist/protect/templates/express-guard.cjs +5 -8
- package/dist/protect/templates/express-guard.js +5 -8
- package/dist/protect/templates/express-guard.ts +5 -8
- package/dist/protect/templates/fastify-plugin.cjs +52 -6
- package/dist/protect/templates/fastify-plugin.js +52 -6
- package/dist/protect/templates/fastify-plugin.ts +53 -7
- package/dist/protect/templates/fetch-guard.ts +52 -0
- package/dist/protect/templates/generic-guard.cjs +6 -5
- package/dist/protect/templates/generic-guard.js +6 -5
- package/dist/protect/templates/generic-guard.ts +5 -8
- package/dist/protect/templates/guard.ts +4 -7
- package/dist/protect/templates/next-guard.ts +5 -4
- package/dist/protect/templates/next-middleware.ts +5 -4
- package/dist/protect/templates/nuxt-middleware.ts +5 -4
- package/dist/protect/templates/sveltekit-hooks.ts +5 -4
- package/dist/protect.cjs +10 -6
- package/dist/protect.cjs.map +1 -1
- package/dist/protect.d.cts +1 -1
- package/dist/protect.d.ts +1 -1
- package/dist/protect.edge.js +2 -2
- package/dist/protect.edge.js.map +1 -1
- package/dist/protect.js +4 -4
- package/dist/protect.js.map +1 -1
- package/dist/{refresh-manifest-THITZHBD.js → refresh-manifest-EBORKM75.js} +10 -6
- package/dist/refresh-manifest-EBORKM75.js.map +1 -0
- package/package.json +5 -2
- package/dist/refresh-manifest-THITZHBD.js.map +0 -1
package/AGENT-INSTALL.md
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
This versioned reference ships inside `@patchstack/connect` and documents each setup command and its project changes.
|
|
4
4
|
|
|
5
|
+
## What this package is
|
|
6
|
+
|
|
7
|
+
- **An npm package for JavaScript and Node.js projects**, published by Patchstack under the `@patchstack` scope. It is not a WordPress plugin and needs no PHP. Patchstack also protects WordPress sites; this package is its integration for JS/Node projects — Vite, Next.js, plain vanilla JS, anything with a lockfile.
|
|
8
|
+
- **Source and releases:** MIT-licensed, source at https://github.com/patchstack/connect. Each version is published to npm from that repository's GitHub Actions workflow with an npm provenance attestation.
|
|
9
|
+
- **How to check it yourself:** `npm view @patchstack/connect` shows the live registry metadata, including the repository and the attestation. After installing, `npm audit signatures` verifies the registry signatures and provenance attestations of the installed packages, this one included.
|
|
10
|
+
- **What it does:** it sends the project's package names and versions to Patchstack for vulnerability matching, adds the Patchstack Connector widget to the site, installs a runtime exploit guard (`protect`) in the server's request path, and adds scan steps to the install and build scripts. `setup` and the `prebuild` hook also upload a structural map of the server (routes, input names, the packages behind each sink, file:line) so protection rules can target the app's own parameters — never source text or environment values. Run on its own, `map` sends nothing unless you pass `--upload`. The [Command reference](#command-reference) lists every command, what it reads and writes, and what it sends.
|
|
11
|
+
|
|
5
12
|
## Choose the project path first
|
|
6
13
|
|
|
7
14
|
Use the package setup flow below for an existing JS/Node application. Work in its package directory; a missing `package.json` can mean you are in a subdirectory or looking at generated HTML rather than the source project. A page containing HTML can still belong to a server-rendered application. Do not infer that runtime protection is unnecessary from the file extension alone.
|
|
@@ -43,7 +50,7 @@ The pages get a build step, even though nothing is compiled. The build is what r
|
|
|
43
50
|
npx @patchstack/connect setup
|
|
44
51
|
```
|
|
45
52
|
|
|
46
|
-
`setup` creates the site, writes its `siteUuid` to `.patchstackrc.json`, adds the Patchstack widget to `public/index.html`, adds `"postinstall": "patchstack-connect scan"`, and wires `"prebuild": "patchstack-connect scan"` and `"postbuild": "patchstack-connect mark-build"` around the build. In a hosted builder, scope `PATCHSTACK_ENVIRONMENT=sandbox` to the `setup` command, as in "Automated setup".
|
|
53
|
+
`setup` creates the site, writes its `siteUuid` to `.patchstackrc.json`, adds the Patchstack widget to `public/index.html`, adds `"postinstall": "patchstack-connect scan"`, and wires `"prebuild": "patchstack-connect scan && patchstack-connect map --upload"` and `"postbuild": "patchstack-connect mark-build"` around the build. In a hosted builder, scope `PATCHSTACK_ENVIRONMENT=sandbox` to the `setup` command, as in "Automated setup".
|
|
47
54
|
2. Add `dist` to `.gitignore` next to the entries `setup` wrote.
|
|
48
55
|
3. Put the widget on the other pages. `setup` adds the tag only to `index.html`, `public/index.html` or `src/app.html`. For any other page it lists the widget under `Missing` and prints the tag to add. Add one tag before `</body>` on each page, or in the shared layout, exactly as printed — no `data-build-mode`.
|
|
49
56
|
4. When the person names where the site is published, add that host's build settings so it publishes `dist/` and runs the build. See "Deploying" below; for Netlify that is a `netlify.toml` with `command = "npm run build"` and `publish = "dist"`.
|
|
@@ -69,8 +76,8 @@ Every command at a glance — what it does, whether it reads your source, what i
|
|
|
69
76
|
| Command | What it does | Reads your source? | Writes to your project | Sends over the network |
|
|
70
77
|
|---|---|---|---|---|
|
|
71
78
|
| `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:
|
|
73
|
-
| `map` | Local attack-surface analysis
|
|
79
|
+
| `setup` | One bounded command: scan, widget, install + verify guard, upload map, pull live rules, wire build hooks. Never starts the app or runs a build. | Local integration and structural source analysis | Config, widget, guard/framework files, scripts, map identity in the guard rules JSON, git-ignored `.patchstack/` cache | Package inventory and site identity; structural map (routes, input names, packages, file:line, identity); authenticated Pulse rules lookup. No source code or environment values |
|
|
80
|
+
| `map` | Local attack-surface analysis; setup invokes it with upload, and wires prebuild uploads. | Server source parsed with TypeScript (app compiler or CLI dependency) | `--out` file if requested; an uploaded map is stamped into the guard rules JSON during setup or a pre-bundle build hook | Standalone command sends nothing unless `--upload`. Setup and its build hook upload structure only, never source text or environment values |
|
|
74
81
|
| `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
82
|
| `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
83
|
| `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 |
|
|
@@ -82,29 +89,27 @@ Every command at a glance — what it does, whether it reads your source, what i
|
|
|
82
89
|
| `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
90
|
| `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
91
|
|
|
85
|
-
|
|
92
|
+
`setup` uploads a structural attack-surface map after installing the guard; the build hooks it installs upload a fresh map before bundling. Standalone `map` remains local without `--upload`. `protect` reads and edits integration source but transmits nothing. `scan` sends package names + versions and the declared public site identity, not source text. Map uploads additionally include routes, parameter names, package attribution, relative file:line locations, coverage limitations, and a policy-map digest. `scan --install-paths` remains separately opt-in for package installation locations.
|
|
86
93
|
|
|
87
94
|
## Package and command behavior
|
|
88
95
|
|
|
89
|
-
-
|
|
90
|
-
- **What is sent to Patchstack is the dependency list, plus this site's public address and name** — the dependencies are read from the lockfile (`package-lock.json`, `pnpm-lock.yaml`, `yarn.lock`) or, on bun projects (`bun.lock`/`bun.lockb`), by enumerating the installed packages under `node_modules/` — package names + versions, for vulnerability matching. No source code, no file paths, no git history is ever transmitted.
|
|
96
|
+
- **`scan` sends the dependency list plus this site's public address and name** — read from lockfiles or installed package metadata. It sends no source code or git history. Setup additionally uploads the structural map described below.
|
|
91
97
|
- **`scan --install-paths` is the one exception, and it is opt-in.** It adds where each package sits in the dependency tree — repo-relative paths made of `node_modules` segments, plus a workspace directory name when a workspace pins its own copy. They are read from the lockfile's own keys or from the `node_modules` walk, **never from your source tree**: no path to a file you wrote is sent by either form of `scan`.
|
|
92
98
|
- Why it exists: the same package is routinely installed twice at different versions, and without the locations an advisory affecting only one of them cannot be matched to the copy your code actually loads. Node resolves an import by walking up from the importing file, so the location is what distinguishes "you are running the vulnerable copy" from "the vulnerable copy is installed but nothing reaches it". Absent them, every installed version has to be treated as if the app used it — warnings about code you never call, and protection rules pinned to routes that run the safe copy.
|
|
93
99
|
- Why it is off by default: it widens what leaves the machine, so it is your explicit choice and not a consequence of upgrading the package. (`mark-build` additionally stamps built HTML with a coarse stack descriptor that may include hosting-related env variable *names* — e.g. `VERCEL`, `CF_PAGES` — never their values.)
|
|
94
100
|
- **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
101
|
- **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
102
|
- **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
|
-
- **
|
|
103
|
+
- **Mapping is automatic in `setup`, and in its prebuild hook.** It parses server source and sends structure, not source text. A standalone `map` command prints locally and uploads only with `--upload`. `protect`, `scan`, `guide`, `status` and `mark-build` do not invoke mapping.
|
|
98
104
|
- **`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
105
|
- 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
|
-
- 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
|
-
- **`setup` runs `scan
|
|
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).
|
|
106
|
+
- 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/`, `_site/`), never to source. `guide`, `status`, and `init` write nothing except `init`'s own `.patchstackrc.json`.
|
|
107
|
+
- **`setup` runs `scan` → `protect` → map upload → live-rule lookup**, then reports the outcome. Provisioning precedes guard installation. The map is stamped into the guard source for the NEXT startup/build; restart an already-running preview/server to load it. The rule lookup uses the runtime validator and source-scoped local cache without creating a running guard or installing global hooks. A successful empty policy is reported as zero assigned rules, not proof of protection. Failed uploads/pulls appear under Missing and can be retried by rerunning setup. It also wires install scans, prebuild scans + map uploads, and postbuild marking (explicit build chains for Yarn, pnpm and Bun), preserving existing commands. It never starts, builds or deploys the app. Ambiguous/custom integration code still requires review rather than being overwritten.
|
|
108
|
+
- 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`), **TanStack Start** (documented server Fetch entry without requiring Supabase), **Next.js** (scaffolds or composes middleware/proxy 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
109
|
- **`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
|
-
-
|
|
105
|
-
- **`map --upload`
|
|
110
|
+
- **Standalone `map` is local unless you pass `--upload`.** It skips dependencies, build output and hidden directories and does not follow external symlinks by default. It reports detected entry points, inputs, sinks, dependency calls and evidence tiers with coverage limitations. Static analysis is best-effort, not a completeness guarantee. `setup` runs this analysis after guard integration and uploads it automatically.
|
|
111
|
+
- **`map --upload` and `setup` send structural analysis** to `monitor/pulse/input-map/<your site uuid>`. The upload includes no source code, file contents or environment variable values. Setup and pre-bundle uploads derive `_patchstack.build_id` from the policy map and write it into the existing guard rules file. A standalone upload outside a build remains unbound and changes no guard file. No recognized routes still means useful import/coverage evidence and is uploaded. API failures are reported without failing a production build. Setup then retrieves Pulse rules, including delivered response-phase policies, using the same build identity. Only a matching server verdict permits scoped enforcement. The local cache is not a client bundle or a replacement for runtime rule refresh; filesystem-less deployments fetch at runtime and need server-side credentials.
|
|
106
112
|
- **`demo-guide node-serialize` is the read-only companion.** It checks the Host-created site configuration and vulnerable lockfile entry, explains the complete local prepare/run/restart/prove/cleanup sequence, and prints the next exact command. It does not require a deployment and does not change files or contact Patchstack.
|
|
107
|
-
- Patchstack is not WordPress-only. Connect monitors any JS/Node project — Vite, Next.js, plain vanilla JS, anything with a lockfile.
|
|
108
113
|
|
|
109
114
|
## Before you start — never install twice
|
|
110
115
|
|
|
@@ -278,6 +283,36 @@ Handle it in this order:
|
|
|
278
283
|
run them, the person runs `npx @patchstack/connect claim` (or `login`) themselves and you relay the
|
|
279
284
|
link from their output.
|
|
280
285
|
|
|
286
|
+
### When the platform blocks the CLI outright
|
|
287
|
+
|
|
288
|
+
Some hosted builders refuse any third-party CLI that contacts an outside service, and offer the person
|
|
289
|
+
neither a terminal nor a way to approve it. Then none of the options above exists in that workspace, and
|
|
290
|
+
running the command again, under any spelling, gets the same answer. Step 1 still applies: do not route
|
|
291
|
+
around the block, and leave `package.json` and the source tree as they were.
|
|
292
|
+
|
|
293
|
+
Tell the person in plain words that this platform will not run Patchstack's setup, then give them these
|
|
294
|
+
choices and wait for theirs:
|
|
295
|
+
|
|
296
|
+
- **Run setup on a copy of the project outside the builder.** Offer this only when the builder can export
|
|
297
|
+
the project or sync it with a git repository; if you do not know whether it can, say so. In that copy,
|
|
298
|
+
the person runs `npx @patchstack/connect setup` — without `PATCHSTACK_ENVIRONMENT=sandbox`, which is for
|
|
299
|
+
a hosted workspace; on their own machine a scan reports `local` by itself. They then bring the changes
|
|
300
|
+
back the same way. `.patchstackrc.local.json` stays behind: it holds the API key and is git-ignored. If
|
|
301
|
+
the builder's own install or build cannot reach Patchstack, the scan steps `setup` added print the error
|
|
302
|
+
and let it continue, so the app still builds and only that build's report is missing. The exception is a
|
|
303
|
+
builder that installs with `bun install`: there the `postinstall` scan fails the install, so remove that
|
|
304
|
+
one script before bringing the changes back.
|
|
305
|
+
- **Add only the Patchstack Connector.** The person creates an "Application" site in the Patchstack
|
|
306
|
+
dashboard and gives you its site ID or widget snippet, and you add the tag as in steps 2 and 3 of
|
|
307
|
+
"Plain HTML sites", in the app's root HTML shell or layout. This adds the widget and nothing else: no
|
|
308
|
+
check of the app's packages, no build steps, no runtime protection. Say that when you offer it.
|
|
309
|
+
- **Stop here.** Nothing else changes.
|
|
310
|
+
|
|
311
|
+
If you installed `@patchstack/connect` for this attempt, it stays in `dependencies` with nothing wired to
|
|
312
|
+
run it. Keep it for the first choice; for the other two, offer to remove it with the project's package
|
|
313
|
+
manager. Report the result as **Patchstack setup did not run on this platform**, with the choice the person
|
|
314
|
+
made, not as an installation.
|
|
315
|
+
|
|
281
316
|
## Manual setup
|
|
282
317
|
|
|
283
318
|
1. **First scan** — provisions a Patchstack site automatically, writes the UUID to `.patchstackrc.json`, and installs the Patchstack Connector's `<script>` tag into the root HTML shell (`index.html`, `public/index.html`, or `src/app.html`) when one exists — or, when the root shell is JSX, the production marker instead. No signup, dashboard step, or UUID is needed up front:
|
|
@@ -293,16 +328,16 @@ Handle it in this order:
|
|
|
293
328
|
```jsonc
|
|
294
329
|
{
|
|
295
330
|
"scripts": {
|
|
296
|
-
|
|
331
|
+
"prebuild": "patchstack-connect scan && patchstack-connect map --upload",
|
|
297
332
|
"postbuild": "patchstack-connect mark-build",
|
|
298
333
|
"postinstall": "patchstack-connect scan"
|
|
299
334
|
}
|
|
300
335
|
}
|
|
301
336
|
```
|
|
302
337
|
|
|
303
|
-
If a lifecycle hook already exists, chain instead of replacing it, e.g. `"prebuild": "existing-command && patchstack-connect
|
|
338
|
+
If a lifecycle hook already exists, chain instead of replacing it, e.g. `"prebuild": "patchstack-connect scan && existing-command && patchstack-connect map --upload"`. The `postinstall` scan reports dependencies added during an iterative sandbox session and covers applications with no build command.
|
|
304
339
|
|
|
305
|
-
**Bun
|
|
340
|
+
**Yarn, pnpm and Bun projects:** use an explicit build chain instead of assuming npm-style `pre`/`post` hooks run: `"build": "patchstack-connect scan && patchstack-connect map --upload && <existing build command> && patchstack-connect mark-build"`. Modern Yarn and Bun skip those hooks; pnpm behavior depends on version and configuration. `setup` uses this chain for all three managers, including Yarn Classic, and preserves existing custom hooks.
|
|
306
341
|
|
|
307
342
|
**Checking a build yourself:** run it through the package manager (`npm run build`), never the framework's own CLI (`astro build`, `vite build`, `next build`). Calling the CLI directly skips the `prebuild`/`postbuild` hooks, so the build is not scanned, not marked and not reported, and it tells you nothing about what the deployed build will carry.
|
|
308
343
|
|
|
@@ -336,14 +371,29 @@ It is server-only. Never put it in the widget tag, client bundles, or public env
|
|
|
336
371
|
check requests and filter returned responses. It writes a shared server-only `patchstack.next`
|
|
337
372
|
helper alongside `patchstack.rules.json`. Unsupported exports, complex matchers or handlers are
|
|
338
373
|
left unchanged and reported by `--check`; re-run `protect` after adding routes. An existing
|
|
339
|
-
`proxy.ts`/`proxy.js`
|
|
340
|
-
|
|
374
|
+
`proxy.ts`/`proxy.js` is composed on Next 16+ using the same conservative export/matcher rules;
|
|
375
|
+
a new Next 16+ install uses `proxy.ts`. Conflicting entries stay untouched. Middleware/proxy alone
|
|
341
376
|
cannot filter downstream page bodies. Rendered pages, Server Actions and Pages API response
|
|
342
377
|
filtering are not verified by this adapter. Keep Next.js patched: a framework middleware bypass
|
|
343
378
|
also bypasses a guard in middleware. Edge middleware needs `PATCHSTACK_API_KEY` in the server
|
|
344
379
|
environment; it cannot read `.patchstackrc.local.json`. Do not put credentials in public variables
|
|
345
380
|
or commit them. Source checks do not verify rule delivery or blocking in the running deployment.
|
|
346
381
|
|
|
382
|
+
**TanStack Start:** the documented `src/server.ts` Fetch entry can be scaffolded without Supabase
|
|
383
|
+
or `src/start.ts`. Supported literal `createServerEntry({ fetch: ... })` configurations are wrapped
|
|
384
|
+
without changing host arguments or application error handling. The installed framework must expose
|
|
385
|
+
`server-entry`; custom entry paths, spreads, getters and competing files need manual integration.
|
|
386
|
+
The existing TanStack/Supabase adapter screens native requests by default and filters the response
|
|
387
|
+
inside TanStack's middleware result. No `PATCHSTACK_ROUTE_WAF` switch is needed. Browser-direct
|
|
388
|
+
services and separately deployed functions are not protected by guarding the frontend server;
|
|
389
|
+
keep backend authorization/RLS and install a guard at each independently exposed backend.
|
|
390
|
+
|
|
391
|
+
Generated guards refresh live rules every five minutes (15 seconds in an explicit sandbox).
|
|
392
|
+
Express/Node guards enable bounded response filtering; Fastify filters buffered `onSend` output,
|
|
393
|
+
leaving streams and bodyless replies untouched. Unmodified recognized helpers can be upgraded;
|
|
394
|
+
customized helpers are preserved and flagged for manual review. Wiring checks inspect executable
|
|
395
|
+
statements, not just marker comments, and cannot establish live delivery or complete coverage.
|
|
396
|
+
|
|
347
397
|
`--check` reads the app's source. It can establish that the guard is imported and called on a request
|
|
348
398
|
path; it cannot establish that a request ever reaches it — an app can wire the guard onto one server
|
|
349
399
|
and serve traffic from another, and that passes. To settle the difference there is an opt-in check
|
|
@@ -449,13 +499,13 @@ which integration API is available.
|
|
|
449
499
|
| [Solid](https://docs.solidjs.com/quick-start) | Separate the UI library from SolidStart or a custom server; keep protection out of client components. |
|
|
450
500
|
| [Qwik](https://qwik.dev/docs/qwikcity/) | Inspect Qwik City and the deployment adapter; component resumability does not identify the request entry. |
|
|
451
501
|
| [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.
|
|
502
|
+
| [Next.js](https://nextjs.org/docs/app/api-reference/file-conventions/proxy) | Inspect root or `src/` middleware/proxy, matchers, APIs and Server Actions. Connect uses `proxy.ts` for new Next 16+ installs and composes supported existing proxies. Conflicting entries and complex routing require manual review. |
|
|
453
503
|
| [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
504
|
| [SvelteKit](https://svelte.dev/docs/kit/hooks) | Compose the existing server `handle` hook; check endpoints, actions, prerendering and the deployed adapter. |
|
|
455
505
|
| [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
506
|
| [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
507
|
| [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
|
|
508
|
+
| [TanStack Start](https://tanstack.com/start/latest/docs/framework/react/guide/middleware) | Inspect the server entry and global request middleware, including server functions. The native Fetch-entry adapter does not require Supabase. Custom entry paths need manual review; the separate TanStack/Supabase adapter matches a specific layout. |
|
|
459
509
|
| [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
510
|
| [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
511
|
| [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. |
|
|
@@ -492,7 +542,7 @@ AI model. A framework or hosting upgrade requires this review again.
|
|
|
492
542
|
- The CLI never opens the dashboard link and never asks for Patchstack credentials.
|
|
493
543
|
- Label hosted workspace scans with `PATCHSTACK_ENVIRONMENT=sandbox` in that process only. Leave production builds unset (a platform's own tier or production branch name, or the hosted builder the project belongs to, makes the build report `production`; a developer machine or a CI runner this does not know reports `local`) and never commit a sandbox label into files shared with production.
|
|
494
544
|
- If a step fails, stop and report it. Don't proceed with placeholders.
|
|
495
|
-
- If your tool refuses to execute the CLI, stop and hand the command to the person — see "When your tool will not run this CLI". Never work around a permission refusal.
|
|
545
|
+
- If your tool refuses to execute the CLI, stop and hand the command to the person — see "When your tool will not run this CLI", and "When the platform blocks the CLI outright" when nobody can approve it there. Never work around a permission refusal.
|
|
496
546
|
- CI never has the credential in a file: `.patchstackrc.local.json` is git-ignored by design, so set `PATCHSTACK_API_KEY` as an env var there (and `PATCHSTACK_SITE_UUID` too where `.patchstackrc.json` is also absent). Precedence for the site UUID and settings: CLI flag → env var → `.patchstackrc.json`. For the API key: env var → `.patchstackrc.local.json` → `.patchstackrc.json` (where installs made before the split still hold it). `login` is interactive and refuses to run in CI, so CI always takes its credential from the environment.
|
|
497
547
|
|
|
498
548
|
## Which build a rule belongs to
|
|
@@ -503,7 +553,7 @@ read from: rename the field two deploys later and the rule addresses something t
|
|
|
503
553
|
while still reporting as active protection. Coverage that is not there is worse than a known gap.
|
|
504
554
|
|
|
505
555
|
Such a rule carries a `build_scope` naming the policy map its coordinate came from, and it blocks only
|
|
506
|
-
when Patchstack **confirms** those coordinates belong to the map carried by the guard now running. Three moving
|
|
556
|
+
when Patchstack **confirms** those coordinates belong to the map carried by the guard now running. Setup performs mapping and rule retrieval for the next startup too; it does not update an already-running process. Three moving
|
|
507
557
|
parts:
|
|
508
558
|
|
|
509
559
|
- **`scan`, during `prebuild`**, removes any previous `_patchstack.build_id` from the guard's own rules
|
|
@@ -536,7 +586,7 @@ rule locally establishes that you intend it, not that its coordinate still descr
|
|
|
536
586
|
A scoped rule you supply blocks when it names the map identity this guard reports (`buildId`), or when you
|
|
537
587
|
set **`trustLocalRuleScope: true`** to take responsibility for the match.
|
|
538
588
|
|
|
539
|
-
|
|
589
|
+
Running `setup` authorizes this workflow, including its prebuild map uploads. Standalone mapping sends nothing without `--upload`. The identifier is a one-way
|
|
540
590
|
digest of the map — never a message, an author, a diff, a branch name, source text, or environment value.
|
|
541
591
|
|
|
542
592
|
## Runtime guard reporting
|
|
@@ -791,7 +841,7 @@ Two more endpoints the package can call, for completeness:
|
|
|
791
841
|
- `npx @patchstack/connect protect --check` verifies from the source that the runtime guard is connected to the request path. It does not run the app.
|
|
792
842
|
- `npx @patchstack/connect protect --check --runtime` additionally **starts the app** on a loopback port and sends it one request, to establish that a request reaches the guard seam. Opt-in, and the only command that runs the application; exit `0`/`1`/`2` as described in step 4.
|
|
793
843
|
- Load the site in a browser — the widget should appear, as the "Connect this website" panel while the site is unclaimed. Refresh a page that was already open before the tag was added: the widget only loads with the page.
|
|
794
|
-
- On the deployed site, the
|
|
844
|
+
- On the deployed site, the widget appears only after a deploy that includes these source changes.
|
|
795
845
|
|
|
796
846
|
## Answering "is Patchstack installed?" / "is Patchstack removed?"
|
|
797
847
|
|
|
@@ -901,7 +951,7 @@ You cannot complete this alone. It is deliberately a human-in-the-loop step: sta
|
|
|
901
951
|
| Situation | What happens | What to do |
|
|
902
952
|
|---|---|---|
|
|
903
953
|
| Site was never claimed | `409` — no owner exists to approve | Ask the user to claim the site in the dashboard first, or, if the site is disposable, delete `.patchstackrc.json` **and** `.patchstackrc.local.json` and `scan` to provision a fresh one — leaving the old credential behind means the next scan starts out holding one that belongs to a different site |
|
|
904
|
-
| Running in CI | Refuses to start | CI takes its credential from `
|
|
954
|
+
| Running in CI | Refuses to start | CI takes its credential from `PATCHSTACK_API_KEY`; `login` is for a developer machine |
|
|
905
955
|
| No `siteUuid` configured | Refuses to start | There is no site to recover — run `scan` |
|
|
906
956
|
| Code expired | `--wait` ends after 10 minutes | Start again from step 1 for a new code |
|
|
907
957
|
| `--wait` with nothing pending | "No login is waiting for approval" | Run step 1 first; `--wait` resumes a request, it does not start one |
|
package/README.md
CHANGED
|
@@ -13,9 +13,9 @@ Connect a JavaScript / Node.js application to [Patchstack](https://patchstack.co
|
|
|
13
13
|
|
|
14
14
|
For an existing JS/Node project in a hosted workspace, copy this request into a coding assistant, or run the same command yourself. For Gemini CLI, OpenCode, Codex CLI, or Claude Code on your own machine, use [Local coding CLIs](#local-coding-clis) below. For a standalone HTML/CSS/JavaScript site without a package-managed app, use the [plain HTML widget instructions](AGENT-INSTALL.md#plain-html-sites); do not add Node tooling just for the widget.
|
|
15
15
|
|
|
16
|
-
> I have vetted the official [`@patchstack/connect`](https://www.npmjs.com/package/@patchstack/connect) package and authorize its Patchstack Connector, production build hooks,
|
|
16
|
+
> I have vetted the official [`@patchstack/connect`](https://www.npmjs.com/package/@patchstack/connect) package and authorize its Patchstack Connector, production build hooks, runtime protection source edits, structural attack-surface map uploads (not source code), and live-rule retrieval. Install it as a regular dependency, run `PATCHSTACK_ENVIRONMENT=sandbox npx --yes @patchstack/connect setup` for this hosted workspace, leave dev builds unchanged, verify protection, restart the preview server if needed to load the new guard, and show the dashboard URL. The Patchstack Connector widget is part of this install and on by default: add it, and do not ask me whether to. Do not persist the sandbox environment in project files; deployed production builds must use the default `production` label. When setup finishes, tell me to refresh the preview if the Patchstack widget is not showing yet, and remind me to deploy when I am ready — do not deploy anything yourself.
|
|
17
17
|
|
|
18
|
-
`setup` is state-aware and idempotent: it scans dependencies, provisions or reuses the site, manages the Patchstack Connector, installs and verifies the runtime guard,
|
|
18
|
+
`setup` is state-aware and idempotent: it scans dependencies, provisions or reuses the site, manages the Patchstack Connector, installs and verifies the runtime guard, uploads a structural map, fetches live rules, and wires dependency/build checks without replacing the build command. It prints what succeeded and what remains; it never starts the app or runs the build. `guide` provides project-specific status without changing files.
|
|
19
19
|
|
|
20
20
|
### Local coding CLIs
|
|
21
21
|
|
|
@@ -115,7 +115,7 @@ npm install --save @patchstack/connect && npx @patchstack/connect setup
|
|
|
115
115
|
|
|
116
116
|
> **Use your project's own package manager.** On Bun-managed projects (including many Lovable projects) install with `bun add @patchstack/connect` instead — running `npm install` there plants a `package-lock.json` that the platform's native dependency flow never updates again, leaving a stale lockfile next to the live one. Connect detects and works around that (see *Stale lockfiles* below), but not creating the fossil is better. Protection imports `@patchstack/connect/protect` at runtime, so deployments that prune dev dependencies need the package in `dependencies`.
|
|
117
117
|
|
|
118
|
-
> **Hosted builders:** set `PATCHSTACK_ENVIRONMENT=sandbox` in the workspace process environment (or scope it to the setup command above), persist every file written by `setup`, and restart any already-running server so it loads the new middleware. Do not write `"environment": "sandbox"` to the committed `.patchstackrc.json`: the same project files reach production, where scans should inherit no override and default to `production`. TanStack Start + Supabase (the server shape emitted by Lovable) is auto-wired: browser Supabase traffic is tunneled through a same-origin guard, server-function arguments are inspected, and responses are screened. A client-only SPA has no server request path to protect; setup will leave a generic scaffold and `protect --check` will remain red until the host adds a server/edge seam.
|
|
118
|
+
> **Hosted builders:** set `PATCHSTACK_ENVIRONMENT=sandbox` in the workspace process environment (or scope it to the setup command above), persist every file written by `setup`, and restart any already-running server so it loads the new middleware. Do not write `"environment": "sandbox"` to the committed `.patchstackrc.json`: the same project files reach production, where scans should inherit no override and default to `production`. TanStack Start + Supabase (the server shape emitted by Lovable) is auto-wired: browser Supabase traffic is tunneled through a same-origin guard, server-function arguments are inspected, and responses are screened. A client-only SPA has no server request path to protect; setup will leave a generic scaffold and `protect --check` will remain red until the host adds a server/edge seam. Native TanStack requests are screened by default; no additional route-WAF switch is needed. New Start apps without that Supabase layout use the documented server Fetch entry. Browser-direct services and separately deployed functions still require their own protection.
|
|
119
119
|
|
|
120
120
|
That's it. `setup`:
|
|
121
121
|
|
|
@@ -126,8 +126,11 @@ That's it. `setup`:
|
|
|
126
126
|
5. Connect installs the Patchstack Connector's `<script>` tag into your root HTML shell (see *The Patchstack Connector* below) so the widget shows up on the next preview reload — as the "Connect this website" panel until the site is claimed, then as the "Report a vulnerability" button. On a server-rendered root it also adds the production marker, which is what tells the widget to switch from build mode to visitor report intake on the published site.
|
|
127
127
|
6. Installs the runtime guard after provisioning, bakes the site UUID into it, and verifies the framework seam. Known server stacks are auto-wired; unmatched or conflicting layouts get a generic scaffold and exact manual checks.
|
|
128
128
|
7. Adds `postinstall: patchstack-connect scan`, preserving any existing command, so dependencies added during a sandbox session and build-less production installs are reported immediately.
|
|
129
|
-
8.
|
|
130
|
-
9.
|
|
129
|
+
8. Uploads a structural attack-surface map (routes, input names, package attribution, relative file:line locations and coverage notes; no source text or environment values), stamps its identity into the guard for the next startup/build, and fetches live request/response rules. Empty policy, upload failures and rule-fetch failures are reported separately.
|
|
130
|
+
9. Wires `scan` followed by `map --upload` before builds and `mark-build` after builds, preserving existing commands. npm uses lifecycle hooks; Yarn, pnpm and Bun use explicit build chains independent of lifecycle settings.
|
|
131
|
+
10. Prints a dashboard link — open it in a browser to attach the new site to your Patchstack account. You can re-display it any time with `npx @patchstack/connect status`.
|
|
132
|
+
|
|
133
|
+
If the server is already running, **restart it** to load the new guard and map identity. Setup does not start, build or deploy your app. Rule delivery does not prove runtime enforcement: scoped rules still need a matching server verdict, and unsupported/custom entries remain reported gaps.
|
|
131
134
|
|
|
132
135
|
Then **refresh your preview**. The widget loads with the page, so a preview that was already open still shows the HTML from before setup. Builders that hot reload will have refreshed it for you; if the widget is missing, refresh it once. Until the site is claimed it shows the "Connect this website" panel. `setup` prints the same reminder, and the CLI has no way to reload a browser itself.
|
|
133
136
|
|
|
@@ -156,7 +159,8 @@ patchstack-connect scan [options] Scan the lockfile and POST to
|
|
|
156
159
|
.patchstackrc.json)
|
|
157
160
|
patchstack-connect setup [options] Run scan, manage the widget, and idempotently
|
|
158
161
|
install + verify runtime protection and wire
|
|
159
|
-
dependency/build scans.
|
|
162
|
+
dependency/build scans + map uploads. Uploads the map and
|
|
163
|
+
fetches live rules; never starts the app or runs the build
|
|
160
164
|
patchstack-connect init <site-uuid> Optional: pre-seed .patchstackrc.json with
|
|
161
165
|
an existing site UUID
|
|
162
166
|
patchstack-connect status [options] Show current configuration
|
|
@@ -230,16 +234,26 @@ Options (for demo and demo-guide):
|
|
|
230
234
|
|
|
231
235
|
### Next.js request and response protection
|
|
232
236
|
|
|
237
|
+
Framework detection follows the exported application's server entry, not the builder's name.
|
|
238
|
+
[Lovable documents TanStack Start for new projects and React/Vite for older ones](https://docs.lovable.dev/introduction/faq);
|
|
239
|
+
[Hostinger Horizons offers a hosted backend](https://www.hostinger.com/blog/horizons-integrated-backend/),
|
|
240
|
+
and [Airo exports React/TypeScript applications](https://airo-builder.godaddy.com/discover/features).
|
|
241
|
+
Those frontends do not establish where backend requests execute. Browser-direct APIs, Supabase Edge
|
|
242
|
+
Functions and other separately deployed services need their own server-side integration; a browser
|
|
243
|
+
tunnel does not replace backend authorization or RLS. Tests use synthetic framework-shaped apps,
|
|
244
|
+
not proprietary builder templates, and do not certify a builder's live hosting environment.
|
|
245
|
+
|
|
233
246
|
`protect` composes straightforward existing middleware instead of replacing its authentication or
|
|
234
247
|
redirect logic. The request guard gets a catch-all matcher; the application's middleware still runs
|
|
235
248
|
only within its original scope. Automatic composition accepts directly exported handlers and literal
|
|
236
249
|
path matchers (including a terminal `/:path*`). Complex matchers, re-exports and custom URL routing
|
|
237
|
-
are left untouched with an integration message. Source-aware edits use
|
|
238
|
-
|
|
250
|
+
are left untouched with an integration message. Source-aware edits use a TypeScript parser supplied
|
|
251
|
+
by the app or Connect's CLI dependency; configuration files are never executed.
|
|
239
252
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
253
|
+
On Next 16+, the installer creates `proxy.ts` for new wiring and composes supported existing
|
|
254
|
+
`proxy.ts`/`proxy.js` handlers (including under `src/`). Older versions retain middleware. Conflicting
|
|
255
|
+
entries, unsupported proxy exports, and custom normalization stay untouched and are reported by
|
|
256
|
+
`protect --check`. Middleware and proxy are never created alongside one another.
|
|
243
257
|
|
|
244
258
|
For App Router `app/**/route.ts` or `route.js` files, it also adds request checks and screens each
|
|
245
259
|
returned response. The shared server-only `patchstack.next` helper initializes one policy per module
|
|
@@ -401,7 +415,7 @@ In App Platform, make the variable available at build time (`BUILD_TIME` or `RUN
|
|
|
401
415
|
|
|
402
416
|
An explicit `PATCHSTACK_ENVIRONMENT` overrides `.patchstackrc.json`, and the file's `environment` overrides automatic detection. When production keeps reporting sandbox after deployment, remove a workspace-only override from the committed config and from the production build environment, then rebuild and deploy. Apply sandbox overrides only to preview processes or preview deployment settings.
|
|
403
417
|
|
|
404
|
-
Do not commit `"environment": "sandbox"` to `.patchstackrc.json` when the same files are deployed to production. Scope the variable to the sandbox command/process instead:
|
|
418
|
+
Do not commit `"environment": "sandbox"` to `.patchstackrc.json` when the same files are deployed to production. If one is committed anyway, a build its platform identifies as production is still treated as production, and `scan` and `mark-build` print a warning naming the file. Scope the variable to the sandbox command/process instead:
|
|
405
419
|
|
|
406
420
|
```bash
|
|
407
421
|
PATCHSTACK_ENVIRONMENT=sandbox npx @patchstack/connect setup
|
|
@@ -413,7 +427,7 @@ During a build, the `prebuild` scan removes any previous map stamp. A later `map
|
|
|
413
427
|
|
|
414
428
|
### `scan` as a build hook
|
|
415
429
|
|
|
416
|
-
`setup` wires `scan` into `postinstall`, `prebuild`, or
|
|
430
|
+
`setup` wires `scan` into `postinstall`, npm's `prebuild`, or an explicit `build` chain for Yarn, pnpm and Bun. Run from one of those, a report Patchstack cannot accept — no credential in the build environment, a rejected credential, a site that no longer exists, an outage — is printed on stderr and `scan` exits 0, so the install or build it is attached to carries on. Patchstack keeps the last manifest it accepted for the site until a scan that can report. Run directly (`npx @patchstack/connect scan`), the same failure exits 1.
|
|
417
431
|
|
|
418
432
|
A deploy never has `.patchstackrc.local.json`, so the usual cause is a missing `PATCHSTACK_API_KEY` in the platform's environment (see *Configuration*). The hook is recognised through `npm_lifecycle_event`, which npm, pnpm, Yarn and `bun run` set to the running script's name. `bun install` does not set it, so a `postinstall` scan under Bun still fails the install when it cannot report.
|
|
419
433
|
|
|
@@ -453,7 +467,7 @@ The Patchstack Connector is a floating control whose form follows the site's cla
|
|
|
453
467
|
|
|
454
468
|
Re-runs update the tag in place (the `data-patchstack-connect-widget` attribute marks it as managed by Connect); a pre-existing manual widget tag is left untouched. `--dry-run` never edits anything; a failed post still skips the widget tag (it needs the site UUID) but the production marker may already have been written, since it runs before the post. Projects whose root layout is code that Connect does not edit (Nuxt, …) get the exact snippet and target file printed instead — `guide` shows framework-specific placement.
|
|
455
469
|
|
|
456
|
-
- **`mark-build`** ensures the same tag in built HTML output, covering builds whose source shell Connect couldn't edit, and stamps `window.__PATCHSTACK_PROD__` so the widget hides the claim/login UI on the published site (owners reach it by appending `#patchstack` to the live URL). It then reports what it did — `stamped`, `withheld`, `no-pages` for a server-rendered build, or `no-output` — alongside the same manifest `scan` sent before the bundler ran, so the dashboard can say why a published app is or is not reporting its build. That report is the second half of one build, not a second build: Patchstack keeps one copy of the manifest and reads the two together. It is sent only for a site that is already registered, and never carries the site's address or name, which `mark-build` does not resolve. The marker says the page is the live site, so **only a production build carries it**: the environment is read the same way `scan` reads it (the build platform's own tier or branch name, then the hosted builder the project belongs to), and a local or preview build gets the widget tag, no marker, and any marker an earlier build left behind removed. Publishing a static build by hand from your machine is the case that needs `--production` (or `PATCHSTACK_ENVIRONMENT=production`), because nothing in that environment can say the build is a deployment.
|
|
470
|
+
- **`mark-build`** ensures the same tag in built HTML output, covering builds whose source shell Connect couldn't edit, and stamps `window.__PATCHSTACK_PROD__` so the widget hides the claim/login UI on the published site (owners reach it by appending `#patchstack` to the live URL). It then reports what it did — `stamped`, `withheld`, `no-pages` for a server-rendered build, or `no-output` — alongside the same manifest `scan` sent before the bundler ran, so the dashboard can say why a published app is or is not reporting its build. That report is the second half of one build, not a second build: Patchstack keeps one copy of the manifest and reads the two together. It is sent only for a site that is already registered, and never carries the site's address or name, which `mark-build` does not resolve. The marker says the page is the live site, so **only a production build carries it**: the environment is read the same way `scan` reads it (the build platform's own tier or branch name, then the hosted builder the project belongs to), and a local or preview build gets the widget tag, no production marker, and any marker an earlier build left behind removed — including an inline script that only sets `window.__PATCHSTACK_PROD__` and was added by hand. A `sandbox` build gets `window.__PATCHSTACK_ENV__="sandbox"` in its place, so the widget shows the owner's panel on a preview host it cannot recognise by name. Publishing a static build by hand from your machine is the case that needs `--production` (or `PATCHSTACK_ENVIRONMENT=production`), because nothing in that environment can say the build is a deployment.
|
|
457
471
|
|
|
458
472
|
- **Opting out:** persist `"widget": false` in `.patchstackrc.json` to disable both the widget tag and the production marker (dependency scanning only). Without it, the next successful scan re-adds the managed tag, and the next scan re-adds the marker on a JSX root or Astro layout.
|
|
459
473
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/protect/safe-origin.js","../src/types.ts","../src/endpoint-policy.ts","../src/bounded-response.ts","../src/pulse-token.ts","../src/build-id.ts"],"mappings":";AAKO,SAAS,aAAa,OAAO;AAClC,MAAI;AACF,UAAM,IAAI,IAAI,IAAI,KAAK;AACvB,QAAI,EAAE,aAAa,SAAU,QAAO;AACpC,WAAO,EAAE,aAAa,YAAY,EAAE,aAAa,eAAe,EAAE,aAAa,eAAe,EAAE,aAAa,WAAW,EAAE,aAAa;AAAA,EACzI,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAMO,SAAS,YAAY,WAAW,UAAU,OAAO;AACtD,MAAI,OAAO,cAAc,YAAY,cAAc,GAAI,QAAO;AAC9D,MAAI,aAAa,SAAS,EAAG,QAAO;AACpC,WAAS,OAAO,gCAAgC,KAAK,cAAc,SAAS,qDAAqD;AACjI,SAAO;AACT;AAEA,IAAM,SAAS,oBAAI,IAAI;AACvB,SAAS,SAAS,KAAK,SAAS;AAC9B,MAAI,OAAO,IAAI,GAAG,EAAG;AACrB,SAAO,IAAI,GAAG;AAEd,UAAQ,KAAK,OAAO;AACtB;;;
|
|
1
|
+
{"version":3,"sources":["../src/protect/safe-origin.js","../src/types.ts","../src/endpoint-policy.ts","../src/bounded-response.ts","../src/pulse-token.ts","../src/build-id.ts"],"mappings":"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","names":[]}
|