@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.
- package/AGENT-INSTALL.md +42 -23
- package/README.md +40 -11
- package/dist/{chunk-MJOTFUDE.js → chunk-LLKP5EJS.js} +1 -1
- package/dist/chunk-LLKP5EJS.js.map +1 -0
- package/dist/cli.js +1265 -287
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +456 -111
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +76 -10
- package/dist/index.d.ts +76 -10
- package/dist/index.js +449 -104
- package/dist/index.js.map +1 -1
- package/dist/protect/templates/astro-middleware.ts +33 -13
- package/dist/protect/templates/demo-rules.json +2 -3
- package/dist/protect/templates/express-guard.cjs +26 -15
- package/dist/protect/templates/express-guard.js +26 -15
- package/dist/protect/templates/express-guard.ts +33 -16
- package/dist/protect/templates/fastify-plugin.cjs +33 -11
- package/dist/protect/templates/fastify-plugin.js +33 -11
- package/dist/protect/templates/fastify-plugin.ts +40 -12
- package/dist/protect/templates/generic-guard.cjs +28 -12
- package/dist/protect/templates/generic-guard.js +28 -13
- package/dist/protect/templates/generic-guard.ts +41 -20
- package/dist/protect/templates/guard.ts +47 -27
- package/dist/protect/templates/next-middleware.ts +29 -12
- package/dist/protect/templates/nuxt-middleware.ts +29 -12
- package/dist/protect/templates/rules.json +2 -2
- package/dist/protect/templates/sveltekit-hooks.ts +33 -13
- package/dist/protect.cjs +1204 -252
- package/dist/protect.cjs.map +1 -1
- package/dist/protect.d.ts +39 -11
- package/dist/protect.edge.js +792 -143
- package/dist/protect.edge.js.map +4 -4
- package/dist/protect.js +794 -145
- package/dist/protect.js.map +1 -1
- package/dist/{refresh-manifest-VRBE6RH6.js → refresh-manifest-KNZQBC4V.js} +387 -100
- package/dist/refresh-manifest-KNZQBC4V.js.map +1 -0
- package/package.json +5 -2
- package/dist/chunk-MJOTFUDE.js.map +0 -1
- package/dist/refresh-manifest-VRBE6RH6.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -58,7 +58,7 @@ __export(src_exports, {
|
|
|
58
58
|
module.exports = __toCommonJS(src_exports);
|
|
59
59
|
|
|
60
60
|
// src/parsers/index.ts
|
|
61
|
-
var
|
|
61
|
+
var import_promises7 = require("fs/promises");
|
|
62
62
|
var import_node_path5 = __toESM(require("path"), 1);
|
|
63
63
|
|
|
64
64
|
// src/types.ts
|
|
@@ -93,7 +93,7 @@ async function readDeclaredDependencyNames(cwd) {
|
|
|
93
93
|
return [];
|
|
94
94
|
}
|
|
95
95
|
const names = /* @__PURE__ */ new Set();
|
|
96
|
-
for (const group of ["dependencies", "devDependencies"]) {
|
|
96
|
+
for (const group of ["dependencies", "devDependencies", "optionalDependencies"]) {
|
|
97
97
|
const deps = parsed[group];
|
|
98
98
|
if (typeof deps !== "object" || deps === null) {
|
|
99
99
|
continue;
|
|
@@ -111,14 +111,171 @@ function missingDependencies(declared, packages) {
|
|
|
111
111
|
const present = new Set(packages.map((entry) => entry.name));
|
|
112
112
|
return declared.filter((name) => !present.has(name));
|
|
113
113
|
}
|
|
114
|
+
function disagreements(packages, other) {
|
|
115
|
+
const otherVersions = /* @__PURE__ */ new Map();
|
|
116
|
+
for (const entry of other) {
|
|
117
|
+
if (!otherVersions.has(entry.name)) otherVersions.set(entry.name, entry.version);
|
|
118
|
+
}
|
|
119
|
+
const seen = /* @__PURE__ */ new Set();
|
|
120
|
+
const conflicts = [];
|
|
121
|
+
for (const entry of packages) {
|
|
122
|
+
if (seen.has(entry.name)) continue;
|
|
123
|
+
seen.add(entry.name);
|
|
124
|
+
const otherVersion = otherVersions.get(entry.name);
|
|
125
|
+
if (otherVersion !== void 0 && otherVersion !== entry.version) {
|
|
126
|
+
conflicts.push({ name: entry.name, version: entry.version, otherVersion });
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return conflicts;
|
|
130
|
+
}
|
|
114
131
|
|
|
115
|
-
// src/parsers/
|
|
132
|
+
// src/parsers/bun.ts
|
|
116
133
|
var import_promises2 = require("fs/promises");
|
|
134
|
+
|
|
135
|
+
// src/parsers/report.ts
|
|
136
|
+
var MAX_SAMPLES = 3;
|
|
137
|
+
function newReport() {
|
|
138
|
+
return { unreadable: 0, samples: [] };
|
|
139
|
+
}
|
|
140
|
+
function recordUnreadable(report, sample) {
|
|
141
|
+
if (!report) return;
|
|
142
|
+
report.unreadable++;
|
|
143
|
+
if (report.samples.length < MAX_SAMPLES) report.samples.push(sample);
|
|
144
|
+
}
|
|
145
|
+
function unreadableWarning(filename, report) {
|
|
146
|
+
if (report.unreadable === 0) return null;
|
|
147
|
+
const shown = report.samples.join(", ");
|
|
148
|
+
const one = report.unreadable === 1;
|
|
149
|
+
return `${filename}: ${report.unreadable} entr${one ? "y was" : "ies were"} not in a form this scanner reads (${shown}${report.unreadable > report.samples.length ? ", \u2026" : ""}), so ${one ? "it is" : "they are"} absent from this manifest. Anything installed only through ${one ? "that entry" : "those entries"} is not being checked.`;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// src/parsers/bun.ts
|
|
153
|
+
async function parseBunLockfile(lockfilePath, report) {
|
|
154
|
+
let raw;
|
|
155
|
+
try {
|
|
156
|
+
raw = await (0, import_promises2.readFile)(lockfilePath, "utf8");
|
|
157
|
+
} catch (cause) {
|
|
158
|
+
throw new PatchstackError(`Could not read lockfile at ${lockfilePath}`, "LOCKFILE_NOT_FOUND", cause);
|
|
159
|
+
}
|
|
160
|
+
let parsed;
|
|
161
|
+
try {
|
|
162
|
+
parsed = JSON.parse(stripTrailingCommas(raw));
|
|
163
|
+
} catch (cause) {
|
|
164
|
+
throw new PatchstackError(`Lockfile at ${lockfilePath} is not valid JSON`, "LOCKFILE_PARSE_ERROR", cause);
|
|
165
|
+
}
|
|
166
|
+
const packages = parsed?.packages;
|
|
167
|
+
if (typeof packages !== "object" || packages === null) {
|
|
168
|
+
throw new PatchstackError(`Lockfile at ${lockfilePath} has no "packages" entries`, "LOCKFILE_PARSE_ERROR");
|
|
169
|
+
}
|
|
170
|
+
const direct = directDependencyNames(parsed);
|
|
171
|
+
const entries = [];
|
|
172
|
+
let skipped = 0;
|
|
173
|
+
for (const [key, value] of Object.entries(packages)) {
|
|
174
|
+
const descriptor = Array.isArray(value) ? value[0] : value;
|
|
175
|
+
if (typeof descriptor !== "string") {
|
|
176
|
+
skipped++;
|
|
177
|
+
recordUnreadable(report, key);
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
const split = splitDescriptor(descriptor);
|
|
181
|
+
if (split === null) {
|
|
182
|
+
skipped++;
|
|
183
|
+
if (!isDeliberatelyExcluded(descriptor)) recordUnreadable(report, key);
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
entries.push({
|
|
187
|
+
name: split.name,
|
|
188
|
+
version: split.version,
|
|
189
|
+
...direct.has(split.name) ? { direct: true } : {},
|
|
190
|
+
...key === split.name ? {} : { path: key }
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
if (entries.length === 0) {
|
|
194
|
+
throw new PatchstackError(
|
|
195
|
+
`Lockfile at ${lockfilePath} lists no registry packages${skipped > 0 ? ` (${skipped} non-registry entr${skipped === 1 ? "y" : "ies"} skipped)` : ""}`,
|
|
196
|
+
"LOCKFILE_PARSE_ERROR"
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
return entries;
|
|
200
|
+
}
|
|
201
|
+
function splitDescriptor(descriptor) {
|
|
202
|
+
const at = descriptor.lastIndexOf("@");
|
|
203
|
+
if (at <= 0) return null;
|
|
204
|
+
const name = descriptor.slice(0, at);
|
|
205
|
+
const version = descriptor.slice(at + 1);
|
|
206
|
+
if (name === "" || version === "") return null;
|
|
207
|
+
if (NON_REGISTRY_VERSION.test(version)) return null;
|
|
208
|
+
return { name, version };
|
|
209
|
+
}
|
|
210
|
+
var NON_REGISTRY_VERSION = /^[a-z][a-z0-9+.-]*:|\//i;
|
|
211
|
+
function isDeliberatelyExcluded(descriptor) {
|
|
212
|
+
const at = descriptor.lastIndexOf("@");
|
|
213
|
+
if (at <= 0) return false;
|
|
214
|
+
return NON_REGISTRY_VERSION.test(descriptor.slice(at + 1));
|
|
215
|
+
}
|
|
216
|
+
function directDependencyNames(parsed) {
|
|
217
|
+
const names = /* @__PURE__ */ new Set();
|
|
218
|
+
const workspaces = parsed?.workspaces;
|
|
219
|
+
if (typeof workspaces !== "object" || workspaces === null) return names;
|
|
220
|
+
for (const workspace of Object.values(workspaces)) {
|
|
221
|
+
if (typeof workspace !== "object" || workspace === null) continue;
|
|
222
|
+
for (const group of ["dependencies", "devDependencies", "optionalDependencies", "peerDependencies"]) {
|
|
223
|
+
const deps = workspace[group];
|
|
224
|
+
if (typeof deps !== "object" || deps === null) continue;
|
|
225
|
+
for (const name of Object.keys(deps)) names.add(name);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return names;
|
|
229
|
+
}
|
|
230
|
+
function stripTrailingCommas(source) {
|
|
231
|
+
const out = [];
|
|
232
|
+
let inString = false;
|
|
233
|
+
let pendingComma = -1;
|
|
234
|
+
for (let i = 0; i < source.length; i++) {
|
|
235
|
+
const ch = source[i];
|
|
236
|
+
if (inString) {
|
|
237
|
+
out.push(ch);
|
|
238
|
+
if (ch === "\\") {
|
|
239
|
+
const next = source[i + 1];
|
|
240
|
+
if (next !== void 0) {
|
|
241
|
+
out.push(next);
|
|
242
|
+
i++;
|
|
243
|
+
}
|
|
244
|
+
} else if (ch === '"') {
|
|
245
|
+
inString = false;
|
|
246
|
+
}
|
|
247
|
+
continue;
|
|
248
|
+
}
|
|
249
|
+
if (ch === '"') {
|
|
250
|
+
inString = true;
|
|
251
|
+
pendingComma = -1;
|
|
252
|
+
out.push(ch);
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
if (ch === ",") {
|
|
256
|
+
pendingComma = out.length;
|
|
257
|
+
out.push(ch);
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
260
|
+
if (ch === "}" || ch === "]") {
|
|
261
|
+
if (pendingComma !== -1) out[pendingComma] = " ";
|
|
262
|
+
pendingComma = -1;
|
|
263
|
+
out.push(ch);
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
266
|
+
if (!/\s/.test(ch)) pendingComma = -1;
|
|
267
|
+
out.push(ch);
|
|
268
|
+
}
|
|
269
|
+
return out.join("");
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// src/parsers/npm.ts
|
|
273
|
+
var import_promises3 = require("fs/promises");
|
|
117
274
|
var import_node_path2 = __toESM(require("path"), 1);
|
|
118
275
|
async function parseNpmLockfile(lockfilePath) {
|
|
119
276
|
let raw;
|
|
120
277
|
try {
|
|
121
|
-
raw = await (0,
|
|
278
|
+
raw = await (0, import_promises3.readFile)(lockfilePath, "utf8");
|
|
122
279
|
} catch (cause) {
|
|
123
280
|
throw new PatchstackError(`Could not read lockfile at ${lockfilePath}`, "LOCKFILE_NOT_FOUND", cause);
|
|
124
281
|
}
|
|
@@ -199,12 +356,13 @@ function isDirectV2(pkgPath) {
|
|
|
199
356
|
}
|
|
200
357
|
|
|
201
358
|
// src/parsers/node_modules.ts
|
|
202
|
-
var
|
|
359
|
+
var import_promises4 = require("fs/promises");
|
|
203
360
|
var import_node_path3 = __toESM(require("path"), 1);
|
|
361
|
+
var PACKAGE_STORE_DIRS = /* @__PURE__ */ new Set([".bun", ".pnpm", ".store"]);
|
|
204
362
|
async function walkNodeModules(cwd) {
|
|
205
363
|
const root = import_node_path3.default.join(cwd, "node_modules");
|
|
206
364
|
try {
|
|
207
|
-
const info = await (0,
|
|
365
|
+
const info = await (0, import_promises4.stat)(root);
|
|
208
366
|
if (!info.isDirectory()) {
|
|
209
367
|
throw new PatchstackError(
|
|
210
368
|
`${root} exists but is not a directory.`,
|
|
@@ -221,96 +379,125 @@ async function walkNodeModules(cwd) {
|
|
|
221
379
|
cause
|
|
222
380
|
);
|
|
223
381
|
}
|
|
224
|
-
const
|
|
225
|
-
|
|
226
|
-
|
|
382
|
+
const seen = /* @__PURE__ */ new Map();
|
|
383
|
+
try {
|
|
384
|
+
seen.set(await (0, import_promises4.realpath)(cwd), -1);
|
|
385
|
+
} catch {
|
|
386
|
+
}
|
|
387
|
+
return dedupeByShallowest(await walk(root, 0, seen, cwd));
|
|
227
388
|
}
|
|
228
|
-
|
|
389
|
+
function dedupeByShallowest(found) {
|
|
390
|
+
const best = /* @__PURE__ */ new Map();
|
|
391
|
+
for (const item of found) {
|
|
392
|
+
const current = best.get(item.realpath);
|
|
393
|
+
if (current === void 0 || item.depth < current.depth) best.set(item.realpath, item);
|
|
394
|
+
}
|
|
395
|
+
return [...best.values()].map(({ entry }) => entry);
|
|
396
|
+
}
|
|
397
|
+
var CONCURRENCY = 32;
|
|
398
|
+
async function walk(dir, depth, seen, root) {
|
|
229
399
|
let names;
|
|
230
400
|
try {
|
|
231
|
-
names = await (0,
|
|
401
|
+
names = await (0, import_promises4.readdir)(dir);
|
|
232
402
|
} catch {
|
|
233
|
-
return;
|
|
403
|
+
return [];
|
|
234
404
|
}
|
|
235
|
-
|
|
236
|
-
if (name.startsWith("."))
|
|
237
|
-
continue;
|
|
238
|
-
}
|
|
405
|
+
const perEntry = await mapLimit(names, async (name) => {
|
|
406
|
+
if (name.startsWith(".") && !PACKAGE_STORE_DIRS.has(name)) return [];
|
|
239
407
|
const fullPath = import_node_path3.default.join(dir, name);
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
408
|
+
const resolved = await claim(fullPath, seen, depth);
|
|
409
|
+
if (resolved === null) return [];
|
|
410
|
+
if (PACKAGE_STORE_DIRS.has(name)) return walk(fullPath, depth, seen, root);
|
|
243
411
|
if (name.startsWith("@")) {
|
|
244
412
|
let subNames;
|
|
245
413
|
try {
|
|
246
|
-
subNames = await (0,
|
|
414
|
+
subNames = await (0, import_promises4.readdir)(fullPath);
|
|
247
415
|
} catch {
|
|
248
|
-
|
|
416
|
+
return [];
|
|
249
417
|
}
|
|
250
|
-
|
|
251
|
-
if (sub.startsWith("."))
|
|
252
|
-
continue;
|
|
253
|
-
}
|
|
418
|
+
const scoped = await mapLimit(subNames, async (sub) => {
|
|
419
|
+
if (sub.startsWith(".")) return [];
|
|
254
420
|
const scopedDir = import_node_path3.default.join(fullPath, sub);
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
}
|
|
261
|
-
continue;
|
|
421
|
+
const scopedReal = await claim(scopedDir, seen, depth);
|
|
422
|
+
if (scopedReal === null) return [];
|
|
423
|
+
return packageAndNested(scopedDir, scopedReal, depth, seen, root);
|
|
424
|
+
});
|
|
425
|
+
return scoped.flat();
|
|
262
426
|
}
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
427
|
+
return packageAndNested(fullPath, resolved, depth, seen, root);
|
|
428
|
+
});
|
|
429
|
+
return perEntry.flat();
|
|
430
|
+
}
|
|
431
|
+
async function packageAndNested(pkgDir, resolved, depth, seen, root) {
|
|
432
|
+
const [own, nested] = await Promise.all([readPackage(pkgDir, depth, root), walkNested(pkgDir, depth, seen, root)]);
|
|
433
|
+
return own === null ? nested : [{ entry: own, realpath: resolved, depth }, ...nested];
|
|
434
|
+
}
|
|
435
|
+
async function mapLimit(items, fn) {
|
|
436
|
+
const results = new Array(items.length);
|
|
437
|
+
let next = 0;
|
|
438
|
+
const workers = Array.from({ length: Math.min(CONCURRENCY, items.length) }, async () => {
|
|
439
|
+
while (next < items.length) {
|
|
440
|
+
const index = next++;
|
|
441
|
+
results[index] = await fn(items[index]);
|
|
442
|
+
}
|
|
443
|
+
});
|
|
444
|
+
await Promise.all(workers);
|
|
445
|
+
return results;
|
|
266
446
|
}
|
|
267
|
-
|
|
447
|
+
function installLocation(root, pkgDir, impl = import_node_path3.default) {
|
|
448
|
+
return impl.relative(root, pkgDir).split(impl.sep).join("/");
|
|
449
|
+
}
|
|
450
|
+
async function readPackage(pkgDir, depth, root) {
|
|
268
451
|
let raw;
|
|
269
452
|
try {
|
|
270
|
-
raw = await (0,
|
|
453
|
+
raw = await (0, import_promises4.readFile)(import_node_path3.default.join(pkgDir, "package.json"), "utf8");
|
|
271
454
|
} catch {
|
|
272
|
-
return;
|
|
455
|
+
return null;
|
|
273
456
|
}
|
|
274
457
|
let parsed;
|
|
275
458
|
try {
|
|
276
459
|
parsed = JSON.parse(raw);
|
|
277
460
|
} catch {
|
|
278
|
-
return;
|
|
461
|
+
return null;
|
|
279
462
|
}
|
|
280
463
|
if (typeof parsed.name !== "string" || parsed.name.length === 0) {
|
|
281
|
-
return;
|
|
464
|
+
return null;
|
|
282
465
|
}
|
|
283
466
|
if (typeof parsed.version !== "string" || parsed.version.length === 0) {
|
|
284
|
-
return;
|
|
467
|
+
return null;
|
|
285
468
|
}
|
|
286
|
-
|
|
287
|
-
name: parsed.name,
|
|
288
|
-
version: parsed.version,
|
|
289
|
-
direct: depth === 0
|
|
290
|
-
});
|
|
469
|
+
return { name: parsed.name, version: parsed.version, path: installLocation(root, pkgDir), direct: depth === 0 };
|
|
291
470
|
}
|
|
292
|
-
async function walkNested(pkgDir,
|
|
471
|
+
async function walkNested(pkgDir, depth, seen, root) {
|
|
293
472
|
const nested = import_node_path3.default.join(pkgDir, "node_modules");
|
|
294
|
-
if (
|
|
295
|
-
return;
|
|
473
|
+
if (await claim(nested, seen, depth + 1) === null) {
|
|
474
|
+
return [];
|
|
296
475
|
}
|
|
297
|
-
|
|
476
|
+
return walk(nested, depth + 1, seen, root);
|
|
298
477
|
}
|
|
299
|
-
async function
|
|
478
|
+
async function claim(dir, seen, depth) {
|
|
479
|
+
let resolved;
|
|
300
480
|
try {
|
|
301
|
-
const info = await (0,
|
|
302
|
-
|
|
481
|
+
const info = await (0, import_promises4.lstat)(dir);
|
|
482
|
+
if (!info.isDirectory() && !info.isSymbolicLink()) return null;
|
|
483
|
+
resolved = await (0, import_promises4.realpath)(dir);
|
|
484
|
+
const target = await (0, import_promises4.stat)(resolved);
|
|
485
|
+
if (!target.isDirectory()) return null;
|
|
303
486
|
} catch {
|
|
304
|
-
return
|
|
487
|
+
return null;
|
|
305
488
|
}
|
|
489
|
+
const claimed = seen.get(resolved);
|
|
490
|
+
if (claimed !== void 0 && claimed <= depth) return null;
|
|
491
|
+
seen.set(resolved, depth);
|
|
492
|
+
return resolved;
|
|
306
493
|
}
|
|
307
494
|
|
|
308
495
|
// src/parsers/pnpm.ts
|
|
309
|
-
var
|
|
310
|
-
async function parsePnpmLockfile(lockfilePath) {
|
|
496
|
+
var import_promises5 = require("fs/promises");
|
|
497
|
+
async function parsePnpmLockfile(lockfilePath, report) {
|
|
311
498
|
let raw;
|
|
312
499
|
try {
|
|
313
|
-
raw = await (0,
|
|
500
|
+
raw = await (0, import_promises5.readFile)(lockfilePath, "utf8");
|
|
314
501
|
} catch (cause) {
|
|
315
502
|
throw new PatchstackError(
|
|
316
503
|
`Could not read lockfile at ${lockfilePath}`,
|
|
@@ -331,6 +518,7 @@ async function parsePnpmLockfile(lockfilePath) {
|
|
|
331
518
|
for (const key of packageKeys) {
|
|
332
519
|
const parsed = parsePackageKey(key);
|
|
333
520
|
if (parsed === null) {
|
|
521
|
+
recordUnreadable(report, key);
|
|
334
522
|
continue;
|
|
335
523
|
}
|
|
336
524
|
entries.push({
|
|
@@ -558,12 +746,12 @@ function extractLeafName(trimmed) {
|
|
|
558
746
|
}
|
|
559
747
|
|
|
560
748
|
// src/parsers/yarn.ts
|
|
561
|
-
var
|
|
749
|
+
var import_promises6 = require("fs/promises");
|
|
562
750
|
var import_node_path4 = __toESM(require("path"), 1);
|
|
563
|
-
async function parseYarnLockfile(lockfilePath) {
|
|
751
|
+
async function parseYarnLockfile(lockfilePath, report) {
|
|
564
752
|
let raw;
|
|
565
753
|
try {
|
|
566
|
-
raw = await (0,
|
|
754
|
+
raw = await (0, import_promises6.readFile)(lockfilePath, "utf8");
|
|
567
755
|
} catch (cause) {
|
|
568
756
|
throw new PatchstackError(
|
|
569
757
|
`Could not read lockfile at ${lockfilePath}`,
|
|
@@ -571,7 +759,7 @@ async function parseYarnLockfile(lockfilePath) {
|
|
|
571
759
|
cause
|
|
572
760
|
);
|
|
573
761
|
}
|
|
574
|
-
const blocks = parseBlocks(raw);
|
|
762
|
+
const blocks = parseBlocks(raw, report);
|
|
575
763
|
if (blocks.length === 0) {
|
|
576
764
|
throw new PatchstackError(
|
|
577
765
|
`Lockfile at ${lockfilePath} contains no package entries`,
|
|
@@ -600,13 +788,19 @@ async function parseYarnLockfile(lockfilePath) {
|
|
|
600
788
|
}
|
|
601
789
|
return entries;
|
|
602
790
|
}
|
|
603
|
-
|
|
791
|
+
var NON_PACKAGE_KEYS = /* @__PURE__ */ new Set(["__metadata"]);
|
|
792
|
+
function parseBlocks(raw, report) {
|
|
604
793
|
const lines = raw.split(/\r?\n/);
|
|
605
794
|
const blocks = [];
|
|
606
795
|
let current = null;
|
|
607
796
|
const finalize = () => {
|
|
608
|
-
if (current
|
|
797
|
+
if (current === null) {
|
|
798
|
+
return;
|
|
799
|
+
}
|
|
800
|
+
if (current.version.length > 0 && current.names.size > 0) {
|
|
609
801
|
blocks.push(current);
|
|
802
|
+
} else if (current.unreadable) {
|
|
803
|
+
recordUnreadable(report, current.key);
|
|
610
804
|
}
|
|
611
805
|
current = null;
|
|
612
806
|
};
|
|
@@ -623,13 +817,13 @@ function parseBlocks(raw) {
|
|
|
623
817
|
}
|
|
624
818
|
const keyLine = trimmed.slice(0, -1);
|
|
625
819
|
const names = /* @__PURE__ */ new Set();
|
|
820
|
+
let unreadable = false;
|
|
626
821
|
for (const spec of splitDescriptors(keyLine)) {
|
|
627
|
-
const
|
|
628
|
-
if (name !==
|
|
629
|
-
|
|
630
|
-
}
|
|
822
|
+
const classified = classifyDescriptor(spec);
|
|
823
|
+
if (classified.name !== void 0) names.add(classified.name);
|
|
824
|
+
else if (!classified.excluded) unreadable = true;
|
|
631
825
|
}
|
|
632
|
-
current = { names, version: "" };
|
|
826
|
+
current = { names, version: "", key: keyLine, unreadable: unreadable && names.size === 0 };
|
|
633
827
|
continue;
|
|
634
828
|
}
|
|
635
829
|
if (current === null) {
|
|
@@ -684,20 +878,37 @@ function splitDescriptors(keyLine) {
|
|
|
684
878
|
}
|
|
685
879
|
return parts;
|
|
686
880
|
}
|
|
687
|
-
|
|
881
|
+
var NON_REGISTRY_PROTOCOLS = /^(?:workspace|patch|virtual|portal|file|link|exec|git|github|https?|ssh):/i;
|
|
882
|
+
function classifyDescriptor(rawSpec) {
|
|
688
883
|
let s = rawSpec.trim();
|
|
689
884
|
if (s.length === 0) {
|
|
690
|
-
return
|
|
885
|
+
return { excluded: true };
|
|
691
886
|
}
|
|
692
887
|
if (s.startsWith('"') && s.endsWith('"') || s.startsWith("'") && s.endsWith("'")) {
|
|
693
888
|
s = s.slice(1, -1);
|
|
694
889
|
}
|
|
695
|
-
|
|
890
|
+
if (NON_PACKAGE_KEYS.has(s)) {
|
|
891
|
+
return { excluded: true };
|
|
892
|
+
}
|
|
893
|
+
const atIdx = s.indexOf("@", 1);
|
|
696
894
|
if (atIdx <= 0) {
|
|
697
|
-
return
|
|
895
|
+
return {};
|
|
698
896
|
}
|
|
699
897
|
const name = s.slice(0, atIdx);
|
|
700
|
-
|
|
898
|
+
const range = s.slice(atIdx + 1);
|
|
899
|
+
if (name.length === 0) {
|
|
900
|
+
return {};
|
|
901
|
+
}
|
|
902
|
+
if (NON_REGISTRY_PROTOCOLS.test(range)) {
|
|
903
|
+
return { excluded: true };
|
|
904
|
+
}
|
|
905
|
+
const alias = /^npm:(.+)$/i.exec(range);
|
|
906
|
+
if (alias !== null) {
|
|
907
|
+
const target = alias[1] ?? "";
|
|
908
|
+
const targetAt = target.indexOf("@", 1);
|
|
909
|
+
return { name: targetAt > 0 ? target.slice(0, targetAt) : name };
|
|
910
|
+
}
|
|
911
|
+
return { name };
|
|
701
912
|
}
|
|
702
913
|
function parseVersionField(content) {
|
|
703
914
|
if (!content.startsWith("version")) {
|
|
@@ -722,7 +933,7 @@ async function readDirectDepNames(cwd) {
|
|
|
722
933
|
const names = /* @__PURE__ */ new Set();
|
|
723
934
|
let raw;
|
|
724
935
|
try {
|
|
725
|
-
raw = await (0,
|
|
936
|
+
raw = await (0, import_promises6.readFile)(import_node_path4.default.join(cwd, "package.json"), "utf8");
|
|
726
937
|
} catch {
|
|
727
938
|
return names;
|
|
728
939
|
}
|
|
@@ -751,7 +962,10 @@ async function readDirectDepNames(cwd) {
|
|
|
751
962
|
// src/parsers/index.ts
|
|
752
963
|
var LOCKFILE_CANDIDATES = [
|
|
753
964
|
{ filename: "package-lock.json", strategy: "npm-lockfile" },
|
|
754
|
-
|
|
965
|
+
// Read directly, not walked. Bun's isolated layout puts packages under a dot-directory and makes the
|
|
966
|
+
// top level symlinks into it, so a `node_modules` walk finds nothing there — and isolated is the default
|
|
967
|
+
// for new workspaces.
|
|
968
|
+
{ filename: "bun.lock", strategy: "bun-lockfile" },
|
|
755
969
|
{ filename: "bun.lockb", strategy: "node-modules-walk" },
|
|
756
970
|
{ filename: "pnpm-lock.yaml", strategy: "pnpm-lockfile" },
|
|
757
971
|
{ filename: "yarn.lock", strategy: "yarn-lockfile" }
|
|
@@ -786,33 +1000,57 @@ async function scanLockfile(cwd) {
|
|
|
786
1000
|
const declared = await readDeclaredDependencyNames(cwd);
|
|
787
1001
|
const warnings = [];
|
|
788
1002
|
let firstParsed = null;
|
|
789
|
-
let
|
|
1003
|
+
let walked = null;
|
|
1004
|
+
let walkWasCandidate = false;
|
|
1005
|
+
const parsedSources = [];
|
|
790
1006
|
for (const candidate of candidates) {
|
|
791
1007
|
let packages;
|
|
1008
|
+
const report = newReport();
|
|
792
1009
|
try {
|
|
793
|
-
packages = await runStrategy(candidate, cwd);
|
|
1010
|
+
packages = await runStrategy(candidate, cwd, report);
|
|
794
1011
|
} catch {
|
|
795
1012
|
continue;
|
|
796
1013
|
}
|
|
797
|
-
|
|
1014
|
+
const unreadable = unreadableWarning(candidate.filename, report);
|
|
1015
|
+
if (unreadable !== null) warnings.push(unreadable);
|
|
1016
|
+
if (candidate.strategy === "node-modules-walk") {
|
|
1017
|
+
walked = packages;
|
|
1018
|
+
walkWasCandidate = true;
|
|
1019
|
+
}
|
|
798
1020
|
firstParsed ??= { packages, filename: candidate.filename };
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
1021
|
+
parsedSources.push({ packages, filename: candidate.filename });
|
|
1022
|
+
}
|
|
1023
|
+
for (const source of parsedSources) {
|
|
1024
|
+
const missing = missingDependencies(declared, source.packages);
|
|
1025
|
+
if (missing.length > 0) {
|
|
1026
|
+
warnings.push(staleWarning(source.filename, missing));
|
|
1027
|
+
continue;
|
|
802
1028
|
}
|
|
803
|
-
|
|
1029
|
+
const conflicts = otherCompleteSources(parsedSources, source, declared).flatMap(
|
|
1030
|
+
(other) => disagreements(source.packages, other.packages).map((conflict) => ({ other: other.filename, conflict }))
|
|
1031
|
+
);
|
|
1032
|
+
if (conflicts.length === 0) {
|
|
1033
|
+
return manifestWith(source.packages, warnings);
|
|
1034
|
+
}
|
|
1035
|
+
warnings.push(conflictWarning(source.filename, conflicts));
|
|
1036
|
+
break;
|
|
804
1037
|
}
|
|
805
|
-
if (
|
|
1038
|
+
if (walked === null) {
|
|
806
1039
|
try {
|
|
807
|
-
|
|
808
|
-
const missing = missingDependencies(declared, packages);
|
|
809
|
-
if (missing.length > 0) {
|
|
810
|
-
warnings.push(staleWarning("node_modules/", missing));
|
|
811
|
-
}
|
|
812
|
-
warnings.push("Scanned node_modules/ instead. Delete the stale lockfile to silence this warning.");
|
|
813
|
-
return manifestWith(packages, warnings);
|
|
1040
|
+
walked = await walkNodeModules(cwd);
|
|
814
1041
|
} catch {
|
|
1042
|
+
walked = null;
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
if (walked !== null) {
|
|
1046
|
+
const missing = missingDependencies(declared, walked);
|
|
1047
|
+
if (missing.length > 0) {
|
|
1048
|
+
warnings.push(staleWarning("node_modules/", missing));
|
|
815
1049
|
}
|
|
1050
|
+
warnings.push(
|
|
1051
|
+
walkWasCandidate ? "Reporting node_modules/, which is what the build loads." : "Scanned node_modules/ instead. Delete the stale lockfile to silence this warning."
|
|
1052
|
+
);
|
|
1053
|
+
return manifestWith(walked, warnings);
|
|
816
1054
|
}
|
|
817
1055
|
if (firstParsed === null) {
|
|
818
1056
|
const expected = LOCKFILE_CANDIDATES.map((candidate) => candidate.filename).join(", ");
|
|
@@ -829,6 +1067,15 @@ async function scanLockfile(cwd) {
|
|
|
829
1067
|
function manifestWith(packages, warnings) {
|
|
830
1068
|
return warnings.length > 0 ? { ecosystem: "npm", packages, warnings } : { ecosystem: "npm", packages };
|
|
831
1069
|
}
|
|
1070
|
+
function otherCompleteSources(all, current, declared) {
|
|
1071
|
+
return all.filter(
|
|
1072
|
+
(source) => source.filename !== current.filename && missingDependencies(declared, source.packages).length === 0
|
|
1073
|
+
);
|
|
1074
|
+
}
|
|
1075
|
+
function conflictWarning(filename, conflicts) {
|
|
1076
|
+
const shown = conflicts.slice(0, 3).map(({ other, conflict }) => `${conflict.name} ${conflict.version} vs ${conflict.otherVersion} in ${other}`).join("; ");
|
|
1077
|
+
return `${filename} and another lockfile disagree about installed versions (${shown}${conflicts.length > 3 ? `, +${conflicts.length - 3} more` : ""}). Scanned node_modules/ instead. Remove whichever lockfile your package manager does not maintain.`;
|
|
1078
|
+
}
|
|
832
1079
|
function staleWarning(source, missing) {
|
|
833
1080
|
const sample = missing.slice(0, 3).join(", ");
|
|
834
1081
|
const suffix = missing.length > 3 ? `, +${missing.length - 3} more` : "";
|
|
@@ -843,21 +1090,25 @@ async function presentLockfiles(cwd) {
|
|
|
843
1090
|
);
|
|
844
1091
|
return probed.filter((candidate) => candidate.present).map(({ filename, strategy, filePath }) => ({ ecosystem: "npm", filename, strategy, filePath }));
|
|
845
1092
|
}
|
|
846
|
-
async function runStrategy(detected, cwd) {
|
|
1093
|
+
async function runStrategy(detected, cwd, report) {
|
|
847
1094
|
switch (detected.strategy) {
|
|
848
1095
|
case "npm-lockfile":
|
|
849
1096
|
return parseNpmLockfile(detected.filePath);
|
|
1097
|
+
case "bun-lockfile":
|
|
1098
|
+
return parseBunLockfile(detected.filePath, report);
|
|
1099
|
+
// The hand-written scanners. Each meets entries it was not written for, and each is asked to say how
|
|
1100
|
+
// many it dropped, because a manifest short a package reads exactly like a project without it.
|
|
850
1101
|
case "pnpm-lockfile":
|
|
851
|
-
return parsePnpmLockfile(detected.filePath);
|
|
1102
|
+
return parsePnpmLockfile(detected.filePath, report);
|
|
852
1103
|
case "yarn-lockfile":
|
|
853
|
-
return parseYarnLockfile(detected.filePath);
|
|
1104
|
+
return parseYarnLockfile(detected.filePath, report);
|
|
854
1105
|
case "node-modules-walk":
|
|
855
1106
|
return walkNodeModules(cwd);
|
|
856
1107
|
}
|
|
857
1108
|
}
|
|
858
1109
|
async function exists(filePath) {
|
|
859
1110
|
try {
|
|
860
|
-
await (0,
|
|
1111
|
+
await (0, import_promises7.access)(filePath);
|
|
861
1112
|
return true;
|
|
862
1113
|
} catch {
|
|
863
1114
|
return false;
|
|
@@ -865,21 +1116,33 @@ async function exists(filePath) {
|
|
|
865
1116
|
}
|
|
866
1117
|
|
|
867
1118
|
// src/normalize.ts
|
|
868
|
-
function buildWirePayload(manifest) {
|
|
1119
|
+
function buildWirePayload(manifest, options = {}) {
|
|
1120
|
+
const withPaths = options.installPaths === true;
|
|
869
1121
|
const seen = /* @__PURE__ */ new Map();
|
|
870
1122
|
const wirePackages = [];
|
|
1123
|
+
const byIdentity = /* @__PURE__ */ new Map();
|
|
1124
|
+
let entriesWithoutPath = 0;
|
|
871
1125
|
for (const entry of manifest.packages) {
|
|
1126
|
+
const identity = `${entry.name}@${entry.version}`;
|
|
1127
|
+
const location = withPaths && entry.path !== void 0 && entry.path !== "" ? entry.path : void 0;
|
|
1128
|
+
if (location === void 0) entriesWithoutPath++;
|
|
1129
|
+
const existing = byIdentity.get(identity);
|
|
1130
|
+
if (existing) {
|
|
1131
|
+
if (location !== void 0) addPath(existing, location);
|
|
1132
|
+
continue;
|
|
1133
|
+
}
|
|
872
1134
|
const versions = seen.get(entry.name);
|
|
873
1135
|
if (versions) {
|
|
874
|
-
if (versions.has(entry.version)) {
|
|
875
|
-
continue;
|
|
876
|
-
}
|
|
877
1136
|
versions.add(entry.version);
|
|
878
1137
|
} else {
|
|
879
1138
|
seen.set(entry.name, /* @__PURE__ */ new Set([entry.version]));
|
|
880
1139
|
}
|
|
881
|
-
|
|
1140
|
+
const wire = { name: entry.name, version: entry.version };
|
|
1141
|
+
if (location !== void 0) addPath(wire, location);
|
|
1142
|
+
byIdentity.set(identity, wire);
|
|
1143
|
+
wirePackages.push(wire);
|
|
882
1144
|
}
|
|
1145
|
+
for (const wire of wirePackages) wire.paths?.sort();
|
|
883
1146
|
wirePackages.sort((a, b) => {
|
|
884
1147
|
if (a.name === b.name) {
|
|
885
1148
|
return compareVersions(a.version, b.version);
|
|
@@ -893,7 +1156,18 @@ function buildWirePayload(manifest) {
|
|
|
893
1156
|
}
|
|
894
1157
|
}
|
|
895
1158
|
return {
|
|
896
|
-
payload: {
|
|
1159
|
+
payload: {
|
|
1160
|
+
ecosystem: manifest.ecosystem,
|
|
1161
|
+
packages: wirePackages,
|
|
1162
|
+
// Every entry had a location, so a missing path anywhere means the package is not installed there.
|
|
1163
|
+
// One entry without one forfeits that for the whole payload: a consumer reading a short `paths` has
|
|
1164
|
+
// no way to tell which entry was the incomplete one.
|
|
1165
|
+
//
|
|
1166
|
+
// No separate check for "locations were not requested": with them off every entry counts as without
|
|
1167
|
+
// one, so this is already false — which is the default, and the safe direction. An explicit
|
|
1168
|
+
// `withPaths &&` here was a guard no test could distinguish from its absence.
|
|
1169
|
+
installPathsComplete: entriesWithoutPath === 0 && manifest.packages.length > 0
|
|
1170
|
+
},
|
|
897
1171
|
stats: {
|
|
898
1172
|
uniqueNames: seen.size,
|
|
899
1173
|
duplicateNames,
|
|
@@ -901,6 +1175,10 @@ function buildWirePayload(manifest) {
|
|
|
901
1175
|
}
|
|
902
1176
|
};
|
|
903
1177
|
}
|
|
1178
|
+
function addPath(wire, installPath) {
|
|
1179
|
+
if (wire.paths === void 0) wire.paths = [installPath];
|
|
1180
|
+
else if (!wire.paths.includes(installPath)) wire.paths.push(installPath);
|
|
1181
|
+
}
|
|
904
1182
|
function compareVersions(a, b) {
|
|
905
1183
|
if (a === b) {
|
|
906
1184
|
return 0;
|
|
@@ -1143,12 +1421,14 @@ function isTimeoutError(cause) {
|
|
|
1143
1421
|
}
|
|
1144
1422
|
|
|
1145
1423
|
// src/config.ts
|
|
1146
|
-
var
|
|
1424
|
+
var import_promises8 = require("fs/promises");
|
|
1147
1425
|
var import_node_path6 = __toESM(require("path"), 1);
|
|
1148
1426
|
var CONFIG_FILENAME = ".patchstackrc.json";
|
|
1427
|
+
var SECRET_FILENAME = ".patchstackrc.local.json";
|
|
1149
1428
|
var DEFAULT_ENVIRONMENT = "production";
|
|
1150
1429
|
async function resolveConfig(options) {
|
|
1151
1430
|
const fromFile = await readConfigFile(options.cwd);
|
|
1431
|
+
const fromSecretFile = await readSecretFile(options.cwd);
|
|
1152
1432
|
const fromEnv = readEnv();
|
|
1153
1433
|
const siteUuid = options.cliSiteUuid ?? fromEnv.siteUuid ?? fromFile.siteUuid ?? null;
|
|
1154
1434
|
const endpoint = options.cliEndpoint ?? fromEnv.endpoint ?? fromFile.endpoint ?? DEFAULT_ENDPOINT;
|
|
@@ -1173,8 +1453,8 @@ async function resolveConfig(options) {
|
|
|
1173
1453
|
"CONFIG_MISSING"
|
|
1174
1454
|
);
|
|
1175
1455
|
}
|
|
1176
|
-
const apiKeyRaw = fromEnv.apiKey ?? fromFile.apiKey ?? null;
|
|
1177
|
-
const pulseAuthRaw = fromEnv.pulseAuth ?? fromFile.pulseAuth ?? apiKeyRaw;
|
|
1456
|
+
const apiKeyRaw = fromEnv.apiKey ?? fromSecretFile.apiKey ?? fromFile.apiKey ?? null;
|
|
1457
|
+
const pulseAuthRaw = fromEnv.pulseAuth ?? fromSecretFile.pulseAuth ?? fromFile.pulseAuth ?? apiKeyRaw;
|
|
1178
1458
|
return {
|
|
1179
1459
|
siteUuid: siteUuid === null || siteUuid.length === 0 ? null : siteUuid,
|
|
1180
1460
|
apiKey: apiKeyRaw === null || apiKeyRaw.length === 0 ? null : apiKeyRaw,
|
|
@@ -1188,26 +1468,91 @@ async function resolveConfig(options) {
|
|
|
1188
1468
|
async function writeConfigFile(cwd, config) {
|
|
1189
1469
|
const target = import_node_path6.default.join(cwd, CONFIG_FILENAME);
|
|
1190
1470
|
const content = JSON.stringify(config, null, 2) + "\n";
|
|
1191
|
-
await (0,
|
|
1471
|
+
await (0, import_promises8.writeFile)(target, content, "utf8");
|
|
1192
1472
|
return target;
|
|
1193
1473
|
}
|
|
1474
|
+
async function writeSecretFile(cwd, secrets) {
|
|
1475
|
+
const target = import_node_path6.default.join(cwd, SECRET_FILENAME);
|
|
1476
|
+
await (0, import_promises8.writeFile)(target, JSON.stringify(secrets, null, 2) + "\n", { encoding: "utf8", mode: 384 });
|
|
1477
|
+
try {
|
|
1478
|
+
await (0, import_promises8.chmod)(target, 384);
|
|
1479
|
+
} catch {
|
|
1480
|
+
}
|
|
1481
|
+
const ignore = await ensureIgnored(cwd, SECRET_FILENAME);
|
|
1482
|
+
return { path: target, ...ignore };
|
|
1483
|
+
}
|
|
1484
|
+
async function ensureIgnored(cwd, entry) {
|
|
1485
|
+
const target = import_node_path6.default.join(cwd, ".gitignore");
|
|
1486
|
+
let existing = "";
|
|
1487
|
+
try {
|
|
1488
|
+
existing = await (0, import_promises8.readFile)(target, "utf8");
|
|
1489
|
+
} catch (err) {
|
|
1490
|
+
const code = err.code;
|
|
1491
|
+
if (code !== "ENOENT") {
|
|
1492
|
+
return { ignored: false, reason: `.gitignore could not be read (${code ?? "unknown error"})` };
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1495
|
+
if (ignoresEntry(existing, entry)) return { ignored: true };
|
|
1496
|
+
const separator = existing === "" || existing.endsWith("\n") ? "" : "\n";
|
|
1497
|
+
const block = `${separator}
|
|
1498
|
+
# Patchstack credential \u2014 never commit this
|
|
1499
|
+
${entry}
|
|
1500
|
+
`;
|
|
1501
|
+
try {
|
|
1502
|
+
await (0, import_promises8.writeFile)(target, existing + block, "utf8");
|
|
1503
|
+
} catch (err) {
|
|
1504
|
+
const code = err.code;
|
|
1505
|
+
return { ignored: false, reason: `.gitignore could not be written (${code ?? "unknown error"})` };
|
|
1506
|
+
}
|
|
1507
|
+
try {
|
|
1508
|
+
const written = await (0, import_promises8.readFile)(target, "utf8");
|
|
1509
|
+
if (ignoresEntry(written, entry)) return { ignored: true };
|
|
1510
|
+
return { ignored: false, reason: ".gitignore does not cover the file after writing it" };
|
|
1511
|
+
} catch (err) {
|
|
1512
|
+
const code = err.code;
|
|
1513
|
+
return { ignored: false, reason: `.gitignore could not be read back (${code ?? "unknown error"})` };
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1516
|
+
function ignoresEntry(contents, entry) {
|
|
1517
|
+
let ignored = false;
|
|
1518
|
+
for (const raw of contents.split("\n")) {
|
|
1519
|
+
const line = raw.trim();
|
|
1520
|
+
if (line === "" || line.startsWith("#")) continue;
|
|
1521
|
+
const negated = line.startsWith("!");
|
|
1522
|
+
const pattern = negated ? line.slice(1).trim() : line;
|
|
1523
|
+
if (pattern === entry || pattern === `/${entry}`) ignored = !negated;
|
|
1524
|
+
}
|
|
1525
|
+
return ignored;
|
|
1526
|
+
}
|
|
1194
1527
|
async function persistSiteUuid(cwd, siteUuid) {
|
|
1195
1528
|
const existing = await readConfigFile(cwd);
|
|
1196
1529
|
return writeConfigFile(cwd, { ...existing, siteUuid });
|
|
1197
1530
|
}
|
|
1198
1531
|
async function persistApiKey(cwd, apiKey) {
|
|
1199
|
-
const { pulseAuth:
|
|
1200
|
-
|
|
1532
|
+
const { apiKey: _movedKey, pulseAuth: _movedPulse, ...publicConfig } = await readConfigFile(cwd);
|
|
1533
|
+
const existingSecrets = await readSecretFile(cwd);
|
|
1534
|
+
const target = await writeSecretFile(cwd, { ...existingSecrets, apiKey, pulseAuth: void 0 });
|
|
1535
|
+
if (_movedKey !== void 0 || _movedPulse !== void 0) {
|
|
1536
|
+
await writeConfigFile(cwd, publicConfig);
|
|
1537
|
+
}
|
|
1538
|
+
return target;
|
|
1201
1539
|
}
|
|
1202
1540
|
async function persistPulseAuth(cwd, pulseAuth) {
|
|
1203
|
-
const existing = await
|
|
1204
|
-
return
|
|
1541
|
+
const existing = await readSecretFile(cwd);
|
|
1542
|
+
return writeSecretFile(cwd, { ...existing, pulseAuth });
|
|
1543
|
+
}
|
|
1544
|
+
async function readSecretFile(cwd) {
|
|
1545
|
+
const file = await readJsonFile(cwd, SECRET_FILENAME);
|
|
1546
|
+
return { apiKey: file.apiKey, pulseAuth: file.pulseAuth };
|
|
1205
1547
|
}
|
|
1206
1548
|
async function readConfigFile(cwd) {
|
|
1207
|
-
|
|
1549
|
+
return readJsonFile(cwd, CONFIG_FILENAME);
|
|
1550
|
+
}
|
|
1551
|
+
async function readJsonFile(cwd, filename) {
|
|
1552
|
+
const target = import_node_path6.default.join(cwd, filename);
|
|
1208
1553
|
let raw;
|
|
1209
1554
|
try {
|
|
1210
|
-
raw = await (0,
|
|
1555
|
+
raw = await (0, import_promises8.readFile)(target, "utf8");
|
|
1211
1556
|
} catch (err) {
|
|
1212
1557
|
if (err.code === "ENOENT") {
|
|
1213
1558
|
return {};
|
|
@@ -1409,7 +1754,7 @@ async function scanAndReport(options = {}) {
|
|
|
1409
1754
|
const cwd = options.cwd ?? process.cwd();
|
|
1410
1755
|
const config = options.config ?? await resolveConfig({ cwd });
|
|
1411
1756
|
const manifest = await scanLockfile(cwd);
|
|
1412
|
-
const { payload, stats } = buildWirePayload(manifest);
|
|
1757
|
+
const { payload, stats } = buildWirePayload(manifest, { installPaths: options.installPaths === true });
|
|
1413
1758
|
const response = await postManifest(config, payload);
|
|
1414
1759
|
if (config.siteUuid === null && response.uuid !== void 0 && response.uuid.length > 0) {
|
|
1415
1760
|
await persistSiteUuid(cwd, response.uuid);
|