@reddoorla/maintenance 0.42.0 → 0.44.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.
- package/dist/cli/bin.js +94 -16
- package/dist/cli/bin.js.map +1 -1
- package/dist/index.d.ts +17 -0
- package/dist/index.js +230 -45
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/bin.js
CHANGED
|
@@ -575,6 +575,44 @@ var init_write_audits_to_airtable = __esm({
|
|
|
575
575
|
}
|
|
576
576
|
});
|
|
577
577
|
|
|
578
|
+
// src/reports/checklist.ts
|
|
579
|
+
function checklistFor(type) {
|
|
580
|
+
return type === "Maintenance" ? MAINTENANCE_CHECKLIST : type === "Testing" ? TESTING_CHECKLIST : [];
|
|
581
|
+
}
|
|
582
|
+
function isChecklistComplete(report) {
|
|
583
|
+
return checklistFor(report.reportType).every((i) => report.checklist[i.field] === true);
|
|
584
|
+
}
|
|
585
|
+
var MAINTENANCE_CHECKLIST, TESTING_CHECKLIST, ALL_CHECKLIST_FIELDS;
|
|
586
|
+
var init_checklist = __esm({
|
|
587
|
+
"src/reports/checklist.ts"() {
|
|
588
|
+
"use strict";
|
|
589
|
+
MAINTENANCE_CHECKLIST = [
|
|
590
|
+
{ key: "deploy", label: "Deploy & Function Health", field: "Maint: Deploy & Function Health" },
|
|
591
|
+
{ key: "cms", label: "CMS Checked", field: "Maint: CMS Checked" },
|
|
592
|
+
{ key: "domain", label: "Domain, DNS & SSL", field: "Maint: Domain, DNS & SSL" },
|
|
593
|
+
{ key: "google", label: "Google Indexed", field: "Maint: Google Indexed" },
|
|
594
|
+
{ key: "security", label: "Security Updates", field: "Maint: Security Updates" },
|
|
595
|
+
{ key: "uptime", label: "Uptime Checked", field: "Maint: Uptime Checked" }
|
|
596
|
+
];
|
|
597
|
+
TESTING_CHECKLIST = [
|
|
598
|
+
{ key: "desktop", label: "Desktop Browsers", field: "Test: Desktop Browsers" },
|
|
599
|
+
{ key: "mobile", label: "Mobile Browsers", field: "Test: Mobile Browsers" },
|
|
600
|
+
{ key: "titles", label: "Page Titles & Meta", field: "Test: Page Titles & Meta" },
|
|
601
|
+
{ key: "links", label: "Links & Navigation", field: "Test: Links & Navigation" },
|
|
602
|
+
{ key: "forms", label: "Form Functionality", field: "Test: Form Functionality" },
|
|
603
|
+
{
|
|
604
|
+
key: "interactions",
|
|
605
|
+
label: "Interactions & Animations",
|
|
606
|
+
field: "Test: Interactions & Animations"
|
|
607
|
+
},
|
|
608
|
+
{ key: "updates", label: "Verified After Updates", field: "Test: Verified After Updates" }
|
|
609
|
+
];
|
|
610
|
+
ALL_CHECKLIST_FIELDS = [...MAINTENANCE_CHECKLIST, ...TESTING_CHECKLIST].map(
|
|
611
|
+
(i) => i.field
|
|
612
|
+
);
|
|
613
|
+
}
|
|
614
|
+
});
|
|
615
|
+
|
|
578
616
|
// src/reports/airtable/reports.ts
|
|
579
617
|
function toReportType(raw) {
|
|
580
618
|
if (raw && REPORT_TYPES.includes(raw)) return raw;
|
|
@@ -613,7 +651,8 @@ function mapRow2(rec) {
|
|
|
613
651
|
approvedBy: f["Approved By"] ?? null,
|
|
614
652
|
deliveryStatus: f["Delivery status"] ?? "pending",
|
|
615
653
|
renderedHtmlAttachment: html,
|
|
616
|
-
resendMessageId: f["Resend message ID"] ?? null
|
|
654
|
+
resendMessageId: f["Resend message ID"] ?? null,
|
|
655
|
+
checklist: Object.fromEntries(ALL_CHECKLIST_FIELDS.map((name) => [name, Boolean(f[name])]))
|
|
617
656
|
};
|
|
618
657
|
}
|
|
619
658
|
function lighthouseFromFields(f) {
|
|
@@ -717,6 +756,7 @@ var REPORTS_TABLE, REPORT_TYPES;
|
|
|
717
756
|
var init_reports = __esm({
|
|
718
757
|
"src/reports/airtable/reports.ts"() {
|
|
719
758
|
"use strict";
|
|
759
|
+
init_checklist();
|
|
720
760
|
REPORTS_TABLE = "Reports";
|
|
721
761
|
REPORT_TYPES = ["Maintenance", "Testing", "Launch", "Announcement"];
|
|
722
762
|
}
|
|
@@ -751,21 +791,22 @@ var init_copy = __esm({
|
|
|
751
791
|
DEFAULT_COPY = {
|
|
752
792
|
maintenanceIntro: "Includes checking the hosting, DNS, Content Management System (CMS, if applicable), search indexing and security of the site for major flaws and updating as necessary.",
|
|
753
793
|
maintenanceChecks: [
|
|
754
|
-
"
|
|
794
|
+
"Deploy & Function Health",
|
|
755
795
|
"CMS Checked",
|
|
756
|
-
"DNS
|
|
796
|
+
"Domain, DNS & SSL",
|
|
757
797
|
"Google Indexed",
|
|
758
|
-
"
|
|
759
|
-
"
|
|
798
|
+
"Security Updates",
|
|
799
|
+
"Uptime Checked"
|
|
760
800
|
],
|
|
761
801
|
testingIntro: "Testing includes checks similar to those at launch: testing on common browsers and operating systems, at different screen sizes, and checking every function, and updating all packages for performance rather than just those needed for security.",
|
|
762
802
|
testingChecklist: [
|
|
763
803
|
"Desktop Browsers",
|
|
764
804
|
"Mobile Browsers",
|
|
765
|
-
"
|
|
766
|
-
"
|
|
805
|
+
"Page Titles & Meta",
|
|
806
|
+
"Links & Navigation",
|
|
767
807
|
"Form Functionality",
|
|
768
|
-
"
|
|
808
|
+
"Interactions & Animations",
|
|
809
|
+
"Verified After Updates"
|
|
769
810
|
],
|
|
770
811
|
notesHeader: "NOTES",
|
|
771
812
|
seoCta: "Contact us if you are interested in more in-depth data or have questions about SEO.",
|
|
@@ -779,13 +820,16 @@ var init_copy = __esm({
|
|
|
779
820
|
"Continuous integration + automatic dependency updates",
|
|
780
821
|
"Analytics and uptime monitoring"
|
|
781
822
|
],
|
|
782
|
-
announceHeading: "YOUR
|
|
783
|
-
announceBody: "We've
|
|
823
|
+
announceHeading: "YOUR ONGOING SITE CARE",
|
|
824
|
+
announceBody: "We've completed a full test of your site and set it up for ongoing care to keep it fast, secure, and healthy. Here's what you can expect from us going forward:",
|
|
825
|
+
announceCadenceHeading: "WHAT TO EXPECT",
|
|
826
|
+
announceTestingLabel: "Full site testing",
|
|
827
|
+
announceMaintenanceLabel: "Routine maintenance",
|
|
784
828
|
announceMonitorItems: ["Performance", "Accessibility", "Security", "Uptime"],
|
|
785
|
-
announcePreviewLabel: "
|
|
829
|
+
announcePreviewLabel: "From your latest full site test:",
|
|
786
830
|
announceImprovementResend: "Your contact forms now deliver straight to your inbox through reliable infrastructure, so no inquiry slips through the cracks.",
|
|
787
831
|
announceImprovementSvelte5: "We've modernized your site to the latest framework \u2014 it's faster, more secure, and built to last.",
|
|
788
|
-
announceCadence: "
|
|
832
|
+
announceCadence: "After each one we'll send you a short report like this \u2014 there's nothing you need to do.",
|
|
789
833
|
announceOpenDoor: "And if you'd ever like to expand the scope, add features, or freshen anything up, just reply \u2014 we'd love to help."
|
|
790
834
|
};
|
|
791
835
|
}
|
|
@@ -1140,6 +1184,23 @@ function buildAnnouncementMjml(data) {
|
|
|
1140
1184
|
).join("")}
|
|
1141
1185
|
</mj-column>
|
|
1142
1186
|
</mj-section>` : "";
|
|
1187
|
+
const cad = data.cadence;
|
|
1188
|
+
const cadenceLines = [];
|
|
1189
|
+
if (cad && cad.testing !== "None")
|
|
1190
|
+
cadenceLines.push(`${copy.announceTestingLabel} \u2014 ${FREQ_PHRASE[cad.testing]}`);
|
|
1191
|
+
if (cad && cad.maintenance !== "None")
|
|
1192
|
+
cadenceLines.push(`${copy.announceMaintenanceLabel} \u2014 ${FREQ_PHRASE[cad.maintenance]}`);
|
|
1193
|
+
const cadenceSection = cadenceLines.length > 0 ? `
|
|
1194
|
+
<mj-section background-color="white">
|
|
1195
|
+
<mj-column>
|
|
1196
|
+
<mj-text color="${RED2}" font-size="20px" font-weight="700" padding-top="36px">${escapeXml(copy.announceCadenceHeading)}</mj-text>
|
|
1197
|
+
${cadenceLines.map(
|
|
1198
|
+
(line) => `
|
|
1199
|
+
<mj-text color="${GREY2}" font-family="helvetica, sans-serif" font-size="16px" font-weight="300" line-height="24px" padding-top="4px" padding-bottom="4px">\u2022 ${escapeXml(line)}</mj-text>`
|
|
1200
|
+
).join("")}
|
|
1201
|
+
<mj-text color="${GREY2}" font-family="helvetica, sans-serif" font-size="16px" font-weight="300" line-height="24px" padding-top="12px">${escapeXml(copy.announceCadence)}</mj-text>
|
|
1202
|
+
</mj-column>
|
|
1203
|
+
</mj-section>` : "";
|
|
1143
1204
|
const monitorRows = copy.announceMonitorItems.map(
|
|
1144
1205
|
(item) => `
|
|
1145
1206
|
<mj-text color="${GREY2}" font-family="helvetica, sans-serif" font-size="16px" font-weight="300" line-height="24px" padding-top="4px" padding-bottom="4px">\u2022 ${escapeXml(item)}</mj-text>`
|
|
@@ -1178,6 +1239,7 @@ function buildAnnouncementMjml(data) {
|
|
|
1178
1239
|
<mj-text color="${GREY2}" font-family="helvetica, sans-serif" font-size="16px" font-weight="300" line-height="24px" padding-top="8px">${escapeXml(copy.announceBody)}</mj-text>
|
|
1179
1240
|
</mj-column>
|
|
1180
1241
|
</mj-section>
|
|
1242
|
+
${cadenceSection}
|
|
1181
1243
|
${improvementsSection}
|
|
1182
1244
|
<mj-section background-color="white">
|
|
1183
1245
|
<mj-column>
|
|
@@ -1193,8 +1255,7 @@ function buildAnnouncementMjml(data) {
|
|
|
1193
1255
|
</mj-section>
|
|
1194
1256
|
<mj-section background-color="white">
|
|
1195
1257
|
<mj-column>
|
|
1196
|
-
<mj-text color="${GREY2}" font-family="helvetica, sans-serif" font-size="16px" font-weight="300" line-height="24px" padding-top="36px">${escapeXml(copy.
|
|
1197
|
-
<mj-text color="${GREY2}" font-family="helvetica, sans-serif" font-size="16px" font-weight="300" line-height="24px" padding-top="8px">${escapeXml(copy.announceOpenDoor)}</mj-text>
|
|
1258
|
+
<mj-text color="${GREY2}" font-family="helvetica, sans-serif" font-size="16px" font-weight="300" line-height="24px" padding-top="36px">${escapeXml(copy.announceOpenDoor)}</mj-text>
|
|
1198
1259
|
</mj-column>
|
|
1199
1260
|
</mj-section>
|
|
1200
1261
|
<mj-section background-color="white">
|
|
@@ -1211,12 +1272,17 @@ function buildAnnouncementMjml(data) {
|
|
|
1211
1272
|
</mj-body>
|
|
1212
1273
|
</mjml>`;
|
|
1213
1274
|
}
|
|
1214
|
-
var RED2, GREY2, SCORE_PREVIEW;
|
|
1275
|
+
var FREQ_PHRASE, RED2, GREY2, SCORE_PREVIEW;
|
|
1215
1276
|
var init_template3 = __esm({
|
|
1216
1277
|
"src/reports/announcement-email/template.ts"() {
|
|
1217
1278
|
"use strict";
|
|
1218
1279
|
init_copy();
|
|
1219
1280
|
init_template();
|
|
1281
|
+
FREQ_PHRASE = {
|
|
1282
|
+
Monthly: "every month",
|
|
1283
|
+
Quarterly: "every quarter",
|
|
1284
|
+
Yearly: "every year"
|
|
1285
|
+
};
|
|
1220
1286
|
RED2 = "#C00";
|
|
1221
1287
|
GREY2 = "#757575";
|
|
1222
1288
|
SCORE_PREVIEW = [
|
|
@@ -1827,6 +1893,13 @@ async function sendApprovedReports(options = {}) {
|
|
|
1827
1893
|
return { output: lines.join("\n"), code: anyFailed ? 1 : 0 };
|
|
1828
1894
|
}
|
|
1829
1895
|
async function sendOne(client, base, site, report) {
|
|
1896
|
+
if (!isChecklistComplete(report)) {
|
|
1897
|
+
const items = checklistFor(report.reportType);
|
|
1898
|
+
const done = items.filter((i) => report.checklist[i.field] === true).length;
|
|
1899
|
+
throw new Error(
|
|
1900
|
+
`Report ${report.reportId} checklist incomplete \u2014 ${done}/${items.length} items checked`
|
|
1901
|
+
);
|
|
1902
|
+
}
|
|
1830
1903
|
if (!site.headerImage) {
|
|
1831
1904
|
throw new Error(`Site '${site.name}' has no Header image set on the Websites row`);
|
|
1832
1905
|
}
|
|
@@ -1970,6 +2043,7 @@ var init_orchestrate = __esm({
|
|
|
1970
2043
|
init_header_image();
|
|
1971
2044
|
init_resend();
|
|
1972
2045
|
init_idempotency();
|
|
2046
|
+
init_checklist();
|
|
1973
2047
|
FROM_ADDRESS2 = "Reddoor Reports <reports@reddoorla.com>";
|
|
1974
2048
|
REPLY_TO = "info@reddoorla.com";
|
|
1975
2049
|
MONTHS2 = [
|
|
@@ -6373,6 +6447,10 @@ async function announce(deps) {
|
|
|
6373
6447
|
commentary: null,
|
|
6374
6448
|
copy: resolveCopy(w),
|
|
6375
6449
|
headerImageCid: `${slug}-header`,
|
|
6450
|
+
// The client's go-forward pace, read straight off the Websites row — the email
|
|
6451
|
+
// states each cadence ("Full site testing — every quarter", etc.); a "None" pace
|
|
6452
|
+
// is omitted so we never claim a cadence the site isn't on.
|
|
6453
|
+
cadence: { maintenance: w.maintenanceFreq, testing: w.testingFreq },
|
|
6376
6454
|
// Default-on fleet-wide for v1: both recent-improvement callouts render for every
|
|
6377
6455
|
// site. Operator review (the draft never auto-sends) is the relevance backstop;
|
|
6378
6456
|
// per-site conditioning of these flags is a future lever, not a v1 requirement.
|
|
@@ -6426,7 +6504,7 @@ function draftInputFor2(w, scores, now, period) {
|
|
|
6426
6504
|
completedOn: now,
|
|
6427
6505
|
lighthouse: scores,
|
|
6428
6506
|
lastTestedDate: null,
|
|
6429
|
-
subjectOverride: `Your
|
|
6507
|
+
subjectOverride: `Your testing & maintenance schedule for ${w.name}`
|
|
6430
6508
|
};
|
|
6431
6509
|
}
|
|
6432
6510
|
|