@reddoorla/maintenance 0.1.1 → 0.1.3
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/dist/cli/bin.js +228 -109
- package/dist/cli/bin.js.map +1 -1
- package/dist/cli/commands/audit.js +116 -73
- package/dist/cli/commands/audit.js.map +1 -1
- package/dist/index.d.ts +7 -2
- package/dist/index.js +176 -81
- package/dist/index.js.map +1 -1
- package/dist/util/pkg.d.ts +6 -2
- package/dist/util/pkg.js +3 -1
- package/dist/util/pkg.js.map +1 -1
- package/package.json +1 -1
|
@@ -4,15 +4,18 @@ import { resolve as resolve2 } from "path";
|
|
|
4
4
|
// src/audits/util/spawn.ts
|
|
5
5
|
import { spawn } from "child_process";
|
|
6
6
|
var defaultSpawn = (cmd, args, opts = {}) => new Promise((resolve3, reject) => {
|
|
7
|
+
const streaming = opts.streaming === true;
|
|
7
8
|
const child = spawn(cmd, [...args], {
|
|
8
9
|
cwd: opts.cwd,
|
|
9
10
|
env: opts.env ?? process.env,
|
|
10
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
11
|
+
stdio: streaming ? ["ignore", "inherit", "inherit"] : ["ignore", "pipe", "pipe"]
|
|
11
12
|
});
|
|
12
13
|
let stdout = "";
|
|
13
14
|
let stderr = "";
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
if (!streaming) {
|
|
16
|
+
child.stdout?.on("data", (chunk) => stdout += String(chunk));
|
|
17
|
+
child.stderr?.on("data", (chunk) => stderr += String(chunk));
|
|
18
|
+
}
|
|
16
19
|
const timer = opts.timeoutMs ? setTimeout(() => {
|
|
17
20
|
child.kill("SIGTERM");
|
|
18
21
|
reject(new Error(`spawn timeout after ${opts.timeoutMs}ms: ${cmd}`));
|
|
@@ -140,7 +143,7 @@ async function depsAudit(ctx) {
|
|
|
140
143
|
// src/audits/lint.ts
|
|
141
144
|
import { existsSync } from "fs";
|
|
142
145
|
import { readFile as readFile2 } from "fs/promises";
|
|
143
|
-
import { join as join2
|
|
146
|
+
import { join as join2 } from "path";
|
|
144
147
|
import { ESLint } from "eslint";
|
|
145
148
|
import { check as prettierCheck, resolveConfig as prettierResolveConfig } from "prettier";
|
|
146
149
|
import { glob } from "tinyglobby";
|
|
@@ -169,19 +172,19 @@ async function lintAudit(ctx) {
|
|
|
169
172
|
errorOnUnmatchedPattern: false
|
|
170
173
|
});
|
|
171
174
|
const relFiles = await listFiles(site.path);
|
|
172
|
-
const
|
|
173
|
-
const eslintResults = await eslint.lintFiles(filesToLint);
|
|
175
|
+
const eslintResults = await eslint.lintFiles(relFiles);
|
|
174
176
|
const eslintErrors = eslintResults.reduce((n, r) => n + r.errorCount, 0);
|
|
175
177
|
const eslintWarnings = eslintResults.reduce((n, r) => n + r.warningCount, 0);
|
|
176
178
|
const prettierUnformatted = [];
|
|
177
|
-
for (const
|
|
178
|
-
const
|
|
179
|
-
const
|
|
180
|
-
const
|
|
181
|
-
|
|
179
|
+
for (const rel of relFiles) {
|
|
180
|
+
const absForResolve = join2(site.path, rel);
|
|
181
|
+
const source = await readFile2(absForResolve, "utf-8");
|
|
182
|
+
const options = await prettierResolveConfig(absForResolve) ?? {};
|
|
183
|
+
const ok = await prettierCheck(source, { ...options, filepath: absForResolve });
|
|
184
|
+
if (!ok) prettierUnformatted.push(rel);
|
|
182
185
|
}
|
|
183
186
|
const status = eslintErrors > 0 || prettierUnformatted.length > 0 ? "fail" : eslintWarnings > 0 ? "warn" : "pass";
|
|
184
|
-
const summary = status === "pass" ? `lint clean across ${
|
|
187
|
+
const summary = status === "pass" ? `lint clean across ${relFiles.length} files` : `${eslintErrors} eslint errors, ${eslintWarnings} warnings, ${prettierUnformatted.length} unformatted`;
|
|
185
188
|
return {
|
|
186
189
|
audit: "lint",
|
|
187
190
|
site: siteLabel2(site),
|
|
@@ -191,7 +194,7 @@ async function lintAudit(ctx) {
|
|
|
191
194
|
eslintErrors,
|
|
192
195
|
eslintWarnings,
|
|
193
196
|
prettierUnformatted,
|
|
194
|
-
files:
|
|
197
|
+
files: relFiles.length
|
|
195
198
|
}
|
|
196
199
|
};
|
|
197
200
|
}
|
|
@@ -207,7 +210,7 @@ function classify(v) {
|
|
|
207
210
|
}
|
|
208
211
|
function normalizeSeverity(s) {
|
|
209
212
|
if (s === "low" || s === "moderate" || s === "high" || s === "critical") return s;
|
|
210
|
-
return "
|
|
213
|
+
return "low";
|
|
211
214
|
}
|
|
212
215
|
function extractAdvisoriesFromPnpm(parsed) {
|
|
213
216
|
const out = [];
|
|
@@ -223,83 +226,101 @@ function extractAdvisoriesFromPnpm(parsed) {
|
|
|
223
226
|
}
|
|
224
227
|
return out;
|
|
225
228
|
}
|
|
229
|
+
function resolveNpmAdvisoryRoot(startName, vulnerabilities) {
|
|
230
|
+
const seen = /* @__PURE__ */ new Set();
|
|
231
|
+
let current = startName;
|
|
232
|
+
while (!seen.has(current)) {
|
|
233
|
+
seen.add(current);
|
|
234
|
+
const entry = vulnerabilities[current];
|
|
235
|
+
if (!entry || !Array.isArray(entry.via)) return { rootName: current };
|
|
236
|
+
const detailed = entry.via.find(
|
|
237
|
+
(e) => typeof e === "object" && e !== null
|
|
238
|
+
);
|
|
239
|
+
if (detailed) return { rootName: current, detail: detailed };
|
|
240
|
+
const next = entry.via.find((e) => typeof e === "string");
|
|
241
|
+
if (!next || next === current) return { rootName: current };
|
|
242
|
+
current = next;
|
|
243
|
+
}
|
|
244
|
+
return { rootName: current };
|
|
245
|
+
}
|
|
226
246
|
function extractAdvisoriesFromNpm(parsed) {
|
|
227
|
-
const
|
|
228
|
-
|
|
247
|
+
const vulnerabilities = parsed.vulnerabilities ?? {};
|
|
248
|
+
const roots = /* @__PURE__ */ new Map();
|
|
249
|
+
for (const [name, v] of Object.entries(vulnerabilities)) {
|
|
229
250
|
if (!v) continue;
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
out.push({
|
|
242
|
-
module: v.name ?? name,
|
|
243
|
-
severity: normalizeSeverity(v.severity),
|
|
251
|
+
const { rootName, detail } = resolveNpmAdvisoryRoot(name, vulnerabilities);
|
|
252
|
+
if (roots.has(rootName)) continue;
|
|
253
|
+
const rootEntry = vulnerabilities[rootName];
|
|
254
|
+
const severity = normalizeSeverity(rootEntry?.severity ?? v.severity);
|
|
255
|
+
const title = detail?.title ?? rootName;
|
|
256
|
+
const url = detail?.url;
|
|
257
|
+
roots.set(rootName, {
|
|
258
|
+
module: rootEntry?.name ?? rootName,
|
|
259
|
+
severity,
|
|
244
260
|
title,
|
|
245
261
|
...url ? { url } : {}
|
|
246
262
|
});
|
|
247
263
|
}
|
|
248
|
-
return
|
|
264
|
+
return [...roots.values()];
|
|
249
265
|
}
|
|
250
|
-
async function
|
|
266
|
+
async function runAuditTool(spawn2, cmd, args, cwd) {
|
|
267
|
+
let raw;
|
|
251
268
|
try {
|
|
252
|
-
|
|
269
|
+
raw = await spawn2(cmd, args, { cwd });
|
|
253
270
|
} catch (err) {
|
|
254
271
|
const e = err;
|
|
255
|
-
if (e.code === "ENOENT" || /ENOENT/.test(String(err))) return {
|
|
256
|
-
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
async function securityAudit(ctx) {
|
|
260
|
-
const spawn2 = ctx.spawn ?? defaultSpawn;
|
|
261
|
-
const site = ctx.site;
|
|
262
|
-
const label = siteLabel3(site);
|
|
263
|
-
let used = "pnpm audit";
|
|
264
|
-
let raw = await tryRun(
|
|
265
|
-
spawn2,
|
|
266
|
-
"pnpm",
|
|
267
|
-
["audit", "--json", "--prod"],
|
|
268
|
-
site.path
|
|
269
|
-
);
|
|
270
|
-
if ("missing" in raw) {
|
|
271
|
-
used = "npm audit";
|
|
272
|
-
raw = await tryRun(spawn2, "npm", ["audit", "--json", "--omit=dev"], site.path);
|
|
273
|
-
}
|
|
274
|
-
if ("missing" in raw) {
|
|
275
|
-
return {
|
|
276
|
-
audit: "security",
|
|
277
|
-
site: label,
|
|
278
|
-
status: "skip",
|
|
279
|
-
summary: "neither pnpm nor npm is available on PATH"
|
|
280
|
-
};
|
|
272
|
+
if (e.code === "ENOENT" || /ENOENT/.test(String(err))) return { kind: "missing" };
|
|
273
|
+
return { kind: "error", reason: `spawn failed: ${String(err).slice(0, 200)}` };
|
|
281
274
|
}
|
|
282
275
|
if (raw.code !== 0 && raw.code !== 1) {
|
|
283
276
|
return {
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
status: "skip",
|
|
287
|
-
summary: `${used} exited with code ${raw.code}`,
|
|
288
|
-
details: { stderr: raw.stderr }
|
|
277
|
+
kind: "error",
|
|
278
|
+
reason: `exit ${raw.code}${raw.stderr ? `: ${raw.stderr.slice(0, 150)}` : ""}`
|
|
289
279
|
};
|
|
290
280
|
}
|
|
291
281
|
let parsed;
|
|
292
282
|
try {
|
|
293
|
-
parsed = JSON.parse(raw.stdout);
|
|
283
|
+
parsed = JSON.parse(raw.stdout || "{}");
|
|
294
284
|
} catch (err) {
|
|
295
|
-
return {
|
|
296
|
-
audit: "security",
|
|
297
|
-
site: label,
|
|
298
|
-
status: "skip",
|
|
299
|
-
summary: `${used} produced unparseable JSON`,
|
|
300
|
-
details: { error: String(err), stdout: raw.stdout.slice(0, 500) }
|
|
301
|
-
};
|
|
285
|
+
return { kind: "error", reason: `unparseable JSON: ${String(err).slice(0, 100)}` };
|
|
302
286
|
}
|
|
287
|
+
const errEnvelope = parsed.error;
|
|
288
|
+
if (errEnvelope && typeof errEnvelope === "object") {
|
|
289
|
+
return { kind: "error", reason: errEnvelope.code ?? "error envelope returned" };
|
|
290
|
+
}
|
|
291
|
+
if (!parsed.metadata?.vulnerabilities) {
|
|
292
|
+
return { kind: "error", reason: "no metadata.vulnerabilities in output" };
|
|
293
|
+
}
|
|
294
|
+
return { kind: "ok", parsed };
|
|
295
|
+
}
|
|
296
|
+
async function securityAudit(ctx) {
|
|
297
|
+
const spawn2 = ctx.spawn ?? defaultSpawn;
|
|
298
|
+
const site = ctx.site;
|
|
299
|
+
const label = siteLabel3(site);
|
|
300
|
+
let used = "pnpm audit";
|
|
301
|
+
let result = await runAuditTool(spawn2, "pnpm", ["audit", "--json", "--prod"], site.path);
|
|
302
|
+
if (result.kind !== "ok") {
|
|
303
|
+
const pnpmReason = result.kind === "missing" ? "not installed" : result.reason;
|
|
304
|
+
const npmResult = await runAuditTool(
|
|
305
|
+
spawn2,
|
|
306
|
+
"npm",
|
|
307
|
+
["audit", "--json", "--omit=dev"],
|
|
308
|
+
site.path
|
|
309
|
+
);
|
|
310
|
+
if (npmResult.kind === "ok") {
|
|
311
|
+
result = npmResult;
|
|
312
|
+
used = "npm audit";
|
|
313
|
+
} else {
|
|
314
|
+
const npmReason = npmResult.kind === "missing" ? "not installed" : npmResult.reason;
|
|
315
|
+
return {
|
|
316
|
+
audit: "security",
|
|
317
|
+
site: label,
|
|
318
|
+
status: "skip",
|
|
319
|
+
summary: `cannot run audit \u2014 pnpm: ${pnpmReason}; npm: ${npmReason}`
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
const parsed = result.parsed;
|
|
303
324
|
const counts = {
|
|
304
325
|
low: parsed.metadata?.vulnerabilities?.low ?? 0,
|
|
305
326
|
moderate: parsed.metadata?.vulnerabilities?.moderate ?? 0,
|
|
@@ -510,6 +531,10 @@ import { dirname } from "node:path";
|
|
|
510
531
|
const pages = ${JSON.stringify(a11yRoutes)};
|
|
511
532
|
const OUTPUT = process.env.REDDOOR_A11Y_OUTPUT;
|
|
512
533
|
|
|
534
|
+
// Playwright's default per-test timeout is 30s. We loop through every
|
|
535
|
+
// configured route in a single test, so the budget needs to scale.
|
|
536
|
+
test.setTimeout(5 * 60_000);
|
|
537
|
+
|
|
513
538
|
test("a11y across configured routes", async ({ page }) => {
|
|
514
539
|
const violations = [];
|
|
515
540
|
for (const { path, name } of pages) {
|
|
@@ -641,6 +666,7 @@ function localPath(path, opts = {}) {
|
|
|
641
666
|
|
|
642
667
|
// src/inventory/json.ts
|
|
643
668
|
import { readFile as readFile5 } from "fs/promises";
|
|
669
|
+
import { isAbsolute } from "path";
|
|
644
670
|
function validate(raw) {
|
|
645
671
|
if (!Array.isArray(raw)) {
|
|
646
672
|
throw new Error("inventory JSON must be an array of sites");
|
|
@@ -653,6 +679,11 @@ function validate(raw) {
|
|
|
653
679
|
if (typeof e.path !== "string" || e.path.length === 0) {
|
|
654
680
|
throw new Error(`inventory entry ${i} is missing required field: path`);
|
|
655
681
|
}
|
|
682
|
+
if (!isAbsolute(e.path)) {
|
|
683
|
+
throw new Error(
|
|
684
|
+
`inventory entry ${i}: path must be absolute (got "${e.path}"). Relative paths are rejected so cwd at invocation can't change which site is targeted.`
|
|
685
|
+
);
|
|
686
|
+
}
|
|
656
687
|
const site = { path: e.path };
|
|
657
688
|
if (typeof e.name === "string") site.name = e.name;
|
|
658
689
|
if (typeof e.repoUrl === "string") site.repoUrl = e.repoUrl;
|
|
@@ -703,11 +734,22 @@ async function resolveSites(input) {
|
|
|
703
734
|
|
|
704
735
|
// src/cli/fleet/clone-if-needed.ts
|
|
705
736
|
import { stat, readdir, mkdir } from "fs/promises";
|
|
706
|
-
import { join as join5 } from "path";
|
|
737
|
+
import { isAbsolute as isAbsolute2, join as join5 } from "path";
|
|
707
738
|
function deriveNameFromRepoUrl(repoUrl) {
|
|
708
739
|
const slash = repoUrl.split("/").pop() ?? repoUrl;
|
|
709
740
|
return slash.replace(/\.git$/, "");
|
|
710
741
|
}
|
|
742
|
+
function assertSafeName(name) {
|
|
743
|
+
if (isAbsolute2(name)) {
|
|
744
|
+
throw new Error(`unsafe site name (absolute path not allowed): ${name}`);
|
|
745
|
+
}
|
|
746
|
+
if (name.includes("/") || name.includes("\\")) {
|
|
747
|
+
throw new Error(`unsafe site name (path separator not allowed): ${name}`);
|
|
748
|
+
}
|
|
749
|
+
if (name.split(/[\\/]/).some((seg) => seg === "..")) {
|
|
750
|
+
throw new Error(`unsafe site name (traversal segment not allowed): ${name}`);
|
|
751
|
+
}
|
|
752
|
+
}
|
|
711
753
|
async function isNonEmptyDir(path) {
|
|
712
754
|
try {
|
|
713
755
|
const s = await stat(path);
|
|
@@ -724,6 +766,7 @@ async function cloneIfNeeded(site, opts) {
|
|
|
724
766
|
throw new Error(`site path does not exist (${site.path}) and no repoUrl is set \u2014 cannot clone`);
|
|
725
767
|
}
|
|
726
768
|
const name = site.name ?? deriveNameFromRepoUrl(site.repoUrl);
|
|
769
|
+
assertSafeName(name);
|
|
727
770
|
const target = join5(opts.workdir, name);
|
|
728
771
|
await mkdir(opts.workdir, { recursive: true });
|
|
729
772
|
if (await isNonEmptyDir(target)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/cli/commands/audit.ts","../../../src/audits/util/spawn.ts","../../../src/audits/deps.ts","../../../src/configs/baseline-versions.ts","../../../src/audits/lint.ts","../../../src/audits/security.ts","../../../src/audits/lighthouse.ts","../../../src/configs/lighthouse.ts","../../../src/audits/a11y.ts","../../../src/configs/playwright-a11y.ts","../../../src/audits/index.ts","../../../src/cli/fleet/resolve-sites.ts","../../../src/inventory/local.ts","../../../src/inventory/json.ts","../../../src/cli/fleet/clone-if-needed.ts"],"sourcesContent":["import { resolve } from \"node:path\";\nimport { runAudits, ALL_AUDIT_NAMES } from \"../../audits/index.js\";\nimport type { AuditName, AuditResult } from \"../../types.js\";\nimport { resolveSites } from \"../fleet/resolve-sites.js\";\nimport { cloneIfNeeded } from \"../fleet/clone-if-needed.js\";\n\nexport type AuditCommandOptions = {\n only?: string;\n json?: boolean;\n fleet?: string;\n workdir?: string;\n cwd?: string;\n};\n\nfunction parseOnly(value: string | undefined): AuditName[] | undefined {\n if (!value) return undefined;\n const names = value.split(\",\").map((s) => s.trim());\n for (const n of names) {\n if (!ALL_AUDIT_NAMES.includes(n as AuditName)) {\n throw Object.assign(new Error(`unknown audit in --only: ${n}`), { exitCode: 2 });\n }\n }\n return names as AuditName[];\n}\n\nfunction formatTable(results: AuditResult[]): string {\n return results\n .map((r) => `${r.audit.padEnd(12)} ${r.status.padEnd(5)} ${r.site}\\n ${r.summary}`)\n .join(\"\\n\");\n}\n\nfunction exitCode(results: AuditResult[]): number {\n return results.some((r) => r.status === \"fail\") ? 1 : 0;\n}\n\nexport async function runAuditCommand(\n site: string | undefined,\n opts: AuditCommandOptions,\n): Promise<{ output: string; code: number }> {\n const which = parseOnly(opts.only);\n const cwd = opts.cwd ? resolve(opts.cwd) : process.cwd();\n\n let sites = await resolveSites({\n ...(site !== undefined ? { site } : {}),\n ...(opts.fleet !== undefined ? { fleet: opts.fleet } : {}),\n cwd,\n });\n\n if (opts.fleet) {\n const workdir = opts.workdir ?? `${process.env.HOME ?? \"\"}/.reddoor-maint/sites`;\n sites = await Promise.all(sites.map((s) => cloneIfNeeded(s, { workdir })));\n }\n\n const results: AuditResult[] = [];\n for (const s of sites) {\n const r = await runAudits(s, which);\n results.push(...r);\n }\n\n const output = opts.json ? JSON.stringify(results, null, 2) : formatTable(results);\n return { output, code: exitCode(results) };\n}\n","import { spawn } from \"node:child_process\";\n\nexport type SpawnResult = { code: number; stdout: string; stderr: string };\n\nexport type SpawnFn = (\n cmd: string,\n args: readonly string[],\n opts?: { cwd?: string; env?: NodeJS.ProcessEnv; timeoutMs?: number },\n) => Promise<SpawnResult>;\n\nexport const defaultSpawn: SpawnFn = (cmd, args, opts = {}) =>\n new Promise((resolve, reject) => {\n const child = spawn(cmd, [...args], {\n cwd: opts.cwd,\n env: opts.env ?? process.env,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n\n let stdout = \"\";\n let stderr = \"\";\n child.stdout.on(\"data\", (chunk) => (stdout += String(chunk)));\n child.stderr.on(\"data\", (chunk) => (stderr += String(chunk)));\n\n const timer = opts.timeoutMs\n ? setTimeout(() => {\n child.kill(\"SIGTERM\");\n reject(new Error(`spawn timeout after ${opts.timeoutMs}ms: ${cmd}`));\n }, opts.timeoutMs)\n : undefined;\n\n child.on(\"error\", (err) => {\n if (timer) clearTimeout(timer);\n reject(err);\n });\n child.on(\"close\", (code) => {\n if (timer) clearTimeout(timer);\n resolve({ code: code ?? -1, stdout, stderr });\n });\n });\n","import { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport type { AuditResult, Site } from \"../types.js\";\nimport { baselineVersions } from \"../configs/baseline-versions.js\";\nimport type { AuditContext } from \"./util/inject.js\";\n\nexport type Drift = \"same\" | \"patch\" | \"minor\" | \"major\" | \"newer\";\n\nexport type DepsDriftEntry = {\n pkg: string;\n baseline: string;\n actual: string;\n drift: Drift;\n};\n\nfunction siteLabel(site: Site): string {\n return site.name ?? site.path;\n}\n\nfunction stripCaret(range: string): string {\n return range.replace(/^[\\^~]/, \"\");\n}\n\nfunction parseSemver(v: string): [number, number, number] {\n const cleaned = stripCaret(v).split(\"-\")[0] ?? \"0.0.0\";\n const parts = cleaned.split(\".\").map((n) => Number.parseInt(n, 10));\n return [parts[0] ?? 0, parts[1] ?? 0, parts[2] ?? 0];\n}\n\nfunction compareSemver(actual: string, baseline: string): Drift {\n const [aMajor, aMinor, aPatch] = parseSemver(actual);\n const [bMajor, bMinor, bPatch] = parseSemver(baseline);\n if (aMajor > bMajor) return \"newer\";\n if (aMajor < bMajor) return \"major\";\n if (aMinor > bMinor) return \"newer\";\n if (aMinor < bMinor) return \"minor\";\n if (aPatch > bPatch) return \"newer\";\n if (aPatch < bPatch) return \"patch\";\n return \"same\";\n}\n\nexport async function depsAudit(ctx: AuditContext): Promise<AuditResult> {\n const pkgPath = join(ctx.site.path, \"package.json\");\n let pkgRaw: string;\n try {\n pkgRaw = await readFile(pkgPath, \"utf-8\");\n } catch (err) {\n return {\n audit: \"deps\",\n site: siteLabel(ctx.site),\n status: \"skip\",\n summary: `no package.json at ${pkgPath}`,\n details: { error: String(err) },\n };\n }\n\n const pkg = JSON.parse(pkgRaw) as {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n };\n const installed: Record<string, string> = {\n ...(pkg.dependencies ?? {}),\n ...(pkg.devDependencies ?? {}),\n };\n\n const details: DepsDriftEntry[] = [];\n for (const [name, baseline] of Object.entries(baselineVersions)) {\n const actual = installed[name];\n if (!actual) continue;\n details.push({\n pkg: name,\n baseline,\n actual,\n drift: compareSemver(actual, baseline),\n });\n }\n\n const anyMajor = details.some((d) => d.drift === \"major\");\n const anyMinor = details.some((d) => d.drift === \"minor\");\n const anyNewer = details.some((d) => d.drift === \"newer\");\n\n const status: AuditResult[\"status\"] = anyMajor ? \"fail\" : anyMinor || anyNewer ? \"warn\" : \"pass\";\n\n const summary =\n status === \"pass\"\n ? `all ${details.length} tracked deps in line with baseline`\n : status === \"warn\"\n ? `${details.filter((d) => d.drift !== \"same\").length} of ${details.length} tracked deps drifted`\n : `${details.filter((d) => d.drift === \"major\").length} deps lagging by a major version`;\n\n return {\n audit: \"deps\",\n site: siteLabel(ctx.site),\n status,\n summary,\n details,\n };\n}\n","// Curated map of the framework deps reddoor sites should stay close to.\n// Refreshed at each package release from reddoor-starter's package.json.\n// Versions are caret ranges to mirror what `pnpm add` would produce.\n\nexport const baselineVersions: Record<string, string> = {\n // SvelteKit core\n svelte: \"^5.55.5\",\n \"@sveltejs/kit\": \"^2.59.0\",\n \"@sveltejs/adapter-netlify\": \"^6.0.4\",\n \"@sveltejs/adapter-auto\": \"^7.0.0\",\n \"@sveltejs/vite-plugin-svelte\": \"^7.0.0\",\n \"svelte-check\": \"^4.4.7\",\n\n // Build tooling\n vite: \"^8.0.10\",\n vitest: \"^4.1.1\",\n typescript: \"^6.0.3\",\n\n // Tailwind 4\n tailwindcss: \"^4.0.14\",\n \"@tailwindcss/vite\": \"^4.3.0\",\n\n // Prismic\n \"@prismicio/client\": \"^7.3.1\",\n \"@prismicio/svelte\": \"^2.0.0\",\n \"@slicemachine/adapter-sveltekit\": \"^0.3.36\",\n \"slice-machine-ui\": \"^2.11.1\",\n\n // Test tooling\n \"@playwright/test\": \"^1.59.1\",\n \"@axe-core/playwright\": \"^4.11.3\",\n \"@lhci/cli\": \"^0.15.1\",\n\n // Lint\n eslint: \"^10.3.0\",\n \"eslint-plugin-svelte\": \"^3.1.0\",\n \"eslint-config-prettier\": \"^10.1.1\",\n prettier: \"^3.1.1\",\n \"prettier-plugin-svelte\": \"^3.2.6\",\n \"typescript-eslint\": \"^8.59.1\",\n \"@eslint/js\": \"^10.0.1\",\n globals: \"^17.6.0\",\n\n // Misc\n \"@lucide/svelte\": \"^1.14.0\",\n \"@zerodevx/svelte-img\": \"^2.1.2\",\n};\n\nexport default baselineVersions;\n","import { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { join, relative } from \"node:path\";\nimport { ESLint } from \"eslint\";\nimport { check as prettierCheck, resolveConfig as prettierResolveConfig } from \"prettier\";\nimport { glob } from \"tinyglobby\";\nimport type { AuditResult, Site } from \"../types.js\";\nimport type { AuditContext } from \"./util/inject.js\";\n\nconst TARGET_GLOBS = [\"**/*.{ts,js,svelte}\"];\nconst IGNORE = [\"node_modules/**\", \"dist/**\", \".svelte-kit/**\", \"build/**\", \".netlify/**\"];\n\nfunction siteLabel(site: Site): string {\n return site.name ?? site.path;\n}\n\nasync function listFiles(cwd: string): Promise<string[]> {\n return glob(TARGET_GLOBS, { cwd, ignore: IGNORE, absolute: false });\n}\n\nexport async function lintAudit(ctx: AuditContext): Promise<AuditResult> {\n const { site } = ctx;\n const configPath = join(site.path, \"eslint.config.js\");\n\n if (!existsSync(configPath)) {\n return {\n audit: \"lint\",\n site: siteLabel(site),\n status: \"skip\",\n summary: \"no eslint config at site root\",\n };\n }\n\n const eslint = new ESLint({\n cwd: site.path,\n overrideConfigFile: configPath,\n errorOnUnmatchedPattern: false,\n });\n\n const relFiles = await listFiles(site.path);\n const filesToLint = relFiles.map((f) => join(site.path, f));\n\n const eslintResults = await eslint.lintFiles(filesToLint);\n const eslintErrors = eslintResults.reduce((n, r) => n + r.errorCount, 0);\n const eslintWarnings = eslintResults.reduce((n, r) => n + r.warningCount, 0);\n\n const prettierUnformatted: string[] = [];\n for (const file of filesToLint) {\n const source = await readFile(file, \"utf-8\");\n const options = (await prettierResolveConfig(file)) ?? {};\n const ok = await prettierCheck(source, { ...options, filepath: file });\n if (!ok) prettierUnformatted.push(relative(site.path, file));\n }\n\n const status: AuditResult[\"status\"] =\n eslintErrors > 0 || prettierUnformatted.length > 0\n ? \"fail\"\n : eslintWarnings > 0\n ? \"warn\"\n : \"pass\";\n\n const summary =\n status === \"pass\"\n ? `lint clean across ${filesToLint.length} files`\n : `${eslintErrors} eslint errors, ${eslintWarnings} warnings, ${prettierUnformatted.length} unformatted`;\n\n return {\n audit: \"lint\",\n site: siteLabel(site),\n status,\n summary,\n details: {\n eslintErrors,\n eslintWarnings,\n prettierUnformatted,\n files: filesToLint.length,\n },\n };\n}\n","import type { AuditResult, Site } from \"../types.js\";\nimport { defaultSpawn, type SpawnResult } from \"./util/spawn.js\";\nimport type { AuditContext } from \"./util/inject.js\";\n\ntype Severity = \"low\" | \"moderate\" | \"high\" | \"critical\";\n\ntype Counts = { low: number; moderate: number; high: number; critical: number };\n\ntype AdvisoryEntry = {\n module: string;\n severity: Severity;\n title: string;\n cves?: string[];\n url?: string;\n};\n\n// pnpm audit output (npm-compat with extra advisories map keyed by ID).\ntype PnpmAuditJson = {\n metadata?: { vulnerabilities?: Partial<Counts> };\n advisories?: Record<\n string,\n {\n id?: number;\n title?: string;\n module_name?: string;\n severity?: string;\n cves?: string[];\n url?: string;\n }\n >;\n};\n\n// npm v7+ shape (vulnerabilities keyed by package name).\ntype NpmAuditJson = {\n metadata?: { vulnerabilities?: Partial<Counts> };\n vulnerabilities?: Record<\n string,\n {\n name?: string;\n severity?: string;\n via?: unknown;\n url?: string;\n }\n >;\n};\n\nfunction siteLabel(site: Site): string {\n return site.name ?? site.path;\n}\n\nfunction classify(v: Counts) {\n if (v.critical > 0 || v.high > 0) return \"fail\" as const;\n if (v.moderate > 0 || v.low > 0) return \"warn\" as const;\n return \"pass\" as const;\n}\n\nfunction normalizeSeverity(s: unknown): Severity {\n if (s === \"low\" || s === \"moderate\" || s === \"high\" || s === \"critical\") return s;\n return \"moderate\";\n}\n\nfunction extractAdvisoriesFromPnpm(parsed: PnpmAuditJson): AdvisoryEntry[] {\n const out: AdvisoryEntry[] = [];\n for (const a of Object.values(parsed.advisories ?? {})) {\n if (!a) continue;\n out.push({\n module: a.module_name ?? \"unknown\",\n severity: normalizeSeverity(a.severity),\n title: a.title ?? \"(no title)\",\n ...(a.cves ? { cves: a.cves } : {}),\n ...(a.url ? { url: a.url } : {}),\n });\n }\n return out;\n}\n\nfunction extractAdvisoriesFromNpm(parsed: NpmAuditJson): AdvisoryEntry[] {\n const out: AdvisoryEntry[] = [];\n for (const [name, v] of Object.entries(parsed.vulnerabilities ?? {})) {\n if (!v) continue;\n // npm's `via` is either a string (name of upstream package) or an array\n // mixing strings and objects with title/url/cve fields. We try the first\n // object-shaped entry for the title; otherwise fall back to the package\n // name itself.\n let title = name;\n let url: string | undefined;\n if (Array.isArray(v.via)) {\n const detailed = v.via.find(\n (entry): entry is { title?: string; url?: string } =>\n typeof entry === \"object\" && entry !== null,\n );\n if (detailed) {\n title = detailed.title ?? name;\n url = detailed.url;\n }\n }\n out.push({\n module: v.name ?? name,\n severity: normalizeSeverity(v.severity),\n title,\n ...(url ? { url } : {}),\n });\n }\n return out;\n}\n\nasync function tryRun(\n spawn: (cmd: string, args: readonly string[], opts?: { cwd?: string }) => Promise<SpawnResult>,\n cmd: string,\n args: readonly string[],\n cwd: string,\n): Promise<SpawnResult | { missing: true }> {\n try {\n return await spawn(cmd, args, { cwd });\n } catch (err) {\n const e = err as NodeJS.ErrnoException;\n if (e.code === \"ENOENT\" || /ENOENT/.test(String(err))) return { missing: true };\n throw err;\n }\n}\n\nexport async function securityAudit(ctx: AuditContext): Promise<AuditResult> {\n const spawn = ctx.spawn ?? defaultSpawn;\n const site = ctx.site;\n const label = siteLabel(site);\n\n let used: \"pnpm audit\" | \"npm audit\" = \"pnpm audit\";\n let raw: SpawnResult | { missing: true } = await tryRun(\n spawn,\n \"pnpm\",\n [\"audit\", \"--json\", \"--prod\"],\n site.path,\n );\n\n if (\"missing\" in raw) {\n used = \"npm audit\";\n raw = await tryRun(spawn, \"npm\", [\"audit\", \"--json\", \"--omit=dev\"], site.path);\n }\n\n if (\"missing\" in raw) {\n return {\n audit: \"security\",\n site: label,\n status: \"skip\",\n summary: \"neither pnpm nor npm is available on PATH\",\n };\n }\n\n // pnpm/npm audit exit codes: 0 = clean, 1 = vulns found. Anything else is a real error.\n if (raw.code !== 0 && raw.code !== 1) {\n return {\n audit: \"security\",\n site: label,\n status: \"skip\",\n summary: `${used} exited with code ${raw.code}`,\n details: { stderr: raw.stderr },\n };\n }\n\n let parsed: PnpmAuditJson & NpmAuditJson;\n try {\n parsed = JSON.parse(raw.stdout) as PnpmAuditJson & NpmAuditJson;\n } catch (err) {\n return {\n audit: \"security\",\n site: label,\n status: \"skip\",\n summary: `${used} produced unparseable JSON`,\n details: { error: String(err), stdout: raw.stdout.slice(0, 500) },\n };\n }\n\n const counts: Counts = {\n low: parsed.metadata?.vulnerabilities?.low ?? 0,\n moderate: parsed.metadata?.vulnerabilities?.moderate ?? 0,\n high: parsed.metadata?.vulnerabilities?.high ?? 0,\n critical: parsed.metadata?.vulnerabilities?.critical ?? 0,\n };\n\n const advisories =\n used === \"pnpm audit\" ? extractAdvisoriesFromPnpm(parsed) : extractAdvisoriesFromNpm(parsed);\n\n const status = classify(counts);\n const total = counts.low + counts.moderate + counts.high + counts.critical;\n const summary =\n status === \"pass\"\n ? `${used}: 0 vulnerabilities`\n : `${used}: ${total} vulnerabilities (${counts.critical}C/${counts.high}H/${counts.moderate}M/${counts.low}L)`;\n\n return {\n audit: \"security\",\n site: label,\n status,\n summary,\n details: { counts, advisories },\n };\n}\n","import { readFile, writeFile, mkdtemp, rm } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type { AuditResult, Site } from \"../types.js\";\nimport { lighthouseConfig } from \"../configs/lighthouse.js\";\nimport { defaultSpawn } from \"./util/spawn.js\";\nimport type { AuditContext } from \"./util/inject.js\";\n\ntype ManifestEntry = {\n url: string;\n summary: Record<string, number>;\n htmlPath?: string;\n jsonPath?: string;\n};\n\ntype AssertionResult = {\n name: string;\n actual: number;\n expected: number;\n operator: string;\n passed: boolean;\n level: \"warn\" | \"error\";\n auditProperty?: string;\n auditId?: string;\n};\n\ntype NormalizedLhciResult = {\n summary: Record<string, number>;\n assertionsFailed: number;\n assertions: Array<{ category: string; level: \"warn\" | \"error\"; message: string }>;\n};\n\nfunction siteLabel(site: Site): string {\n return site.name ?? site.path;\n}\n\nasync function readJsonMaybe<T>(path: string): Promise<T | null> {\n try {\n const raw = await readFile(path, \"utf-8\");\n return JSON.parse(raw) as T;\n } catch {\n return null;\n }\n}\n\nfunction averageSummaries(entries: ManifestEntry[]): Record<string, number> {\n if (entries.length === 0) return {};\n const sums: Record<string, number> = {};\n const counts: Record<string, number> = {};\n for (const e of entries) {\n for (const [k, v] of Object.entries(e.summary ?? {})) {\n if (typeof v !== \"number\") continue;\n sums[k] = (sums[k] ?? 0) + v;\n counts[k] = (counts[k] ?? 0) + 1;\n }\n }\n const out: Record<string, number> = {};\n for (const k of Object.keys(sums)) {\n const total = sums[k] ?? 0;\n const count = counts[k] ?? 1;\n out[k] = total / count;\n }\n return out;\n}\n\nfunction categoryFromAssertion(a: AssertionResult): string {\n // `name` looks like \"categories:accessibility\" or \"audits:uses-http2\".\n const colonIdx = a.name.indexOf(\":\");\n return colonIdx >= 0 ? a.name.slice(colonIdx + 1) : a.name;\n}\n\nfunction messageForAssertion(a: AssertionResult): string {\n return `${a.name} ${a.operator} ${a.expected} (actual: ${a.actual.toFixed(2)})`;\n}\n\nexport async function lighthouseAudit(ctx: AuditContext): Promise<AuditResult> {\n const spawn = ctx.spawn ?? defaultSpawn;\n const site = ctx.site;\n const label = siteLabel(site);\n\n const configDir = await mkdtemp(join(tmpdir(), \"reddoor-lhci-\"));\n const configPath = join(configDir, \"lighthouserc.json\");\n await writeFile(configPath, JSON.stringify(lighthouseConfig), \"utf-8\");\n\n const resultsDir = join(site.path, \".lighthouseci\");\n // Clear any stale artifacts before the run so we never confuse a failed\n // spawn with old results.\n await rm(resultsDir, { recursive: true, force: true });\n\n let raw;\n try {\n raw = await spawn(\"npx\", [\"--yes\", \"@lhci/cli\", \"autorun\", `--config=${configPath}`], {\n cwd: site.path,\n });\n } catch (err) {\n await rm(configDir, { recursive: true, force: true });\n const e = err as NodeJS.ErrnoException;\n if (e.code === \"ENOENT\" || /ENOENT/.test(String(err))) {\n return {\n audit: \"lighthouse\",\n site: label,\n status: \"skip\",\n summary: \"npx/@lhci/cli not available\",\n };\n }\n throw err;\n }\n await rm(configDir, { recursive: true, force: true });\n\n const manifest = await readJsonMaybe<ManifestEntry[]>(join(resultsDir, \"manifest.json\"));\n\n if (!manifest || manifest.length === 0) {\n return {\n audit: \"lighthouse\",\n site: label,\n status: \"fail\",\n summary: `lighthouse: no manifest written (exit ${raw.code})${\n raw.stderr ? ` — ${raw.stderr.slice(0, 200)}` : \"\"\n }`,\n };\n }\n\n const assertionResults =\n (await readJsonMaybe<AssertionResult[]>(join(resultsDir, \"assertion-results.json\"))) ?? [];\n\n const failed = assertionResults.filter((a) => !a.passed);\n const assertions = failed.map((a) => ({\n category: categoryFromAssertion(a),\n level: a.level,\n message: messageForAssertion(a),\n }));\n\n const anyError = assertions.some((a) => a.level === \"error\");\n const anyWarn = assertions.some((a) => a.level === \"warn\");\n const status: AuditResult[\"status\"] = anyError ? \"fail\" : anyWarn ? \"warn\" : \"pass\";\n\n const normalized: NormalizedLhciResult = {\n summary: averageSummaries(manifest),\n assertionsFailed: failed.length,\n assertions,\n };\n\n const summary =\n status === \"pass\"\n ? \"lighthouse: all categories passing\"\n : `lighthouse: ${failed.length} assertion(s) failed`;\n\n return {\n audit: \"lighthouse\",\n site: label,\n status,\n summary,\n details: normalized,\n };\n}\n","export const lighthouseConfig = {\n ci: {\n collect: {\n url: [\"http://localhost:5173/dev/a11y-fixtures\"],\n startServerCommand: \"pnpm vite:dev\",\n startServerReadyPattern: \"ready in\",\n startServerReadyTimeout: 120_000,\n numberOfRuns: 1,\n settings: {\n preset: \"desktop\",\n skipAudits: [\"uses-http2\"],\n },\n },\n assert: {\n assertions: {\n \"categories:accessibility\": [\"error\", { minScore: 0.95 }],\n \"categories:best-practices\": [\"error\", { minScore: 0.9 }],\n \"categories:seo\": [\"error\", { minScore: 0.9 }],\n \"categories:performance\": [\"warn\", { minScore: 0.7 }],\n },\n },\n upload: {\n target: \"temporary-public-storage\",\n },\n },\n} as const;\n\nexport default lighthouseConfig;\n","import { readFile, writeFile, mkdtemp, rm } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type { AuditResult, Site } from \"../types.js\";\nimport { a11yRoutes } from \"../configs/playwright-a11y.js\";\nimport { defaultSpawn } from \"./util/spawn.js\";\nimport type { AuditContext } from \"./util/inject.js\";\n\ntype Impact = \"minor\" | \"moderate\" | \"serious\" | \"critical\";\n\ntype AxeViolation = {\n id: string;\n impact: Impact;\n route: string;\n help?: string;\n helpUrl?: string;\n nodes?: Array<{ html?: string; target?: string[] }>;\n};\n\ntype NormalizedA11y = {\n totalViolations: number;\n byImpact: Partial<Record<Impact, number>>;\n violations: AxeViolation[];\n};\n\nconst RESULTS_REL = \".reddoor-a11y/results.json\";\n\nfunction siteLabel(site: Site): string {\n return site.name ?? site.path;\n}\n\nasync function readJsonMaybe<T>(path: string): Promise<T | null> {\n try {\n const raw = await readFile(path, \"utf-8\");\n return JSON.parse(raw) as T;\n } catch {\n return null;\n }\n}\n\n// The spec the audit writes runs all configured routes through axe in a single\n// test (so worker isolation doesn't fragment the collected violations) and\n// writes the structured result to <cwd>/.reddoor-a11y/results.json before\n// asserting. That way, the audit can read real axe details even when the\n// expect(...).toEqual([]) assertion fails.\nfunction buildSpec(): string {\n return `import { test, expect } from \"@playwright/test\";\nimport AxeBuilder from \"@axe-core/playwright\";\nimport { mkdir, writeFile } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\n\nconst pages = ${JSON.stringify(a11yRoutes)};\nconst OUTPUT = process.env.REDDOOR_A11Y_OUTPUT;\n\ntest(\"a11y across configured routes\", async ({ page }) => {\n const violations = [];\n for (const { path, name } of pages) {\n await page.goto(path);\n const results = await new AxeBuilder({ page })\n .withTags([\"wcag2a\",\"wcag2aa\",\"wcag21a\",\"wcag21aa\",\"wcag22aa\"])\n .analyze();\n for (const v of results.violations) {\n violations.push({\n id: v.id,\n impact: v.impact ?? \"moderate\",\n route: name,\n help: v.help,\n helpUrl: v.helpUrl,\n nodes: v.nodes.map((n) => ({ html: n.html, target: n.target })),\n });\n }\n }\n const byImpact = {};\n for (const v of violations) {\n byImpact[v.impact] = (byImpact[v.impact] ?? 0) + 1;\n }\n if (OUTPUT) {\n await mkdir(dirname(OUTPUT), { recursive: true });\n await writeFile(\n OUTPUT,\n JSON.stringify({ totalViolations: violations.length, byImpact, violations }, null, 2),\n );\n }\n expect(violations).toEqual([]);\n});\n`;\n}\n\nexport async function a11yAudit(ctx: AuditContext): Promise<AuditResult> {\n const spawn = ctx.spawn ?? defaultSpawn;\n const site = ctx.site;\n const label = siteLabel(site);\n\n const specDir = await mkdtemp(join(tmpdir(), \"reddoor-a11y-spec-\"));\n const specPath = join(specDir, \"a11y.spec.ts\");\n await writeFile(specPath, buildSpec(), \"utf-8\");\n\n const resultsPath = join(site.path, RESULTS_REL);\n // Clear stale artifacts so a failed spawn never reports old data.\n await rm(join(site.path, \".reddoor-a11y\"), { recursive: true, force: true });\n\n let raw;\n try {\n raw = await spawn(\"npx\", [\"--yes\", \"playwright\", \"test\", \"--reporter=line\", specPath], {\n cwd: site.path,\n env: { ...process.env, REDDOOR_A11Y_OUTPUT: resultsPath },\n });\n } catch (err) {\n await rm(specDir, { recursive: true, force: true });\n const e = err as NodeJS.ErrnoException;\n if (e.code === \"ENOENT\" || /ENOENT/.test(String(err))) {\n return {\n audit: \"a11y\",\n site: label,\n status: \"skip\",\n summary: \"npx/playwright not available\",\n };\n }\n throw err;\n }\n await rm(specDir, { recursive: true, force: true });\n\n const artifact = await readJsonMaybe<NormalizedA11y>(resultsPath);\n\n if (!artifact) {\n return {\n audit: \"a11y\",\n site: label,\n status: \"fail\",\n summary: `a11y: no results written (exit ${raw.code})${\n raw.stderr ? ` — ${raw.stderr.slice(0, 200)}` : \"\"\n }`,\n };\n }\n\n const hasSerious = (artifact.byImpact.serious ?? 0) > 0 || (artifact.byImpact.critical ?? 0) > 0;\n const hasAny = artifact.totalViolations > 0;\n\n const status: AuditResult[\"status\"] = hasSerious ? \"fail\" : hasAny ? \"warn\" : \"pass\";\n const summary =\n status === \"pass\"\n ? `a11y: 0 violations across ${a11yRoutes.length} routes`\n : `a11y: ${artifact.totalViolations} violations`;\n\n return {\n audit: \"a11y\",\n site: label,\n status,\n summary,\n details: artifact,\n };\n}\n","import { defineConfig, devices, type PlaywrightTestConfig } from \"@playwright/test\";\n\nexport type A11yRoute = { path: string; name: string };\n\nexport const a11yRoutes: A11yRoute[] = [\n { path: \"/dev/a11y-fixtures\", name: \"a11y fixtures\" },\n { path: \"/dev/animate-in\", name: \"animate-in demo\" },\n];\n\nexport const playwrightA11yConfig: PlaywrightTestConfig = defineConfig({\n testDir: \"tests\",\n testMatch: /.*\\.spec\\.ts$/,\n fullyParallel: true,\n forbidOnly: !!process.env.CI,\n retries: process.env.CI ? 2 : 0,\n reporter: process.env.CI ? \"github\" : \"list\",\n use: {\n baseURL: \"http://localhost:5173\",\n trace: \"on-first-retry\",\n },\n projects: [\n {\n name: \"chromium\",\n use: { ...devices[\"Desktop Chrome\"] },\n },\n ],\n webServer: {\n command: \"pnpm vite:dev\",\n url: \"http://localhost:5173/dev/a11y-fixtures\",\n reuseExistingServer: !process.env.CI,\n timeout: 120_000,\n },\n});\n\nexport default playwrightA11yConfig;\n","import type { AuditName, AuditResult, Site } from \"../types.js\";\nimport type { AuditContext } from \"./util/inject.js\";\nimport { defaultSpawn } from \"./util/spawn.js\";\nimport type { SpawnFn } from \"./util/spawn.js\";\nimport { depsAudit } from \"./deps.js\";\nimport { lintAudit } from \"./lint.js\";\nimport { securityAudit } from \"./security.js\";\nimport { lighthouseAudit } from \"./lighthouse.js\";\nimport { a11yAudit } from \"./a11y.js\";\n\nconst REGISTRY: Record<AuditName, (ctx: AuditContext) => Promise<AuditResult>> = {\n deps: depsAudit,\n lint: lintAudit,\n security: securityAudit,\n lighthouse: lighthouseAudit,\n a11y: a11yAudit,\n};\n\nexport const ALL_AUDIT_NAMES = Object.keys(REGISTRY) as AuditName[];\n\n/** Default per-audit spawn timeout when running via runAudits (30 s). */\nconst DEFAULT_AUDIT_TIMEOUT_MS = 30_000;\n\nfunction timedSpawn(timeoutMs: number): SpawnFn {\n return (cmd, args, opts = {}) =>\n defaultSpawn(cmd, args, { ...opts, timeoutMs: opts.timeoutMs ?? timeoutMs });\n}\n\nexport async function runAudits(site: Site, which?: AuditName[]): Promise<AuditResult[]> {\n const names = which ?? ALL_AUDIT_NAMES;\n for (const n of names) {\n if (!(n in REGISTRY)) throw new Error(`unknown audit: ${n}`);\n }\n const spawn = timedSpawn(DEFAULT_AUDIT_TIMEOUT_MS);\n const label = site.name ?? site.path;\n return Promise.all(\n names.map((n) =>\n REGISTRY[n]({ site, spawn }).catch(\n (err): AuditResult => ({\n audit: n,\n site: label,\n status: \"fail\",\n summary: `${n}: unexpected error — ${String(err)}`,\n }),\n ),\n ),\n );\n}\n\nexport async function runAuditsAcross(sites: Site[], which?: AuditName[]): Promise<AuditResult[]> {\n const all = await Promise.all(sites.map((s) => runAudits(s, which)));\n return all.flat();\n}\n\nexport { depsAudit, lintAudit, securityAudit, lighthouseAudit, a11yAudit };\n","import { pathToFileURL } from \"node:url\";\nimport { resolve, extname } from \"node:path\";\nimport type { InventoryProvider, Site } from \"../../types.js\";\nimport { localPath } from \"../../inventory/local.js\";\nimport { fromJsonFile } from \"../../inventory/json.js\";\n\nexport type ResolveSitesInput = {\n site?: string;\n fleet?: string;\n cwd: string;\n};\n\nexport async function resolveSites(input: ResolveSitesInput): Promise<Site[]> {\n if (input.site && input.fleet) {\n throw Object.assign(new Error(\"cannot combine a positional [site] with --fleet\"), {\n exitCode: 2,\n });\n }\n\n if (input.fleet) {\n const fleetPath = resolve(input.cwd, input.fleet);\n const ext = extname(fleetPath).toLowerCase();\n let provider: InventoryProvider;\n if (ext === \".json\") {\n provider = fromJsonFile(fleetPath);\n } else if (ext === \".js\" || ext === \".mjs\" || ext === \".cjs\") {\n const mod = (await import(pathToFileURL(fleetPath).href)) as {\n default?: InventoryProvider;\n };\n if (!mod.default || typeof mod.default !== \"function\") {\n throw Object.assign(new Error(`--fleet ${input.fleet}: default export is not a function`), {\n exitCode: 2,\n });\n }\n provider = mod.default;\n } else {\n throw Object.assign(\n new Error(`--fleet ${input.fleet}: unsupported extension ${ext || \"(none)\"}`),\n { exitCode: 2 },\n );\n }\n return provider();\n }\n\n return localPath(resolve(input.cwd, input.site ?? input.cwd))();\n}\n","import { basename } from \"node:path\";\nimport type { InventoryProvider, Site } from \"../types.js\";\n\nexport type LocalPathOptions = {\n name?: string;\n};\n\nexport function localPath(path: string, opts: LocalPathOptions = {}): InventoryProvider {\n const site: Site = { path, name: opts.name ?? basename(path) };\n return async () => [site];\n}\n","import { readFile } from \"node:fs/promises\";\nimport type { InventoryProvider, Site } from \"../types.js\";\n\nfunction validate(raw: unknown): Site[] {\n if (!Array.isArray(raw)) {\n throw new Error(\"inventory JSON must be an array of sites\");\n }\n return raw.map((entry, i) => {\n if (!entry || typeof entry !== \"object\") {\n throw new Error(`inventory entry ${i} is not an object`);\n }\n const e = entry as Record<string, unknown>;\n if (typeof e.path !== \"string\" || e.path.length === 0) {\n throw new Error(`inventory entry ${i} is missing required field: path`);\n }\n const site: Site = { path: e.path };\n if (typeof e.name === \"string\") site.name = e.name;\n if (typeof e.repoUrl === \"string\") site.repoUrl = e.repoUrl;\n if (typeof e.meta === \"object\" && e.meta !== null) {\n site.meta = e.meta as Record<string, unknown>;\n }\n return site;\n });\n}\n\nexport function fromJsonFile(path: string): InventoryProvider {\n return async () => {\n const raw = JSON.parse(await readFile(path, \"utf-8\")) as unknown;\n return validate(raw);\n };\n}\n","import { stat, readdir, mkdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport type { Site } from \"../../types.js\";\nimport { defaultSpawn, type SpawnFn } from \"../../audits/util/spawn.js\";\n\nexport type CloneIfNeededOptions = {\n workdir: string;\n spawn?: SpawnFn;\n};\n\nfunction deriveNameFromRepoUrl(repoUrl: string): string {\n const slash = repoUrl.split(\"/\").pop() ?? repoUrl;\n return slash.replace(/\\.git$/, \"\");\n}\n\nasync function isNonEmptyDir(path: string): Promise<boolean> {\n try {\n const s = await stat(path);\n if (!s.isDirectory()) return false;\n const entries = await readdir(path);\n return entries.length > 0;\n } catch {\n return false;\n }\n}\n\nexport async function cloneIfNeeded(site: Site, opts: CloneIfNeededOptions): Promise<Site> {\n if (await isNonEmptyDir(site.path)) return site;\n\n if (!site.repoUrl) {\n throw new Error(`site path does not exist (${site.path}) and no repoUrl is set — cannot clone`);\n }\n\n const name = site.name ?? deriveNameFromRepoUrl(site.repoUrl);\n const target = join(opts.workdir, name);\n await mkdir(opts.workdir, { recursive: true });\n\n if (await isNonEmptyDir(target)) {\n return { ...site, name, path: target };\n }\n\n const spawn = opts.spawn ?? defaultSpawn;\n const result = await spawn(\"git\", [\"clone\", site.repoUrl, target], {\n cwd: opts.workdir,\n timeoutMs: 5 * 60_000,\n });\n if (result.code !== 0) {\n throw new Error(`git clone failed (code ${result.code}): ${result.stderr}`);\n }\n return { ...site, name, path: target };\n}\n"],"mappings":"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","names":["resolve","resolve","readFile","join","siteLabel","siteLabel","spawn","readFile","join","siteLabel","readFile","spawn","join","readFile","writeFile","mkdtemp","rm","tmpdir","join","siteLabel","readJsonMaybe","readFile","spawn","mkdtemp","join","tmpdir","writeFile","rm","spawn","readFile","join","join","spawn","resolve"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/cli/commands/audit.ts","../../../src/audits/util/spawn.ts","../../../src/audits/deps.ts","../../../src/configs/baseline-versions.ts","../../../src/audits/lint.ts","../../../src/audits/security.ts","../../../src/audits/lighthouse.ts","../../../src/configs/lighthouse.ts","../../../src/audits/a11y.ts","../../../src/configs/playwright-a11y.ts","../../../src/audits/index.ts","../../../src/cli/fleet/resolve-sites.ts","../../../src/inventory/local.ts","../../../src/inventory/json.ts","../../../src/cli/fleet/clone-if-needed.ts"],"sourcesContent":["import { resolve } from \"node:path\";\nimport { runAudits, ALL_AUDIT_NAMES } from \"../../audits/index.js\";\nimport type { AuditName, AuditResult } from \"../../types.js\";\nimport { resolveSites } from \"../fleet/resolve-sites.js\";\nimport { cloneIfNeeded } from \"../fleet/clone-if-needed.js\";\n\nexport type AuditCommandOptions = {\n only?: string;\n json?: boolean;\n fleet?: string;\n workdir?: string;\n cwd?: string;\n};\n\nfunction parseOnly(value: string | undefined): AuditName[] | undefined {\n if (!value) return undefined;\n const names = value.split(\",\").map((s) => s.trim());\n for (const n of names) {\n if (!ALL_AUDIT_NAMES.includes(n as AuditName)) {\n throw Object.assign(new Error(`unknown audit in --only: ${n}`), { exitCode: 2 });\n }\n }\n return names as AuditName[];\n}\n\nfunction formatTable(results: AuditResult[]): string {\n return results\n .map((r) => `${r.audit.padEnd(12)} ${r.status.padEnd(5)} ${r.site}\\n ${r.summary}`)\n .join(\"\\n\");\n}\n\nfunction exitCode(results: AuditResult[]): number {\n return results.some((r) => r.status === \"fail\") ? 1 : 0;\n}\n\nexport async function runAuditCommand(\n site: string | undefined,\n opts: AuditCommandOptions,\n): Promise<{ output: string; code: number }> {\n const which = parseOnly(opts.only);\n const cwd = opts.cwd ? resolve(opts.cwd) : process.cwd();\n\n let sites = await resolveSites({\n ...(site !== undefined ? { site } : {}),\n ...(opts.fleet !== undefined ? { fleet: opts.fleet } : {}),\n cwd,\n });\n\n if (opts.fleet) {\n const workdir = opts.workdir ?? `${process.env.HOME ?? \"\"}/.reddoor-maint/sites`;\n sites = await Promise.all(sites.map((s) => cloneIfNeeded(s, { workdir })));\n }\n\n const results: AuditResult[] = [];\n for (const s of sites) {\n const r = await runAudits(s, which);\n results.push(...r);\n }\n\n const output = opts.json ? JSON.stringify(results, null, 2) : formatTable(results);\n return { output, code: exitCode(results) };\n}\n","import { spawn } from \"node:child_process\";\n\nexport type SpawnResult = { code: number; stdout: string; stderr: string };\n\nexport type SpawnOptions = {\n cwd?: string;\n env?: NodeJS.ProcessEnv;\n timeoutMs?: number;\n /** When true, the child inherits stdout/stderr so the user sees live\n * progress (useful for long-running `pnpm up` / `npm install`). The\n * returned `stdout` and `stderr` will be empty strings in that case. */\n streaming?: boolean;\n};\n\nexport type SpawnFn = (\n cmd: string,\n args: readonly string[],\n opts?: SpawnOptions,\n) => Promise<SpawnResult>;\n\nexport const defaultSpawn: SpawnFn = (cmd, args, opts = {}) =>\n new Promise((resolve, reject) => {\n const streaming = opts.streaming === true;\n const child = spawn(cmd, [...args], {\n cwd: opts.cwd,\n env: opts.env ?? process.env,\n stdio: streaming ? [\"ignore\", \"inherit\", \"inherit\"] : [\"ignore\", \"pipe\", \"pipe\"],\n });\n\n let stdout = \"\";\n let stderr = \"\";\n if (!streaming) {\n child.stdout?.on(\"data\", (chunk) => (stdout += String(chunk)));\n child.stderr?.on(\"data\", (chunk) => (stderr += String(chunk)));\n }\n\n const timer = opts.timeoutMs\n ? setTimeout(() => {\n child.kill(\"SIGTERM\");\n reject(new Error(`spawn timeout after ${opts.timeoutMs}ms: ${cmd}`));\n }, opts.timeoutMs)\n : undefined;\n\n child.on(\"error\", (err) => {\n if (timer) clearTimeout(timer);\n reject(err);\n });\n child.on(\"close\", (code) => {\n if (timer) clearTimeout(timer);\n resolve({ code: code ?? -1, stdout, stderr });\n });\n });\n","import { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport type { AuditResult, Site } from \"../types.js\";\nimport { baselineVersions } from \"../configs/baseline-versions.js\";\nimport type { AuditContext } from \"./util/inject.js\";\n\nexport type Drift = \"same\" | \"patch\" | \"minor\" | \"major\" | \"newer\";\n\nexport type DepsDriftEntry = {\n pkg: string;\n baseline: string;\n actual: string;\n drift: Drift;\n};\n\nfunction siteLabel(site: Site): string {\n return site.name ?? site.path;\n}\n\nfunction stripCaret(range: string): string {\n return range.replace(/^[\\^~]/, \"\");\n}\n\nfunction parseSemver(v: string): [number, number, number] {\n const cleaned = stripCaret(v).split(\"-\")[0] ?? \"0.0.0\";\n const parts = cleaned.split(\".\").map((n) => Number.parseInt(n, 10));\n return [parts[0] ?? 0, parts[1] ?? 0, parts[2] ?? 0];\n}\n\nfunction compareSemver(actual: string, baseline: string): Drift {\n const [aMajor, aMinor, aPatch] = parseSemver(actual);\n const [bMajor, bMinor, bPatch] = parseSemver(baseline);\n if (aMajor > bMajor) return \"newer\";\n if (aMajor < bMajor) return \"major\";\n if (aMinor > bMinor) return \"newer\";\n if (aMinor < bMinor) return \"minor\";\n if (aPatch > bPatch) return \"newer\";\n if (aPatch < bPatch) return \"patch\";\n return \"same\";\n}\n\nexport async function depsAudit(ctx: AuditContext): Promise<AuditResult> {\n const pkgPath = join(ctx.site.path, \"package.json\");\n let pkgRaw: string;\n try {\n pkgRaw = await readFile(pkgPath, \"utf-8\");\n } catch (err) {\n return {\n audit: \"deps\",\n site: siteLabel(ctx.site),\n status: \"skip\",\n summary: `no package.json at ${pkgPath}`,\n details: { error: String(err) },\n };\n }\n\n const pkg = JSON.parse(pkgRaw) as {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n };\n const installed: Record<string, string> = {\n ...(pkg.dependencies ?? {}),\n ...(pkg.devDependencies ?? {}),\n };\n\n const details: DepsDriftEntry[] = [];\n for (const [name, baseline] of Object.entries(baselineVersions)) {\n const actual = installed[name];\n if (!actual) continue;\n details.push({\n pkg: name,\n baseline,\n actual,\n drift: compareSemver(actual, baseline),\n });\n }\n\n const anyMajor = details.some((d) => d.drift === \"major\");\n const anyMinor = details.some((d) => d.drift === \"minor\");\n const anyNewer = details.some((d) => d.drift === \"newer\");\n\n const status: AuditResult[\"status\"] = anyMajor ? \"fail\" : anyMinor || anyNewer ? \"warn\" : \"pass\";\n\n const summary =\n status === \"pass\"\n ? `all ${details.length} tracked deps in line with baseline`\n : status === \"warn\"\n ? `${details.filter((d) => d.drift !== \"same\").length} of ${details.length} tracked deps drifted`\n : `${details.filter((d) => d.drift === \"major\").length} deps lagging by a major version`;\n\n return {\n audit: \"deps\",\n site: siteLabel(ctx.site),\n status,\n summary,\n details,\n };\n}\n","// Curated map of the framework deps reddoor sites should stay close to.\n// Refreshed at each package release from reddoor-starter's package.json.\n// Versions are caret ranges to mirror what `pnpm add` would produce.\n\nexport const baselineVersions: Record<string, string> = {\n // SvelteKit core\n svelte: \"^5.55.5\",\n \"@sveltejs/kit\": \"^2.59.0\",\n \"@sveltejs/adapter-netlify\": \"^6.0.4\",\n \"@sveltejs/adapter-auto\": \"^7.0.0\",\n \"@sveltejs/vite-plugin-svelte\": \"^7.0.0\",\n \"svelte-check\": \"^4.4.7\",\n\n // Build tooling\n vite: \"^8.0.10\",\n vitest: \"^4.1.1\",\n typescript: \"^6.0.3\",\n\n // Tailwind 4\n tailwindcss: \"^4.0.14\",\n \"@tailwindcss/vite\": \"^4.3.0\",\n\n // Prismic\n \"@prismicio/client\": \"^7.3.1\",\n \"@prismicio/svelte\": \"^2.0.0\",\n \"@slicemachine/adapter-sveltekit\": \"^0.3.36\",\n \"slice-machine-ui\": \"^2.11.1\",\n\n // Test tooling\n \"@playwright/test\": \"^1.59.1\",\n \"@axe-core/playwright\": \"^4.11.3\",\n \"@lhci/cli\": \"^0.15.1\",\n\n // Lint\n eslint: \"^10.3.0\",\n \"eslint-plugin-svelte\": \"^3.1.0\",\n \"eslint-config-prettier\": \"^10.1.1\",\n prettier: \"^3.1.1\",\n \"prettier-plugin-svelte\": \"^3.2.6\",\n \"typescript-eslint\": \"^8.59.1\",\n \"@eslint/js\": \"^10.0.1\",\n globals: \"^17.6.0\",\n\n // Misc\n \"@lucide/svelte\": \"^1.14.0\",\n \"@zerodevx/svelte-img\": \"^2.1.2\",\n};\n\nexport default baselineVersions;\n","import { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { ESLint } from \"eslint\";\nimport { check as prettierCheck, resolveConfig as prettierResolveConfig } from \"prettier\";\nimport { glob } from \"tinyglobby\";\nimport type { AuditResult, Site } from \"../types.js\";\nimport type { AuditContext } from \"./util/inject.js\";\n\nconst TARGET_GLOBS = [\"**/*.{ts,js,svelte}\"];\nconst IGNORE = [\"node_modules/**\", \"dist/**\", \".svelte-kit/**\", \"build/**\", \".netlify/**\"];\n\nfunction siteLabel(site: Site): string {\n return site.name ?? site.path;\n}\n\nasync function listFiles(cwd: string): Promise<string[]> {\n return glob(TARGET_GLOBS, { cwd, ignore: IGNORE, absolute: false });\n}\n\nexport async function lintAudit(ctx: AuditContext): Promise<AuditResult> {\n const { site } = ctx;\n const configPath = join(site.path, \"eslint.config.js\");\n\n if (!existsSync(configPath)) {\n return {\n audit: \"lint\",\n site: siteLabel(site),\n status: \"skip\",\n summary: \"no eslint config at site root\",\n };\n }\n\n const eslint = new ESLint({\n cwd: site.path,\n overrideConfigFile: configPath,\n errorOnUnmatchedPattern: false,\n });\n\n const relFiles = await listFiles(site.path);\n\n // Pass relative paths to ESLint; its cwd is already site.path. Avoids\n // dereferencing symlinks on pnpm workspaces.\n const eslintResults = await eslint.lintFiles(relFiles);\n const eslintErrors = eslintResults.reduce((n, r) => n + r.errorCount, 0);\n const eslintWarnings = eslintResults.reduce((n, r) => n + r.warningCount, 0);\n\n const prettierUnformatted: string[] = [];\n for (const rel of relFiles) {\n const absForResolve = join(site.path, rel);\n const source = await readFile(absForResolve, \"utf-8\");\n const options = (await prettierResolveConfig(absForResolve)) ?? {};\n const ok = await prettierCheck(source, { ...options, filepath: absForResolve });\n if (!ok) prettierUnformatted.push(rel);\n }\n\n const status: AuditResult[\"status\"] =\n eslintErrors > 0 || prettierUnformatted.length > 0\n ? \"fail\"\n : eslintWarnings > 0\n ? \"warn\"\n : \"pass\";\n\n const summary =\n status === \"pass\"\n ? `lint clean across ${relFiles.length} files`\n : `${eslintErrors} eslint errors, ${eslintWarnings} warnings, ${prettierUnformatted.length} unformatted`;\n\n return {\n audit: \"lint\",\n site: siteLabel(site),\n status,\n summary,\n details: {\n eslintErrors,\n eslintWarnings,\n prettierUnformatted,\n files: relFiles.length,\n },\n };\n}\n","import type { AuditResult, Site } from \"../types.js\";\nimport { defaultSpawn, type SpawnResult } from \"./util/spawn.js\";\nimport type { AuditContext } from \"./util/inject.js\";\n\ntype Severity = \"low\" | \"moderate\" | \"high\" | \"critical\";\n\ntype Counts = { low: number; moderate: number; high: number; critical: number };\n\ntype AdvisoryEntry = {\n module: string;\n severity: Severity;\n title: string;\n cves?: string[];\n url?: string;\n};\n\n// pnpm audit output (npm-compat with extra advisories map keyed by ID).\ntype PnpmAuditJson = {\n metadata?: { vulnerabilities?: Partial<Counts> };\n advisories?: Record<\n string,\n {\n id?: number;\n title?: string;\n module_name?: string;\n severity?: string;\n cves?: string[];\n url?: string;\n }\n >;\n};\n\n// npm v7+ shape (vulnerabilities keyed by package name).\ntype NpmAuditJson = {\n metadata?: { vulnerabilities?: Partial<Counts> };\n vulnerabilities?: Record<\n string,\n {\n name?: string;\n severity?: string;\n via?: unknown;\n url?: string;\n }\n >;\n};\n\nfunction siteLabel(site: Site): string {\n return site.name ?? site.path;\n}\n\nfunction classify(v: Counts) {\n if (v.critical > 0 || v.high > 0) return \"fail\" as const;\n if (v.moderate > 0 || v.low > 0) return \"warn\" as const;\n return \"pass\" as const;\n}\n\nfunction normalizeSeverity(s: unknown): Severity {\n if (s === \"low\" || s === \"moderate\" || s === \"high\" || s === \"critical\") return s;\n // npm/pnpm sometimes emit \"info\" for informational advisories. Map down\n // rather than defaulting to \"moderate\" (which would inflate severity).\n return \"low\";\n}\n\nfunction extractAdvisoriesFromPnpm(parsed: PnpmAuditJson): AdvisoryEntry[] {\n const out: AdvisoryEntry[] = [];\n for (const a of Object.values(parsed.advisories ?? {})) {\n if (!a) continue;\n out.push({\n module: a.module_name ?? \"unknown\",\n severity: normalizeSeverity(a.severity),\n title: a.title ?? \"(no title)\",\n ...(a.cves ? { cves: a.cves } : {}),\n ...(a.url ? { url: a.url } : {}),\n });\n }\n return out;\n}\n\n/** Walk an npm v7+ `via` chain to find the root entry whose `via` array\n * contains a real advisory object (rather than another package name string).\n * Returns the package name at the root and the advisory detail. */\nfunction resolveNpmAdvisoryRoot(\n startName: string,\n vulnerabilities: NonNullable<NpmAuditJson[\"vulnerabilities\"]>,\n): { rootName: string; detail?: { title?: string; url?: string } } {\n const seen = new Set<string>();\n let current = startName;\n while (!seen.has(current)) {\n seen.add(current);\n const entry = vulnerabilities[current];\n if (!entry || !Array.isArray(entry.via)) return { rootName: current };\n\n const detailed = entry.via.find(\n (e): e is { title?: string; url?: string } => typeof e === \"object\" && e !== null,\n );\n if (detailed) return { rootName: current, detail: detailed };\n\n const next = entry.via.find((e): e is string => typeof e === \"string\");\n if (!next || next === current) return { rootName: current };\n current = next;\n }\n return { rootName: current };\n}\n\nfunction extractAdvisoriesFromNpm(parsed: NpmAuditJson): AdvisoryEntry[] {\n const vulnerabilities = parsed.vulnerabilities ?? {};\n const roots = new Map<string, AdvisoryEntry>();\n\n for (const [name, v] of Object.entries(vulnerabilities)) {\n if (!v) continue;\n const { rootName, detail } = resolveNpmAdvisoryRoot(name, vulnerabilities);\n if (roots.has(rootName)) continue; // already surfaced via another transitive entry\n\n const rootEntry = vulnerabilities[rootName];\n const severity = normalizeSeverity(rootEntry?.severity ?? v.severity);\n const title = detail?.title ?? rootName;\n const url = detail?.url;\n\n roots.set(rootName, {\n module: rootEntry?.name ?? rootName,\n severity,\n title,\n ...(url ? { url } : {}),\n });\n }\n\n return [...roots.values()];\n}\n\ntype ToolResult =\n | { kind: \"missing\" }\n | { kind: \"error\"; reason: string }\n | { kind: \"ok\"; parsed: PnpmAuditJson & NpmAuditJson };\n\nasync function runAuditTool(\n spawn: (cmd: string, args: readonly string[], opts?: { cwd?: string }) => Promise<SpawnResult>,\n cmd: string,\n args: readonly string[],\n cwd: string,\n): Promise<ToolResult> {\n let raw: SpawnResult;\n try {\n raw = await spawn(cmd, args, { cwd });\n } catch (err) {\n const e = err as NodeJS.ErrnoException;\n if (e.code === \"ENOENT\" || /ENOENT/.test(String(err))) return { kind: \"missing\" };\n return { kind: \"error\", reason: `spawn failed: ${String(err).slice(0, 200)}` };\n }\n\n // 0 = clean, 1 = vulns found. Anything else is a real error.\n if (raw.code !== 0 && raw.code !== 1) {\n return {\n kind: \"error\",\n reason: `exit ${raw.code}${raw.stderr ? `: ${raw.stderr.slice(0, 150)}` : \"\"}`,\n };\n }\n\n let parsed: PnpmAuditJson & NpmAuditJson;\n try {\n parsed = JSON.parse(raw.stdout || \"{}\") as PnpmAuditJson & NpmAuditJson;\n } catch (err) {\n return { kind: \"error\", reason: `unparseable JSON: ${String(err).slice(0, 100)}` };\n }\n\n // pnpm error envelope: { error: { code, message } }. npm sometimes emits\n // a top-level error too. Either means the audit didn't actually run.\n const errEnvelope = (parsed as unknown as { error?: { code?: string } }).error;\n if (errEnvelope && typeof errEnvelope === \"object\") {\n return { kind: \"error\", reason: errEnvelope.code ?? \"error envelope returned\" };\n }\n\n // Without metadata.vulnerabilities there are no counts to report and we\n // can't trust the result. Treat as a tool failure so the caller can fall\n // through to the other audit tool.\n if (!parsed.metadata?.vulnerabilities) {\n return { kind: \"error\", reason: \"no metadata.vulnerabilities in output\" };\n }\n\n return { kind: \"ok\", parsed };\n}\n\nexport async function securityAudit(ctx: AuditContext): Promise<AuditResult> {\n const spawn = ctx.spawn ?? defaultSpawn;\n const site = ctx.site;\n const label = siteLabel(site);\n\n let used: \"pnpm audit\" | \"npm audit\" = \"pnpm audit\";\n let result = await runAuditTool(spawn, \"pnpm\", [\"audit\", \"--json\", \"--prod\"], site.path);\n\n // Fall through to npm if pnpm is missing OR pnpm couldn't actually\n // audit the project (e.g., no pnpm-lock.yaml). Previously we only fell\n // through on ENOENT, which meant npm-using sites silently reported \"pass\"\n // because pnpm returned an error envelope with no metadata.\n if (result.kind !== \"ok\") {\n const pnpmReason = result.kind === \"missing\" ? \"not installed\" : result.reason;\n const npmResult = await runAuditTool(\n spawn,\n \"npm\",\n [\"audit\", \"--json\", \"--omit=dev\"],\n site.path,\n );\n if (npmResult.kind === \"ok\") {\n result = npmResult;\n used = \"npm audit\";\n } else {\n const npmReason = npmResult.kind === \"missing\" ? \"not installed\" : npmResult.reason;\n return {\n audit: \"security\",\n site: label,\n status: \"skip\",\n summary: `cannot run audit — pnpm: ${pnpmReason}; npm: ${npmReason}`,\n };\n }\n }\n\n const parsed = result.parsed;\n\n const counts: Counts = {\n low: parsed.metadata?.vulnerabilities?.low ?? 0,\n moderate: parsed.metadata?.vulnerabilities?.moderate ?? 0,\n high: parsed.metadata?.vulnerabilities?.high ?? 0,\n critical: parsed.metadata?.vulnerabilities?.critical ?? 0,\n };\n\n const advisories =\n used === \"pnpm audit\" ? extractAdvisoriesFromPnpm(parsed) : extractAdvisoriesFromNpm(parsed);\n\n const status = classify(counts);\n const total = counts.low + counts.moderate + counts.high + counts.critical;\n const summary =\n status === \"pass\"\n ? `${used}: 0 vulnerabilities`\n : `${used}: ${total} vulnerabilities (${counts.critical}C/${counts.high}H/${counts.moderate}M/${counts.low}L)`;\n\n return {\n audit: \"security\",\n site: label,\n status,\n summary,\n details: { counts, advisories },\n };\n}\n","import { readFile, writeFile, mkdtemp, rm } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type { AuditResult, Site } from \"../types.js\";\nimport { lighthouseConfig } from \"../configs/lighthouse.js\";\nimport { defaultSpawn } from \"./util/spawn.js\";\nimport type { AuditContext } from \"./util/inject.js\";\n\ntype ManifestEntry = {\n url: string;\n summary: Record<string, number>;\n htmlPath?: string;\n jsonPath?: string;\n};\n\ntype AssertionResult = {\n name: string;\n actual: number;\n expected: number;\n operator: string;\n passed: boolean;\n level: \"warn\" | \"error\";\n auditProperty?: string;\n auditId?: string;\n};\n\ntype NormalizedLhciResult = {\n summary: Record<string, number>;\n assertionsFailed: number;\n assertions: Array<{ category: string; level: \"warn\" | \"error\"; message: string }>;\n};\n\nfunction siteLabel(site: Site): string {\n return site.name ?? site.path;\n}\n\nasync function readJsonMaybe<T>(path: string): Promise<T | null> {\n try {\n const raw = await readFile(path, \"utf-8\");\n return JSON.parse(raw) as T;\n } catch {\n return null;\n }\n}\n\nfunction averageSummaries(entries: ManifestEntry[]): Record<string, number> {\n if (entries.length === 0) return {};\n const sums: Record<string, number> = {};\n const counts: Record<string, number> = {};\n for (const e of entries) {\n for (const [k, v] of Object.entries(e.summary ?? {})) {\n if (typeof v !== \"number\") continue;\n sums[k] = (sums[k] ?? 0) + v;\n counts[k] = (counts[k] ?? 0) + 1;\n }\n }\n const out: Record<string, number> = {};\n for (const k of Object.keys(sums)) {\n const total = sums[k] ?? 0;\n const count = counts[k] ?? 1;\n out[k] = total / count;\n }\n return out;\n}\n\nfunction categoryFromAssertion(a: AssertionResult): string {\n // `name` looks like \"categories:accessibility\" or \"audits:uses-http2\".\n const colonIdx = a.name.indexOf(\":\");\n return colonIdx >= 0 ? a.name.slice(colonIdx + 1) : a.name;\n}\n\nfunction messageForAssertion(a: AssertionResult): string {\n return `${a.name} ${a.operator} ${a.expected} (actual: ${a.actual.toFixed(2)})`;\n}\n\nexport async function lighthouseAudit(ctx: AuditContext): Promise<AuditResult> {\n const spawn = ctx.spawn ?? defaultSpawn;\n const site = ctx.site;\n const label = siteLabel(site);\n\n const configDir = await mkdtemp(join(tmpdir(), \"reddoor-lhci-\"));\n const configPath = join(configDir, \"lighthouserc.json\");\n await writeFile(configPath, JSON.stringify(lighthouseConfig), \"utf-8\");\n\n const resultsDir = join(site.path, \".lighthouseci\");\n // Clear any stale artifacts before the run so we never confuse a failed\n // spawn with old results.\n await rm(resultsDir, { recursive: true, force: true });\n\n let raw;\n try {\n raw = await spawn(\"npx\", [\"--yes\", \"@lhci/cli\", \"autorun\", `--config=${configPath}`], {\n cwd: site.path,\n });\n } catch (err) {\n await rm(configDir, { recursive: true, force: true });\n const e = err as NodeJS.ErrnoException;\n if (e.code === \"ENOENT\" || /ENOENT/.test(String(err))) {\n return {\n audit: \"lighthouse\",\n site: label,\n status: \"skip\",\n summary: \"npx/@lhci/cli not available\",\n };\n }\n throw err;\n }\n await rm(configDir, { recursive: true, force: true });\n\n const manifest = await readJsonMaybe<ManifestEntry[]>(join(resultsDir, \"manifest.json\"));\n\n if (!manifest || manifest.length === 0) {\n return {\n audit: \"lighthouse\",\n site: label,\n status: \"fail\",\n summary: `lighthouse: no manifest written (exit ${raw.code})${\n raw.stderr ? ` — ${raw.stderr.slice(0, 200)}` : \"\"\n }`,\n };\n }\n\n const assertionResults =\n (await readJsonMaybe<AssertionResult[]>(join(resultsDir, \"assertion-results.json\"))) ?? [];\n\n const failed = assertionResults.filter((a) => !a.passed);\n const assertions = failed.map((a) => ({\n category: categoryFromAssertion(a),\n level: a.level,\n message: messageForAssertion(a),\n }));\n\n const anyError = assertions.some((a) => a.level === \"error\");\n const anyWarn = assertions.some((a) => a.level === \"warn\");\n const status: AuditResult[\"status\"] = anyError ? \"fail\" : anyWarn ? \"warn\" : \"pass\";\n\n const normalized: NormalizedLhciResult = {\n summary: averageSummaries(manifest),\n assertionsFailed: failed.length,\n assertions,\n };\n\n const summary =\n status === \"pass\"\n ? \"lighthouse: all categories passing\"\n : `lighthouse: ${failed.length} assertion(s) failed`;\n\n return {\n audit: \"lighthouse\",\n site: label,\n status,\n summary,\n details: normalized,\n };\n}\n","export const lighthouseConfig = {\n ci: {\n collect: {\n url: [\"http://localhost:5173/dev/a11y-fixtures\"],\n startServerCommand: \"pnpm vite:dev\",\n startServerReadyPattern: \"ready in\",\n startServerReadyTimeout: 120_000,\n numberOfRuns: 1,\n settings: {\n preset: \"desktop\",\n skipAudits: [\"uses-http2\"],\n },\n },\n assert: {\n assertions: {\n \"categories:accessibility\": [\"error\", { minScore: 0.95 }],\n \"categories:best-practices\": [\"error\", { minScore: 0.9 }],\n \"categories:seo\": [\"error\", { minScore: 0.9 }],\n \"categories:performance\": [\"warn\", { minScore: 0.7 }],\n },\n },\n upload: {\n target: \"temporary-public-storage\",\n },\n },\n} as const;\n\nexport default lighthouseConfig;\n","import { readFile, writeFile, mkdtemp, rm } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type { AuditResult, Site } from \"../types.js\";\nimport { a11yRoutes } from \"../configs/playwright-a11y.js\";\nimport { defaultSpawn } from \"./util/spawn.js\";\nimport type { AuditContext } from \"./util/inject.js\";\n\ntype Impact = \"minor\" | \"moderate\" | \"serious\" | \"critical\";\n\ntype AxeViolation = {\n id: string;\n impact: Impact;\n route: string;\n help?: string;\n helpUrl?: string;\n nodes?: Array<{ html?: string; target?: string[] }>;\n};\n\ntype NormalizedA11y = {\n totalViolations: number;\n byImpact: Partial<Record<Impact, number>>;\n violations: AxeViolation[];\n};\n\nconst RESULTS_REL = \".reddoor-a11y/results.json\";\n\nfunction siteLabel(site: Site): string {\n return site.name ?? site.path;\n}\n\nasync function readJsonMaybe<T>(path: string): Promise<T | null> {\n try {\n const raw = await readFile(path, \"utf-8\");\n return JSON.parse(raw) as T;\n } catch {\n return null;\n }\n}\n\n// The spec the audit writes runs all configured routes through axe in a single\n// test (so worker isolation doesn't fragment the collected violations) and\n// writes the structured result to <cwd>/.reddoor-a11y/results.json before\n// asserting. That way, the audit can read real axe details even when the\n// expect(...).toEqual([]) assertion fails.\nfunction buildSpec(): string {\n return `import { test, expect } from \"@playwright/test\";\nimport AxeBuilder from \"@axe-core/playwright\";\nimport { mkdir, writeFile } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\n\nconst pages = ${JSON.stringify(a11yRoutes)};\nconst OUTPUT = process.env.REDDOOR_A11Y_OUTPUT;\n\n// Playwright's default per-test timeout is 30s. We loop through every\n// configured route in a single test, so the budget needs to scale.\ntest.setTimeout(5 * 60_000);\n\ntest(\"a11y across configured routes\", async ({ page }) => {\n const violations = [];\n for (const { path, name } of pages) {\n await page.goto(path);\n const results = await new AxeBuilder({ page })\n .withTags([\"wcag2a\",\"wcag2aa\",\"wcag21a\",\"wcag21aa\",\"wcag22aa\"])\n .analyze();\n for (const v of results.violations) {\n violations.push({\n id: v.id,\n impact: v.impact ?? \"moderate\",\n route: name,\n help: v.help,\n helpUrl: v.helpUrl,\n nodes: v.nodes.map((n) => ({ html: n.html, target: n.target })),\n });\n }\n }\n const byImpact = {};\n for (const v of violations) {\n byImpact[v.impact] = (byImpact[v.impact] ?? 0) + 1;\n }\n if (OUTPUT) {\n await mkdir(dirname(OUTPUT), { recursive: true });\n await writeFile(\n OUTPUT,\n JSON.stringify({ totalViolations: violations.length, byImpact, violations }, null, 2),\n );\n }\n expect(violations).toEqual([]);\n});\n`;\n}\n\nexport async function a11yAudit(ctx: AuditContext): Promise<AuditResult> {\n const spawn = ctx.spawn ?? defaultSpawn;\n const site = ctx.site;\n const label = siteLabel(site);\n\n const specDir = await mkdtemp(join(tmpdir(), \"reddoor-a11y-spec-\"));\n const specPath = join(specDir, \"a11y.spec.ts\");\n await writeFile(specPath, buildSpec(), \"utf-8\");\n\n const resultsPath = join(site.path, RESULTS_REL);\n // Clear stale artifacts so a failed spawn never reports old data.\n await rm(join(site.path, \".reddoor-a11y\"), { recursive: true, force: true });\n\n let raw;\n try {\n raw = await spawn(\"npx\", [\"--yes\", \"playwright\", \"test\", \"--reporter=line\", specPath], {\n cwd: site.path,\n env: { ...process.env, REDDOOR_A11Y_OUTPUT: resultsPath },\n });\n } catch (err) {\n await rm(specDir, { recursive: true, force: true });\n const e = err as NodeJS.ErrnoException;\n if (e.code === \"ENOENT\" || /ENOENT/.test(String(err))) {\n return {\n audit: \"a11y\",\n site: label,\n status: \"skip\",\n summary: \"npx/playwright not available\",\n };\n }\n throw err;\n }\n await rm(specDir, { recursive: true, force: true });\n\n const artifact = await readJsonMaybe<NormalizedA11y>(resultsPath);\n\n if (!artifact) {\n return {\n audit: \"a11y\",\n site: label,\n status: \"fail\",\n summary: `a11y: no results written (exit ${raw.code})${\n raw.stderr ? ` — ${raw.stderr.slice(0, 200)}` : \"\"\n }`,\n };\n }\n\n const hasSerious = (artifact.byImpact.serious ?? 0) > 0 || (artifact.byImpact.critical ?? 0) > 0;\n const hasAny = artifact.totalViolations > 0;\n\n const status: AuditResult[\"status\"] = hasSerious ? \"fail\" : hasAny ? \"warn\" : \"pass\";\n const summary =\n status === \"pass\"\n ? `a11y: 0 violations across ${a11yRoutes.length} routes`\n : `a11y: ${artifact.totalViolations} violations`;\n\n return {\n audit: \"a11y\",\n site: label,\n status,\n summary,\n details: artifact,\n };\n}\n","import { defineConfig, devices, type PlaywrightTestConfig } from \"@playwright/test\";\n\nexport type A11yRoute = { path: string; name: string };\n\nexport const a11yRoutes: A11yRoute[] = [\n { path: \"/dev/a11y-fixtures\", name: \"a11y fixtures\" },\n { path: \"/dev/animate-in\", name: \"animate-in demo\" },\n];\n\nexport const playwrightA11yConfig: PlaywrightTestConfig = defineConfig({\n testDir: \"tests\",\n testMatch: /.*\\.spec\\.ts$/,\n fullyParallel: true,\n forbidOnly: !!process.env.CI,\n retries: process.env.CI ? 2 : 0,\n reporter: process.env.CI ? \"github\" : \"list\",\n use: {\n baseURL: \"http://localhost:5173\",\n trace: \"on-first-retry\",\n },\n projects: [\n {\n name: \"chromium\",\n use: { ...devices[\"Desktop Chrome\"] },\n },\n ],\n webServer: {\n command: \"pnpm vite:dev\",\n url: \"http://localhost:5173/dev/a11y-fixtures\",\n reuseExistingServer: !process.env.CI,\n timeout: 120_000,\n },\n});\n\nexport default playwrightA11yConfig;\n","import type { AuditName, AuditResult, Site } from \"../types.js\";\nimport type { AuditContext } from \"./util/inject.js\";\nimport { defaultSpawn } from \"./util/spawn.js\";\nimport type { SpawnFn } from \"./util/spawn.js\";\nimport { depsAudit } from \"./deps.js\";\nimport { lintAudit } from \"./lint.js\";\nimport { securityAudit } from \"./security.js\";\nimport { lighthouseAudit } from \"./lighthouse.js\";\nimport { a11yAudit } from \"./a11y.js\";\n\nconst REGISTRY: Record<AuditName, (ctx: AuditContext) => Promise<AuditResult>> = {\n deps: depsAudit,\n lint: lintAudit,\n security: securityAudit,\n lighthouse: lighthouseAudit,\n a11y: a11yAudit,\n};\n\nexport const ALL_AUDIT_NAMES = Object.keys(REGISTRY) as AuditName[];\n\n/** Default per-audit spawn timeout when running via runAudits (30 s). */\nconst DEFAULT_AUDIT_TIMEOUT_MS = 30_000;\n\nfunction timedSpawn(timeoutMs: number): SpawnFn {\n return (cmd, args, opts = {}) =>\n defaultSpawn(cmd, args, { ...opts, timeoutMs: opts.timeoutMs ?? timeoutMs });\n}\n\nexport async function runAudits(site: Site, which?: AuditName[]): Promise<AuditResult[]> {\n const names = which ?? ALL_AUDIT_NAMES;\n for (const n of names) {\n if (!(n in REGISTRY)) throw new Error(`unknown audit: ${n}`);\n }\n const spawn = timedSpawn(DEFAULT_AUDIT_TIMEOUT_MS);\n const label = site.name ?? site.path;\n return Promise.all(\n names.map((n) =>\n REGISTRY[n]({ site, spawn }).catch(\n (err): AuditResult => ({\n audit: n,\n site: label,\n status: \"fail\",\n summary: `${n}: unexpected error — ${String(err)}`,\n }),\n ),\n ),\n );\n}\n\nexport async function runAuditsAcross(sites: Site[], which?: AuditName[]): Promise<AuditResult[]> {\n const all = await Promise.all(sites.map((s) => runAudits(s, which)));\n return all.flat();\n}\n\nexport { depsAudit, lintAudit, securityAudit, lighthouseAudit, a11yAudit };\n","import { pathToFileURL } from \"node:url\";\nimport { resolve, extname } from \"node:path\";\nimport type { InventoryProvider, Site } from \"../../types.js\";\nimport { localPath } from \"../../inventory/local.js\";\nimport { fromJsonFile } from \"../../inventory/json.js\";\n\nexport type ResolveSitesInput = {\n site?: string;\n fleet?: string;\n cwd: string;\n};\n\nexport async function resolveSites(input: ResolveSitesInput): Promise<Site[]> {\n if (input.site && input.fleet) {\n throw Object.assign(new Error(\"cannot combine a positional [site] with --fleet\"), {\n exitCode: 2,\n });\n }\n\n if (input.fleet) {\n const fleetPath = resolve(input.cwd, input.fleet);\n const ext = extname(fleetPath).toLowerCase();\n let provider: InventoryProvider;\n if (ext === \".json\") {\n provider = fromJsonFile(fleetPath);\n } else if (ext === \".js\" || ext === \".mjs\" || ext === \".cjs\") {\n const mod = (await import(pathToFileURL(fleetPath).href)) as {\n default?: InventoryProvider;\n };\n if (!mod.default || typeof mod.default !== \"function\") {\n throw Object.assign(new Error(`--fleet ${input.fleet}: default export is not a function`), {\n exitCode: 2,\n });\n }\n provider = mod.default;\n } else {\n throw Object.assign(\n new Error(`--fleet ${input.fleet}: unsupported extension ${ext || \"(none)\"}`),\n { exitCode: 2 },\n );\n }\n return provider();\n }\n\n return localPath(resolve(input.cwd, input.site ?? input.cwd))();\n}\n","import { basename } from \"node:path\";\nimport type { InventoryProvider, Site } from \"../types.js\";\n\nexport type LocalPathOptions = {\n name?: string;\n};\n\nexport function localPath(path: string, opts: LocalPathOptions = {}): InventoryProvider {\n const site: Site = { path, name: opts.name ?? basename(path) };\n return async () => [site];\n}\n","import { readFile } from \"node:fs/promises\";\nimport { isAbsolute } from \"node:path\";\nimport type { InventoryProvider, Site } from \"../types.js\";\n\nfunction validate(raw: unknown): Site[] {\n if (!Array.isArray(raw)) {\n throw new Error(\"inventory JSON must be an array of sites\");\n }\n return raw.map((entry, i) => {\n if (!entry || typeof entry !== \"object\") {\n throw new Error(`inventory entry ${i} is not an object`);\n }\n const e = entry as Record<string, unknown>;\n if (typeof e.path !== \"string\" || e.path.length === 0) {\n throw new Error(`inventory entry ${i} is missing required field: path`);\n }\n if (!isAbsolute(e.path)) {\n throw new Error(\n `inventory entry ${i}: path must be absolute (got \"${e.path}\"). ` +\n `Relative paths are rejected so cwd at invocation can't change which site is targeted.`,\n );\n }\n const site: Site = { path: e.path };\n if (typeof e.name === \"string\") site.name = e.name;\n if (typeof e.repoUrl === \"string\") site.repoUrl = e.repoUrl;\n if (typeof e.meta === \"object\" && e.meta !== null) {\n site.meta = e.meta as Record<string, unknown>;\n }\n return site;\n });\n}\n\nexport function fromJsonFile(path: string): InventoryProvider {\n return async () => {\n const raw = JSON.parse(await readFile(path, \"utf-8\")) as unknown;\n return validate(raw);\n };\n}\n","import { stat, readdir, mkdir } from \"node:fs/promises\";\nimport { isAbsolute, join } from \"node:path\";\nimport type { Site } from \"../../types.js\";\nimport { defaultSpawn, type SpawnFn } from \"../../audits/util/spawn.js\";\n\nexport type CloneIfNeededOptions = {\n workdir: string;\n spawn?: SpawnFn;\n};\n\nfunction deriveNameFromRepoUrl(repoUrl: string): string {\n const slash = repoUrl.split(\"/\").pop() ?? repoUrl;\n return slash.replace(/\\.git$/, \"\");\n}\n\n/** Reject names that would let an inventory entry write outside `workdir`. */\nfunction assertSafeName(name: string): void {\n if (isAbsolute(name)) {\n throw new Error(`unsafe site name (absolute path not allowed): ${name}`);\n }\n if (name.includes(\"/\") || name.includes(\"\\\\\")) {\n throw new Error(`unsafe site name (path separator not allowed): ${name}`);\n }\n if (name.split(/[\\\\/]/).some((seg) => seg === \"..\")) {\n throw new Error(`unsafe site name (traversal segment not allowed): ${name}`);\n }\n}\n\nasync function isNonEmptyDir(path: string): Promise<boolean> {\n try {\n const s = await stat(path);\n if (!s.isDirectory()) return false;\n const entries = await readdir(path);\n return entries.length > 0;\n } catch {\n return false;\n }\n}\n\nexport async function cloneIfNeeded(site: Site, opts: CloneIfNeededOptions): Promise<Site> {\n if (await isNonEmptyDir(site.path)) return site;\n\n if (!site.repoUrl) {\n throw new Error(`site path does not exist (${site.path}) and no repoUrl is set — cannot clone`);\n }\n\n const name = site.name ?? deriveNameFromRepoUrl(site.repoUrl);\n assertSafeName(name);\n const target = join(opts.workdir, name);\n await mkdir(opts.workdir, { recursive: true });\n\n if (await isNonEmptyDir(target)) {\n return { ...site, name, path: target };\n }\n\n const spawn = opts.spawn ?? defaultSpawn;\n const result = await spawn(\"git\", [\"clone\", site.repoUrl, target], {\n cwd: opts.workdir,\n timeoutMs: 5 * 60_000,\n });\n if (result.code !== 0) {\n throw new Error(`git clone failed (code ${result.code}): ${result.stderr}`);\n }\n return { ...site, name, path: target };\n}\n"],"mappings":"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","names":["resolve","resolve","readFile","join","siteLabel","siteLabel","spawn","readFile","join","siteLabel","readFile","spawn","join","readFile","writeFile","mkdtemp","rm","tmpdir","join","siteLabel","readJsonMaybe","readFile","spawn","mkdtemp","join","tmpdir","writeFile","rm","spawn","readFile","isAbsolute","join","isAbsolute","join","spawn","resolve"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -6,11 +6,16 @@ type SpawnResult = {
|
|
|
6
6
|
stdout: string;
|
|
7
7
|
stderr: string;
|
|
8
8
|
};
|
|
9
|
-
type
|
|
9
|
+
type SpawnOptions = {
|
|
10
10
|
cwd?: string;
|
|
11
11
|
env?: NodeJS.ProcessEnv;
|
|
12
12
|
timeoutMs?: number;
|
|
13
|
-
|
|
13
|
+
/** When true, the child inherits stdout/stderr so the user sees live
|
|
14
|
+
* progress (useful for long-running `pnpm up` / `npm install`). The
|
|
15
|
+
* returned `stdout` and `stderr` will be empty strings in that case. */
|
|
16
|
+
streaming?: boolean;
|
|
17
|
+
};
|
|
18
|
+
type SpawnFn = (cmd: string, args: readonly string[], opts?: SpawnOptions) => Promise<SpawnResult>;
|
|
14
19
|
|
|
15
20
|
type AuditContext = {
|
|
16
21
|
site: Site;
|