@reddoorla/maintenance 0.86.0 → 0.88.2
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/airtable-QG5ICI3Y.js +9 -0
- package/dist/{announce-MXTUQ6C7.js → announce-GKD5YJNB.js} +49 -28
- package/dist/announce-GKD5YJNB.js.map +1 -0
- package/dist/attachments-NLZIJ5NU.js +9 -0
- package/dist/{blux-ZGDSHI3U.js → blux-DN4MI532.js} +5 -5
- package/dist/{bump-deps-EC74CPLS.js → bump-deps-KGH5UYSF.js} +4 -4
- package/dist/{chunk-N45M3FDK.js → chunk-6I6L3CMX.js} +4 -4
- package/dist/{chunk-KTH5ZODA.js → chunk-7BZUOZPU.js} +2 -2
- package/dist/{chunk-2EVEFOZY.js → chunk-7FFUBF4I.js} +6 -3
- package/dist/chunk-7FFUBF4I.js.map +1 -0
- package/dist/{chunk-LDWZSLSU.js → chunk-7NYN2P6I.js} +7 -4
- package/dist/{chunk-LDWZSLSU.js.map → chunk-7NYN2P6I.js.map} +1 -1
- package/dist/{chunk-X3B723J4.js → chunk-7TMWBXX7.js} +184 -25
- package/dist/chunk-7TMWBXX7.js.map +1 -0
- package/dist/{chunk-3VQWSE3F.js → chunk-7UAYMAKR.js} +4 -4
- package/dist/{chunk-W7Z3BGCI.js → chunk-A2UNJIKH.js} +15 -7
- package/dist/chunk-A2UNJIKH.js.map +1 -0
- package/dist/{chunk-F5KM4LEQ.js → chunk-ANJNTAMM.js} +4 -70
- package/dist/chunk-ANJNTAMM.js.map +1 -0
- package/dist/{chunk-2ZPT7GLV.js → chunk-B23FFWU4.js} +4 -4
- package/dist/chunk-B23FFWU4.js.map +1 -0
- package/dist/{chunk-DJZWYIPP.js → chunk-BGTYPVLT.js} +1 -1
- package/dist/chunk-BGTYPVLT.js.map +1 -0
- package/dist/chunk-BRYXFH77.js +70 -0
- package/dist/chunk-BRYXFH77.js.map +1 -0
- package/dist/{chunk-2NDRHXMR.js → chunk-DGZWFI2G.js} +18 -141
- package/dist/chunk-DGZWFI2G.js.map +1 -0
- package/dist/{chunk-ACBRLLFT.js → chunk-F3JWOPTG.js} +7 -3
- package/dist/chunk-F3JWOPTG.js.map +1 -0
- package/dist/chunk-GQDDWYU2.js +372 -0
- package/dist/chunk-GQDDWYU2.js.map +1 -0
- package/dist/{chunk-Z7AXYKQB.js → chunk-IY6256GK.js} +1 -1
- package/dist/{chunk-BYK66EWO.js → chunk-J3WEZGIN.js} +52 -46
- package/dist/chunk-J3WEZGIN.js.map +1 -0
- package/dist/{chunk-BNM5POSJ.js → chunk-JRHIFA5R.js} +2 -2
- package/dist/{chunk-ZKXSX4LO.js → chunk-K6SLF6GI.js} +6 -6
- package/dist/{chunk-CQR4LIM7.js → chunk-KJGKZLCT.js} +7 -3
- package/dist/{chunk-CQR4LIM7.js.map → chunk-KJGKZLCT.js.map} +1 -1
- package/dist/{chunk-PPE5KZJK.js → chunk-KMCZA7CH.js} +13 -3
- package/dist/chunk-KMCZA7CH.js.map +1 -0
- package/dist/{chunk-3SF7D4DY.js → chunk-MFHS7IQ2.js} +36 -1
- package/dist/{chunk-3SF7D4DY.js.map → chunk-MFHS7IQ2.js.map} +1 -1
- package/dist/{chunk-SNSTJLQW.js → chunk-NO74DXDP.js} +48 -2
- package/dist/chunk-NO74DXDP.js.map +1 -0
- package/dist/{chunk-C6B4RHXR.js → chunk-O3GT46R2.js} +8 -2
- package/dist/chunk-O3GT46R2.js.map +1 -0
- package/dist/{chunk-ITIOFN7A.js → chunk-P6AORG32.js} +29 -10
- package/dist/chunk-P6AORG32.js.map +1 -0
- package/dist/{chunk-SLUQ7R6I.js → chunk-PR343K7F.js} +5 -5
- package/dist/{chunk-P2FE5AI6.js → chunk-Q47DU255.js} +4 -4
- package/dist/{chunk-EVBCK2KC.js → chunk-RARREDQE.js} +2 -1
- package/dist/{chunk-EVBCK2KC.js.map → chunk-RARREDQE.js.map} +1 -1
- package/dist/chunk-RUPPWAD6.js +7 -0
- package/dist/chunk-RUPPWAD6.js.map +1 -0
- package/dist/{chunk-VSBFM7DS.js → chunk-SJOXWJ5Y.js} +3 -3
- package/dist/{chunk-TERE5SDF.js → chunk-ULHPALI5.js} +4 -4
- package/dist/{chunk-XUGSZP7Z.js → chunk-W45FZEGE.js} +2 -2
- package/dist/{chunk-JHGHLKFS.js → chunk-WS6NU475.js} +2 -2
- package/dist/chunk-XP5WM2LV.js +146 -0
- package/dist/chunk-XP5WM2LV.js.map +1 -0
- package/dist/{chunk-ILUNZHYV.js → chunk-YFAXOD7Z.js} +10 -6
- package/dist/chunk-YFAXOD7Z.js.map +1 -0
- package/dist/{chunk-6TWWY7ZU.js → chunk-Z3JXLULD.js} +2 -2
- package/dist/cli/bin.js +34 -29
- package/dist/cli/bin.js.map +1 -1
- package/dist/cli/commands/audit.d.ts +4 -0
- package/dist/cli/commands/audit.js +25 -18
- package/dist/cli/commands/audit.js.map +1 -1
- package/dist/client-JYKPVCJX.js +11 -0
- package/dist/configs/playwright-a11y.js +1 -1
- package/dist/{convert-to-pnpm-6L6P74WR.js → convert-to-pnpm-NWB5FCQ2.js} +4 -4
- package/dist/{db-B35OGV3G.js → db-V6UIS433.js} +124 -29
- package/dist/db-V6UIS433.js.map +1 -0
- package/dist/{digest-BL6UJYKH.js → digest-2JEAEJK6.js} +60 -35
- package/dist/digest-2JEAEJK6.js.map +1 -0
- package/dist/digest-state-CRZRNGDI.js +25 -0
- package/dist/digest-state-CRZRNGDI.js.map +1 -0
- package/dist/digest-state-F37XUCS5.js +13 -0
- package/dist/{dump-P6EBSIOH.js → dump-EPL7AZFR.js} +38 -13
- package/dist/dump-EPL7AZFR.js.map +1 -0
- package/dist/{email-VTTTKKL5.js → email-SL7464YI.js} +16 -6
- package/dist/{email-VTTTKKL5.js.map → email-SL7464YI.js.map} +1 -1
- package/dist/{ensure-site-DFTB7MN3.js → ensure-site-FU6527OU.js} +19 -11
- package/dist/ensure-site-FU6527OU.js.map +1 -0
- package/dist/fleet-state-R5LU7IC3.js +41 -0
- package/dist/{forms-notify-target-75U6OU7L.js → forms-notify-target-SGDGXXK5.js} +10 -7
- package/dist/forms-notify-target-SGDGXXK5.js.map +1 -0
- package/dist/{github-signals-IJUPGCUX.js → github-signals-GWGCKEE2.js} +13 -12
- package/dist/{github-signals-IJUPGCUX.js.map → github-signals-GWGCKEE2.js.map} +1 -1
- package/dist/{header-image-AWLLQA4L.js → header-image-7A7XLVEU.js} +8 -8
- package/dist/{header-images-335L2AKB.js → header-images-SQBCE5OD.js} +21 -1
- package/dist/header-images-SQBCE5OD.js.map +1 -0
- package/dist/{health-endpoint-WJC2UMYS.js → health-endpoint-UVX6R5N5.js} +4 -4
- package/dist/health-mirror-GCDN7BJL.js +46 -0
- package/dist/health-mirror-GCDN7BJL.js.map +1 -0
- package/dist/{import-airtable-HE43FB4H.js → import-airtable-OHVY344G.js} +7 -5
- package/dist/index.d.ts +149 -0
- package/dist/index.js +245 -108
- package/dist/index.js.map +1 -1
- package/dist/{init-NJEOEO7I.js → init-FGTYNGUI.js} +11 -11
- package/dist/{launch-XNAX427U.js → launch-5H7LPEGP.js} +59 -29
- package/dist/launch-5H7LPEGP.js.map +1 -0
- package/dist/{lighthouse-airtable-LBVIYYP5.js → lighthouse-airtable-3GUWHETW.js} +3 -3
- package/dist/migrate-YITCXBLS.js +7 -0
- package/dist/{notify-C645PGD5.js → notify-4HP4GZ2H.js} +5 -5
- package/dist/{onboard-GK4PHPNI.js → onboard-BKCYBAVW.js} +4 -4
- package/dist/{orchestrate-77UO4BYJ.js → orchestrate-JNKCWU5K.js} +14 -13
- package/dist/parity-NBYZUBFU.js +14 -0
- package/dist/pdf-N5QLQ5ZQ.js +38 -0
- package/dist/pdf-N5QLQ5ZQ.js.map +1 -0
- package/dist/{pipeline-S6CVHDGB.js → pipeline-WYTXSLHX.js} +3 -3
- package/dist/{preflight-6WBNU2GZ.js → preflight-IMTYDDD4.js} +15 -14
- package/dist/{preflight-6WBNU2GZ.js.map → preflight-IMTYDDD4.js.map} +1 -1
- package/dist/{prismic-ci-3RHOZUUT.js → prismic-ci-MY2U6NN7.js} +7 -7
- package/dist/{prismic-models-QBGUT2Q3.js → prismic-models-NJN5JORF.js} +15 -10
- package/dist/prismic-models-NJN5JORF.js.map +1 -0
- package/dist/prospect/types.d.ts +281 -0
- package/dist/prospect/types.js +1 -0
- package/dist/{prospect-audit-IUNCJ2LV.js → prospect-audit-JMBRVXSG.js} +32 -13
- package/dist/prospect-audit-JMBRVXSG.js.map +1 -0
- package/dist/recipes/sync-configs.js +2 -2
- package/dist/render-VX72AESY.js +10 -0
- package/dist/render-VX72AESY.js.map +1 -0
- package/dist/render-from-row-DOYJDO2L.js +17 -0
- package/dist/render-from-row-DOYJDO2L.js.map +1 -0
- package/dist/{renovate-dispatch-QJY75ODR.js → renovate-dispatch-6GQWTRKX.js} +10 -10
- package/dist/{renovate-dispatch-QJY75ODR.js.map → renovate-dispatch-6GQWTRKX.js.map} +1 -1
- package/dist/{replay-C2LXMJZP.js → replay-4S6ENYCH.js} +3 -3
- package/dist/{report-4EVNDHOZ.js → report-TALY5P3L.js} +63 -21
- package/dist/report-TALY5P3L.js.map +1 -0
- package/dist/report-mirror-AAK3MXHY.js +55 -0
- package/dist/report-mirror-AAK3MXHY.js.map +1 -0
- package/dist/rerender-3FM6DNRH.js +32 -0
- package/dist/rerender-3FM6DNRH.js.map +1 -0
- package/dist/schema-75PJECAE.js +18 -0
- package/dist/schema-75PJECAE.js.map +1 -0
- package/dist/{self-updating-6DWI2Z56.js → self-updating-NTCCWJYZ.js} +4 -4
- package/dist/{selftest-RC36MTKP.js → selftest-NZTR4SM2.js} +26 -24
- package/dist/{selftest-RC36MTKP.js.map → selftest-NZTR4SM2.js.map} +1 -1
- package/dist/site-mirror-Q763PLGG.js +62 -0
- package/dist/site-mirror-Q763PLGG.js.map +1 -0
- package/dist/{smoke-suite-VYY2LXM2.js → smoke-suite-4JFZZYVW.js} +4 -4
- package/dist/{spam-classifier-XLBFCO7G.js → spam-classifier-T5H4VTP6.js} +4 -2
- package/dist/spam-classifier-T5H4VTP6.js.map +1 -0
- package/dist/{submissions-Q7DRFOCD.js → submissions-TEHPBSZJ.js} +5 -5
- package/dist/{svelte-codemods-25J2FO22.js → svelte-codemods-QAPDZC6F.js} +4 -4
- package/dist/{sync-34HNZZ56.js → sync-GBFV45WX.js} +6 -4
- package/dist/{sync-34HNZZ56.js.map → sync-GBFV45WX.js.map} +1 -1
- package/dist/{sync-configs-3SE6PSCO.js → sync-configs-34JIA6KZ.js} +6 -6
- package/dist/{upgrade-WBRQ62FX.js → upgrade-IR2OO3KP.js} +4 -4
- package/dist/{webflow-IRKOIT7S.js → webflow-624FEBFD.js} +4 -4
- package/dist/{webhook-VOGOW3W6.js → webhook-XM6EV4XT.js} +2 -2
- package/dist/{websites-SXWTP72S.js → websites-D6WYFAES.js} +2 -2
- package/dist/websites-D6WYFAES.js.map +1 -0
- package/dist/write-audits-to-airtable-OBHGR7DQ.js +17 -0
- package/dist/write-audits-to-airtable-OBHGR7DQ.js.map +1 -0
- package/package.json +5 -1
- package/dist/airtable-G7WBQQMI.js +0 -9
- package/dist/announce-MXTUQ6C7.js.map +0 -1
- package/dist/chunk-2EVEFOZY.js.map +0 -1
- package/dist/chunk-2NDRHXMR.js.map +0 -1
- package/dist/chunk-2ZPT7GLV.js.map +0 -1
- package/dist/chunk-ACBRLLFT.js.map +0 -1
- package/dist/chunk-BYK66EWO.js.map +0 -1
- package/dist/chunk-C6B4RHXR.js.map +0 -1
- package/dist/chunk-DJZWYIPP.js.map +0 -1
- package/dist/chunk-F5KM4LEQ.js.map +0 -1
- package/dist/chunk-ILUNZHYV.js.map +0 -1
- package/dist/chunk-ITIOFN7A.js.map +0 -1
- package/dist/chunk-PPE5KZJK.js.map +0 -1
- package/dist/chunk-SNSTJLQW.js.map +0 -1
- package/dist/chunk-W7Z3BGCI.js.map +0 -1
- package/dist/chunk-X3B723J4.js.map +0 -1
- package/dist/client-AUE3XUPO.js +0 -11
- package/dist/db-B35OGV3G.js.map +0 -1
- package/dist/digest-BL6UJYKH.js.map +0 -1
- package/dist/dump-P6EBSIOH.js.map +0 -1
- package/dist/ensure-site-DFTB7MN3.js.map +0 -1
- package/dist/forms-notify-target-75U6OU7L.js.map +0 -1
- package/dist/header-images-335L2AKB.js.map +0 -1
- package/dist/health-mirror-4B2L7T2Y.js +0 -75
- package/dist/health-mirror-4B2L7T2Y.js.map +0 -1
- package/dist/launch-XNAX427U.js.map +0 -1
- package/dist/migrate-GQH237A6.js +0 -7
- package/dist/parity-MWS24A3H.js +0 -12
- package/dist/prismic-models-QBGUT2Q3.js.map +0 -1
- package/dist/prospect-audit-IUNCJ2LV.js.map +0 -1
- package/dist/render-AQAVQDPZ.js +0 -10
- package/dist/report-4EVNDHOZ.js.map +0 -1
- package/dist/write-audits-to-airtable-MBEILLPU.js +0 -14
- /package/dist/{airtable-G7WBQQMI.js.map → airtable-QG5ICI3Y.js.map} +0 -0
- /package/dist/{client-AUE3XUPO.js.map → attachments-NLZIJ5NU.js.map} +0 -0
- /package/dist/{blux-ZGDSHI3U.js.map → blux-DN4MI532.js.map} +0 -0
- /package/dist/{bump-deps-EC74CPLS.js.map → bump-deps-KGH5UYSF.js.map} +0 -0
- /package/dist/{chunk-N45M3FDK.js.map → chunk-6I6L3CMX.js.map} +0 -0
- /package/dist/{chunk-KTH5ZODA.js.map → chunk-7BZUOZPU.js.map} +0 -0
- /package/dist/{chunk-3VQWSE3F.js.map → chunk-7UAYMAKR.js.map} +0 -0
- /package/dist/{chunk-Z7AXYKQB.js.map → chunk-IY6256GK.js.map} +0 -0
- /package/dist/{chunk-BNM5POSJ.js.map → chunk-JRHIFA5R.js.map} +0 -0
- /package/dist/{chunk-ZKXSX4LO.js.map → chunk-K6SLF6GI.js.map} +0 -0
- /package/dist/{chunk-SLUQ7R6I.js.map → chunk-PR343K7F.js.map} +0 -0
- /package/dist/{chunk-P2FE5AI6.js.map → chunk-Q47DU255.js.map} +0 -0
- /package/dist/{chunk-VSBFM7DS.js.map → chunk-SJOXWJ5Y.js.map} +0 -0
- /package/dist/{chunk-TERE5SDF.js.map → chunk-ULHPALI5.js.map} +0 -0
- /package/dist/{chunk-XUGSZP7Z.js.map → chunk-W45FZEGE.js.map} +0 -0
- /package/dist/{chunk-JHGHLKFS.js.map → chunk-WS6NU475.js.map} +0 -0
- /package/dist/{chunk-6TWWY7ZU.js.map → chunk-Z3JXLULD.js.map} +0 -0
- /package/dist/{import-airtable-HE43FB4H.js.map → client-JYKPVCJX.js.map} +0 -0
- /package/dist/{convert-to-pnpm-6L6P74WR.js.map → convert-to-pnpm-NWB5FCQ2.js.map} +0 -0
- /package/dist/{lighthouse-airtable-LBVIYYP5.js.map → digest-state-F37XUCS5.js.map} +0 -0
- /package/dist/{migrate-GQH237A6.js.map → fleet-state-R5LU7IC3.js.map} +0 -0
- /package/dist/{header-image-AWLLQA4L.js.map → header-image-7A7XLVEU.js.map} +0 -0
- /package/dist/{health-endpoint-WJC2UMYS.js.map → health-endpoint-UVX6R5N5.js.map} +0 -0
- /package/dist/{notify-C645PGD5.js.map → import-airtable-OHVY344G.js.map} +0 -0
- /package/dist/{init-NJEOEO7I.js.map → init-FGTYNGUI.js.map} +0 -0
- /package/dist/{orchestrate-77UO4BYJ.js.map → lighthouse-airtable-3GUWHETW.js.map} +0 -0
- /package/dist/{parity-MWS24A3H.js.map → migrate-YITCXBLS.js.map} +0 -0
- /package/dist/{pipeline-S6CVHDGB.js.map → notify-4HP4GZ2H.js.map} +0 -0
- /package/dist/{onboard-GK4PHPNI.js.map → onboard-BKCYBAVW.js.map} +0 -0
- /package/dist/{render-AQAVQDPZ.js.map → orchestrate-JNKCWU5K.js.map} +0 -0
- /package/dist/{spam-classifier-XLBFCO7G.js.map → parity-NBYZUBFU.js.map} +0 -0
- /package/dist/{websites-SXWTP72S.js.map → pipeline-WYTXSLHX.js.map} +0 -0
- /package/dist/{prismic-ci-3RHOZUUT.js.map → prismic-ci-MY2U6NN7.js.map} +0 -0
- /package/dist/{write-audits-to-airtable-MBEILLPU.js.map → prospect/types.js.map} +0 -0
- /package/dist/{replay-C2LXMJZP.js.map → replay-4S6ENYCH.js.map} +0 -0
- /package/dist/{self-updating-6DWI2Z56.js.map → self-updating-NTCCWJYZ.js.map} +0 -0
- /package/dist/{smoke-suite-VYY2LXM2.js.map → smoke-suite-4JFZZYVW.js.map} +0 -0
- /package/dist/{submissions-Q7DRFOCD.js.map → submissions-TEHPBSZJ.js.map} +0 -0
- /package/dist/{svelte-codemods-25J2FO22.js.map → svelte-codemods-QAPDZC6F.js.map} +0 -0
- /package/dist/{sync-configs-3SE6PSCO.js.map → sync-configs-34JIA6KZ.js.map} +0 -0
- /package/dist/{upgrade-WBRQ62FX.js.map → upgrade-IR2OO3KP.js.map} +0 -0
- /package/dist/{webflow-IRKOIT7S.js.map → webflow-624FEBFD.js.map} +0 -0
- /package/dist/{webhook-VOGOW3W6.js.map → webhook-XM6EV4XT.js.map} +0 -0
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
fetchGaUsers,
|
|
3
3
|
fetchSearch
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-J3WEZGIN.js";
|
|
5
5
|
import {
|
|
6
6
|
announcementSiteExtras,
|
|
7
7
|
resolveCopy
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-KJGKZLCT.js";
|
|
9
9
|
import {
|
|
10
10
|
siteSlug
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-7NYN2P6I.js";
|
|
12
12
|
|
|
13
13
|
// src/reports/report-data.ts
|
|
14
14
|
var PREVIEW_WINDOW_DAYS = 30;
|
|
@@ -60,4 +60,4 @@ export {
|
|
|
60
60
|
scoresFromRow,
|
|
61
61
|
buildReportDataForSite
|
|
62
62
|
};
|
|
63
|
-
//# sourceMappingURL=chunk-
|
|
63
|
+
//# sourceMappingURL=chunk-ULHPALI5.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
openDb,
|
|
3
3
|
readDbConfig
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-WS6NU475.js";
|
|
5
5
|
|
|
6
6
|
// src/db/fleet-events.ts
|
|
7
7
|
async function recordFleetEvent(db, e) {
|
|
@@ -47,4 +47,4 @@ async function recordFleetEventsBestEffort(events, now, open = () => openDb(read
|
|
|
47
47
|
export {
|
|
48
48
|
recordFleetEventsBestEffort
|
|
49
49
|
};
|
|
50
|
-
//# sourceMappingURL=chunk-
|
|
50
|
+
//# sourceMappingURL=chunk-W45FZEGE.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
runMigrations
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-MFHS7IQ2.js";
|
|
4
4
|
import {
|
|
5
5
|
defaultCredentialsPath
|
|
6
6
|
} from "./chunk-6VAL7XJT.js";
|
|
@@ -48,4 +48,4 @@ export {
|
|
|
48
48
|
readDbConfig,
|
|
49
49
|
openDb
|
|
50
50
|
};
|
|
51
|
-
//# sourceMappingURL=chunk-
|
|
51
|
+
//# sourceMappingURL=chunk-WS6NU475.js.map
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defaultReportSubject
|
|
3
|
+
} from "./chunk-GECESMVS.js";
|
|
4
|
+
import {
|
|
5
|
+
applyReportTypeHeadline
|
|
6
|
+
} from "./chunk-5UINJNAJ.js";
|
|
7
|
+
import {
|
|
8
|
+
announcementSiteExtras,
|
|
9
|
+
loadBundledImages,
|
|
10
|
+
renderReportHtml,
|
|
11
|
+
resolveCopy
|
|
12
|
+
} from "./chunk-KJGKZLCT.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-XP5WM2LV.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":"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","names":[]}
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
isPendingApproval,
|
|
3
3
|
listReportsForSite,
|
|
4
4
|
setDraftReady
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-F3JWOPTG.js";
|
|
6
6
|
|
|
7
7
|
// src/reports/queue.ts
|
|
8
8
|
var REPORT_TIER = {
|
|
@@ -14,20 +14,24 @@ var REPORT_TIER = {
|
|
|
14
14
|
function reportTier(type) {
|
|
15
15
|
return REPORT_TIER[type];
|
|
16
16
|
}
|
|
17
|
-
async function queueDraft(base, report) {
|
|
17
|
+
async function queueDraft(base, report, mirror) {
|
|
18
|
+
const setReady = async (id, ready) => {
|
|
19
|
+
await setDraftReady(base, id, ready);
|
|
20
|
+
await mirror?.patch(id, { draft_ready: ready ? 1 : 0 });
|
|
21
|
+
};
|
|
18
22
|
const newTier = reportTier(report.reportType);
|
|
19
23
|
const others = (await listReportsForSite(base, report.siteId)).filter(isPendingApproval).filter((r) => r.id !== report.id);
|
|
20
24
|
const blocker = others.find((r) => reportTier(r.reportType) >= newTier);
|
|
21
25
|
if (blocker) {
|
|
22
|
-
await
|
|
26
|
+
await setReady(report.id, false);
|
|
23
27
|
return { queued: false, blockedBy: blocker.reportType, supersededIds: [] };
|
|
24
28
|
}
|
|
25
29
|
const supersededIds = [];
|
|
26
30
|
for (const r of others) {
|
|
27
|
-
await
|
|
31
|
+
await setReady(r.id, false);
|
|
28
32
|
supersededIds.push(r.id);
|
|
29
33
|
}
|
|
30
|
-
await
|
|
34
|
+
await setReady(report.id, true);
|
|
31
35
|
return { queued: true, supersededIds };
|
|
32
36
|
}
|
|
33
37
|
|
|
@@ -35,4 +39,4 @@ export {
|
|
|
35
39
|
reportTier,
|
|
36
40
|
queueDraft
|
|
37
41
|
};
|
|
38
|
-
//# sourceMappingURL=chunk-
|
|
42
|
+
//# sourceMappingURL=chunk-YFAXOD7Z.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/reports/queue.ts"],"sourcesContent":["import type { ReportType } from \"./types.js\";\nimport type { AirtableBase } from \"./airtable/client.js\";\nimport { listReportsForSite, isPendingApproval, setDraftReady } from \"./airtable/reports.js\";\nimport type { ReportMirror } from \"./report-mirror.js\";\n\n/**\n * Report tiers — a higher tier is a SUPERSET of the lower ones, so only the highest-tier\n * un-sent draft is worth keeping in a site's approve queue. Maintenance ⊂ Testing ⊂\n * {Announcement, Launch}. Announcement and Launch share tier 3 (neither supersets the other).\n */\nexport const REPORT_TIER: Record<ReportType, number> = {\n Maintenance: 1,\n Testing: 2,\n Announcement: 3,\n Launch: 3,\n};\n\nexport function reportTier(type: ReportType): number {\n return REPORT_TIER[type];\n}\n\nexport type QueueOutcome = {\n /** Whether `report` was placed in (kept in) the approve queue. */\n queued: boolean;\n /** When `queued` is false, the queued report type that subsumes this one. */\n blockedBy?: ReportType;\n /** Ids of lower-tier queued reports that this one superseded (un-queued). */\n supersededIds: string[];\n};\n\n/**\n * Enforce \"one report queued per site, highest tier wins\" at draft time. Given a freshly\n * created/reused report, look at the OTHER reports already pending approval for the same site\n * (Draft ready ∧ ¬Approved ∧ ¬Sent) and:\n *\n * - If any is of an EQUAL-OR-HIGHER tier → the new report is subsumed: leave it un-queued\n * (Draft ready = false) and report `blockedBy`. (Equal-tier, e.g. a queued Launch when an\n * Announcement is drafted, keeps the existing one rather than silently replacing it.)\n * - Otherwise the new report is strictly the highest → un-queue every (strictly lower) pending\n * report for the site (superseded, not deleted — the row is kept) and queue the new one.\n *\n * Returns what happened so the caller can surface it. PURE side effects are all `setDraftReady`.\n *\n * #539 Phase 5: each flag is mirrored into Turso. The SUPERSEDED rows matter as\n * much as the new one — un-queueing them is the whole point of this function, so\n * a mirror covering only `report.id` would leave the console showing a site with\n * two queued reports until the next hourly sync.\n */\nexport async function queueDraft(\n base: AirtableBase,\n report: { id: string; siteId: string; reportType: ReportType },\n mirror?: ReportMirror,\n): Promise<QueueOutcome> {\n const setReady = async (id: string, ready: boolean): Promise<void> => {\n await setDraftReady(base, id, ready);\n await mirror?.patch(id, { draft_ready: ready ? 1 : 0 });\n };\n const newTier = reportTier(report.reportType);\n const others = (await listReportsForSite(base, report.siteId))\n .filter(isPendingApproval)\n .filter((r) => r.id !== report.id);\n\n const blocker = others.find((r) => reportTier(r.reportType) >= newTier);\n if (blocker) {\n // A queued report already covers this one. Make sure the new draft is NOT queued (the reuse\n // path may hand us a row that was Draft-ready from a prior run) and stand down.\n await setReady(report.id, false);\n return { queued: false, blockedBy: blocker.reportType, supersededIds: [] };\n }\n\n // The new report is strictly the highest-tier pending — supersede the rest (un-queue), keep it.\n const supersededIds: string[] = [];\n for (const r of others) {\n await setReady(r.id, false);\n supersededIds.push(r.id);\n }\n await setReady(report.id, true);\n return { queued: true, supersededIds };\n}\n"],"mappings":";;;;;;;AAUO,IAAM,cAA0C;AAAA,EACrD,aAAa;AAAA,EACb,SAAS;AAAA,EACT,cAAc;AAAA,EACd,QAAQ;AACV;AAEO,SAAS,WAAW,MAA0B;AACnD,SAAO,YAAY,IAAI;AACzB;AA6BA,eAAsB,WACpB,MACA,QACA,QACuB;AACvB,QAAM,WAAW,OAAO,IAAY,UAAkC;AACpE,UAAM,cAAc,MAAM,IAAI,KAAK;AACnC,UAAM,QAAQ,MAAM,IAAI,EAAE,aAAa,QAAQ,IAAI,EAAE,CAAC;AAAA,EACxD;AACA,QAAM,UAAU,WAAW,OAAO,UAAU;AAC5C,QAAM,UAAU,MAAM,mBAAmB,MAAM,OAAO,MAAM,GACzD,OAAO,iBAAiB,EACxB,OAAO,CAAC,MAAM,EAAE,OAAO,OAAO,EAAE;AAEnC,QAAM,UAAU,OAAO,KAAK,CAAC,MAAM,WAAW,EAAE,UAAU,KAAK,OAAO;AACtE,MAAI,SAAS;AAGX,UAAM,SAAS,OAAO,IAAI,KAAK;AAC/B,WAAO,EAAE,QAAQ,OAAO,WAAW,QAAQ,YAAY,eAAe,CAAC,EAAE;AAAA,EAC3E;AAGA,QAAM,gBAA0B,CAAC;AACjC,aAAW,KAAK,QAAQ;AACtB,UAAM,SAAS,EAAE,IAAI,KAAK;AAC1B,kBAAc,KAAK,EAAE,EAAE;AAAA,EACzB;AACA,QAAM,SAAS,OAAO,IAAI,IAAI;AAC9B,SAAO,EAAE,QAAQ,MAAM,cAAc;AACvC;","names":[]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
isHttpUrl
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-RARREDQE.js";
|
|
4
4
|
|
|
5
5
|
// src/inventory/local.ts
|
|
6
6
|
import { basename } from "path";
|
|
@@ -67,4 +67,4 @@ export {
|
|
|
67
67
|
localPath,
|
|
68
68
|
fromJsonFile
|
|
69
69
|
};
|
|
70
|
-
//# sourceMappingURL=chunk-
|
|
70
|
+
//# sourceMappingURL=chunk-Z3JXLULD.js.map
|
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-34JIA6KZ.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-KGH5UYSF.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-NTCCWJYZ.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-MY2U6NN7.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-NJN5JORF.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-IR2OO3KP.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-NWB5FCQ2.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-QAPDZC6F.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-UVX6R5N5.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-4JFZZYVW.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-BKCYBAVW.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-FGTYNGUI.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-5H7LPEGP.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-7A7XLVEU.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-GKD5YJNB.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-SGDGXXK5.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-NZTR4SM2.js")).runSelftestCommand(kind, site, opts),
|
|
277
277
|
opts
|
|
278
278
|
)
|
|
279
279
|
);
|
|
@@ -285,13 +285,13 @@ 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-IMTYDDD4.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-FU6527OU.js")).runEnsureSiteCommand(slug, opts),
|
|
295
295
|
opts
|
|
296
296
|
)
|
|
297
297
|
);
|
|
@@ -309,7 +309,7 @@ cli.command(
|
|
|
309
309
|
"Email the internal sheet (scores, what wasn't measured, top fixes, the link) to PROSPECT_AUDIT_RECIPIENTS."
|
|
310
310
|
).action(
|
|
311
311
|
async (url, opts) => runOrExit(
|
|
312
|
-
async () => (await import("../prospect-audit-
|
|
312
|
+
async () => (await import("../prospect-audit-JMBRVXSG.js")).runProspectAuditCommand(url, opts),
|
|
313
313
|
opts
|
|
314
314
|
)
|
|
315
315
|
);
|
|
@@ -325,9 +325,12 @@ cli.command("report [site]", "Draft or send maintenance/testing reports.").optio
|
|
|
325
325
|
).option(
|
|
326
326
|
"--digest",
|
|
327
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."
|
|
328
331
|
).action(
|
|
329
332
|
async (site, opts) => runOrExit(
|
|
330
|
-
async () => (await import("../report-
|
|
333
|
+
async () => (await import("../report-TALY5P3L.js")).runReportCommand(site, opts),
|
|
331
334
|
opts
|
|
332
335
|
)
|
|
333
336
|
);
|
|
@@ -336,7 +339,7 @@ cli.command(
|
|
|
336
339
|
"Sweep the fleet for GitHub signals (Renovate-failing/CI/last-commit) and write Airtable."
|
|
337
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(
|
|
338
341
|
async (opts) => runOrExit(
|
|
339
|
-
async () => (await import("../github-signals-
|
|
342
|
+
async () => (await import("../github-signals-GWGCKEE2.js")).runGitHubSignalsCommand({
|
|
340
343
|
fleet: opts.fleet,
|
|
341
344
|
writeAirtable: opts.writeAirtable
|
|
342
345
|
}),
|
|
@@ -356,9 +359,9 @@ cli.command(
|
|
|
356
359
|
);
|
|
357
360
|
cli.command(
|
|
358
361
|
"db <action>",
|
|
359
|
-
"Operate the libSQL store (migrate | replay-deadletters | import-airtable | parity | sync | backfill-header-images | dump | verify-dump)."
|
|
362
|
+
"Operate the libSQL store (migrate | replay-deadletters | import-airtable | parity | sync | backfill-header-images | backfill-digest-state | dump | verify-dump | restore)."
|
|
360
363
|
).option("--file <path>", "verify-dump: the dump file to load into a scratch engine").action(
|
|
361
|
-
async (action, opts) => runOrExit(async () => (await import("../db-
|
|
364
|
+
async (action, opts) => runOrExit(async () => (await import("../db-V6UIS433.js")).runDbCommand(action, opts), opts)
|
|
362
365
|
);
|
|
363
366
|
cli.command(
|
|
364
367
|
"submissions <action>",
|
|
@@ -368,7 +371,7 @@ cli.command(
|
|
|
368
371
|
"Write the re-buckets: status \u2192 spam_auto, spam_score/spam_reason replaced with the new verdict + 'retro-rescore' marker."
|
|
369
372
|
).action(
|
|
370
373
|
async (action, opts) => runOrExit(
|
|
371
|
-
async () => (await import("../submissions-
|
|
374
|
+
async () => (await import("../submissions-TEHPBSZJ.js")).runSubmissionsCommand(action, opts),
|
|
372
375
|
opts
|
|
373
376
|
)
|
|
374
377
|
);
|
|
@@ -377,8 +380,10 @@ cli.command(
|
|
|
377
380
|
"Trigger Renovate on fleet sites the security sweep flagged with critical/high vulns."
|
|
378
381
|
).option("--fleet", "Run across every active, repo-backed site in the Airtable inventory.").action(
|
|
379
382
|
async (opts) => runOrExit(
|
|
380
|
-
async () => (await import("../renovate-dispatch-
|
|
381
|
-
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-Q763PLGG.js")).makeSiteMirror()
|
|
382
387
|
}),
|
|
383
388
|
opts
|
|
384
389
|
)
|
|
@@ -403,7 +408,7 @@ cli.command(
|
|
|
403
408
|
"freeze: JSON declaring slots the template has no token for (video poster, a panel rebuilt from a baked image). Keys must start with 'x.'"
|
|
404
409
|
).action(
|
|
405
410
|
async (action, dir, opts) => runOrExit(
|
|
406
|
-
async () => (await import("../blux-
|
|
411
|
+
async () => (await import("../blux-DN4MI532.js")).runBluxCommand(action, dir, opts),
|
|
407
412
|
opts
|
|
408
413
|
)
|
|
409
414
|
);
|
|
@@ -415,7 +420,7 @@ cli.command(
|
|
|
415
420
|
"Output directory for capture (default: webflow-out) / docs (default: dirname of the ir.json)"
|
|
416
421
|
).action(
|
|
417
422
|
async (action, target, opts) => runOrExit(
|
|
418
|
-
async () => (await import("../webflow-
|
|
423
|
+
async () => (await import("../webflow-624FEBFD.js")).runWebflowCommand(action, target, opts),
|
|
419
424
|
opts
|
|
420
425
|
)
|
|
421
426
|
);
|