@patchstack/connect 0.5.15 → 0.5.16
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 +37 -11
- package/dist/cli.js +654 -174
- package/dist/cli.js.map +1 -1
- package/dist/protect/templates/demo-rules.json +2 -2
- package/dist/protect.cjs +1384 -747
- package/dist/protect.cjs.map +1 -1
- package/dist/protect.d.cts +110 -16
- package/dist/protect.d.ts +110 -16
- package/dist/protect.edge.js +1372 -735
- package/dist/protect.edge.js.map +3 -3
- package/dist/protect.js +1372 -735
- package/dist/protect.js.map +1 -1
- package/package.json +1 -1
package/AGENT-INSTALL.md
CHANGED
|
@@ -85,7 +85,7 @@ Only `map` analyses your source, and only `map --upload` sends anything derived
|
|
|
85
85
|
|
|
86
86
|
## Talk to the person while you work
|
|
87
87
|
|
|
88
|
-
The person who asked for this usually did not write the project and has never installed a package. Installs and builds here can run for several minutes, and a silent wall of build output is the worst part of their first experience of Patchstack. Narrate it.
|
|
88
|
+
The person who asked for this usually did not write the project and has never installed a package. Installs and builds here can run for several minutes, and a silent wall of build output is the worst part of their first experience of Patchstack. Narrate it, one or two sentences at a time.
|
|
89
89
|
|
|
90
90
|
- **Say what you are about to do, before the slow command.** One sentence, no command names: "I'm adding Patchstack to your site — this takes a few minutes because it has to reinstall everything the site is built from."
|
|
91
91
|
- **Say what the wait is.** "It's downloading the pieces your site is built out of. Nothing is broken; this is just slow."
|
|
@@ -97,6 +97,17 @@ The person who asked for this usually did not write the project and has never in
|
|
|
97
97
|
|
|
98
98
|
This is a request, not a mechanism: nothing in the install depends on it. Do it anyway — the wait is the only moment where the person is paying full attention.
|
|
99
99
|
|
|
100
|
+
### The message you end on
|
|
101
|
+
|
|
102
|
+
When setup is finished, the person reads one short message, not a transcript of the install. Keep it to about ten lines, in this order:
|
|
103
|
+
|
|
104
|
+
1. **One sentence on the result.** "Patchstack is now watching your site." If something did not finish, say what, in one line.
|
|
105
|
+
2. **The four steps**, copied from the end of the `setup` output with their `✔` and `✘`.
|
|
106
|
+
3. **The next step**, from the `Next:` line, in plain words, with its link or command.
|
|
107
|
+
4. **Refresh and deploy.** Refresh the preview to see the Patchstack Connector, and deploy when ready.
|
|
108
|
+
|
|
109
|
+
Leave out the files you changed, the commands you ran, settings, and anything that worked as expected. If the person asks for the detail, give it then. `--verbose` prints it.
|
|
110
|
+
|
|
100
111
|
## Automated setup
|
|
101
112
|
|
|
102
113
|
1. **Install** (skip if already present), matching the project's package manager:
|
|
@@ -135,7 +146,7 @@ This is a request, not a mechanism: nothing in the install depends on it. Do it
|
|
|
135
146
|
|
|
136
147
|
**A `✘` line under `Missing` is yours to finish, not a result to report.** `setup` applies what it can apply safely and prints the exact edit (or the command that prints it) for anything it would have had to overwrite user code to do. They are: moving `@patchstack/connect` out of `devDependencies`, the widget tag in a root layout `setup` could not edit, the production marker on a server-rendered root, and wiring a generic guard into the server entry. The last three are steps 3 and 4 of "Manual setup" below; after the guard one, `npx @patchstack/connect protect --check` must exit 0.
|
|
137
148
|
|
|
138
|
-
**Read the report.** `setup` and `scan` start with `Done` (what this run did) and `Missing` (what is still missing, each with the one thing to do); `guide` shows `Missing` only. All three end on the same four steps — `Install the Patchstack connector`, `Connect project to Patchstack account`, `Sync and monitor in local environment`, `Deploy project to protect live app` — each marked `✔` (done) or `✘` (not yet), followed by the one next step. A part the project cannot carry (no build script, no request path for runtime protection) is simply not listed. The CLI does not store whether the site has an owner, so `Connect` stays `✘` until a scan hears otherwise from Patchstack; do not report the site as connected from that line alone, and do not report it as unconnected once the person has signed in.
|
|
149
|
+
**Read the report.** `setup` and `scan` start with `Done` (what this run did) and `Missing` (what is still missing, each with the one thing to do); `guide` shows `Missing` only. All three end on the same four steps — `Install the Patchstack connector`, `Connect project to Patchstack account`, `Sync and monitor in local environment`, `Deploy project to protect live app` — each marked `✔` (done) or `✘` (not yet), followed by the one next step. A part the project cannot carry (no build script, no request path for runtime protection) is simply not listed. The CLI does not store whether the site has an owner, so `Connect` stays `✘` until a scan hears otherwise from Patchstack; do not report the site as connected from that line alone, and do not report it as unconnected once the person has signed in. In the message you end on, name only the parts that are not active — dependency scans, the Patchstack Connector, the build hooks, runtime protection — and why, one line each; the four steps already say what is done.
|
|
139
150
|
|
|
140
151
|
**The widget is part of the install.** It is on by default; add it without asking the person whether to. Honour `"widget": false` in `.patchstackrc.json` only when the person set it themselves. If it is there and they did not ask for it, remove it, run `setup` again, and tell them the widget is back on.
|
|
141
152
|
|
|
@@ -459,8 +470,9 @@ requests are aborted, it starts nothing further, and it discards what it was hol
|
|
|
459
470
|
request to stop, not a guarantee — a transport that ignores it is detached rather than completed, so
|
|
460
471
|
"resolved" means the reporter is finished with it, and a runtime that kills the process still wins
|
|
461
472
|
regardless. Every detection event ends up delivered, refused or dropped and is reported in the health
|
|
462
|
-
counts
|
|
463
|
-
|
|
473
|
+
counts. The block log keeps the same kind of local counts: `protection.blockLogHealth()` returns how many
|
|
474
|
+
block records were accepted, delivered, failed or dropped, and how many are still queued. Those counts
|
|
475
|
+
carry no request data and stay in your process.
|
|
464
476
|
|
|
465
477
|
The client address is reported with its **provenance**, because an address is only as trustworthy as
|
|
466
478
|
whatever supplied it. `client_ip_source` is one of `runtime` (the address the transport observed),
|
|
@@ -468,7 +480,8 @@ whatever supplied it. `client_ip_source` is one of `runtime` (the address the tr
|
|
|
468
480
|
`unavailable`. When it is `unavailable` the `client_ip` field is **omitted entirely** rather than sent
|
|
469
481
|
empty, so a missing address cannot read as a failed lookup of a real one. A forwarded header is never
|
|
470
482
|
trusted implicitly: with no `trustedProxy` policy the address is whatever the transport observed, and in a
|
|
471
|
-
runtime that exposes no transport peer there is no address to report at all
|
|
483
|
+
runtime that exposes no transport peer there is no address to report at all unless your code supplies one
|
|
484
|
+
with `peerAddress` (below).
|
|
472
485
|
|
|
473
486
|
### Behaviour change: how the client address is determined
|
|
474
487
|
|
|
@@ -483,11 +496,17 @@ Two consequences if you are upgrading:
|
|
|
483
496
|
peer. **If your app runs behind a proxy or load balancer, addresses will now show as the proxy's**
|
|
484
497
|
until you declare your proxies with `trustedProxy` (below) — which affects attribution in reports and
|
|
485
498
|
any rule matching on `server.ip` or `REMOTE_ADDR`.
|
|
486
|
-
- **Fetch runtimes report no address
|
|
487
|
-
guard (Workers, Deno, Bun, edge) has nothing to observe, and no
|
|
488
|
-
|
|
499
|
+
- **Fetch runtimes report no address unless you supply the peer.** A WHATWG `Request` exposes no
|
|
500
|
+
transport peer, so a Fetch guard (Workers, Deno, Bun, edge) has nothing to observe on its own, and no
|
|
501
|
+
forwarded header is accepted in its place: `client_ip_source` is `unavailable` and no address is sent.
|
|
489
502
|
Earlier versions reported the forwarded header here, so an address-scoped rule that appeared to work on
|
|
490
|
-
such a runtime was matching a client-supplied value.
|
|
503
|
+
such a runtime was matching a client-supplied value. Where your runtime does know the peer, pass
|
|
504
|
+
`peerAddress: (request, ...handlerArgs) => string` — for example `(req, info) => info.remoteAddr.hostname`
|
|
505
|
+
on Deno, or `(req, server) => server.requestIP(req)?.address` on Bun. It receives the request and the
|
|
506
|
+
arguments your handler was called with (`fetchGuard()(request, ...args)` and
|
|
507
|
+
`screenResponse(response, request, ...args)` pass them on), and that address then counts as the
|
|
508
|
+
transport peer, including for `trustedProxy`. With `trustedProxy` set and no peer supplied, the guard
|
|
509
|
+
warns once, because the policy can never apply.
|
|
491
510
|
|
|
492
511
|
`trustedProxy` is the only way to make a forwarded header count. It takes the proxies you actually run —
|
|
493
512
|
`{ peers: ['10.0.0.0/8'] }`, or `{ hops: 1 }` to trust that many hops in from the peer, plus optional
|
|
@@ -576,8 +595,15 @@ carries no detections and would otherwise read as one. Those counts stay in your
|
|
|
576
595
|
sent to report them.
|
|
577
596
|
|
|
578
597
|
`protection.stop()` stops everything the guard has running in the background — the rule-refresh loop, the
|
|
579
|
-
block-log reporter, the detection reporter — and flushes what is buffered. `
|
|
580
|
-
|
|
598
|
+
block-log reporter, the detection reporter — and flushes what is buffered. With `egress: true` it also
|
|
599
|
+
removes this guard's outbound-request screening; once no guard in the process is screening, `fetch` and
|
|
600
|
+
`node:http`/`node:https` are restored. Call it on shutdown; it is safe to call twice.
|
|
601
|
+
`protection.stopRefresh()` stops only the rule refresh: the reporters and outbound-request screening keep
|
|
602
|
+
running.
|
|
603
|
+
|
|
604
|
+
When more than one guard in a process has `egress: true`, an outbound call is checked by each of them and
|
|
605
|
+
refused if any one refuses it. A host listed in one guard's `allowHosts` is still refused when another guard
|
|
606
|
+
refuses it.
|
|
581
607
|
|
|
582
608
|
Two more endpoints the package can call, for completeness:
|
|
583
609
|
|