@reddoorla/maintenance 0.12.1 → 0.14.0

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.
@@ -39,7 +39,10 @@ __export(websites_exports, {
39
39
  listWebsites: () => listWebsites,
40
40
  mapRow: () => mapRow,
41
41
  siteSlug: () => siteSlug,
42
- updateScores: () => updateScores
42
+ updateA11yCounts: () => updateA11yCounts,
43
+ updateDepsCounts: () => updateDepsCounts,
44
+ updateScores: () => updateScores,
45
+ updateSecurityCounts: () => updateSecurityCounts
43
46
  });
44
47
  function siteSlug(name) {
45
48
  return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
@@ -67,6 +70,13 @@ function mapRow(rec) {
67
70
  bpScore: f["bpScore"] ?? null,
68
71
  seoScore: f["seoScore"] ?? null,
69
72
  lastLighthouseAuditAt: f["Last lighthouse audit at"] ?? null,
73
+ a11yViolations: f["A11y Violations"] ?? null,
74
+ depsDrifted: f["Deps Drifted"] ?? null,
75
+ depsMajorBehind: f["Deps Major Behind"] ?? null,
76
+ securityVulnsCritical: f["Security Vulns Critical"] ?? null,
77
+ securityVulnsHigh: f["Security Vulns High"] ?? null,
78
+ securityVulnsModerate: f["Security Vulns Moderate"] ?? null,
79
+ securityVulnsLow: f["Security Vulns Low"] ?? null,
70
80
  dashboardToken: (() => {
71
81
  const raw = f["Dashboard Token"];
72
82
  if (typeof raw !== "string") return null;
@@ -97,6 +107,28 @@ async function updateScores(base, recordId, scores) {
97
107
  };
98
108
  await base(WEBSITES_TABLE).update([{ id: recordId, fields }]);
99
109
  }
110
+ async function updateA11yCounts(base, recordId, counts) {
111
+ const fields = {
112
+ "A11y Violations": counts.violations
113
+ };
114
+ await base(WEBSITES_TABLE).update([{ id: recordId, fields }]);
115
+ }
116
+ async function updateDepsCounts(base, recordId, counts) {
117
+ const fields = {
118
+ "Deps Drifted": counts.drifted,
119
+ "Deps Major Behind": counts.majorBehind
120
+ };
121
+ await base(WEBSITES_TABLE).update([{ id: recordId, fields }]);
122
+ }
123
+ async function updateSecurityCounts(base, recordId, counts) {
124
+ const fields = {
125
+ "Security Vulns Critical": counts.critical,
126
+ "Security Vulns High": counts.high,
127
+ "Security Vulns Moderate": counts.moderate,
128
+ "Security Vulns Low": counts.low
129
+ };
130
+ await base(WEBSITES_TABLE).update([{ id: recordId, fields }]);
131
+ }
100
132
  var WEBSITES_TABLE;
101
133
  var init_websites = __esm({
102
134
  "src/reports/airtable/websites.ts"() {
@@ -192,6 +224,128 @@ var init_lighthouse_airtable = __esm({
192
224
  }
193
225
  });
194
226
 
227
+ // src/audits/a11y-airtable.ts
228
+ function hasA11yCounts(result) {
229
+ if (result.audit !== "a11y") return false;
230
+ const details = result.details;
231
+ return typeof details?.totalViolations === "number";
232
+ }
233
+ function a11yCountsFromResult(result) {
234
+ if (result.audit !== "a11y") {
235
+ throw new Error(`Expected an 'a11y' AuditResult, got '${result.audit}'`);
236
+ }
237
+ const details = result.details;
238
+ return { violations: details?.totalViolations ?? 0 };
239
+ }
240
+ var init_a11y_airtable = __esm({
241
+ "src/audits/a11y-airtable.ts"() {
242
+ "use strict";
243
+ }
244
+ });
245
+
246
+ // src/audits/deps-airtable.ts
247
+ function hasDepsCounts(result) {
248
+ if (result.audit !== "deps") return false;
249
+ return Array.isArray(result.details);
250
+ }
251
+ function depsCountsFromResult(result) {
252
+ if (result.audit !== "deps") {
253
+ throw new Error(`Expected a 'deps' AuditResult, got '${result.audit}'`);
254
+ }
255
+ const entries = result.details ?? [];
256
+ const drifted = entries.filter((e) => e.drift !== "same").length;
257
+ const majorBehind = entries.filter((e) => e.drift === "major").length;
258
+ return { drifted, majorBehind };
259
+ }
260
+ var init_deps_airtable = __esm({
261
+ "src/audits/deps-airtable.ts"() {
262
+ "use strict";
263
+ }
264
+ });
265
+
266
+ // src/audits/security-airtable.ts
267
+ function hasSecurityCounts(result) {
268
+ if (result.audit !== "security") return false;
269
+ const details = result.details;
270
+ return !!details && typeof details.counts === "object";
271
+ }
272
+ function securityCountsFromResult(result) {
273
+ if (result.audit !== "security") {
274
+ throw new Error(`Expected a 'security' AuditResult, got '${result.audit}'`);
275
+ }
276
+ const details = result.details;
277
+ const c = details?.counts ?? { low: 0, moderate: 0, high: 0, critical: 0 };
278
+ return { critical: c.critical, high: c.high, moderate: c.moderate, low: c.low };
279
+ }
280
+ var init_security_airtable = __esm({
281
+ "src/audits/security-airtable.ts"() {
282
+ "use strict";
283
+ }
284
+ });
285
+
286
+ // src/audits/write-audits-to-airtable.ts
287
+ var write_audits_to_airtable_exports = {};
288
+ __export(write_audits_to_airtable_exports, {
289
+ writeAuditsToAirtable: () => writeAuditsToAirtable
290
+ });
291
+ async function writeAuditsToAirtable(args) {
292
+ const { base, websites, slug, results } = args;
293
+ const lhResult = results.find((r) => r.audit === "lighthouse");
294
+ if (!lhResult) {
295
+ throw Object.assign(
296
+ new Error(
297
+ "--write-airtable requires a lighthouse result; did you pass --only without lighthouse?"
298
+ ),
299
+ { exitCode: 2 }
300
+ );
301
+ }
302
+ if (!hasRealScores(lhResult)) {
303
+ throw Object.assign(
304
+ new Error(
305
+ `Lighthouse audit produced no scores; refusing to write to Airtable. Summary: ${lhResult.summary}`
306
+ ),
307
+ { exitCode: 1 }
308
+ );
309
+ }
310
+ const target = websites.find((w) => siteSlug(w.name) === slug);
311
+ if (!target) {
312
+ throw Object.assign(new Error(`No Websites row matched slug "${slug}"`), { exitCode: 2 });
313
+ }
314
+ const writes = [];
315
+ const scores = lighthouseScoresFromResult(lhResult);
316
+ await updateScores(base, target.id, scores);
317
+ writes.push({ audit: "lighthouse", counts: scores });
318
+ const a11y = results.find((r) => r.audit === "a11y");
319
+ if (a11y && hasA11yCounts(a11y)) {
320
+ const counts = a11yCountsFromResult(a11y);
321
+ await updateA11yCounts(base, target.id, counts);
322
+ writes.push({ audit: "a11y", counts });
323
+ }
324
+ const deps = results.find((r) => r.audit === "deps");
325
+ if (deps && hasDepsCounts(deps)) {
326
+ const counts = depsCountsFromResult(deps);
327
+ await updateDepsCounts(base, target.id, counts);
328
+ writes.push({ audit: "deps", counts });
329
+ }
330
+ const sec = results.find((r) => r.audit === "security");
331
+ if (sec && hasSecurityCounts(sec)) {
332
+ const counts = securityCountsFromResult(sec);
333
+ await updateSecurityCounts(base, target.id, counts);
334
+ writes.push({ audit: "security", counts });
335
+ }
336
+ return { siteName: target.name, writes };
337
+ }
338
+ var init_write_audits_to_airtable = __esm({
339
+ "src/audits/write-audits-to-airtable.ts"() {
340
+ "use strict";
341
+ init_websites();
342
+ init_lighthouse_airtable();
343
+ init_a11y_airtable();
344
+ init_deps_airtable();
345
+ init_security_airtable();
346
+ }
347
+ });
348
+
195
349
  // src/cli/commands/audit.ts
196
350
  import { resolve as resolve2 } from "path";
197
351
 
@@ -236,39 +390,39 @@ function siteLabel(site) {
236
390
  // src/configs/baseline-versions.ts
237
391
  var baselineVersions = {
238
392
  // SvelteKit core
239
- svelte: "^5.55.5",
240
- "@sveltejs/kit": "^2.59.0",
393
+ svelte: "^5.55.10",
394
+ "@sveltejs/kit": "^2.61.1",
241
395
  "@sveltejs/adapter-netlify": "^6.0.4",
242
- "@sveltejs/adapter-auto": "^7.0.0",
243
- "@sveltejs/vite-plugin-svelte": "^7.0.0",
244
- "svelte-check": "^4.4.7",
396
+ "@sveltejs/adapter-auto": "^7.0.1",
397
+ "@sveltejs/vite-plugin-svelte": "^7.1.2",
398
+ "svelte-check": "^4.4.8",
245
399
  // Build tooling
246
- vite: "^8.0.10",
247
- vitest: "^4.1.1",
400
+ vite: "^8.0.14",
401
+ vitest: "^4.1.7",
248
402
  typescript: "^6.0.3",
249
403
  // Tailwind 4
250
- tailwindcss: "^4.0.14",
404
+ tailwindcss: "^4.3.0",
251
405
  "@tailwindcss/vite": "^4.3.0",
252
406
  // Prismic
253
- "@prismicio/client": "^7.3.1",
254
- "@prismicio/svelte": "^2.0.0",
255
- "@slicemachine/adapter-sveltekit": "^0.3.36",
256
- "slice-machine-ui": "^2.11.1",
407
+ "@prismicio/client": "^7.21.8",
408
+ "@prismicio/svelte": "^2.2.1",
409
+ "@slicemachine/adapter-sveltekit": "^0.3.96",
410
+ "slice-machine-ui": "^2.21.3",
257
411
  // Test tooling
258
- "@playwright/test": "^1.59.1",
412
+ "@playwright/test": "^1.60.0",
259
413
  "@axe-core/playwright": "^4.11.3",
260
414
  "@lhci/cli": "^0.15.1",
261
415
  // Lint
262
- eslint: "^10.3.0",
263
- "eslint-plugin-svelte": "^3.1.0",
264
- "eslint-config-prettier": "^10.1.1",
265
- prettier: "^3.1.1",
266
- "prettier-plugin-svelte": "^3.2.6",
267
- "typescript-eslint": "^8.59.1",
416
+ eslint: "^10.4.0",
417
+ "eslint-plugin-svelte": "^3.18.0",
418
+ "eslint-config-prettier": "^10.1.8",
419
+ prettier: "^3.8.3",
420
+ "prettier-plugin-svelte": "^4.0.1",
421
+ "typescript-eslint": "^8.60.0",
268
422
  "@eslint/js": "^10.0.1",
269
423
  globals: "^17.6.0",
270
424
  // Misc
271
- "@lucide/svelte": "^1.14.0",
425
+ "@lucide/svelte": "^1.17.0",
272
426
  "@zerodevx/svelte-img": "^2.1.2"
273
427
  };
274
428
 
@@ -1155,37 +1309,32 @@ async function runAuditCommand(site, opts) {
1155
1309
  let output = opts.json ? JSON.stringify(results, null, 2) : formatTable(results);
1156
1310
  if (opts.writeAirtable !== void 0) {
1157
1311
  const { openBase: openBase2, readAirtableConfig: readAirtableConfig2 } = await Promise.resolve().then(() => (init_client(), client_exports));
1158
- const { listWebsites: listWebsites2, updateScores: updateScores2, siteSlug: siteSlug2 } = await Promise.resolve().then(() => (init_websites(), websites_exports));
1159
- const { lighthouseScoresFromResult: lighthouseScoresFromResult2, hasRealScores: hasRealScores2, resolveSlugFromCwd: resolveSlugFromCwd2 } = await Promise.resolve().then(() => (init_lighthouse_airtable(), lighthouse_airtable_exports));
1312
+ const { listWebsites: listWebsites2 } = await Promise.resolve().then(() => (init_websites(), websites_exports));
1313
+ const { resolveSlugFromCwd: resolveSlugFromCwd2 } = await Promise.resolve().then(() => (init_lighthouse_airtable(), lighthouse_airtable_exports));
1314
+ const { writeAuditsToAirtable: writeAuditsToAirtable2 } = await Promise.resolve().then(() => (init_write_audits_to_airtable(), write_audits_to_airtable_exports));
1160
1315
  const slug = typeof opts.writeAirtable === "string" && opts.writeAirtable.length > 0 ? opts.writeAirtable : await resolveSlugFromCwd2(cwd);
1161
- const lhResult = results.find((r) => r.audit === "lighthouse");
1162
- if (!lhResult) {
1163
- throw Object.assign(
1164
- new Error(
1165
- "--write-airtable requires a lighthouse result; did you pass --only without lighthouse?"
1166
- ),
1167
- { exitCode: 2 }
1168
- );
1169
- }
1170
- if (!hasRealScores2(lhResult)) {
1171
- throw Object.assign(
1172
- new Error(
1173
- `Lighthouse audit produced no scores; refusing to write to Airtable. Summary: ${lhResult.summary}`
1174
- ),
1175
- { exitCode: 1 }
1176
- );
1177
- }
1178
1316
  const base = openBase2(readAirtableConfig2());
1179
1317
  const websites = await listWebsites2(base);
1180
- const target = websites.find((w) => siteSlug2(w.name) === slug);
1181
- if (!target) {
1182
- throw Object.assign(new Error(`No Websites row matched slug "${slug}"`), { exitCode: 2 });
1183
- }
1184
- const scores = lighthouseScoresFromResult2(lhResult);
1185
- await updateScores2(base, target.id, scores);
1318
+ const summary = await writeAuditsToAirtable2({ base, websites, slug, results });
1319
+ const lines = summary.writes.map((w) => {
1320
+ if (w.audit === "lighthouse") {
1321
+ const s = w.counts;
1322
+ return ` lighthouse: P=${s.performance} A=${s.accessibility} BP=${s.bestPractices} SEO=${s.seo}`;
1323
+ }
1324
+ if (w.audit === "a11y") {
1325
+ return ` a11y: ${w.counts.violations} violations`;
1326
+ }
1327
+ if (w.audit === "deps") {
1328
+ const c2 = w.counts;
1329
+ return ` deps: ${c2.drifted} drifted (${c2.majorBehind} major)`;
1330
+ }
1331
+ const c = w.counts;
1332
+ return ` security: ${c.critical}C/${c.high}H/${c.moderate}M/${c.low}L`;
1333
+ });
1186
1334
  output += `
1187
1335
 
1188
- \u2192 wrote scores to Websites[${target.name}]: P=${scores.performance} A=${scores.accessibility} BP=${scores.bestPractices} SEO=${scores.seo}`;
1336
+ \u2192 wrote to Websites[${summary.siteName}]:
1337
+ ${lines.join("\n")}`;
1189
1338
  }
1190
1339
  return { output, code: exitCode(results) };
1191
1340
  }