@reddoorla/maintenance 0.10.7 → 0.11.1
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 +8 -1
- package/dist/cli/bin.js.map +1 -1
- package/dist/cli/commands/audit.js +8 -1
- package/dist/cli/commands/audit.js.map +1 -1
- package/dist/index.d.ts +31 -1
- package/dist/index.js +100 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2216,7 +2216,13 @@ function mapRow(rec) {
|
|
|
2216
2216
|
rScore: f["rScore"] ?? null,
|
|
2217
2217
|
bpScore: f["bpScore"] ?? null,
|
|
2218
2218
|
seoScore: f["seoScore"] ?? null,
|
|
2219
|
-
lastLighthouseAuditAt: f["Last lighthouse audit at"] ?? null
|
|
2219
|
+
lastLighthouseAuditAt: f["Last lighthouse audit at"] ?? null,
|
|
2220
|
+
dashboardToken: (() => {
|
|
2221
|
+
const raw = f["Dashboard Token"];
|
|
2222
|
+
if (typeof raw !== "string") return null;
|
|
2223
|
+
const trimmed = raw.trim();
|
|
2224
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
2225
|
+
})()
|
|
2220
2226
|
};
|
|
2221
2227
|
}
|
|
2222
2228
|
async function listWebsites(base) {
|
|
@@ -2921,6 +2927,96 @@ function findDueReports(websites, reports, today) {
|
|
|
2921
2927
|
}
|
|
2922
2928
|
return out;
|
|
2923
2929
|
}
|
|
2930
|
+
|
|
2931
|
+
// src/dashboard/render.ts
|
|
2932
|
+
function escapeHtml(s) {
|
|
2933
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
2934
|
+
}
|
|
2935
|
+
function safeUrl(raw) {
|
|
2936
|
+
try {
|
|
2937
|
+
const u = new URL(raw);
|
|
2938
|
+
if (u.protocol === "http:" || u.protocol === "https:") return raw;
|
|
2939
|
+
} catch {
|
|
2940
|
+
}
|
|
2941
|
+
return "#";
|
|
2942
|
+
}
|
|
2943
|
+
function scoreTile(label, value) {
|
|
2944
|
+
const display = value === null ? "\u2014" : String(value);
|
|
2945
|
+
return `<div class="tile"><div class="tile-value">${escapeHtml(display)}</div><div class="tile-label">${escapeHtml(label)}</div></div>`;
|
|
2946
|
+
}
|
|
2947
|
+
function reportRow(r) {
|
|
2948
|
+
const date = r.completedOn ? escapeHtml(r.completedOn) : "\u2014";
|
|
2949
|
+
const type = escapeHtml(r.reportType);
|
|
2950
|
+
const id = escapeHtml(r.reportId);
|
|
2951
|
+
const link = r.renderedHtmlAttachment ? `<a href="${escapeHtml(safeUrl(r.renderedHtmlAttachment.url))}">view</a>` : `<span class="muted">no attachment</span>`;
|
|
2952
|
+
return `<tr><td>${date}</td><td>${type}</td><td><code>${id}</code></td><td>${link}</td></tr>`;
|
|
2953
|
+
}
|
|
2954
|
+
var STYLES = `
|
|
2955
|
+
:root { color-scheme: light dark; }
|
|
2956
|
+
body { font: 16px/1.5 system-ui, -apple-system, sans-serif; max-width: 860px; margin: 2rem auto; padding: 0 1rem; color: #1a1a1a; }
|
|
2957
|
+
@media (prefers-color-scheme: dark) { body { color: #e8e8e8; background: #111; } a { color: #6cb6ff; } }
|
|
2958
|
+
h1 { margin: 0 0 0.25rem; font-size: 1.75rem; }
|
|
2959
|
+
.meta { color: #666; margin-bottom: 2rem; }
|
|
2960
|
+
.meta a { color: inherit; }
|
|
2961
|
+
.section { margin: 2rem 0; }
|
|
2962
|
+
.section h2 { font-size: 1.1rem; margin: 0 0 0.75rem; text-transform: uppercase; letter-spacing: 0.05em; color: #666; }
|
|
2963
|
+
.tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 0.75rem; }
|
|
2964
|
+
.tile { padding: 1rem; border: 1px solid #ddd; border-radius: 6px; text-align: center; }
|
|
2965
|
+
@media (prefers-color-scheme: dark) { .tile { border-color: #333; } }
|
|
2966
|
+
.tile-value { font-size: 2rem; font-weight: 600; }
|
|
2967
|
+
.tile-label { font-size: 0.85rem; color: #666; margin-top: 0.25rem; }
|
|
2968
|
+
table { width: 100%; border-collapse: collapse; }
|
|
2969
|
+
th, td { text-align: left; padding: 0.5rem; border-bottom: 1px solid #eee; }
|
|
2970
|
+
@media (prefers-color-scheme: dark) { th, td { border-color: #2a2a2a; } }
|
|
2971
|
+
.muted { color: #999; }
|
|
2972
|
+
.empty { color: #999; padding: 1rem; border: 1px dashed #ccc; border-radius: 6px; text-align: center; }
|
|
2973
|
+
`;
|
|
2974
|
+
function renderSiteDashboardHtml(site, reports) {
|
|
2975
|
+
const name = escapeHtml(site.name);
|
|
2976
|
+
const urlSafe = safeUrl(site.url);
|
|
2977
|
+
const allScoresNull = site.pScore === null && site.rScore === null && site.bpScore === null && site.seoScore === null;
|
|
2978
|
+
const scoresSection = allScoresNull ? `<div class="empty">No lighthouse data yet \u2014 run <code>reddoor-maint audit --write-airtable</code> from the site checkout.</div>` : `<div class="tiles">
|
|
2979
|
+
${scoreTile("Performance", site.pScore)}
|
|
2980
|
+
${scoreTile("Accessibility", site.rScore)}
|
|
2981
|
+
${scoreTile("Best Practices", site.bpScore)}
|
|
2982
|
+
${scoreTile("SEO", site.seoScore)}
|
|
2983
|
+
</div>`;
|
|
2984
|
+
const reportsSection = reports.length === 0 ? `<div class="empty">No reports yet.</div>` : `<table>
|
|
2985
|
+
<thead><tr><th>Completed</th><th>Type</th><th>ID</th><th>Report</th></tr></thead>
|
|
2986
|
+
<tbody>${reports.map(reportRow).join("")}</tbody>
|
|
2987
|
+
</table>`;
|
|
2988
|
+
return `<!doctype html>
|
|
2989
|
+
<html lang="en">
|
|
2990
|
+
<head>
|
|
2991
|
+
<meta charset="utf-8" />
|
|
2992
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
2993
|
+
<title>${name} \u2014 Reddoor maintenance</title>
|
|
2994
|
+
<style>${STYLES}</style>
|
|
2995
|
+
</head>
|
|
2996
|
+
<body>
|
|
2997
|
+
<h1>${name}</h1>
|
|
2998
|
+
<div class="meta"><a href="${escapeHtml(urlSafe)}">${escapeHtml(site.url)}</a></div>
|
|
2999
|
+
|
|
3000
|
+
<div class="section">
|
|
3001
|
+
<h2>Lighthouse</h2>
|
|
3002
|
+
${scoresSection}
|
|
3003
|
+
</div>
|
|
3004
|
+
|
|
3005
|
+
<div class="section">
|
|
3006
|
+
<h2>Reports</h2>
|
|
3007
|
+
${reportsSection}
|
|
3008
|
+
</div>
|
|
3009
|
+
</body>
|
|
3010
|
+
</html>`;
|
|
3011
|
+
}
|
|
3012
|
+
|
|
3013
|
+
// src/dashboard/auth.ts
|
|
3014
|
+
import { timingSafeEqual } from "crypto";
|
|
3015
|
+
function verifyDashboardToken(provided, expected) {
|
|
3016
|
+
if (!provided || !expected) return false;
|
|
3017
|
+
if (provided.length !== expected.length) return false;
|
|
3018
|
+
return timingSafeEqual(Buffer.from(provided, "utf-8"), Buffer.from(expected, "utf-8"));
|
|
3019
|
+
}
|
|
2924
3020
|
export {
|
|
2925
3021
|
ALL_AUDIT_NAMES,
|
|
2926
3022
|
ALL_RECIPE_NAMES,
|
|
@@ -2944,6 +3040,7 @@ export {
|
|
|
2944
3040
|
localPath,
|
|
2945
3041
|
onboard,
|
|
2946
3042
|
renderReportHtml,
|
|
3043
|
+
renderSiteDashboardHtml,
|
|
2947
3044
|
runAudits,
|
|
2948
3045
|
runAuditsAcross,
|
|
2949
3046
|
securityAudit,
|
|
@@ -2952,6 +3049,7 @@ export {
|
|
|
2952
3049
|
sendApprovedReports,
|
|
2953
3050
|
svelteCodemods,
|
|
2954
3051
|
syncConfigs,
|
|
2955
|
-
upgradeSvelte4to5
|
|
3052
|
+
upgradeSvelte4to5,
|
|
3053
|
+
verifyDashboardToken
|
|
2956
3054
|
};
|
|
2957
3055
|
//# sourceMappingURL=index.js.map
|