@reddoorla/maintenance 0.17.0 → 0.18.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 +66 -8
- package/dist/cli/bin.js.map +1 -1
- package/dist/cli/commands/audit.js +8 -0
- package/dist/cli/commands/audit.js.map +1 -1
- package/dist/index.d.ts +10 -0
- package/dist/index.js +51 -8
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/dist/cli/bin.js
CHANGED
|
@@ -658,9 +658,16 @@ function commentarySection(text) {
|
|
|
658
658
|
</mj-column>
|
|
659
659
|
</mj-section>`;
|
|
660
660
|
}
|
|
661
|
+
function headerImageTag(data) {
|
|
662
|
+
const src = `cid:${data.headerImageCid}`;
|
|
663
|
+
const alt = `${data.siteName} maintenance report`;
|
|
664
|
+
if (data.headerWidth && data.headerHeight && data.headerBgColor) {
|
|
665
|
+
return `<mj-image href="${data.siteUrl}" src="${src}" alt="${alt}" width="${data.headerWidth}px" height="${data.headerHeight}px" container-background-color="${data.headerBgColor}" />`;
|
|
666
|
+
}
|
|
667
|
+
return `<mj-image href="${data.siteUrl}" src="${src}" alt="${alt}" />`;
|
|
668
|
+
}
|
|
661
669
|
function buildMjml(data) {
|
|
662
670
|
const isTesting = data.reportType === "Testing";
|
|
663
|
-
const headerSrc = `cid:${data.headerImageCid}`;
|
|
664
671
|
const previewText = `Checked up on ${data.siteName}`;
|
|
665
672
|
return `<mjml>
|
|
666
673
|
<mj-head>
|
|
@@ -674,7 +681,7 @@ function buildMjml(data) {
|
|
|
674
681
|
<mj-body background-color="white">
|
|
675
682
|
<mj-section background-color="#F4F4F4" padding-top="0px" padding-bottom="0px" padding-left="0px" padding-right="0px">
|
|
676
683
|
<mj-column>
|
|
677
|
-
|
|
684
|
+
${headerImageTag(data)}
|
|
678
685
|
</mj-column>
|
|
679
686
|
</mj-section>
|
|
680
687
|
<mj-section background-color="white">
|
|
@@ -796,6 +803,44 @@ var init_attachments = __esm({
|
|
|
796
803
|
}
|
|
797
804
|
});
|
|
798
805
|
|
|
806
|
+
// src/reports/maintenance-email/header-image.ts
|
|
807
|
+
import sharp from "sharp";
|
|
808
|
+
function channelToHex(value) {
|
|
809
|
+
return Math.max(0, Math.min(255, Math.round(value))).toString(16).padStart(2, "0");
|
|
810
|
+
}
|
|
811
|
+
async function prepareHeaderImage(bytes, options = {}) {
|
|
812
|
+
const requestedDisplayWidth = options.displayWidth ?? DEFAULT_DISPLAY_WIDTH;
|
|
813
|
+
const input = Buffer.from(bytes);
|
|
814
|
+
const meta = await sharp(input).metadata();
|
|
815
|
+
const origWidth = meta.width;
|
|
816
|
+
const origHeight = meta.height;
|
|
817
|
+
if (!origWidth || !origHeight) {
|
|
818
|
+
throw new Error("prepareHeaderImage: could not read source image dimensions");
|
|
819
|
+
}
|
|
820
|
+
const displayWidth = Math.min(requestedDisplayWidth, origWidth);
|
|
821
|
+
const displayHeight = Math.round(displayWidth * origHeight / origWidth);
|
|
822
|
+
const targetSourceWidth = Math.min(origWidth, displayWidth * RETINA_SCALE);
|
|
823
|
+
const out = await sharp(input).resize({ width: targetSourceWidth, withoutEnlargement: true }).flatten({ background: "#ffffff" }).jpeg({ quality: JPEG_QUALITY }).toBuffer();
|
|
824
|
+
const { dominant } = await sharp(out).stats();
|
|
825
|
+
const placeholderColor = `#${channelToHex(dominant.r)}${channelToHex(dominant.g)}${channelToHex(dominant.b)}`;
|
|
826
|
+
return {
|
|
827
|
+
bytes: new Uint8Array(out),
|
|
828
|
+
contentType: "image/jpeg",
|
|
829
|
+
displayWidth,
|
|
830
|
+
displayHeight,
|
|
831
|
+
placeholderColor
|
|
832
|
+
};
|
|
833
|
+
}
|
|
834
|
+
var DEFAULT_DISPLAY_WIDTH, RETINA_SCALE, JPEG_QUALITY;
|
|
835
|
+
var init_header_image = __esm({
|
|
836
|
+
"src/reports/maintenance-email/header-image.ts"() {
|
|
837
|
+
"use strict";
|
|
838
|
+
DEFAULT_DISPLAY_WIDTH = 600;
|
|
839
|
+
RETINA_SCALE = 2;
|
|
840
|
+
JPEG_QUALITY = 82;
|
|
841
|
+
}
|
|
842
|
+
});
|
|
843
|
+
|
|
799
844
|
// src/reports/send/resend.ts
|
|
800
845
|
import { Resend } from "resend";
|
|
801
846
|
function defaultResendClient() {
|
|
@@ -868,7 +913,8 @@ async function sendOne(client, base, site, report) {
|
|
|
868
913
|
if (!report.lighthouse) {
|
|
869
914
|
throw new Error(`Report ${report.reportId} has no Lighthouse scores`);
|
|
870
915
|
}
|
|
871
|
-
const
|
|
916
|
+
const original = await fetchAttachmentBytes(site.headerImage.url);
|
|
917
|
+
const header = await prepareHeaderImage(original.bytes);
|
|
872
918
|
const bundled = await loadBundledImages();
|
|
873
919
|
const slug = siteSlug(site.name);
|
|
874
920
|
const cidName = `${slug}-header`;
|
|
@@ -882,7 +928,10 @@ async function sendOne(client, base, site, report) {
|
|
|
882
928
|
gaUsersPrevious: report.gaUsersPrevious ?? 0,
|
|
883
929
|
lastTestedDate: report.lastTestedDate ? new Date(report.lastTestedDate) : null,
|
|
884
930
|
commentary: report.commentary,
|
|
885
|
-
headerImageCid: cidName
|
|
931
|
+
headerImageCid: cidName,
|
|
932
|
+
headerWidth: header.displayWidth,
|
|
933
|
+
headerHeight: header.displayHeight,
|
|
934
|
+
headerBgColor: header.placeholderColor
|
|
886
935
|
});
|
|
887
936
|
const subject = report.subjectOverride ?? `${site.name} ${report.reportType} Report`;
|
|
888
937
|
const explicitTo = parseAddresses(site.reportRecipientsTo);
|
|
@@ -918,9 +967,9 @@ async function sendOne(client, base, site, report) {
|
|
|
918
967
|
html,
|
|
919
968
|
attachments: [
|
|
920
969
|
{
|
|
921
|
-
filename:
|
|
922
|
-
content: Buffer.from(bytes).toString("base64"),
|
|
923
|
-
contentType,
|
|
970
|
+
filename: `${cidName}.jpg`,
|
|
971
|
+
content: Buffer.from(header.bytes).toString("base64"),
|
|
972
|
+
contentType: header.contentType,
|
|
924
973
|
inlineContentId: cidName
|
|
925
974
|
},
|
|
926
975
|
// Bundled images referenced via cid:rd-check-png / cid:rd-blurred-tests-jpg
|
|
@@ -982,6 +1031,7 @@ var init_orchestrate = __esm({
|
|
|
982
1031
|
init_attachments();
|
|
983
1032
|
init_render();
|
|
984
1033
|
init_assets();
|
|
1034
|
+
init_header_image();
|
|
985
1035
|
init_resend();
|
|
986
1036
|
FROM_ADDRESS = "Reddoor Reports <reports@reddoorla.com>";
|
|
987
1037
|
REPLY_TO = "info@reddoorla.com";
|
|
@@ -2021,6 +2071,14 @@ function rendererFor(json) {
|
|
|
2021
2071
|
async function runAuditCommand(site, opts) {
|
|
2022
2072
|
const which = parseOnly(opts.only) ?? ALL_AUDIT_NAMES;
|
|
2023
2073
|
const cwd = opts.cwd ? resolve2(opts.cwd) : process.cwd();
|
|
2074
|
+
if (opts.writeAirtable !== void 0 && opts.fleet !== void 0) {
|
|
2075
|
+
throw Object.assign(
|
|
2076
|
+
new Error(
|
|
2077
|
+
"--write-airtable is not supported with --fleet. Each site has its own Airtable row; run per-site instead: `cd <site>/ && reddoor-maint audit --write-airtable`."
|
|
2078
|
+
),
|
|
2079
|
+
{ exitCode: 2 }
|
|
2080
|
+
);
|
|
2081
|
+
}
|
|
2024
2082
|
let sites = await resolveSites({
|
|
2025
2083
|
...site !== void 0 ? { site } : {},
|
|
2026
2084
|
...opts.fleet !== void 0 ? { fleet: opts.fleet } : {},
|
|
@@ -3654,7 +3712,7 @@ function scoresFromWebsite(siteRow) {
|
|
|
3654
3712
|
}
|
|
3655
3713
|
function daysAgo(today, n) {
|
|
3656
3714
|
const out = new Date(today);
|
|
3657
|
-
out.
|
|
3715
|
+
out.setUTCDate(out.getUTCDate() - n);
|
|
3658
3716
|
return out;
|
|
3659
3717
|
}
|
|
3660
3718
|
async function draftReportForSite(base, siteRow, reportType, options = {}) {
|