@reddoorla/maintenance 0.85.2 → 0.87.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/README.md +8 -0
- package/dist/airtable-ZBUPQJSC.js +9 -0
- package/dist/{announce-GIAYN67S.js → announce-I2Z4JN3I.js} +58 -30
- package/dist/announce-I2Z4JN3I.js.map +1 -0
- package/dist/attachments-NLZIJ5NU.js +9 -0
- package/dist/{bump-deps-SWJB6H5V.js → bump-deps-CGVELRLK.js} +9 -9
- package/dist/{chunk-SDUJIANJ.js → chunk-2NJQLSEU.js} +3 -3
- package/dist/chunk-2NQUCS7O.js +243 -0
- package/dist/chunk-2NQUCS7O.js.map +1 -0
- package/dist/{chunk-ZTPPCHDB.js → chunk-3G25KIWW.js} +4 -4
- package/dist/{chunk-DTTIFYAM.js → chunk-3JQ2FO3D.js} +44 -405
- package/dist/chunk-3JQ2FO3D.js.map +1 -0
- package/dist/chunk-3SF7D4DY.js +359 -0
- package/dist/chunk-3SF7D4DY.js.map +1 -0
- package/dist/{chunk-37S6L6G4.js → chunk-5UINJNAJ.js} +72 -2
- package/dist/chunk-5UINJNAJ.js.map +1 -0
- package/dist/{chunk-THEFTZ7F.js → chunk-62CMMGEO.js} +5 -5
- package/dist/{chunk-FDIFTIXC.js → chunk-6TWWY7ZU.js} +2 -2
- package/dist/{chunk-PBWDDDQH.js → chunk-7BZUOZPU.js} +2 -2
- package/dist/{chunk-577HCGZO.js → chunk-7NYN2P6I.js} +44 -26
- package/dist/chunk-7NYN2P6I.js.map +1 -0
- package/dist/{chunk-UYCAF77E.js → chunk-7RJ2HMMJ.js} +3 -3
- package/dist/{chunk-Q276MZ7E.js → chunk-7UAYMAKR.js} +2 -2
- package/dist/{chunk-MGR2H7F4.js → chunk-BBUSGEES.js} +58 -45
- package/dist/chunk-BBUSGEES.js.map +1 -0
- package/dist/chunk-BNM5POSJ.js +284 -0
- package/dist/chunk-BNM5POSJ.js.map +1 -0
- package/dist/{chunk-R6FPFMOS.js → chunk-BQRFQSGY.js} +3 -3
- package/dist/{chunk-NWB4O5EY.js → chunk-C6CLRKPV.js} +5 -5
- package/dist/chunk-C6CLRKPV.js.map +1 -0
- package/dist/{chunk-7J53SUT6.js → chunk-CROKUHJB.js} +4 -4
- package/dist/chunk-DEWJMMG3.js +274 -0
- package/dist/chunk-DEWJMMG3.js.map +1 -0
- package/dist/{chunk-SEEA6RXF.js → chunk-DJZWYIPP.js} +2 -2
- package/dist/chunk-DJZWYIPP.js.map +1 -0
- package/dist/chunk-EVBCK2KC.js +68 -0
- package/dist/chunk-EVBCK2KC.js.map +1 -0
- package/dist/chunk-F3JWOPTG.js +202 -0
- package/dist/chunk-F3JWOPTG.js.map +1 -0
- package/dist/{chunk-GZNBCHAZ.js → chunk-HEWSRXYV.js} +4 -4
- package/dist/chunk-HHMMUR4P.js +335 -0
- package/dist/chunk-HHMMUR4P.js.map +1 -0
- package/dist/chunk-HSI6Q7MI.js +1238 -0
- package/dist/chunk-HSI6Q7MI.js.map +1 -0
- package/dist/{chunk-MPBXOJ3N.js → chunk-IY6256GK.js} +33 -2
- package/dist/chunk-IY6256GK.js.map +1 -0
- package/dist/{chunk-LS6QPANO.js → chunk-IYSEC543.js} +2 -2
- package/dist/{chunk-DC5H7KEQ.js → chunk-JHGHLKFS.js} +2 -2
- package/dist/{chunk-4DHQCN5H.js → chunk-LBYOLBW7.js} +17 -2
- package/dist/chunk-LBYOLBW7.js.map +1 -0
- package/dist/{chunk-6QRLRT3P.js → chunk-MT2JINSS.js} +16 -265
- package/dist/chunk-MT2JINSS.js.map +1 -0
- package/dist/{chunk-TP5M2NQB.js → chunk-NCMZMLY7.js} +3 -3
- package/dist/{chunk-COZPL62X.js → chunk-NDWYJLRF.js} +24 -139
- package/dist/chunk-NDWYJLRF.js.map +1 -0
- package/dist/{chunk-3YXDSCM6.js → chunk-NXNPDCF3.js} +29 -11
- package/dist/chunk-NXNPDCF3.js.map +1 -0
- package/dist/chunk-NYUYNYQL.js +48 -0
- package/dist/chunk-NYUYNYQL.js.map +1 -0
- package/dist/chunk-P6AORG32.js +415 -0
- package/dist/chunk-P6AORG32.js.map +1 -0
- package/dist/chunk-PTDMVGKL.js +31 -0
- package/dist/chunk-PTDMVGKL.js.map +1 -0
- package/dist/{chunk-D4FVAIEJ.js → chunk-PZR4EBPY.js} +5 -2
- package/dist/chunk-PZR4EBPY.js.map +1 -0
- package/dist/{chunk-LTB6KVJW.js → chunk-SDDPUAWH.js} +13 -11
- package/dist/{chunk-LTB6KVJW.js.map → chunk-SDDPUAWH.js.map} +1 -1
- package/dist/{chunk-WYYQK4D3.js → chunk-TD2NNXLZ.js} +13 -13
- package/dist/{chunk-ZMIPG6TR.js → chunk-TVL5MVUF.js} +4 -4
- package/dist/chunk-UDRHAQT7.js +172 -0
- package/dist/chunk-UDRHAQT7.js.map +1 -0
- package/dist/chunk-VAD43MOR.js +72 -0
- package/dist/chunk-VAD43MOR.js.map +1 -0
- package/dist/chunk-VSBFM7DS.js +229 -0
- package/dist/chunk-VSBFM7DS.js.map +1 -0
- package/dist/{chunk-VRWUL4TR.js → chunk-XHHMM5HX.js} +2 -2
- package/dist/{chunk-RJB3QUSP.js → chunk-XIDUYLSR.js} +3 -3
- package/dist/{chunk-QG6OSL4M.js → chunk-XUGSZP7Z.js} +2 -2
- package/dist/{chunk-S56JQJ4F.js → chunk-Y53WOQIJ.js} +3 -3
- package/dist/{chunk-62VF32IC.js → chunk-YFAXOD7Z.js} +10 -6
- package/dist/chunk-YFAXOD7Z.js.map +1 -0
- package/dist/{chunk-ICXV25N7.js → chunk-Z3KYFUN6.js} +3 -3
- package/dist/chunk-ZBDZTJUO.js +129 -0
- package/dist/chunk-ZBDZTJUO.js.map +1 -0
- package/dist/chunk-ZGBEIWSC.js +146 -0
- package/dist/chunk-ZGBEIWSC.js.map +1 -0
- package/dist/cli/bin.js +51 -28
- package/dist/cli/bin.js.map +1 -1
- package/dist/cli/commands/audit.d.ts +30 -1
- package/dist/cli/commands/audit.js +69 -33
- package/dist/cli/commands/audit.js.map +1 -1
- package/dist/client-AUE3XUPO.js +11 -0
- package/dist/{convert-to-pnpm-AT52NWZB.js → convert-to-pnpm-QFJOEP5V.js} +9 -9
- package/dist/db-UXNIZ2RG.js +217 -0
- package/dist/db-UXNIZ2RG.js.map +1 -0
- package/dist/{digest-UVHYZUYE.js → digest-FW6QMZZJ.js} +26 -22
- package/dist/{digest-UVHYZUYE.js.map → digest-FW6QMZZJ.js.map} +1 -1
- package/dist/dump-P6EBSIOH.js +68 -0
- package/dist/dump-P6EBSIOH.js.map +1 -0
- package/dist/email-KJXASVH5.js +195 -0
- package/dist/email-KJXASVH5.js.map +1 -0
- package/dist/{ensure-site-S25MDDHW.js → ensure-site-4DCEBAPM.js} +25 -16
- package/dist/ensure-site-4DCEBAPM.js.map +1 -0
- package/dist/fleet-events-cF2Om88w.d.ts +24 -0
- package/dist/fleet-state-7TJ2GYT2.js +39 -0
- package/dist/{forms-notify-target-TWN4EH6K.js → forms-notify-target-2EAWCWBW.js} +42 -133
- package/dist/forms-notify-target-2EAWCWBW.js.map +1 -0
- package/dist/{github-signals-G4ILZAJ6.js → github-signals-E2WPYTBK.js} +42 -21
- package/dist/github-signals-E2WPYTBK.js.map +1 -0
- package/dist/{header-image-T7XD37JL.js → header-image-6IC53W27.js} +36 -13
- package/dist/header-image-6IC53W27.js.map +1 -0
- package/dist/header-images-SQBCE5OD.js +88 -0
- package/dist/header-images-SQBCE5OD.js.map +1 -0
- package/dist/{health-endpoint-242WG2OJ.js → health-endpoint-RFXL2F4A.js} +9 -9
- package/dist/health-mirror-L5JBEJVA.js +41 -0
- package/dist/health-mirror-L5JBEJVA.js.map +1 -0
- package/dist/import-airtable-OHVY344G.js +37 -0
- package/dist/index.d.ts +324 -21
- package/dist/index.js +215 -76
- package/dist/index.js.map +1 -1
- package/dist/{init-JN26NTWF.js → init-XRAQZYID.js} +21 -18
- package/dist/{init-JN26NTWF.js.map → init-XRAQZYID.js.map} +1 -1
- package/dist/{launch-JA7Z4CIM.js → launch-IX4Y5JJC.js} +65 -30
- package/dist/launch-IX4Y5JJC.js.map +1 -0
- package/dist/lighthouse-VHI77PFB.js +11 -0
- package/dist/{lighthouse-airtable-BIPM26SZ.js → lighthouse-airtable-3GUWHETW.js} +3 -3
- package/dist/mailchimp-XYCTEEJY.js +72 -0
- package/dist/mailchimp-XYCTEEJY.js.map +1 -0
- package/dist/migrate-GQH237A6.js +7 -0
- package/dist/migrate-GQH237A6.js.map +1 -0
- package/dist/notify-C645PGD5.js +22 -0
- package/dist/notify-C645PGD5.js.map +1 -0
- package/dist/{onboard-53CITIM7.js → onboard-O4IAHJMO.js} +9 -9
- package/dist/orchestrate-YLWQ6KK2.js +31 -0
- package/dist/orchestrate-YLWQ6KK2.js.map +1 -0
- package/dist/parity-56KA2DGR.js +12 -0
- package/dist/parity-56KA2DGR.js.map +1 -0
- package/dist/pipeline-3AANZFCR.js +12 -0
- package/dist/pipeline-3AANZFCR.js.map +1 -0
- package/dist/{preflight-3XPDUHFJ.js → preflight-TNORKGCX.js} +17 -13
- package/dist/{preflight-3XPDUHFJ.js.map → preflight-TNORKGCX.js.map} +1 -1
- package/dist/{prismic-ci-UTQ6LRR3.js → prismic-ci-G2AK53VL.js} +12 -12
- package/dist/{prismic-models-PVES6R5V.js → prismic-models-O6Z3OK3A.js} +18 -13
- package/dist/prismic-models-O6Z3OK3A.js.map +1 -0
- package/dist/prospect/types.d.ts +267 -0
- package/dist/prospect/types.js +1 -0
- package/dist/prospect/types.js.map +1 -0
- package/dist/prospect-audit-KSXUNQ5J.js +174 -0
- package/dist/prospect-audit-KSXUNQ5J.js.map +1 -0
- package/dist/prospect-audits-3PMIO73D.js +19 -0
- package/dist/prospect-audits-3PMIO73D.js.map +1 -0
- package/dist/{protection-audit-64PLLBLI.js → protection-audit-SJO53MEQ.js} +3 -3
- package/dist/recipes/sync-configs.js +3 -3
- package/dist/render-IFOGFB5T.js +10 -0
- package/dist/render-IFOGFB5T.js.map +1 -0
- package/dist/render-from-row-BWSOIYDS.js +17 -0
- package/dist/render-from-row-BWSOIYDS.js.map +1 -0
- package/dist/{renovate-dispatch-ICJGSFCE.js → renovate-dispatch-6GQWTRKX.js} +12 -12
- package/dist/{renovate-dispatch-ICJGSFCE.js.map → renovate-dispatch-6GQWTRKX.js.map} +1 -1
- package/dist/replay-C2LXMJZP.js +66 -0
- package/dist/replay-C2LXMJZP.js.map +1 -0
- package/dist/{report-6CKSWJNG.js → report-R3E3Y7HR.js} +100 -32
- package/dist/report-R3E3Y7HR.js.map +1 -0
- package/dist/report-mirror-4MNORYQ4.js +49 -0
- package/dist/report-mirror-4MNORYQ4.js.map +1 -0
- package/dist/reports/header-image/assets/headline-announcement.png +0 -0
- package/dist/reports/header-image/assets/headline-launch.png +0 -0
- package/dist/reports/header-image/assets/headline-maintenance.png +0 -0
- package/dist/reports/header-image/assets/headline-testing.png +0 -0
- package/dist/reports/header-image/assets/plate-clean.png +0 -0
- package/dist/rerender-3FM6DNRH.js +32 -0
- package/dist/rerender-3FM6DNRH.js.map +1 -0
- package/dist/{self-updating-PPQVV6UA.js → self-updating-UCIWESAX.js} +9 -9
- package/dist/{selftest-CQ6NOX52.js → selftest-VGHWPN72.js} +31 -24
- package/dist/selftest-VGHWPN72.js.map +1 -0
- package/dist/site-mirror-NIREX5ME.js +52 -0
- package/dist/site-mirror-NIREX5ME.js.map +1 -0
- package/dist/smoke-B2GQOSIZ.js +20 -0
- package/dist/smoke-B2GQOSIZ.js.map +1 -0
- package/dist/{smoke-suite-TMCSOYRK.js → smoke-suite-U3UKD3NS.js} +9 -9
- package/dist/{submissions-GJ6ITBRH.js → submissions-IQEJX6FK.js} +3 -3
- package/dist/{svelte-codemods-ZOBDHIES.js → svelte-codemods-GOKXTBHW.js} +9 -9
- package/dist/sync-CTUVXMCK.js +44 -0
- package/dist/sync-CTUVXMCK.js.map +1 -0
- package/dist/{sync-configs-CJXUX6MD.js → sync-configs-SPTLFJCC.js} +9 -9
- package/dist/{upgrade-WLX27UPC.js → upgrade-W6ZR3FJH.js} +9 -9
- package/dist/webhook-VOGOW3W6.js +38 -0
- package/dist/webhook-VOGOW3W6.js.map +1 -0
- package/dist/{websites-SADZR4XQ.js → websites-D6WYFAES.js} +6 -2
- package/dist/websites-D6WYFAES.js.map +1 -0
- package/dist/{write-audits-to-airtable-7PH75YWY.js → write-audits-to-airtable-CMKHGJNQ.js} +4 -4
- package/dist/write-audits-to-airtable-CMKHGJNQ.js.map +1 -0
- package/package.json +9 -2
- package/dist/airtable-HRKSA7V4.js +0 -9
- package/dist/announce-GIAYN67S.js.map +0 -1
- package/dist/chunk-37S6L6G4.js.map +0 -1
- package/dist/chunk-3YXDSCM6.js.map +0 -1
- package/dist/chunk-4DHQCN5H.js.map +0 -1
- package/dist/chunk-4SOCPK7A.js +0 -108
- package/dist/chunk-4SOCPK7A.js.map +0 -1
- package/dist/chunk-577HCGZO.js.map +0 -1
- package/dist/chunk-62VF32IC.js.map +0 -1
- package/dist/chunk-6QRLRT3P.js.map +0 -1
- package/dist/chunk-COZPL62X.js.map +0 -1
- package/dist/chunk-D4FVAIEJ.js.map +0 -1
- package/dist/chunk-DTTIFYAM.js.map +0 -1
- package/dist/chunk-MGR2H7F4.js.map +0 -1
- package/dist/chunk-MPBXOJ3N.js.map +0 -1
- package/dist/chunk-NWB4O5EY.js.map +0 -1
- package/dist/chunk-SEEA6RXF.js.map +0 -1
- package/dist/chunk-U5SZ4FOP.js +0 -26
- package/dist/chunk-U5SZ4FOP.js.map +0 -1
- package/dist/client-X5WUJWDE.js +0 -11
- package/dist/db-JSIZYT23.js +0 -23
- package/dist/db-JSIZYT23.js.map +0 -1
- package/dist/ensure-site-S25MDDHW.js.map +0 -1
- package/dist/forms-notify-target-TWN4EH6K.js.map +0 -1
- package/dist/github-signals-G4ILZAJ6.js.map +0 -1
- package/dist/header-image-T7XD37JL.js.map +0 -1
- package/dist/launch-JA7Z4CIM.js.map +0 -1
- package/dist/migrate-LJUFGXQZ.js +0 -7
- package/dist/orchestrate-KDNXZQX7.js +0 -27
- package/dist/prismic-models-PVES6R5V.js.map +0 -1
- package/dist/report-6CKSWJNG.js.map +0 -1
- package/dist/reports/header-image/assets/plate.png +0 -0
- package/dist/selftest-CQ6NOX52.js.map +0 -1
- /package/dist/{airtable-HRKSA7V4.js.map → airtable-ZBUPQJSC.js.map} +0 -0
- /package/dist/{client-X5WUJWDE.js.map → attachments-NLZIJ5NU.js.map} +0 -0
- /package/dist/{bump-deps-SWJB6H5V.js.map → bump-deps-CGVELRLK.js.map} +0 -0
- /package/dist/{chunk-SDUJIANJ.js.map → chunk-2NJQLSEU.js.map} +0 -0
- /package/dist/{chunk-ZTPPCHDB.js.map → chunk-3G25KIWW.js.map} +0 -0
- /package/dist/{chunk-THEFTZ7F.js.map → chunk-62CMMGEO.js.map} +0 -0
- /package/dist/{chunk-FDIFTIXC.js.map → chunk-6TWWY7ZU.js.map} +0 -0
- /package/dist/{chunk-PBWDDDQH.js.map → chunk-7BZUOZPU.js.map} +0 -0
- /package/dist/{chunk-UYCAF77E.js.map → chunk-7RJ2HMMJ.js.map} +0 -0
- /package/dist/{chunk-Q276MZ7E.js.map → chunk-7UAYMAKR.js.map} +0 -0
- /package/dist/{chunk-R6FPFMOS.js.map → chunk-BQRFQSGY.js.map} +0 -0
- /package/dist/{chunk-7J53SUT6.js.map → chunk-CROKUHJB.js.map} +0 -0
- /package/dist/{chunk-GZNBCHAZ.js.map → chunk-HEWSRXYV.js.map} +0 -0
- /package/dist/{chunk-LS6QPANO.js.map → chunk-IYSEC543.js.map} +0 -0
- /package/dist/{chunk-DC5H7KEQ.js.map → chunk-JHGHLKFS.js.map} +0 -0
- /package/dist/{chunk-TP5M2NQB.js.map → chunk-NCMZMLY7.js.map} +0 -0
- /package/dist/{chunk-WYYQK4D3.js.map → chunk-TD2NNXLZ.js.map} +0 -0
- /package/dist/{chunk-ZMIPG6TR.js.map → chunk-TVL5MVUF.js.map} +0 -0
- /package/dist/{chunk-VRWUL4TR.js.map → chunk-XHHMM5HX.js.map} +0 -0
- /package/dist/{chunk-RJB3QUSP.js.map → chunk-XIDUYLSR.js.map} +0 -0
- /package/dist/{chunk-QG6OSL4M.js.map → chunk-XUGSZP7Z.js.map} +0 -0
- /package/dist/{chunk-S56JQJ4F.js.map → chunk-Y53WOQIJ.js.map} +0 -0
- /package/dist/{chunk-ICXV25N7.js.map → chunk-Z3KYFUN6.js.map} +0 -0
- /package/dist/{lighthouse-airtable-BIPM26SZ.js.map → client-AUE3XUPO.js.map} +0 -0
- /package/dist/{convert-to-pnpm-AT52NWZB.js.map → convert-to-pnpm-QFJOEP5V.js.map} +0 -0
- /package/dist/{migrate-LJUFGXQZ.js.map → fleet-state-7TJ2GYT2.js.map} +0 -0
- /package/dist/{health-endpoint-242WG2OJ.js.map → health-endpoint-RFXL2F4A.js.map} +0 -0
- /package/dist/{orchestrate-KDNXZQX7.js.map → import-airtable-OHVY344G.js.map} +0 -0
- /package/dist/{websites-SADZR4XQ.js.map → lighthouse-VHI77PFB.js.map} +0 -0
- /package/dist/{write-audits-to-airtable-7PH75YWY.js.map → lighthouse-airtable-3GUWHETW.js.map} +0 -0
- /package/dist/{onboard-53CITIM7.js.map → onboard-O4IAHJMO.js.map} +0 -0
- /package/dist/{prismic-ci-UTQ6LRR3.js.map → prismic-ci-G2AK53VL.js.map} +0 -0
- /package/dist/{protection-audit-64PLLBLI.js.map → protection-audit-SJO53MEQ.js.map} +0 -0
- /package/dist/{self-updating-PPQVV6UA.js.map → self-updating-UCIWESAX.js.map} +0 -0
- /package/dist/{smoke-suite-TMCSOYRK.js.map → smoke-suite-U3UKD3NS.js.map} +0 -0
- /package/dist/{submissions-GJ6ITBRH.js.map → submissions-IQEJX6FK.js.map} +0 -0
- /package/dist/{svelte-codemods-ZOBDHIES.js.map → svelte-codemods-GOKXTBHW.js.map} +0 -0
- /package/dist/{sync-configs-CJXUX6MD.js.map → sync-configs-SPTLFJCC.js.map} +0 -0
- /package/dist/{upgrade-WLX27UPC.js.map → upgrade-W6ZR3FJH.js.map} +0 -0
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defaultReportSubject
|
|
3
|
+
} from "./chunk-GECESMVS.js";
|
|
4
|
+
import {
|
|
5
|
+
announcementSiteExtras,
|
|
6
|
+
loadBundledImages,
|
|
7
|
+
renderReportHtml,
|
|
8
|
+
resolveCopy
|
|
9
|
+
} from "./chunk-MT2JINSS.js";
|
|
10
|
+
import {
|
|
11
|
+
applyReportTypeHeadline
|
|
12
|
+
} from "./chunk-5UINJNAJ.js";
|
|
13
|
+
import {
|
|
14
|
+
siteSlug
|
|
15
|
+
} from "./chunk-7NYN2P6I.js";
|
|
16
|
+
|
|
17
|
+
// src/reports/send/render-email.ts
|
|
18
|
+
function toInlineAttachment(a) {
|
|
19
|
+
return {
|
|
20
|
+
filename: a.filename,
|
|
21
|
+
content: Buffer.from(a.bytes).toString("base64"),
|
|
22
|
+
contentType: a.contentType,
|
|
23
|
+
inlineContentId: a.cid
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
async function renderReportEmail(reportData, ctx) {
|
|
27
|
+
const { html } = await renderReportHtml(reportData);
|
|
28
|
+
const bundled = await loadBundledImages();
|
|
29
|
+
const attachments = [
|
|
30
|
+
toInlineAttachment({
|
|
31
|
+
bytes: ctx.header.bytes,
|
|
32
|
+
filename: `${ctx.cidName}.jpg`,
|
|
33
|
+
contentType: ctx.header.contentType,
|
|
34
|
+
cid: ctx.cidName
|
|
35
|
+
})
|
|
36
|
+
];
|
|
37
|
+
for (const img of [bundled.check, bundled.blurred]) {
|
|
38
|
+
if (html.includes(`cid:${img.cid}`)) {
|
|
39
|
+
attachments.push(
|
|
40
|
+
toInlineAttachment({
|
|
41
|
+
bytes: img.bytes,
|
|
42
|
+
filename: img.filename,
|
|
43
|
+
contentType: img.contentType,
|
|
44
|
+
cid: img.cid
|
|
45
|
+
})
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
const subject = ctx.subjectOverride ?? defaultReportSubject({
|
|
50
|
+
name: reportData.siteName,
|
|
51
|
+
url: reportData.siteUrl,
|
|
52
|
+
type: reportData.reportType,
|
|
53
|
+
date: reportData.completedOn
|
|
54
|
+
});
|
|
55
|
+
return { html, attachments, subject };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// src/reports/maintenance-email/header-image.ts
|
|
59
|
+
import sharp from "sharp";
|
|
60
|
+
var DEFAULT_DISPLAY_WIDTH = 600;
|
|
61
|
+
var RETINA_SCALE = 2;
|
|
62
|
+
var JPEG_QUALITY = 82;
|
|
63
|
+
function channelToHex(value) {
|
|
64
|
+
return Math.max(0, Math.min(255, Math.round(value))).toString(16).padStart(2, "0");
|
|
65
|
+
}
|
|
66
|
+
async function prepareHeaderImage(bytes, options = {}) {
|
|
67
|
+
const requestedDisplayWidth = options.displayWidth ?? DEFAULT_DISPLAY_WIDTH;
|
|
68
|
+
const input = Buffer.from(bytes);
|
|
69
|
+
const meta = await sharp(input).metadata();
|
|
70
|
+
const origWidth = meta.width;
|
|
71
|
+
const origHeight = meta.height;
|
|
72
|
+
if (!origWidth || !origHeight) {
|
|
73
|
+
throw new Error("prepareHeaderImage: could not read source image dimensions");
|
|
74
|
+
}
|
|
75
|
+
const displayWidth = Math.min(requestedDisplayWidth, origWidth);
|
|
76
|
+
const displayHeight = Math.round(displayWidth * origHeight / origWidth);
|
|
77
|
+
const targetSourceWidth = Math.min(origWidth, displayWidth * RETINA_SCALE);
|
|
78
|
+
const out = await sharp(input).resize({ width: targetSourceWidth, withoutEnlargement: true }).flatten({ background: "#ffffff" }).jpeg({ quality: JPEG_QUALITY }).toBuffer();
|
|
79
|
+
const { dominant } = await sharp(out).stats();
|
|
80
|
+
const placeholderColor = `#${channelToHex(dominant.r)}${channelToHex(dominant.g)}${channelToHex(dominant.b)}`;
|
|
81
|
+
return {
|
|
82
|
+
bytes: new Uint8Array(out),
|
|
83
|
+
contentType: "image/jpeg",
|
|
84
|
+
displayWidth,
|
|
85
|
+
displayHeight,
|
|
86
|
+
placeholderColor
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// src/reports/send/render-from-row.ts
|
|
91
|
+
function requireLighthouse(report) {
|
|
92
|
+
if (!report.lighthouse) {
|
|
93
|
+
throw new Error(
|
|
94
|
+
`Report ${report.reportId} has no Lighthouse scores \u2014 all four cells (Lighthouse \u2014 Performance / Accessibility / Best Practices / SEO) must be numeric on the Reports row; one non-numeric or blank cell nulls all four`
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
return report.lighthouse;
|
|
98
|
+
}
|
|
99
|
+
async function renderReportFromRow(site, report, headerPlateBytes) {
|
|
100
|
+
const withHeadline = await applyReportTypeHeadline(headerPlateBytes, report.reportType);
|
|
101
|
+
const header = await prepareHeaderImage(withHeadline);
|
|
102
|
+
const slug = siteSlug(site.name);
|
|
103
|
+
const cidName = `${slug}-header`;
|
|
104
|
+
const gaPeriodDays = report.reportType === "Announcement" ? 30 : windowDays(report.periodStart, report.periodEnd);
|
|
105
|
+
const reportData = {
|
|
106
|
+
siteName: site.name,
|
|
107
|
+
siteUrl: site.url,
|
|
108
|
+
reportType: report.reportType,
|
|
109
|
+
completedOn: report.completedOn ? new Date(report.completedOn) : /* @__PURE__ */ new Date(),
|
|
110
|
+
lighthouse: requireLighthouse(report),
|
|
111
|
+
gaUsersCurrent: report.gaUsersCurrent ?? void 0,
|
|
112
|
+
gaUsersPrevious: report.gaUsersPrevious ?? void 0,
|
|
113
|
+
gaPeriodDays,
|
|
114
|
+
searchPosition: report.searchFoundPage1 && report.searchPosition !== null ? report.searchPosition : void 0,
|
|
115
|
+
lastTestedDate: report.lastTestedDate ? new Date(report.lastTestedDate) : null,
|
|
116
|
+
commentary: report.commentary,
|
|
117
|
+
copy: resolveCopy(site),
|
|
118
|
+
headerImageCid: cidName,
|
|
119
|
+
headerWidth: header.displayWidth,
|
|
120
|
+
headerHeight: header.displayHeight,
|
|
121
|
+
headerBgColor: header.placeholderColor,
|
|
122
|
+
// Announcement-only: re-derive cadence + improvements from the site row so the SENT email
|
|
123
|
+
// keeps its cadence copy + improvement callouts (not stored on the Reports row).
|
|
124
|
+
...report.reportType === "Announcement" ? announcementSiteExtras(site) : {}
|
|
125
|
+
};
|
|
126
|
+
return renderReportEmail(reportData, {
|
|
127
|
+
header,
|
|
128
|
+
cidName,
|
|
129
|
+
subjectOverride: report.subjectOverride ?? void 0
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
function windowDays(start, end) {
|
|
133
|
+
if (!start || !end) return void 0;
|
|
134
|
+
const ms = new Date(end).getTime() - new Date(start).getTime();
|
|
135
|
+
if (!Number.isFinite(ms) || ms <= 0) return void 0;
|
|
136
|
+
return Math.round(ms / (24 * 60 * 60 * 1e3));
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export {
|
|
140
|
+
renderReportEmail,
|
|
141
|
+
prepareHeaderImage,
|
|
142
|
+
requireLighthouse,
|
|
143
|
+
renderReportFromRow,
|
|
144
|
+
windowDays
|
|
145
|
+
};
|
|
146
|
+
//# sourceMappingURL=chunk-ZGBEIWSC.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/reports/send/render-email.ts","../src/reports/maintenance-email/header-image.ts","../src/reports/send/render-from-row.ts"],"sourcesContent":["import { renderReportHtml } from \"../render.js\";\nimport { loadBundledImages } from \"../maintenance-email/assets/index.js\";\nimport { defaultReportSubject } from \"../subject.js\";\nimport type { ReportData } from \"../types.js\";\nimport type { ResendSendInput } from \"./resend.js\";\n\n/** A single Resend inline attachment (CID-referenced). */\nexport type InlineAttachment = NonNullable<ResendSendInput[\"attachments\"]>[number];\n\n/** The downscaled header image + display metadata produced by `prepareHeaderImage`. */\nexport type PreparedHeader = {\n bytes: Uint8Array;\n contentType: string;\n displayWidth: number;\n displayHeight: number;\n placeholderColor: string;\n};\n\nexport type RenderedReportEmail = {\n html: string;\n attachments: InlineAttachment[];\n subject: string;\n};\n\n/** Build a Resend inline (CID-referenced) attachment from raw bytes — the header image and both\n * bundled images share this exact shape. */\nfunction toInlineAttachment(a: {\n bytes: Uint8Array;\n filename: string;\n contentType: string;\n cid: string;\n}): InlineAttachment {\n return {\n filename: a.filename,\n content: Buffer.from(a.bytes).toString(\"base64\"),\n contentType: a.contentType,\n inlineContentId: a.cid,\n };\n}\n\n/**\n * Render a report email from fully-assembled `ReportData`: produce the HTML, the gated inline\n * attachments, and the subject. The per-site header attaches always; the two bundled images\n * (`rd-check-png`, `rd-blurred-tests-jpg`) attach only when their cid actually appears in the\n * rendered HTML (a dangling inline part shows as a stray download in some clients). The subject\n * is `subjectOverride` when given, else `defaultReportSubject`. Shared by the production send path\n * (`sendOne`) and the `selftest` command so the rendered email, attachments, and subject can't\n * drift between them. The only I/O is `loadBundledImages` (a disk read of two bundled images).\n */\nexport async function renderReportEmail(\n reportData: ReportData,\n ctx: { header: PreparedHeader; cidName: string; subjectOverride?: string | undefined },\n): Promise<RenderedReportEmail> {\n const { html } = await renderReportHtml(reportData);\n const bundled = await loadBundledImages();\n const attachments: InlineAttachment[] = [\n toInlineAttachment({\n bytes: ctx.header.bytes,\n filename: `${ctx.cidName}.jpg`,\n contentType: ctx.header.contentType,\n cid: ctx.cidName,\n }),\n ];\n for (const img of [bundled.check, bundled.blurred]) {\n if (html.includes(`cid:${img.cid}`)) {\n attachments.push(\n toInlineAttachment({\n bytes: img.bytes,\n filename: img.filename,\n contentType: img.contentType,\n cid: img.cid,\n }),\n );\n }\n }\n const subject =\n ctx.subjectOverride ??\n defaultReportSubject({\n name: reportData.siteName,\n url: reportData.siteUrl,\n type: reportData.reportType,\n date: reportData.completedOn,\n });\n return { html, attachments, subject };\n}\n","import sharp from \"sharp\";\n\nexport type PreparedHeaderImage = {\n /** Resized JPEG bytes to attach inline (CID) in place of the Airtable original. */\n bytes: Uint8Array;\n /** Always \"image/jpeg\" — we re-encode for predictable size and a flat white background. */\n contentType: string;\n /** CSS display width in px (≤ requested, never wider than the source has pixels for). */\n displayWidth: number;\n /** CSS display height in px, source aspect ratio preserved (no distortion). */\n displayHeight: number;\n /** Dominant-color hex (e.g. \"#cfc3a8\"), used as the loading/blocked placeholder box. */\n placeholderColor: string;\n};\n\nexport type PrepareHeaderImageOptions = {\n /** Intended CSS display width. The email body is 600px, so that's the default. */\n displayWidth?: number;\n};\n\nconst DEFAULT_DISPLAY_WIDTH = 600;\n/** Encode the source at 2× display width so it stays crisp on retina screens. */\nconst RETINA_SCALE = 2;\n/** Quality is for *resized* pixels — at 1200px the texture/text read as sharp; bytes are tiny. */\nconst JPEG_QUALITY = 82;\n\nfunction channelToHex(value: number): string {\n return Math.max(0, Math.min(255, Math.round(value)))\n .toString(16)\n .padStart(2, \"0\");\n}\n\n/**\n * Downscale an oversized header image for email: 2× the display width (retina) at most,\n * never upscaled, re-encoded as JPEG on a flat white background. Also reports the display\n * dimensions (so the template can reserve the box and stop reflow) and a dominant color\n * (so the reserved box shows a matched placeholder while the image loads).\n *\n * Root cause this addresses: Airtable headers can be multi-MB / 2400px+ while the email\n * renders them at ~600px — shipping ~16× more pixels than the display can use.\n */\nexport async function prepareHeaderImage(\n bytes: Uint8Array,\n options: PrepareHeaderImageOptions = {},\n): Promise<PreparedHeaderImage> {\n const requestedDisplayWidth = options.displayWidth ?? DEFAULT_DISPLAY_WIDTH;\n const input = Buffer.from(bytes);\n\n const meta = await sharp(input).metadata();\n const origWidth = meta.width;\n const origHeight = meta.height;\n if (!origWidth || !origHeight) {\n throw new Error(\"prepareHeaderImage: could not read source image dimensions\");\n }\n\n // Never claim a wider display than the source can fill at 1×.\n const displayWidth = Math.min(requestedDisplayWidth, origWidth);\n const displayHeight = Math.round((displayWidth * origHeight) / origWidth);\n\n // Encode at 2× display for retina, but never enlarge a smaller original.\n const targetSourceWidth = Math.min(origWidth, displayWidth * RETINA_SCALE);\n\n const out = await sharp(input)\n .resize({ width: targetSourceWidth, withoutEnlargement: true })\n .flatten({ background: \"#ffffff\" })\n .jpeg({ quality: JPEG_QUALITY })\n .toBuffer();\n\n const { dominant } = await sharp(out).stats();\n const placeholderColor = `#${channelToHex(dominant.r)}${channelToHex(dominant.g)}${channelToHex(dominant.b)}`;\n\n return {\n bytes: new Uint8Array(out),\n contentType: \"image/jpeg\",\n displayWidth,\n displayHeight,\n placeholderColor,\n };\n}\n","import { siteSlug } from \"../airtable/websites.js\";\nimport type { WebsiteRow } from \"../airtable/websites.js\";\nimport type { ReportRow } from \"../airtable/reports.js\";\nimport { resolveCopy } from \"../copy.js\";\nimport { announcementSiteExtras } from \"../announcement-email/template.js\";\nimport { renderReportEmail, type RenderedReportEmail } from \"./render-email.js\";\nimport type { ReportData } from \"../types.js\";\nimport { prepareHeaderImage } from \"../maintenance-email/header-image.js\";\nimport { applyReportTypeHeadline } from \"../header-image/index.js\";\n\n/**\n * The scores a render cannot proceed without, or a message naming the exact\n * Airtable cause. Exported so `sendOne` can fail fast on it BEFORE the header\n * fetch and the sharp downscale, while the renderer stays independently safe for\n * a caller that did not — one message, one rule, two call sites.\n */\nexport function requireLighthouse(report: ReportRow): NonNullable<ReportRow[\"lighthouse\"]> {\n if (!report.lighthouse) {\n throw new Error(\n `Report ${report.reportId} has no Lighthouse scores — all four cells ` +\n `(Lighthouse — Performance / Accessibility / Best Practices / SEO) must be numeric ` +\n `on the Reports row; one non-numeric or blank cell nulls all four`,\n );\n }\n return report.lighthouse;\n}\n\n/**\n * Assemble and render EXACTLY the email a send would produce, from a stored\n * report row plus the site's clean header plate.\n *\n * Lifted verbatim out of `sendOne`, which is the point: it is now the ONE path\n * from a row to rendered output, so the on-demand re-render behind the console's\n * report preview cannot drift from what the client actually receives. A preview\n * whose only job is fidelity is worthless if it renders through a second code\n * path that agrees with the sender by coincidence.\n *\n * Deliberately NOT included: recipient resolution, the health gate, and the\n * Resend call. Those are send concerns — a preview must be renderable for a\n * report that is not yet approvable, and must never be able to email anyone.\n *\n * `headerPlateBytes` is the CLEAN plate, not a finished header: this stamps the\n * report type's headline onto it and downscales the result, which is why the\n * caller can hand over Airtable's attachment bytes or Turso's stored BLOB\n * interchangeably.\n */\nexport async function renderReportFromRow(\n site: WebsiteRow,\n report: ReportRow,\n headerPlateBytes: Uint8Array,\n): Promise<RenderedReportEmail> {\n // The stored header is the CLEAN plate; stamp this report type's headline\n // onto it (all four types are registered — see assets/index.ts HEADLINE_FILES),\n // then downscale the (often multi-MB / 2400px+) result to email display\n // size, getting back display dims + a placeholder color so the template can\n // reserve the box.\n const withHeadline = await applyReportTypeHeadline(headerPlateBytes, report.reportType);\n const header = await prepareHeaderImage(withHeadline);\n\n const slug = siteSlug(site.name);\n const cidName = `${slug}-header`;\n const gaPeriodDays =\n report.reportType === \"Announcement\" ? 30 : windowDays(report.periodStart, report.periodEnd);\n const reportData: ReportData = {\n siteName: site.name,\n siteUrl: site.url,\n reportType: report.reportType,\n completedOn: report.completedOn ? new Date(report.completedOn) : new Date(),\n lighthouse: requireLighthouse(report),\n gaUsersCurrent: report.gaUsersCurrent ?? undefined,\n gaUsersPrevious: report.gaUsersPrevious ?? undefined,\n gaPeriodDays,\n searchPosition:\n report.searchFoundPage1 && report.searchPosition !== null ? report.searchPosition : undefined,\n lastTestedDate: report.lastTestedDate ? new Date(report.lastTestedDate) : null,\n commentary: report.commentary,\n copy: resolveCopy(site),\n headerImageCid: cidName,\n headerWidth: header.displayWidth,\n headerHeight: header.displayHeight,\n headerBgColor: header.placeholderColor,\n // Announcement-only: re-derive cadence + improvements from the site row so the SENT email\n // keeps its cadence copy + improvement callouts (not stored on the Reports row).\n ...(report.reportType === \"Announcement\" ? announcementSiteExtras(site) : {}),\n };\n\n return renderReportEmail(reportData, {\n header,\n cidName,\n subjectOverride: report.subjectOverride ?? undefined,\n });\n}\n\n/** Whole days spanned by an ISO period window, or undefined when either bound is missing or the\n * span isn't positive. Drives the analytics trend's \"vs the previous N days\" label. */\nexport function windowDays(start: string | null, end: string | null): number | undefined {\n if (!start || !end) return undefined;\n const ms = new Date(end).getTime() - new Date(start).getTime();\n if (!Number.isFinite(ms) || ms <= 0) return undefined;\n return Math.round(ms / (24 * 60 * 60 * 1000));\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AA0BA,SAAS,mBAAmB,GAKP;AACnB,SAAO;AAAA,IACL,UAAU,EAAE;AAAA,IACZ,SAAS,OAAO,KAAK,EAAE,KAAK,EAAE,SAAS,QAAQ;AAAA,IAC/C,aAAa,EAAE;AAAA,IACf,iBAAiB,EAAE;AAAA,EACrB;AACF;AAWA,eAAsB,kBACpB,YACA,KAC8B;AAC9B,QAAM,EAAE,KAAK,IAAI,MAAM,iBAAiB,UAAU;AAClD,QAAM,UAAU,MAAM,kBAAkB;AACxC,QAAM,cAAkC;AAAA,IACtC,mBAAmB;AAAA,MACjB,OAAO,IAAI,OAAO;AAAA,MAClB,UAAU,GAAG,IAAI,OAAO;AAAA,MACxB,aAAa,IAAI,OAAO;AAAA,MACxB,KAAK,IAAI;AAAA,IACX,CAAC;AAAA,EACH;AACA,aAAW,OAAO,CAAC,QAAQ,OAAO,QAAQ,OAAO,GAAG;AAClD,QAAI,KAAK,SAAS,OAAO,IAAI,GAAG,EAAE,GAAG;AACnC,kBAAY;AAAA,QACV,mBAAmB;AAAA,UACjB,OAAO,IAAI;AAAA,UACX,UAAU,IAAI;AAAA,UACd,aAAa,IAAI;AAAA,UACjB,KAAK,IAAI;AAAA,QACX,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AACA,QAAM,UACJ,IAAI,mBACJ,qBAAqB;AAAA,IACnB,MAAM,WAAW;AAAA,IACjB,KAAK,WAAW;AAAA,IAChB,MAAM,WAAW;AAAA,IACjB,MAAM,WAAW;AAAA,EACnB,CAAC;AACH,SAAO,EAAE,MAAM,aAAa,QAAQ;AACtC;;;ACpFA,OAAO,WAAW;AAoBlB,IAAM,wBAAwB;AAE9B,IAAM,eAAe;AAErB,IAAM,eAAe;AAErB,SAAS,aAAa,OAAuB;AAC3C,SAAO,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,KAAK,MAAM,KAAK,CAAC,CAAC,EAChD,SAAS,EAAE,EACX,SAAS,GAAG,GAAG;AACpB;AAWA,eAAsB,mBACpB,OACA,UAAqC,CAAC,GACR;AAC9B,QAAM,wBAAwB,QAAQ,gBAAgB;AACtD,QAAM,QAAQ,OAAO,KAAK,KAAK;AAE/B,QAAM,OAAO,MAAM,MAAM,KAAK,EAAE,SAAS;AACzC,QAAM,YAAY,KAAK;AACvB,QAAM,aAAa,KAAK;AACxB,MAAI,CAAC,aAAa,CAAC,YAAY;AAC7B,UAAM,IAAI,MAAM,4DAA4D;AAAA,EAC9E;AAGA,QAAM,eAAe,KAAK,IAAI,uBAAuB,SAAS;AAC9D,QAAM,gBAAgB,KAAK,MAAO,eAAe,aAAc,SAAS;AAGxE,QAAM,oBAAoB,KAAK,IAAI,WAAW,eAAe,YAAY;AAEzE,QAAM,MAAM,MAAM,MAAM,KAAK,EAC1B,OAAO,EAAE,OAAO,mBAAmB,oBAAoB,KAAK,CAAC,EAC7D,QAAQ,EAAE,YAAY,UAAU,CAAC,EACjC,KAAK,EAAE,SAAS,aAAa,CAAC,EAC9B,SAAS;AAEZ,QAAM,EAAE,SAAS,IAAI,MAAM,MAAM,GAAG,EAAE,MAAM;AAC5C,QAAM,mBAAmB,IAAI,aAAa,SAAS,CAAC,CAAC,GAAG,aAAa,SAAS,CAAC,CAAC,GAAG,aAAa,SAAS,CAAC,CAAC;AAE3G,SAAO;AAAA,IACL,OAAO,IAAI,WAAW,GAAG;AAAA,IACzB,aAAa;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;AC9DO,SAAS,kBAAkB,QAAyD;AACzF,MAAI,CAAC,OAAO,YAAY;AACtB,UAAM,IAAI;AAAA,MACR,UAAU,OAAO,QAAQ;AAAA,IAG3B;AAAA,EACF;AACA,SAAO,OAAO;AAChB;AAqBA,eAAsB,oBACpB,MACA,QACA,kBAC8B;AAM9B,QAAM,eAAe,MAAM,wBAAwB,kBAAkB,OAAO,UAAU;AACtF,QAAM,SAAS,MAAM,mBAAmB,YAAY;AAEpD,QAAM,OAAO,SAAS,KAAK,IAAI;AAC/B,QAAM,UAAU,GAAG,IAAI;AACvB,QAAM,eACJ,OAAO,eAAe,iBAAiB,KAAK,WAAW,OAAO,aAAa,OAAO,SAAS;AAC7F,QAAM,aAAyB;AAAA,IAC7B,UAAU,KAAK;AAAA,IACf,SAAS,KAAK;AAAA,IACd,YAAY,OAAO;AAAA,IACnB,aAAa,OAAO,cAAc,IAAI,KAAK,OAAO,WAAW,IAAI,oBAAI,KAAK;AAAA,IAC1E,YAAY,kBAAkB,MAAM;AAAA,IACpC,gBAAgB,OAAO,kBAAkB;AAAA,IACzC,iBAAiB,OAAO,mBAAmB;AAAA,IAC3C;AAAA,IACA,gBACE,OAAO,oBAAoB,OAAO,mBAAmB,OAAO,OAAO,iBAAiB;AAAA,IACtF,gBAAgB,OAAO,iBAAiB,IAAI,KAAK,OAAO,cAAc,IAAI;AAAA,IAC1E,YAAY,OAAO;AAAA,IACnB,MAAM,YAAY,IAAI;AAAA,IACtB,gBAAgB;AAAA,IAChB,aAAa,OAAO;AAAA,IACpB,cAAc,OAAO;AAAA,IACrB,eAAe,OAAO;AAAA;AAAA;AAAA,IAGtB,GAAI,OAAO,eAAe,iBAAiB,uBAAuB,IAAI,IAAI,CAAC;AAAA,EAC7E;AAEA,SAAO,kBAAkB,YAAY;AAAA,IACnC;AAAA,IACA;AAAA,IACA,iBAAiB,OAAO,mBAAmB;AAAA,EAC7C,CAAC;AACH;AAIO,SAAS,WAAW,OAAsB,KAAwC;AACvF,MAAI,CAAC,SAAS,CAAC,IAAK,QAAO;AAC3B,QAAM,KAAK,IAAI,KAAK,GAAG,EAAE,QAAQ,IAAI,IAAI,KAAK,KAAK,EAAE,QAAQ;AAC7D,MAAI,CAAC,OAAO,SAAS,EAAE,KAAK,MAAM,EAAG,QAAO;AAC5C,SAAO,KAAK,MAAM,MAAM,KAAK,KAAK,KAAK,IAAK;AAC9C;","names":[]}
|
package/dist/cli/bin.js
CHANGED
|
@@ -111,7 +111,7 @@ cli.command("sync-configs [site]", "Sync canonical configs into a site.").option
|
|
|
111
111
|
'Inventory file (.json or .mjs/.js), or "airtable" to read from Websites table'
|
|
112
112
|
).option("--workdir <path>", "Clone target for fleet mode (default ~/.reddoor-maint/sites)").action(
|
|
113
113
|
async (site, opts) => runOrExit(
|
|
114
|
-
async () => (await import("../sync-configs-
|
|
114
|
+
async () => (await import("../sync-configs-SPTLFJCC.js")).runSyncConfigsCommand(site, opts),
|
|
115
115
|
opts
|
|
116
116
|
)
|
|
117
117
|
);
|
|
@@ -120,7 +120,7 @@ cli.command("bump-deps [site]", "Bump dependencies.").option("--group <group>",
|
|
|
120
120
|
'Inventory file (.json or .mjs/.js), or "airtable" to read from Websites table'
|
|
121
121
|
).option("--workdir <path>", "Clone target for fleet mode (default ~/.reddoor-maint/sites)").action(
|
|
122
122
|
async (site, opts) => runOrExit(
|
|
123
|
-
async () => (await import("../bump-deps-
|
|
123
|
+
async () => (await import("../bump-deps-CGVELRLK.js")).runBumpDepsCommand(site, opts),
|
|
124
124
|
opts
|
|
125
125
|
)
|
|
126
126
|
);
|
|
@@ -129,7 +129,7 @@ cli.command(
|
|
|
129
129
|
"Bootstrap a repo to keep itself updated (Renovate + protection; platform auto-merge off; ci.yml is the starter's, not managed here)."
|
|
130
130
|
).option("--dry", "List what would be enabled without writing or opening PRs").option("--fleet <inventory>", 'Inventory file (.json or .mjs/.js), or "airtable"').option("--workdir <path>", "Clone target for fleet mode (default ~/.reddoor-maint/sites)").action(
|
|
131
131
|
async (site, opts) => runOrExit(
|
|
132
|
-
async () => (await import("../self-updating-
|
|
132
|
+
async () => (await import("../self-updating-UCIWESAX.js")).runSelfUpdatingCommand(site, opts),
|
|
133
133
|
opts
|
|
134
134
|
)
|
|
135
135
|
);
|
|
@@ -138,7 +138,7 @@ cli.command(
|
|
|
138
138
|
"Add the Prismic model delivery workflow to a site via PR (one PR per repo; never pushes to main)."
|
|
139
139
|
).option("--dry", "List the sites that would be offered the workflow, without opening any PR").option("--fleet <inventory>", 'Inventory file (.json or .mjs/.js), or "airtable"').option("--workdir <path>", "Clone target for fleet mode (default ~/.reddoor-maint/sites)").action(
|
|
140
140
|
async (site, opts) => runOrExit(
|
|
141
|
-
async () => (await import("../prismic-ci-
|
|
141
|
+
async () => (await import("../prismic-ci-G2AK53VL.js")).runPrismicCiCommand(site, opts),
|
|
142
142
|
opts
|
|
143
143
|
)
|
|
144
144
|
);
|
|
@@ -153,7 +153,7 @@ cli.command(
|
|
|
153
153
|
"Write the report to this file (the CI workflow posts it as a PR comment)"
|
|
154
154
|
).action(
|
|
155
155
|
async (site, opts) => runOrExit(
|
|
156
|
-
async () => (await import("../prismic-models-
|
|
156
|
+
async () => (await import("../prismic-models-O6Z3OK3A.js")).runPrismicModelsCommand(site, opts),
|
|
157
157
|
opts
|
|
158
158
|
)
|
|
159
159
|
);
|
|
@@ -162,7 +162,7 @@ cli.command("upgrade <upgrade> [site]", "Run a named upgrade recipe (svelte-4-to
|
|
|
162
162
|
'Inventory file (.json or .mjs/.js), or "airtable" to read from Websites table'
|
|
163
163
|
).option("--workdir <path>", "Clone target for fleet mode (default ~/.reddoor-maint/sites)").action(
|
|
164
164
|
async (upgrade, site, opts) => runOrExit(
|
|
165
|
-
async () => (await import("../upgrade-
|
|
165
|
+
async () => (await import("../upgrade-W6ZR3FJH.js")).runUpgradeCommand(upgrade, site, opts),
|
|
166
166
|
opts
|
|
167
167
|
)
|
|
168
168
|
);
|
|
@@ -174,7 +174,7 @@ cli.command(
|
|
|
174
174
|
'Inventory file (.json or .mjs/.js), or "airtable" to read from Websites table'
|
|
175
175
|
).option("--workdir <path>", "Clone target for fleet mode (default ~/.reddoor-maint/sites)").action(
|
|
176
176
|
async (site, opts) => runOrExit(
|
|
177
|
-
async () => (await import("../convert-to-pnpm-
|
|
177
|
+
async () => (await import("../convert-to-pnpm-QFJOEP5V.js")).runConvertToPnpmCommand(site, opts),
|
|
178
178
|
opts
|
|
179
179
|
)
|
|
180
180
|
);
|
|
@@ -183,7 +183,7 @@ cli.command("svelte-codemods [site]", "Apply Svelte 5 gotcha codemods to an alre
|
|
|
183
183
|
'Inventory file (.json or .mjs/.js), or "airtable" to read from Websites table'
|
|
184
184
|
).option("--workdir <path>", "Clone target for fleet mode (default ~/.reddoor-maint/sites)").action(
|
|
185
185
|
async (site, opts) => runOrExit(
|
|
186
|
-
async () => (await import("../svelte-codemods-
|
|
186
|
+
async () => (await import("../svelte-codemods-GOKXTBHW.js")).runSvelteCodemodsCommand(site, opts),
|
|
187
187
|
opts
|
|
188
188
|
)
|
|
189
189
|
);
|
|
@@ -195,7 +195,7 @@ cli.command(
|
|
|
195
195
|
'Inventory file (.json or .mjs/.js), or "airtable" to read from Websites table'
|
|
196
196
|
).option("--workdir <path>", "Clone target for fleet mode (default ~/.reddoor-maint/sites)").action(
|
|
197
197
|
async (site, opts) => runOrExit(
|
|
198
|
-
async () => (await import("../health-endpoint-
|
|
198
|
+
async () => (await import("../health-endpoint-RFXL2F4A.js")).runHealthEndpointCommand(site, opts),
|
|
199
199
|
opts
|
|
200
200
|
)
|
|
201
201
|
);
|
|
@@ -207,7 +207,7 @@ cli.command(
|
|
|
207
207
|
'Inventory file (.json or .mjs/.js), or "airtable" to read from Websites table'
|
|
208
208
|
).option("--workdir <path>", "Clone target for fleet mode (default ~/.reddoor-maint/sites)").action(
|
|
209
209
|
async (site, opts) => runOrExit(
|
|
210
|
-
async () => (await import("../smoke-suite-
|
|
210
|
+
async () => (await import("../smoke-suite-U3UKD3NS.js")).runSmokeSuiteCommand(site, opts),
|
|
211
211
|
opts
|
|
212
212
|
)
|
|
213
213
|
);
|
|
@@ -219,7 +219,7 @@ cli.command(
|
|
|
219
219
|
'Inventory file (.json or .mjs/.js), or "airtable" to read from Websites table'
|
|
220
220
|
).option("--workdir <path>", "Clone target for fleet mode (default ~/.reddoor-maint/sites)").action(
|
|
221
221
|
async (site, opts) => runOrExit(
|
|
222
|
-
async () => (await import("../onboard-
|
|
222
|
+
async () => (await import("../onboard-O4IAHJMO.js")).runOnboardCommand(site, opts),
|
|
223
223
|
opts
|
|
224
224
|
)
|
|
225
225
|
);
|
|
@@ -230,20 +230,20 @@ cli.command(
|
|
|
230
230
|
"--fleet <inventory>",
|
|
231
231
|
'Inventory file (.json or .mjs/.js), or "airtable" to read from Websites table'
|
|
232
232
|
).option("--workdir <path>", "Clone target for fleet mode (default ~/.reddoor-maint/sites)").action(
|
|
233
|
-
async (site, opts) => runOrExit(async () => (await import("../init-
|
|
233
|
+
async (site, opts) => runOrExit(async () => (await import("../init-XRAQZYID.js")).runInitCommand(site, opts), opts)
|
|
234
234
|
);
|
|
235
235
|
cli.command(
|
|
236
236
|
"launch <site>",
|
|
237
237
|
"Bootstrap + first-audit a site, then draft its launch email for approval."
|
|
238
238
|
).action(
|
|
239
239
|
async (site, opts) => runOrExit(
|
|
240
|
-
async () => (await import("../launch-
|
|
240
|
+
async () => (await import("../launch-IX4Y5JJC.js")).runLaunchCommand(site, opts),
|
|
241
241
|
opts
|
|
242
242
|
)
|
|
243
243
|
);
|
|
244
244
|
cli.command("header-image [site]", "Generate a site's report header image from its live homepage.").option("--all", "Every live site with no Header image yet (backfill)").option("--force", "With --all, regenerate sites that already have one").option("--write-airtable", "Upload to the Websites row instead of writing a local file").option("--out-dir <path>", "Directory for local output (default: reports/)").option("--settle-ms <ms>", "Override the post-load settle delay for slow/animated homepages").action(
|
|
245
245
|
async (site, opts) => runOrExit(
|
|
246
|
-
async () => (await import("../header-image-
|
|
246
|
+
async () => (await import("../header-image-6IC53W27.js")).runHeaderImageCommand(site, opts),
|
|
247
247
|
opts
|
|
248
248
|
)
|
|
249
249
|
);
|
|
@@ -252,7 +252,7 @@ cli.command(
|
|
|
252
252
|
"Draft the monthly-report announcement email for maintenance sites (all, or one) for approval."
|
|
253
253
|
).action(
|
|
254
254
|
async (site, opts) => runOrExit(
|
|
255
|
-
async () => (await import("../announce-
|
|
255
|
+
async () => (await import("../announce-I2Z4JN3I.js")).runAnnounceCommand(site, opts),
|
|
256
256
|
opts
|
|
257
257
|
)
|
|
258
258
|
);
|
|
@@ -261,7 +261,7 @@ cli.command(
|
|
|
261
261
|
"Show who a form submission would email, and optionally flip the pre-launch guard (read-back confirmed)."
|
|
262
262
|
).option("--set <on|off>", "Flip the guard: on = route to operator, off = restore.").option("--restore <status>", "Status to restore with --set off. Required; never inferred.").action(
|
|
263
263
|
async (site, opts) => runOrExit(
|
|
264
|
-
async () => (await import("../forms-notify-target-
|
|
264
|
+
async () => (await import("../forms-notify-target-2EAWCWBW.js")).runFormsNotifyTargetCommand(
|
|
265
265
|
site,
|
|
266
266
|
opts
|
|
267
267
|
),
|
|
@@ -273,7 +273,7 @@ cli.command(
|
|
|
273
273
|
"Operator self-tests. kind=email: preview a report email for a site (or --all) to yourself."
|
|
274
274
|
).option("--type <type>", "Report type: announcement (default) | maintenance | testing | launch").option("--to <addr>", "Recipient(s), comma-separated. Default: OPERATOR_EMAIL.").option("--all", "Send a preview for every maintenance site (to --to/operator).").option("--dry-run", "Render only; write reports/<slug>/selftest-<type>.html; do not send.").action(
|
|
275
275
|
async (kind, site, opts) => runOrExit(
|
|
276
|
-
async () => (await import("../selftest-
|
|
276
|
+
async () => (await import("../selftest-VGHWPN72.js")).runSelftestCommand(kind, site, opts),
|
|
277
277
|
opts
|
|
278
278
|
)
|
|
279
279
|
);
|
|
@@ -285,13 +285,31 @@ cli.command(
|
|
|
285
285
|
"Fleet mode: announcement\u2192maintenance sites; maintenance/testing\u2192all schedulable sites."
|
|
286
286
|
).action(
|
|
287
287
|
async (site, opts) => runOrExit(
|
|
288
|
-
async () => (await import("../preflight-
|
|
288
|
+
async () => (await import("../preflight-TNORKGCX.js")).runPreflightCommand(site, opts),
|
|
289
289
|
opts
|
|
290
290
|
)
|
|
291
291
|
);
|
|
292
292
|
cli.command("ensure-site <slug>", "Create/verify the Airtable Websites row for a new site.").option("--name <display name>", "Human Name for the row (client-facing copy uses it verbatim).").option("--url <url>", "Deployed URL (e.g. the Netlify site URL).").option("--contact <email>", "point of contact \u2014 the client address reports resolve to.").option("--git-repo <owner/repo>", "GitHub identity. Default on create: reddoorla/<slug>.").action(
|
|
293
293
|
async (slug, opts) => runOrExit(
|
|
294
|
-
async () => (await import("../ensure-site-
|
|
294
|
+
async () => (await import("../ensure-site-4DCEBAPM.js")).runEnsureSiteCommand(slug, opts),
|
|
295
|
+
opts
|
|
296
|
+
)
|
|
297
|
+
);
|
|
298
|
+
cli.command(
|
|
299
|
+
"prospect-audit <url>",
|
|
300
|
+
"AEO/SEO audit an external prospect's site and publish the report."
|
|
301
|
+
).option(
|
|
302
|
+
"--business <name>",
|
|
303
|
+
"The prospect's business name (defaults to what the model reads off the site)."
|
|
304
|
+
).option(
|
|
305
|
+
"--competitors <list>",
|
|
306
|
+
"Comma-separated competitor domains to add comparison probes for."
|
|
307
|
+
).option("--no-probes", "Skip the live AI-visibility probes (tier 3).").option("--out <file>", "Also write the rendered report to this file.").option("--json", "Print the raw result JSON instead of the report summary.").option(
|
|
308
|
+
"--email",
|
|
309
|
+
"Email the internal sheet (scores, what wasn't measured, top fixes, the link) to PROSPECT_AUDIT_RECIPIENTS."
|
|
310
|
+
).action(
|
|
311
|
+
async (url, opts) => runOrExit(
|
|
312
|
+
async () => (await import("../prospect-audit-KSXUNQ5J.js")).runProspectAuditCommand(url, opts),
|
|
295
313
|
opts
|
|
296
314
|
)
|
|
297
315
|
);
|
|
@@ -307,9 +325,12 @@ cli.command("report [site]", "Draft or send maintenance/testing reports.").optio
|
|
|
307
325
|
).option(
|
|
308
326
|
"--digest",
|
|
309
327
|
"Email the operator one daily digest of reports ready for approval (skips when empty)."
|
|
328
|
+
).option(
|
|
329
|
+
"--rerender <reportId>",
|
|
330
|
+
"Regenerate one UNSENT report's stored HTML from its current row, so the console preview shows edited commentary. Refuses a sent report."
|
|
310
331
|
).action(
|
|
311
332
|
async (site, opts) => runOrExit(
|
|
312
|
-
async () => (await import("../report-
|
|
333
|
+
async () => (await import("../report-R3E3Y7HR.js")).runReportCommand(site, opts),
|
|
313
334
|
opts
|
|
314
335
|
)
|
|
315
336
|
);
|
|
@@ -318,7 +339,7 @@ cli.command(
|
|
|
318
339
|
"Sweep the fleet for GitHub signals (Renovate-failing/CI/last-commit) and write Airtable."
|
|
319
340
|
).option("--fleet", "Run across every site in the Airtable inventory.").option("--write-airtable", "Write each site's signals back to its Websites row.").action(
|
|
320
341
|
async (opts) => runOrExit(
|
|
321
|
-
async () => (await import("../github-signals-
|
|
342
|
+
async () => (await import("../github-signals-E2WPYTBK.js")).runGitHubSignalsCommand({
|
|
322
343
|
fleet: opts.fleet,
|
|
323
344
|
writeAirtable: opts.writeAirtable
|
|
324
345
|
}),
|
|
@@ -330,7 +351,7 @@ cli.command(
|
|
|
330
351
|
"Verify every public org repo carries a sound branch ruleset (empty bypass, PR-required)."
|
|
331
352
|
).option("--org <org>", "GitHub org to sweep (enumerated from the API, never a hand list).").action(
|
|
332
353
|
async (opts) => runOrExit(
|
|
333
|
-
async () => (await import("../protection-audit-
|
|
354
|
+
async () => (await import("../protection-audit-SJO53MEQ.js")).runProtectionAuditCommand({
|
|
334
355
|
org: opts.org
|
|
335
356
|
}),
|
|
336
357
|
opts
|
|
@@ -338,9 +359,9 @@ cli.command(
|
|
|
338
359
|
);
|
|
339
360
|
cli.command(
|
|
340
361
|
"db <action>",
|
|
341
|
-
"
|
|
342
|
-
).action(
|
|
343
|
-
async (action, opts) => runOrExit(async () => (await import("../db-
|
|
362
|
+
"Operate the libSQL store (migrate | replay-deadletters | import-airtable | parity | sync | backfill-header-images | dump | verify-dump)."
|
|
363
|
+
).option("--file <path>", "verify-dump: the dump file to load into a scratch engine").action(
|
|
364
|
+
async (action, opts) => runOrExit(async () => (await import("../db-UXNIZ2RG.js")).runDbCommand(action, opts), opts)
|
|
344
365
|
);
|
|
345
366
|
cli.command(
|
|
346
367
|
"submissions <action>",
|
|
@@ -350,7 +371,7 @@ cli.command(
|
|
|
350
371
|
"Write the re-buckets: status \u2192 spam_auto, spam_score/spam_reason replaced with the new verdict + 'retro-rescore' marker."
|
|
351
372
|
).action(
|
|
352
373
|
async (action, opts) => runOrExit(
|
|
353
|
-
async () => (await import("../submissions-
|
|
374
|
+
async () => (await import("../submissions-IQEJX6FK.js")).runSubmissionsCommand(action, opts),
|
|
354
375
|
opts
|
|
355
376
|
)
|
|
356
377
|
);
|
|
@@ -359,8 +380,10 @@ cli.command(
|
|
|
359
380
|
"Trigger Renovate on fleet sites the security sweep flagged with critical/high vulns."
|
|
360
381
|
).option("--fleet", "Run across every active, repo-backed site in the Airtable inventory.").action(
|
|
361
382
|
async (opts) => runOrExit(
|
|
362
|
-
async () => (await import("../renovate-dispatch-
|
|
363
|
-
fleet: opts.fleet
|
|
383
|
+
async () => (await import("../renovate-dispatch-6GQWTRKX.js")).runRenovateDispatchCommand({
|
|
384
|
+
fleet: opts.fleet,
|
|
385
|
+
// #539 Phase 5: mirror the auto-fix counter into site_health.
|
|
386
|
+
siteMirror: await (await import("../site-mirror-NIREX5ME.js")).makeSiteMirror()
|
|
364
387
|
}),
|
|
365
388
|
opts
|
|
366
389
|
)
|