@patchstack/connect 0.5.8 → 0.5.10
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 +64 -2
- package/README.md +65 -2
- package/dist/{chunk-4OHAYSV2.js → chunk-YG5C7HYB.js} +1 -1
- package/dist/{chunk-4OHAYSV2.js.map → chunk-YG5C7HYB.js.map} +1 -1
- package/dist/cli.js +54 -10
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +20 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +23 -1
- package/dist/index.d.ts +23 -1
- package/dist/index.js +20 -6
- package/dist/index.js.map +1 -1
- package/dist/protect.cjs +20 -6
- package/dist/protect.cjs.map +1 -1
- package/dist/protect.edge.js.map +1 -1
- package/dist/protect.js +2 -2
- package/dist/{refresh-manifest-IE6SPHG6.js → refresh-manifest-PPV22Q2E.js} +22 -8
- package/dist/refresh-manifest-PPV22Q2E.js.map +1 -0
- package/package.json +1 -1
- package/dist/refresh-manifest-IE6SPHG6.js.map +0 -1
package/AGENT-INSTALL.md
CHANGED
|
@@ -17,7 +17,7 @@ Every command at a glance — what it does, whether it reads your source, what i
|
|
|
17
17
|
| `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 |
|
|
18
18
|
| `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 |
|
|
19
19
|
| `init <site-uuid>` | Optional: pre-seed `.patchstackrc.json` with an existing UUID. | No | `.patchstackrc.json` only | Nothing |
|
|
20
|
-
| `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 |
|
|
20
|
+
| `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 |
|
|
21
21
|
| `claim` | Attach the site to a Patchstack account from the terminal: print a link the user opens to sign in (or sign up) and poll (10 min). Whoever approves becomes the owner. Does **not** rotate the credential. Same result as opening the dashboard link `scan` prints. Not usable in CI. | No | Nothing, unless the server issues a credential for a checkout that had none — then `.patchstackrc.local.json` | Device-code request + approval poll |
|
|
22
22
|
| `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 |
|
|
23
23
|
| `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 |
|
|
@@ -94,6 +94,66 @@ This is a request, not a mechanism: nothing in the install depends on it. Do it
|
|
|
94
94
|
|
|
95
95
|
**Then tell them to deploy.** Setup changes source files, and the deployed site keeps serving its previous build until the next deploy — so visitors get no widget, and on a server-rendered root no production marker, until the user deploys (or hits Publish) again. Say it as a reminder; do not deploy anything yourself.
|
|
96
96
|
|
|
97
|
+
## When your tool will not run this CLI
|
|
98
|
+
|
|
99
|
+
Some coding tools refuse to execute a third-party command until the person approves it. In Claude Code,
|
|
100
|
+
auto mode's classifier can decline `npx @patchstack/connect setup` and the installed `patchstack-connect`
|
|
101
|
+
binary on that ground instead of prompting. The command is not the problem; the approval is missing.
|
|
102
|
+
Handle it in this order:
|
|
103
|
+
|
|
104
|
+
1. **Stop at the refused command.** Do not route around the refusal: do not call the Patchstack API
|
|
105
|
+
yourself, do not wrap the command in a `package.json` script so a later install runs it, and do not add
|
|
106
|
+
the `postinstall` / `prebuild` hooks first so the next install provisions the site. Each of those runs
|
|
107
|
+
the command the tool declined, with the person's decision taken away from them. Leave `package.json`
|
|
108
|
+
and the source tree as they were.
|
|
109
|
+
|
|
110
|
+
2. **Hand the person the ways forward, with the exact text.** Say what the command does in plain words —
|
|
111
|
+
it registers the site with Patchstack, writes two small config files, adds the "Report a vulnerability"
|
|
112
|
+
line to the page, and adds the protection files and build steps described above — then give them:
|
|
113
|
+
|
|
114
|
+
- **Run it themselves, in this session.** In Claude Code a line that starts with `!` runs in their shell
|
|
115
|
+
and its output lands in the conversation: `! npx @patchstack/connect setup`. Other tools have a
|
|
116
|
+
terminal beside the chat; the command is the same without the `!`.
|
|
117
|
+
- **Approve it once.** In Claude Code, `/permissions` → **Recently denied** → `r` retries the command
|
|
118
|
+
with a manual approval; or `Shift+Tab` switches to Manual mode, and the tool prompts them when you
|
|
119
|
+
try again.
|
|
120
|
+
- **Allow it for good, then ask you to run it again.** For Claude Code these rules pre-approve every
|
|
121
|
+
`npx @patchstack/connect …` command and nothing else. They go in `.claude/settings.json` (shared with
|
|
122
|
+
the repository), `.claude/settings.local.json` (this person only), or through `/permissions`:
|
|
123
|
+
|
|
124
|
+
```json
|
|
125
|
+
{
|
|
126
|
+
"permissions": {
|
|
127
|
+
"allow": [
|
|
128
|
+
"Bash(npx @patchstack/connect *)",
|
|
129
|
+
"Bash(npx --yes @patchstack/connect *)"
|
|
130
|
+
]
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Other tools keep their own allowlists; the README section "If your coding tool blocks the command"
|
|
136
|
+
shows the Gemini CLI and OpenCode forms.
|
|
137
|
+
|
|
138
|
+
3. **Write the command as `npx @patchstack/connect <command>`.** A rule matches the command text as
|
|
139
|
+
written. `./node_modules/.bin/patchstack-connect setup`, `PATCHSTACK_ENVIRONMENT=sandbox npx …` and
|
|
140
|
+
`npx --yes patchstack-connect setup` are different texts, and the rules above do not cover them. On a
|
|
141
|
+
developer's machine the sandbox label is not needed anyway: a scan there reports `local` on its own.
|
|
142
|
+
|
|
143
|
+
4. **Resume from the output.** `setup` prints the same checklist, dashboard link and outcome block whoever
|
|
144
|
+
ran it, and re-running it changes nothing that is already done. If the person ran it, relay the
|
|
145
|
+
dashboard link and the outcome block from their output as they are. If your tool still will not run
|
|
146
|
+
`guide` or `status` for you, verify from the files instead of guessing: `siteUuid` in
|
|
147
|
+
`.patchstackrc.json` means the site is provisioned; `patchstack-connect scan` and
|
|
148
|
+
`patchstack-connect mark-build` in the `package.json` scripts mean the hooks are wired;
|
|
149
|
+
`patchstack-widget.js` in the root shell means the widget is in place; `.patchstackrc.local.json` in
|
|
150
|
+
`.gitignore` means the credential stays out of the commit. Never construct a dashboard link yourself —
|
|
151
|
+
it comes from `setup`, `status` or `claim` output.
|
|
152
|
+
|
|
153
|
+
5. **`claim` and `login` are the same shape.** Both print a link the person opens. If your tool will not
|
|
154
|
+
run them, the person runs `npx @patchstack/connect claim` (or `login`) themselves and you relay the
|
|
155
|
+
link from their output.
|
|
156
|
+
|
|
97
157
|
## Manual setup
|
|
98
158
|
|
|
99
159
|
1. **First scan** — provisions a Patchstack site automatically, writes the UUID to `.patchstackrc.json`, and installs the disclosure widget'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:
|
|
@@ -181,7 +241,8 @@ It is server-only. Never put it in the widget tag, client bundles, or public env
|
|
|
181
241
|
rules were delivered, that the deployed app is wired, or that ordinary traffic is blocked.
|
|
182
242
|
|
|
183
243
|
Nothing else runs the application. `protect`, `protect --check`, `setup`, `guide`, `scan`, `status`
|
|
184
|
-
and `mark-build` only read and write files
|
|
244
|
+
and `mark-build` only read and write files; `scan` and `mark-build` also report the dependency
|
|
245
|
+
manifest they read.
|
|
185
246
|
|
|
186
247
|
5. **Commit** `.patchstackrc.json`, the updated `package.json`, the guard/framework source changes, and the layout/HTML file carrying the widget tag (and the production marker, when `scan` wrote one into a JSX root), so every developer and CI run reports to the same site.
|
|
187
248
|
|
|
@@ -196,6 +257,7 @@ It is server-only. Never put it in the widget tag, client bundles, or public env
|
|
|
196
257
|
- The CLI never opens the dashboard link and never asks for Patchstack credentials.
|
|
197
258
|
- 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.
|
|
198
259
|
- If a step fails, stop and report it. Don't proceed with placeholders.
|
|
260
|
+
- 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.
|
|
199
261
|
- 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.
|
|
200
262
|
|
|
201
263
|
## Which build a rule belongs to
|
package/README.md
CHANGED
|
@@ -10,6 +10,68 @@ Copy this request into a coding assistant, or run the same command yourself:
|
|
|
10
10
|
|
|
11
11
|
`setup` is state-aware and idempotent: it scans dependencies, provisions or reuses the site, manages the disclosure widget, installs and verifies the runtime guard, adds a dependency-install scan, wires the existing build command without replacing it, and prints the remaining setup status. It never runs the project build. `guide` provides the same project-specific status without changing files.
|
|
12
12
|
|
|
13
|
+
### If your coding tool blocks the command
|
|
14
|
+
|
|
15
|
+
Some tools will not run a third-party command until you approve it. Claude Code's auto mode, for example,
|
|
16
|
+
can decline `npx @patchstack/connect setup` instead of prompting you, and the assistant then stops and asks
|
|
17
|
+
you how to proceed. Any of these works:
|
|
18
|
+
|
|
19
|
+
- **Run it yourself, in the same session.** In Claude Code, a line that starts with `!` runs in your shell
|
|
20
|
+
and its output lands in the conversation, so the assistant carries on from it:
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
! npx @patchstack/connect setup
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Elsewhere, run the same command without the `!` in a terminal and tell the assistant it is done. `setup`
|
|
27
|
+
is idempotent, so a partial earlier attempt does no harm.
|
|
28
|
+
|
|
29
|
+
- **Approve it once.** In Claude Code, open `/permissions`, pick the **Recently denied** tab and press `r`
|
|
30
|
+
to retry the command with a manual approval — or press `Shift+Tab` to switch to Manual mode and approve
|
|
31
|
+
the prompt when the assistant tries again.
|
|
32
|
+
|
|
33
|
+
- **Allow it, then ask again.** Claude Code resolves explicit allow rules before its classifier. These two
|
|
34
|
+
rules cover every `npx @patchstack/connect …` command (`setup`, `guide`, `status`, `claim`) and nothing
|
|
35
|
+
else. Put them in `.claude/settings.json` to share them with the repository, in
|
|
36
|
+
`.claude/settings.local.json` to keep them to yourself, or add them through `/permissions`:
|
|
37
|
+
|
|
38
|
+
```json
|
|
39
|
+
{
|
|
40
|
+
"permissions": {
|
|
41
|
+
"allow": [
|
|
42
|
+
"Bash(npx @patchstack/connect *)",
|
|
43
|
+
"Bash(npx --yes @patchstack/connect *)"
|
|
44
|
+
]
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
A rule matches the command text as written, so use the plain `npx @patchstack/connect …` form: a leading
|
|
50
|
+
`PATCHSTACK_ENVIRONMENT=sandbox`, a path such as `./node_modules/.bin/patchstack-connect`, or the bare
|
|
51
|
+
`patchstack-connect` binary name is a different text and is not covered. On your own machine the sandbox
|
|
52
|
+
label is not needed — a scan there reports `local` by itself. Rules in a project's `.claude/settings.json`
|
|
53
|
+
apply once you have accepted that folder's trust dialog. If auto mode still declines the command with the
|
|
54
|
+
rules in place, use one of the first two options.
|
|
55
|
+
|
|
56
|
+
Other tools keep their own allowlists. Gemini CLI reads policy files from `~/.gemini/policies/`:
|
|
57
|
+
|
|
58
|
+
```toml
|
|
59
|
+
[[rule]]
|
|
60
|
+
toolName = "run_shell_command"
|
|
61
|
+
commandPrefix = "npx @patchstack/connect"
|
|
62
|
+
decision = "allow"
|
|
63
|
+
priority = 100
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
OpenCode takes the pattern in `opencode.json` (project root, or `~/.config/opencode/opencode.json`):
|
|
67
|
+
|
|
68
|
+
```json
|
|
69
|
+
{ "permission": { "bash": { "npx @patchstack/connect *": "allow" } } }
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Codex CLI asks according to `approval_policy` in `~/.codex/config.toml`: approve the command when it
|
|
73
|
+
asks, or run it yourself.
|
|
74
|
+
|
|
13
75
|
## Quick start (zero configuration)
|
|
14
76
|
|
|
15
77
|
```bash
|
|
@@ -192,7 +254,8 @@ Windows reports exit `2` without starting anything: the cleanup this relies on i
|
|
|
192
254
|
group, and a verification that can leave a server running is worse than an unanswered question.
|
|
193
255
|
|
|
194
256
|
No other command runs your application. `protect`, `protect --check`, `setup`, `guide`, `scan`,
|
|
195
|
-
`status` and `mark-build` only read and write files
|
|
257
|
+
`status` and `mark-build` only read and write files, and — for `scan` and `mark-build` — report the
|
|
258
|
+
dependency manifest they read.
|
|
196
259
|
|
|
197
260
|
## Configuration
|
|
198
261
|
|
|
@@ -311,7 +374,7 @@ The widget is a floating "Report a vulnerability" button — a disclosure channe
|
|
|
311
374
|
|
|
312
375
|
Re-runs update the tag in place (the `data-patchstack-connect-widget` attribute marks it as connector-managed); 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 rather than HTML (Next.js, Nuxt, Astro, …) get the exact snippet and target file printed instead — `guide` shows framework-specific placement.
|
|
313
376
|
|
|
314
|
-
- **`mark-build`** ensures the same tag in built HTML output, covering builds whose source shell the connector 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). 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.
|
|
377
|
+
- **`mark-build`** ensures the same tag in built HTML output, covering builds whose source shell the connector 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.
|
|
315
378
|
|
|
316
379
|
- **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.
|
|
317
380
|
|
|
@@ -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":[]}
|
package/dist/cli.js
CHANGED
|
@@ -1790,11 +1790,18 @@ async function fetchSiteStatus(config) {
|
|
|
1790
1790
|
return "unknown";
|
|
1791
1791
|
}
|
|
1792
1792
|
}
|
|
1793
|
-
function buildManifestBody(config, payload, env = process.env) {
|
|
1793
|
+
function buildManifestBody(config, payload, env = process.env, marker = null) {
|
|
1794
1794
|
const hosting = config.environment === "local" ? null : detectHostingPlatform(env);
|
|
1795
1795
|
return {
|
|
1796
1796
|
...payload,
|
|
1797
1797
|
environment: config.environment,
|
|
1798
|
+
// What the label rests on, sent with the label itself: a `production` claim decided by an
|
|
1799
|
+
// assumption about the project is worth less than one the platform declared, and only the
|
|
1800
|
+
// report can say which this was.
|
|
1801
|
+
...config.environmentSource != null ? { environment_source: config.environmentSource } : {},
|
|
1802
|
+
// Present only on the report from a finished build, which is also what tells the two reports
|
|
1803
|
+
// of one build apart.
|
|
1804
|
+
...marker !== null ? { marker } : {},
|
|
1798
1805
|
...typeof config.siteUrl === "string" && config.siteUrl !== "" ? { url: config.siteUrl } : {},
|
|
1799
1806
|
...typeof config.siteName === "string" && config.siteName !== "" ? { name: config.siteName } : {},
|
|
1800
1807
|
...hosting !== null && hosting.platform !== null ? { hosting } : {}
|
|
@@ -1848,16 +1855,19 @@ function environmentRejected(err) {
|
|
|
1848
1855
|
function canRetryManifestPost(config) {
|
|
1849
1856
|
return config.siteUuid !== null;
|
|
1850
1857
|
}
|
|
1851
|
-
async function postManifestWithEnvironmentFallback(config, payload) {
|
|
1858
|
+
async function postManifestWithEnvironmentFallback(config, payload, marker = null) {
|
|
1852
1859
|
try {
|
|
1853
|
-
return {
|
|
1860
|
+
return {
|
|
1861
|
+
response: await postManifest(config, payload, marker),
|
|
1862
|
+
environmentUsed: config.environment
|
|
1863
|
+
};
|
|
1854
1864
|
} catch (err) {
|
|
1855
1865
|
if (config.environment !== "local" || !environmentRejected(err)) throw err;
|
|
1856
1866
|
const fallback = { ...config, environment: "sandbox" };
|
|
1857
|
-
return { response: await postManifest(fallback, payload), environmentUsed: "sandbox" };
|
|
1867
|
+
return { response: await postManifest(fallback, payload, marker), environmentUsed: "sandbox" };
|
|
1858
1868
|
}
|
|
1859
1869
|
}
|
|
1860
|
-
async function postManifest(config, payload) {
|
|
1870
|
+
async function postManifest(config, payload, marker = null) {
|
|
1861
1871
|
const url = buildEndpointUrl(config.endpoint, config.siteUuid);
|
|
1862
1872
|
const timeoutMs = config.timeoutMs;
|
|
1863
1873
|
assertConnectableEndpoint(config, url);
|
|
@@ -1871,7 +1881,7 @@ async function postManifest(config, payload) {
|
|
|
1871
1881
|
"User-Agent": "@patchstack/connect",
|
|
1872
1882
|
...claimTokenHeader(config)
|
|
1873
1883
|
},
|
|
1874
|
-
body: JSON.stringify(buildManifestBody(config, payload)),
|
|
1884
|
+
body: JSON.stringify(buildManifestBody(config, payload, process.env, marker)),
|
|
1875
1885
|
signal: AbortSignal.timeout(timeoutMs)
|
|
1876
1886
|
});
|
|
1877
1887
|
} catch (cause) {
|
|
@@ -2287,16 +2297,21 @@ function inferEnvironment(env = process.env, builder = null) {
|
|
|
2287
2297
|
for (const discriminator of DISCRIMINATORS) {
|
|
2288
2298
|
const verdict = discriminator.read(env);
|
|
2289
2299
|
if (verdict !== null) {
|
|
2290
|
-
return {
|
|
2300
|
+
return {
|
|
2301
|
+
environment: verdict.environment,
|
|
2302
|
+
evidence: [`${discriminator.platform}: ${verdict.evidence}`],
|
|
2303
|
+
source: "platform"
|
|
2304
|
+
};
|
|
2291
2305
|
}
|
|
2292
2306
|
}
|
|
2293
2307
|
if (builder !== null) {
|
|
2294
2308
|
return {
|
|
2295
2309
|
environment: "production",
|
|
2296
|
-
evidence: [`${builder}: a build in a ${builder} project is its publish step`]
|
|
2310
|
+
evidence: [`${builder}: a build in a ${builder} project is its publish step`],
|
|
2311
|
+
source: "builder"
|
|
2297
2312
|
};
|
|
2298
2313
|
}
|
|
2299
|
-
return { environment: "local", evidence: [] };
|
|
2314
|
+
return { environment: "local", evidence: [], source: null };
|
|
2300
2315
|
}
|
|
2301
2316
|
|
|
2302
2317
|
// src/site-url.ts
|
|
@@ -2515,6 +2530,7 @@ async function resolveConfig(options) {
|
|
|
2515
2530
|
const inferred = environmentRaw === void 0 ? inferEnvironment(process.env, detectHostedBuilder(options.cwd)) : null;
|
|
2516
2531
|
const environment = environmentRaw ?? inferred.environment;
|
|
2517
2532
|
const environmentEvidence = inferred?.evidence ?? [];
|
|
2533
|
+
const environmentSource = environmentRaw !== void 0 ? "override" : inferred.source;
|
|
2518
2534
|
if (siteUuid !== null && siteUuid.length > 0 && !isCanonicalUuid(siteUuid)) {
|
|
2519
2535
|
throw new PatchstackError(
|
|
2520
2536
|
`Site UUID "${siteUuid}" does not look like a valid UUID.`,
|
|
@@ -2542,6 +2558,7 @@ async function resolveConfig(options) {
|
|
|
2542
2558
|
timeoutMs,
|
|
2543
2559
|
environment,
|
|
2544
2560
|
environmentEvidence,
|
|
2561
|
+
environmentSource,
|
|
2545
2562
|
widget: fromFile.widget !== false,
|
|
2546
2563
|
claimToken
|
|
2547
2564
|
};
|
|
@@ -5838,6 +5855,8 @@ function renderGuideChecklist(state, useColor) {
|
|
|
5838
5855
|
lines.push(detail("Run \u2192 npx @patchstack/connect scan"));
|
|
5839
5856
|
lines.push(detail("Reads the lockfile, registers the project, writes .patchstackrc.json,"));
|
|
5840
5857
|
lines.push(detail("and prints a dashboard link. The CLI prints the link but never opens it."));
|
|
5858
|
+
lines.push(detail("If your tool refuses to run this command, hand it to the person instead of working"));
|
|
5859
|
+
lines.push(detail('around it \u2014 see "When your tool will not run this CLI" in the reference guide.'));
|
|
5841
5860
|
}
|
|
5842
5861
|
if (state.installScanWired) {
|
|
5843
5862
|
lines.push(done("Dependency-install scan wired (postinstall)"));
|
|
@@ -10041,17 +10060,36 @@ function readBuildScript(cwd) {
|
|
|
10041
10060
|
return void 0;
|
|
10042
10061
|
}
|
|
10043
10062
|
}
|
|
10063
|
+
var REPORT_TIMEOUT_MS = 1e4;
|
|
10064
|
+
async function reportBuildStamp(config, payload, marker) {
|
|
10065
|
+
if (config === null || payload === null || config.siteUuid === null || config.siteUuid === "") {
|
|
10066
|
+
return;
|
|
10067
|
+
}
|
|
10068
|
+
try {
|
|
10069
|
+
const bounded = {
|
|
10070
|
+
...config,
|
|
10071
|
+
timeoutMs: Math.min(config.timeoutMs, REPORT_TIMEOUT_MS)
|
|
10072
|
+
};
|
|
10073
|
+
await postManifestWithEnvironmentFallback(bounded, payload, marker);
|
|
10074
|
+
} catch (err) {
|
|
10075
|
+
console.warn(
|
|
10076
|
+
`mark-build: this build was not reported to Patchstack (${err.message}). The pages were still marked as described above.`
|
|
10077
|
+
);
|
|
10078
|
+
}
|
|
10079
|
+
}
|
|
10044
10080
|
async function runMarkBuild(args) {
|
|
10045
10081
|
const cwd = process.cwd();
|
|
10046
10082
|
const startedAt = Date.now();
|
|
10047
10083
|
let checksum = null;
|
|
10048
10084
|
let stack = null;
|
|
10085
|
+
let wirePayload = null;
|
|
10049
10086
|
try {
|
|
10050
10087
|
const manifest = await scanLockfile(cwd);
|
|
10051
10088
|
for (const warning of manifest.warnings ?? []) {
|
|
10052
10089
|
console.warn(`mark-build: ${warning}`);
|
|
10053
10090
|
}
|
|
10054
10091
|
const { payload } = buildWirePayload(manifest);
|
|
10092
|
+
wirePayload = payload;
|
|
10055
10093
|
checksum = computeManifestChecksum(payload.packages);
|
|
10056
10094
|
stack = detectStack(payload.packages);
|
|
10057
10095
|
} catch (err) {
|
|
@@ -10059,11 +10097,12 @@ async function runMarkBuild(args) {
|
|
|
10059
10097
|
`mark-build: could not compute the build fingerprint (${err.message}). Stamping the production flag only.`
|
|
10060
10098
|
);
|
|
10061
10099
|
}
|
|
10100
|
+
let config = null;
|
|
10062
10101
|
let widgetUuid = null;
|
|
10063
10102
|
let environment = "local";
|
|
10064
10103
|
let environmentEvidence = [];
|
|
10065
10104
|
try {
|
|
10066
|
-
|
|
10105
|
+
config = await resolveConfig({
|
|
10067
10106
|
cwd,
|
|
10068
10107
|
cliSiteUuid: getStringFlag(args.flags, "site-uuid")
|
|
10069
10108
|
});
|
|
@@ -10079,6 +10118,7 @@ async function runMarkBuild(args) {
|
|
|
10079
10118
|
}
|
|
10080
10119
|
const forcedProduction = args.flags.get("production") === true;
|
|
10081
10120
|
const published = forcedProduction || marksPublishedBuild(environment);
|
|
10121
|
+
const reported = config !== null && forcedProduction && config.environment !== "production" ? { ...config, environment: "production", environmentSource: "override" } : config;
|
|
10082
10122
|
const buildDirOptions = { framework: stack?.framework ?? null, buildScript: readBuildScript(cwd) };
|
|
10083
10123
|
const dir = resolveBuildDir(cwd, getStringFlag(args.flags, "dir"), buildDirOptions);
|
|
10084
10124
|
if (dir === null) {
|
|
@@ -10089,6 +10129,7 @@ async function runMarkBuild(args) {
|
|
|
10089
10129
|
console.warn(
|
|
10090
10130
|
'mark-build: if the build writes elsewhere, set it once in package.json \u2192 "postbuild": "patchstack-connect mark-build --dir <path>".'
|
|
10091
10131
|
);
|
|
10132
|
+
await reportBuildStamp(reported, wirePayload, "no-output");
|
|
10092
10133
|
return 0;
|
|
10093
10134
|
}
|
|
10094
10135
|
const files = findHtmlFiles(dir);
|
|
@@ -10100,6 +10141,7 @@ async function runMarkBuild(args) {
|
|
|
10100
10141
|
console.warn(
|
|
10101
10142
|
"mark-build: add the marker to your root shell instead \u2014 run `patchstack-connect guide` for the snippet."
|
|
10102
10143
|
);
|
|
10144
|
+
await reportBuildStamp(reported, wirePayload, "no-pages");
|
|
10103
10145
|
return 0;
|
|
10104
10146
|
}
|
|
10105
10147
|
const staleBy = staleBuildAge(files, startedAt);
|
|
@@ -10134,6 +10176,7 @@ async function runMarkBuild(args) {
|
|
|
10134
10176
|
console.log(
|
|
10135
10177
|
`mark-build: marked ${marked} HTML file(s) in ${dir}${checksum !== null ? ` (build ${checksum})` : ""}${widgetTouched > 0 ? `, widget tag ensured in ${widgetTouched}` : ""}${stackSummary !== null ? ` [${stackSummary}]` : ""}.`
|
|
10136
10178
|
);
|
|
10179
|
+
await reportBuildStamp(reported, wirePayload, "stamped");
|
|
10137
10180
|
return 0;
|
|
10138
10181
|
}
|
|
10139
10182
|
const because = environmentEvidence.length > 0 ? ` (${environmentEvidence.join("; ")})` : "";
|
|
@@ -10146,6 +10189,7 @@ async function runMarkBuild(args) {
|
|
|
10146
10189
|
console.log(
|
|
10147
10190
|
"mark-build: publishing this directory by hand? Re-run with --production (or set PATCHSTACK_ENVIRONMENT=production) so the deployed pages carry it."
|
|
10148
10191
|
);
|
|
10192
|
+
await reportBuildStamp(reported, wirePayload, "withheld");
|
|
10149
10193
|
return 0;
|
|
10150
10194
|
}
|
|
10151
10195
|
function packageVersion() {
|