@patchstack/connect 0.3.29 → 0.3.31

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.
Files changed (40) hide show
  1. package/AGENT-INSTALL.md +42 -23
  2. package/README.md +40 -11
  3. package/dist/{chunk-MJOTFUDE.js → chunk-LLKP5EJS.js} +1 -1
  4. package/dist/chunk-LLKP5EJS.js.map +1 -0
  5. package/dist/cli.js +1265 -287
  6. package/dist/cli.js.map +1 -1
  7. package/dist/index.cjs +456 -111
  8. package/dist/index.cjs.map +1 -1
  9. package/dist/index.d.cts +76 -10
  10. package/dist/index.d.ts +76 -10
  11. package/dist/index.js +449 -104
  12. package/dist/index.js.map +1 -1
  13. package/dist/protect/templates/astro-middleware.ts +33 -13
  14. package/dist/protect/templates/demo-rules.json +2 -3
  15. package/dist/protect/templates/express-guard.cjs +26 -15
  16. package/dist/protect/templates/express-guard.js +26 -15
  17. package/dist/protect/templates/express-guard.ts +33 -16
  18. package/dist/protect/templates/fastify-plugin.cjs +33 -11
  19. package/dist/protect/templates/fastify-plugin.js +33 -11
  20. package/dist/protect/templates/fastify-plugin.ts +40 -12
  21. package/dist/protect/templates/generic-guard.cjs +28 -12
  22. package/dist/protect/templates/generic-guard.js +28 -13
  23. package/dist/protect/templates/generic-guard.ts +41 -20
  24. package/dist/protect/templates/guard.ts +47 -27
  25. package/dist/protect/templates/next-middleware.ts +29 -12
  26. package/dist/protect/templates/nuxt-middleware.ts +29 -12
  27. package/dist/protect/templates/rules.json +2 -2
  28. package/dist/protect/templates/sveltekit-hooks.ts +33 -13
  29. package/dist/protect.cjs +1204 -252
  30. package/dist/protect.cjs.map +1 -1
  31. package/dist/protect.d.ts +39 -11
  32. package/dist/protect.edge.js +792 -143
  33. package/dist/protect.edge.js.map +4 -4
  34. package/dist/protect.js +794 -145
  35. package/dist/protect.js.map +1 -1
  36. package/dist/{refresh-manifest-VRBE6RH6.js → refresh-manifest-KNZQBC4V.js} +387 -100
  37. package/dist/refresh-manifest-KNZQBC4V.js.map +1 -0
  38. package/package.json +5 -2
  39. package/dist/chunk-MJOTFUDE.js.map +0 -1
  40. package/dist/refresh-manifest-VRBE6RH6.js.map +0 -1
package/dist/index.d.cts CHANGED
@@ -74,7 +74,7 @@ declare class PatchstackError extends Error {
74
74
  }
75
75
 
76
76
  type LockfileFilename = 'package-lock.json' | 'bun.lock' | 'bun.lockb' | 'yarn.lock' | 'pnpm-lock.yaml';
77
- type DetectionStrategy = 'npm-lockfile' | 'node-modules-walk' | 'pnpm-lockfile' | 'yarn-lockfile';
77
+ type DetectionStrategy = 'npm-lockfile' | 'bun-lockfile' | 'node-modules-walk' | 'pnpm-lockfile' | 'yarn-lockfile';
78
78
  interface DetectedLockfile {
79
79
  ecosystem: 'npm';
80
80
  filePath: string;
@@ -87,10 +87,45 @@ declare function scanLockfile(cwd: string): Promise<Manifest>;
87
87
  interface WirePackage {
88
88
  name: string;
89
89
  version: string;
90
+ /**
91
+ * Where this exact name+version is installed, repo-relative and sorted.
92
+ *
93
+ * The same package can be installed more than once at different versions — a workspace pinning an old
94
+ * copy under `apps/api/node_modules`, a transitive dependency getting its own nested install. Without
95
+ * the locations, `lodash@4.17.11` and `lodash@4.17.21` arrive as two bare pairs and nothing can say
96
+ * WHICH one the app's own import resolves to. A consumer then has to treat every installed version as
97
+ * if the code used it: it warns on a copy nothing reaches, or pins a rule to a route running the safe
98
+ * one — a rule that never fires while reporting as protection.
99
+ *
100
+ * Node resolves an import by walking up from the importing file, so the map's import sites plus these
101
+ * paths together answer the question. Neither half answers it alone.
102
+ *
103
+ * OPT-IN. Absent unless the caller asks for locations (`scan --install-paths`), and absent even then
104
+ * when the scan source does not record them — see `installPathsComplete`, which is what separates
105
+ * "not installed there" from "we were not told".
106
+ *
107
+ * Off by default because it changes what leaves the machine. The package's standing promise is that
108
+ * `scan` sends names and versions and no paths of any kind; locations are a real widening of that, and
109
+ * an upload that widens it should be an explicit choice rather than a consequence of upgrading.
110
+ */
111
+ paths?: string[];
90
112
  }
91
113
  interface WirePayload {
92
114
  ecosystem: Manifest['ecosystem'];
93
115
  packages: WirePackage[];
116
+ /**
117
+ * Whether every entry's `paths` is the complete set of locations for it.
118
+ *
119
+ * False when locations were not requested at all, when the scan source cannot supply them (a yarn.lock
120
+ * is flat — hoisting is decided at install time and the file does not record it; a v1 npm lockfile
121
+ * describes the dependency graph, not the tree), or when only some entries had one. A consumer MUST NOT
122
+ * read a missing or short `paths` as "installed nowhere else" while this is false; absence is then "not
123
+ * recorded", which is not an answer.
124
+ *
125
+ * The default is therefore `false`, and that is the safe direction: the field withholds a negative
126
+ * rather than granting one.
127
+ */
128
+ installPathsComplete: boolean;
94
129
  }
95
130
  interface NormalizeStats {
96
131
  uniqueNames: number;
@@ -101,7 +136,14 @@ interface NormalizeResult {
101
136
  payload: WirePayload;
102
137
  stats: NormalizeStats;
103
138
  }
104
- declare function buildWirePayload(manifest: Manifest): NormalizeResult;
139
+ interface WireOptions {
140
+ /**
141
+ * Include each package's install location. Off by default — see `WirePackage.paths`: it widens what
142
+ * `scan` transmits, so it is the caller's explicit choice, not a side effect of upgrading.
143
+ */
144
+ installPaths?: boolean;
145
+ }
146
+ declare function buildWirePayload(manifest: Manifest, options?: WireOptions): NormalizeResult;
105
147
  declare function compareVersions(a: string, b: string): number;
106
148
 
107
149
  declare const DEFAULT_ENDPOINT = "https://api.patchstack.com/monitor/pulse/manifest";
@@ -145,21 +187,40 @@ interface ResolveConfigOptions {
145
187
  }
146
188
  declare function resolveConfig(options: ResolveConfigOptions): Promise<Config>;
147
189
  declare function writeConfigFile(cwd: string, config: ConfigFile): Promise<string>;
190
+ /**
191
+ * What happened to the credential file, so a caller can say only what is true.
192
+ *
193
+ * `ignored` is the OUTCOME of the ignore entry, verified by reading the file back — not the fact that a
194
+ * write was attempted. Telling somebody their credential is ignored when it is not is worse than telling
195
+ * them nothing: they stop looking, and a credential committed once is in the history whether or not the
196
+ * file is removed afterwards.
197
+ */
198
+ interface SecretFileResult {
199
+ /** Absolute path of the credential file. */
200
+ path: string;
201
+ /** True only when `.gitignore` was read back and really covers it. */
202
+ ignored: boolean;
203
+ /** Why not, when it is not — for the caller to print instead of a false assurance. */
204
+ reason?: string;
205
+ }
148
206
  /**
149
207
  * Merge a new siteUuid into the existing `.patchstackrc.json` (or create it).
150
208
  * Preserves any `endpoint` / `timeoutMs` / `apiKey` the user already wrote.
151
209
  */
152
210
  declare function persistSiteUuid(cwd: string, siteUuid: string): Promise<string>;
153
211
  /**
154
- * Persist the WP-format api_key issued at provision. Authenticates both the
155
- * Pulse endpoints and connector log reporting. Never embed it in the public
156
- * disclosure widget.
212
+ * Persist the WP-format api_key issued at provision. Authenticates both the Pulse endpoints and connector
213
+ * log reporting. Never embed it in the public disclosure widget.
157
214
  *
158
- * Drops any `pulseAuth` written by an earlier version. That field resolves
159
- * ahead of `apiKey`, so leaving a copy behind after the credential changes
160
- * would leave Pulse authenticating with the value the server just replaced.
215
+ * Written to the credential file, which setup adds to the project's ignore list — the public config is
216
+ * meant to be committed, so a credential in it is a credential in the repository.
217
+ *
218
+ * Any copy in the committed config is REMOVED at the same time. Leaving it would mean the value that just
219
+ * got moved is still in the file everyone commits, which is the state this split exists to end. `pulseAuth`
220
+ * goes with it: that field resolves ahead of `apiKey`, so a stale copy would keep authenticating with a
221
+ * credential the server has replaced.
161
222
  */
162
- declare function persistApiKey(cwd: string, apiKey: string): Promise<string>;
223
+ declare function persistApiKey(cwd: string, apiKey: string): Promise<SecretFileResult>;
163
224
  /**
164
225
  * Persist a Pulse-specific credential.
165
226
  *
@@ -167,7 +228,7 @@ declare function persistApiKey(cwd: string, apiKey: string): Promise<string>;
167
228
  * credentials; they share one today, so `persistApiKey` covers both. Retained
168
229
  * for callers that separate them.
169
230
  */
170
- declare function persistPulseAuth(cwd: string, pulseAuth: string): Promise<string>;
231
+ declare function persistPulseAuth(cwd: string, pulseAuth: string): Promise<SecretFileResult>;
171
232
 
172
233
  /**
173
234
  * A best-effort description of the stack a build was produced with, derived
@@ -251,6 +312,11 @@ declare function ensureSourceWidget(cwd: string, siteUuid: string): SourceWidget
251
312
  interface ScanAndReportOptions {
252
313
  cwd?: string;
253
314
  config?: Config;
315
+ /**
316
+ * Include each package's install location in the uploaded payload. Off by default: it widens what
317
+ * leaves the machine, so it is an explicit choice rather than something an upgrade turns on.
318
+ */
319
+ installPaths?: boolean;
254
320
  }
255
321
  interface ScanAndReportResult {
256
322
  manifest: Manifest;
package/dist/index.d.ts CHANGED
@@ -74,7 +74,7 @@ declare class PatchstackError extends Error {
74
74
  }
75
75
 
76
76
  type LockfileFilename = 'package-lock.json' | 'bun.lock' | 'bun.lockb' | 'yarn.lock' | 'pnpm-lock.yaml';
77
- type DetectionStrategy = 'npm-lockfile' | 'node-modules-walk' | 'pnpm-lockfile' | 'yarn-lockfile';
77
+ type DetectionStrategy = 'npm-lockfile' | 'bun-lockfile' | 'node-modules-walk' | 'pnpm-lockfile' | 'yarn-lockfile';
78
78
  interface DetectedLockfile {
79
79
  ecosystem: 'npm';
80
80
  filePath: string;
@@ -87,10 +87,45 @@ declare function scanLockfile(cwd: string): Promise<Manifest>;
87
87
  interface WirePackage {
88
88
  name: string;
89
89
  version: string;
90
+ /**
91
+ * Where this exact name+version is installed, repo-relative and sorted.
92
+ *
93
+ * The same package can be installed more than once at different versions — a workspace pinning an old
94
+ * copy under `apps/api/node_modules`, a transitive dependency getting its own nested install. Without
95
+ * the locations, `lodash@4.17.11` and `lodash@4.17.21` arrive as two bare pairs and nothing can say
96
+ * WHICH one the app's own import resolves to. A consumer then has to treat every installed version as
97
+ * if the code used it: it warns on a copy nothing reaches, or pins a rule to a route running the safe
98
+ * one — a rule that never fires while reporting as protection.
99
+ *
100
+ * Node resolves an import by walking up from the importing file, so the map's import sites plus these
101
+ * paths together answer the question. Neither half answers it alone.
102
+ *
103
+ * OPT-IN. Absent unless the caller asks for locations (`scan --install-paths`), and absent even then
104
+ * when the scan source does not record them — see `installPathsComplete`, which is what separates
105
+ * "not installed there" from "we were not told".
106
+ *
107
+ * Off by default because it changes what leaves the machine. The package's standing promise is that
108
+ * `scan` sends names and versions and no paths of any kind; locations are a real widening of that, and
109
+ * an upload that widens it should be an explicit choice rather than a consequence of upgrading.
110
+ */
111
+ paths?: string[];
90
112
  }
91
113
  interface WirePayload {
92
114
  ecosystem: Manifest['ecosystem'];
93
115
  packages: WirePackage[];
116
+ /**
117
+ * Whether every entry's `paths` is the complete set of locations for it.
118
+ *
119
+ * False when locations were not requested at all, when the scan source cannot supply them (a yarn.lock
120
+ * is flat — hoisting is decided at install time and the file does not record it; a v1 npm lockfile
121
+ * describes the dependency graph, not the tree), or when only some entries had one. A consumer MUST NOT
122
+ * read a missing or short `paths` as "installed nowhere else" while this is false; absence is then "not
123
+ * recorded", which is not an answer.
124
+ *
125
+ * The default is therefore `false`, and that is the safe direction: the field withholds a negative
126
+ * rather than granting one.
127
+ */
128
+ installPathsComplete: boolean;
94
129
  }
95
130
  interface NormalizeStats {
96
131
  uniqueNames: number;
@@ -101,7 +136,14 @@ interface NormalizeResult {
101
136
  payload: WirePayload;
102
137
  stats: NormalizeStats;
103
138
  }
104
- declare function buildWirePayload(manifest: Manifest): NormalizeResult;
139
+ interface WireOptions {
140
+ /**
141
+ * Include each package's install location. Off by default — see `WirePackage.paths`: it widens what
142
+ * `scan` transmits, so it is the caller's explicit choice, not a side effect of upgrading.
143
+ */
144
+ installPaths?: boolean;
145
+ }
146
+ declare function buildWirePayload(manifest: Manifest, options?: WireOptions): NormalizeResult;
105
147
  declare function compareVersions(a: string, b: string): number;
106
148
 
107
149
  declare const DEFAULT_ENDPOINT = "https://api.patchstack.com/monitor/pulse/manifest";
@@ -145,21 +187,40 @@ interface ResolveConfigOptions {
145
187
  }
146
188
  declare function resolveConfig(options: ResolveConfigOptions): Promise<Config>;
147
189
  declare function writeConfigFile(cwd: string, config: ConfigFile): Promise<string>;
190
+ /**
191
+ * What happened to the credential file, so a caller can say only what is true.
192
+ *
193
+ * `ignored` is the OUTCOME of the ignore entry, verified by reading the file back — not the fact that a
194
+ * write was attempted. Telling somebody their credential is ignored when it is not is worse than telling
195
+ * them nothing: they stop looking, and a credential committed once is in the history whether or not the
196
+ * file is removed afterwards.
197
+ */
198
+ interface SecretFileResult {
199
+ /** Absolute path of the credential file. */
200
+ path: string;
201
+ /** True only when `.gitignore` was read back and really covers it. */
202
+ ignored: boolean;
203
+ /** Why not, when it is not — for the caller to print instead of a false assurance. */
204
+ reason?: string;
205
+ }
148
206
  /**
149
207
  * Merge a new siteUuid into the existing `.patchstackrc.json` (or create it).
150
208
  * Preserves any `endpoint` / `timeoutMs` / `apiKey` the user already wrote.
151
209
  */
152
210
  declare function persistSiteUuid(cwd: string, siteUuid: string): Promise<string>;
153
211
  /**
154
- * Persist the WP-format api_key issued at provision. Authenticates both the
155
- * Pulse endpoints and connector log reporting. Never embed it in the public
156
- * disclosure widget.
212
+ * Persist the WP-format api_key issued at provision. Authenticates both the Pulse endpoints and connector
213
+ * log reporting. Never embed it in the public disclosure widget.
157
214
  *
158
- * Drops any `pulseAuth` written by an earlier version. That field resolves
159
- * ahead of `apiKey`, so leaving a copy behind after the credential changes
160
- * would leave Pulse authenticating with the value the server just replaced.
215
+ * Written to the credential file, which setup adds to the project's ignore list — the public config is
216
+ * meant to be committed, so a credential in it is a credential in the repository.
217
+ *
218
+ * Any copy in the committed config is REMOVED at the same time. Leaving it would mean the value that just
219
+ * got moved is still in the file everyone commits, which is the state this split exists to end. `pulseAuth`
220
+ * goes with it: that field resolves ahead of `apiKey`, so a stale copy would keep authenticating with a
221
+ * credential the server has replaced.
161
222
  */
162
- declare function persistApiKey(cwd: string, apiKey: string): Promise<string>;
223
+ declare function persistApiKey(cwd: string, apiKey: string): Promise<SecretFileResult>;
163
224
  /**
164
225
  * Persist a Pulse-specific credential.
165
226
  *
@@ -167,7 +228,7 @@ declare function persistApiKey(cwd: string, apiKey: string): Promise<string>;
167
228
  * credentials; they share one today, so `persistApiKey` covers both. Retained
168
229
  * for callers that separate them.
169
230
  */
170
- declare function persistPulseAuth(cwd: string, pulseAuth: string): Promise<string>;
231
+ declare function persistPulseAuth(cwd: string, pulseAuth: string): Promise<SecretFileResult>;
171
232
 
172
233
  /**
173
234
  * A best-effort description of the stack a build was produced with, derived
@@ -251,6 +312,11 @@ declare function ensureSourceWidget(cwd: string, siteUuid: string): SourceWidget
251
312
  interface ScanAndReportOptions {
252
313
  cwd?: string;
253
314
  config?: Config;
315
+ /**
316
+ * Include each package's install location in the uploaded payload. Off by default: it widens what
317
+ * leaves the machine, so it is an explicit choice rather than something an upgrade turns on.
318
+ */
319
+ installPaths?: boolean;
254
320
  }
255
321
  interface ScanAndReportResult {
256
322
  manifest: Manifest;