@reddoorla/maintenance 0.87.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-I2Z4JN3I.js → announce-GKD5YJNB.js} +9 -9
- package/dist/{blux-ZGDSHI3U.js → blux-DN4MI532.js} +5 -5
- package/dist/{bump-deps-CGVELRLK.js → bump-deps-KGH5UYSF.js} +4 -4
- package/dist/{chunk-SDDPUAWH.js → chunk-6I6L3CMX.js} +2 -2
- package/dist/{chunk-ZBDZTJUO.js → chunk-7FFUBF4I.js} +5 -2
- package/dist/chunk-7FFUBF4I.js.map +1 -0
- package/dist/{chunk-HSI6Q7MI.js → chunk-7TMWBXX7.js} +159 -29
- package/dist/chunk-7TMWBXX7.js.map +1 -0
- package/dist/{chunk-DEWJMMG3.js → chunk-A2UNJIKH.js} +15 -7
- package/dist/chunk-A2UNJIKH.js.map +1 -0
- package/dist/{chunk-NCMZMLY7.js → chunk-ANJNTAMM.js} +3 -69
- package/dist/chunk-ANJNTAMM.js.map +1 -0
- package/dist/{chunk-3JQ2FO3D.js → chunk-B23FFWU4.js} +2 -2
- 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-NDWYJLRF.js → chunk-DGZWFI2G.js} +3 -3
- package/dist/{chunk-HHMMUR4P.js → chunk-GQDDWYU2.js} +45 -8
- package/dist/chunk-GQDDWYU2.js.map +1 -0
- package/dist/{chunk-BBUSGEES.js → chunk-J3WEZGIN.js} +6 -6
- package/dist/{chunk-BNM5POSJ.js → chunk-JRHIFA5R.js} +2 -2
- package/dist/{chunk-TD2NNXLZ.js → chunk-K6SLF6GI.js} +5 -5
- package/dist/{chunk-MT2JINSS.js → chunk-KJGKZLCT.js} +3 -3
- package/dist/{chunk-NXNPDCF3.js → chunk-KMCZA7CH.js} +11 -1
- 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-C6CLRKPV.js → chunk-PR343K7F.js} +2 -2
- package/dist/{chunk-CROKUHJB.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-HEWSRXYV.js → chunk-ULHPALI5.js} +3 -3
- package/dist/{chunk-XUGSZP7Z.js → chunk-W45FZEGE.js} +2 -2
- package/dist/{chunk-JHGHLKFS.js → chunk-WS6NU475.js} +2 -2
- package/dist/{chunk-ZGBEIWSC.js → chunk-XP5WM2LV.js} +5 -5
- package/dist/{chunk-6TWWY7ZU.js → chunk-Z3JXLULD.js} +2 -2
- package/dist/cli/bin.js +27 -27
- package/dist/cli/bin.js.map +1 -1
- package/dist/cli/commands/audit.d.ts +4 -0
- package/dist/cli/commands/audit.js +16 -13
- 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-QFJOEP5V.js → convert-to-pnpm-NWB5FCQ2.js} +4 -4
- package/dist/{db-UXNIZ2RG.js → db-V6UIS433.js} +121 -26
- package/dist/db-V6UIS433.js.map +1 -0
- package/dist/{digest-FW6QMZZJ.js → digest-2JEAEJK6.js} +53 -29
- 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-KJXASVH5.js → email-SL7464YI.js} +16 -6
- package/dist/{email-KJXASVH5.js.map → email-SL7464YI.js.map} +1 -1
- package/dist/{ensure-site-4DCEBAPM.js → ensure-site-FU6527OU.js} +2 -2
- package/dist/{fleet-state-7TJ2GYT2.js → fleet-state-R5LU7IC3.js} +4 -2
- package/dist/{forms-notify-target-2EAWCWBW.js → forms-notify-target-SGDGXXK5.js} +6 -6
- package/dist/{github-signals-E2WPYTBK.js → github-signals-GWGCKEE2.js} +7 -6
- package/dist/{github-signals-E2WPYTBK.js.map → github-signals-GWGCKEE2.js.map} +1 -1
- package/dist/{header-image-6IC53W27.js → header-image-7A7XLVEU.js} +2 -2
- package/dist/{health-endpoint-RFXL2F4A.js → health-endpoint-UVX6R5N5.js} +4 -4
- package/dist/{health-mirror-L5JBEJVA.js → health-mirror-GCDN7BJL.js} +11 -6
- package/dist/health-mirror-GCDN7BJL.js.map +1 -0
- package/dist/index.js +128 -88
- package/dist/index.js.map +1 -1
- package/dist/{init-XRAQZYID.js → init-FGTYNGUI.js} +9 -9
- package/dist/{launch-IX4Y5JJC.js → launch-5H7LPEGP.js} +12 -11
- package/dist/{launch-IX4Y5JJC.js.map → launch-5H7LPEGP.js.map} +1 -1
- package/dist/migrate-YITCXBLS.js +7 -0
- package/dist/{notify-C645PGD5.js → notify-4HP4GZ2H.js} +5 -5
- package/dist/{onboard-O4IAHJMO.js → onboard-BKCYBAVW.js} +4 -4
- package/dist/{orchestrate-YLWQ6KK2.js → orchestrate-JNKCWU5K.js} +9 -9
- package/dist/{parity-56KA2DGR.js → parity-NBYZUBFU.js} +4 -2
- package/dist/pdf-N5QLQ5ZQ.js +38 -0
- package/dist/pdf-N5QLQ5ZQ.js.map +1 -0
- package/dist/{pipeline-3AANZFCR.js → pipeline-WYTXSLHX.js} +3 -3
- package/dist/{preflight-TNORKGCX.js → preflight-IMTYDDD4.js} +10 -10
- package/dist/{prismic-ci-G2AK53VL.js → prismic-ci-MY2U6NN7.js} +4 -4
- package/dist/{prismic-models-O6Z3OK3A.js → prismic-models-NJN5JORF.js} +6 -6
- package/dist/prospect/types.d.ts +14 -0
- package/dist/{prospect-audit-KSXUNQ5J.js → prospect-audit-JMBRVXSG.js} +32 -13
- package/dist/prospect-audit-JMBRVXSG.js.map +1 -0
- package/dist/render-VX72AESY.js +10 -0
- package/dist/{render-from-row-BWSOIYDS.js → render-from-row-DOYJDO2L.js} +5 -5
- package/dist/{replay-C2LXMJZP.js → replay-4S6ENYCH.js} +3 -3
- package/dist/{report-R3E3Y7HR.js → report-TALY5P3L.js} +17 -17
- package/dist/{report-mirror-4MNORYQ4.js → report-mirror-AAK3MXHY.js} +12 -6
- package/dist/report-mirror-AAK3MXHY.js.map +1 -0
- package/dist/schema-75PJECAE.js +18 -0
- package/dist/schema-75PJECAE.js.map +1 -0
- package/dist/{self-updating-UCIWESAX.js → self-updating-NTCCWJYZ.js} +4 -4
- package/dist/{selftest-VGHWPN72.js → selftest-NZTR4SM2.js} +11 -11
- package/dist/{site-mirror-NIREX5ME.js → site-mirror-Q763PLGG.js} +17 -7
- package/dist/site-mirror-Q763PLGG.js.map +1 -0
- package/dist/{smoke-suite-U3UKD3NS.js → smoke-suite-4JFZZYVW.js} +4 -4
- package/dist/{spam-classifier-XLBFCO7G.js → spam-classifier-T5H4VTP6.js} +4 -2
- package/dist/{submissions-IQEJX6FK.js → submissions-TEHPBSZJ.js} +4 -4
- package/dist/{svelte-codemods-GOKXTBHW.js → svelte-codemods-QAPDZC6F.js} +4 -4
- package/dist/{sync-CTUVXMCK.js → sync-GBFV45WX.js} +4 -2
- package/dist/{sync-CTUVXMCK.js.map → sync-GBFV45WX.js.map} +1 -1
- package/dist/{sync-configs-SPTLFJCC.js → sync-configs-34JIA6KZ.js} +4 -4
- package/dist/{upgrade-W6ZR3FJH.js → upgrade-IR2OO3KP.js} +4 -4
- package/dist/{webhook-VOGOW3W6.js → webhook-XM6EV4XT.js} +2 -2
- package/dist/{write-audits-to-airtable-CMKHGJNQ.js → write-audits-to-airtable-OBHGR7DQ.js} +5 -2
- package/dist/write-audits-to-airtable-OBHGR7DQ.js.map +1 -0
- package/package.json +1 -1
- package/dist/airtable-ZBUPQJSC.js +0 -9
- package/dist/chunk-C6B4RHXR.js.map +0 -1
- package/dist/chunk-DEWJMMG3.js.map +0 -1
- package/dist/chunk-DJZWYIPP.js.map +0 -1
- package/dist/chunk-HHMMUR4P.js.map +0 -1
- package/dist/chunk-HSI6Q7MI.js.map +0 -1
- package/dist/chunk-NCMZMLY7.js.map +0 -1
- package/dist/chunk-NXNPDCF3.js.map +0 -1
- package/dist/chunk-SNSTJLQW.js.map +0 -1
- package/dist/chunk-ZBDZTJUO.js.map +0 -1
- package/dist/client-AUE3XUPO.js +0 -11
- package/dist/db-UXNIZ2RG.js.map +0 -1
- package/dist/digest-FW6QMZZJ.js.map +0 -1
- package/dist/dump-P6EBSIOH.js.map +0 -1
- package/dist/health-mirror-L5JBEJVA.js.map +0 -1
- package/dist/migrate-GQH237A6.js +0 -7
- package/dist/prospect-audit-KSXUNQ5J.js.map +0 -1
- package/dist/render-IFOGFB5T.js +0 -10
- package/dist/report-mirror-4MNORYQ4.js.map +0 -1
- package/dist/site-mirror-NIREX5ME.js.map +0 -1
- /package/dist/{airtable-ZBUPQJSC.js.map → airtable-QG5ICI3Y.js.map} +0 -0
- /package/dist/{announce-I2Z4JN3I.js.map → announce-GKD5YJNB.js.map} +0 -0
- /package/dist/{blux-ZGDSHI3U.js.map → blux-DN4MI532.js.map} +0 -0
- /package/dist/{bump-deps-CGVELRLK.js.map → bump-deps-KGH5UYSF.js.map} +0 -0
- /package/dist/{chunk-SDDPUAWH.js.map → chunk-6I6L3CMX.js.map} +0 -0
- /package/dist/{chunk-3JQ2FO3D.js.map → chunk-B23FFWU4.js.map} +0 -0
- /package/dist/{chunk-NDWYJLRF.js.map → chunk-DGZWFI2G.js.map} +0 -0
- /package/dist/{chunk-BBUSGEES.js.map → chunk-J3WEZGIN.js.map} +0 -0
- /package/dist/{chunk-BNM5POSJ.js.map → chunk-JRHIFA5R.js.map} +0 -0
- /package/dist/{chunk-TD2NNXLZ.js.map → chunk-K6SLF6GI.js.map} +0 -0
- /package/dist/{chunk-MT2JINSS.js.map → chunk-KJGKZLCT.js.map} +0 -0
- /package/dist/{chunk-C6CLRKPV.js.map → chunk-PR343K7F.js.map} +0 -0
- /package/dist/{chunk-CROKUHJB.js.map → chunk-Q47DU255.js.map} +0 -0
- /package/dist/{chunk-VSBFM7DS.js.map → chunk-SJOXWJ5Y.js.map} +0 -0
- /package/dist/{chunk-HEWSRXYV.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-ZGBEIWSC.js.map → chunk-XP5WM2LV.js.map} +0 -0
- /package/dist/{chunk-6TWWY7ZU.js.map → chunk-Z3JXLULD.js.map} +0 -0
- /package/dist/{client-AUE3XUPO.js.map → client-JYKPVCJX.js.map} +0 -0
- /package/dist/{convert-to-pnpm-QFJOEP5V.js.map → convert-to-pnpm-NWB5FCQ2.js.map} +0 -0
- /package/dist/{fleet-state-7TJ2GYT2.js.map → digest-state-F37XUCS5.js.map} +0 -0
- /package/dist/{ensure-site-4DCEBAPM.js.map → ensure-site-FU6527OU.js.map} +0 -0
- /package/dist/{migrate-GQH237A6.js.map → fleet-state-R5LU7IC3.js.map} +0 -0
- /package/dist/{forms-notify-target-2EAWCWBW.js.map → forms-notify-target-SGDGXXK5.js.map} +0 -0
- /package/dist/{header-image-6IC53W27.js.map → header-image-7A7XLVEU.js.map} +0 -0
- /package/dist/{health-endpoint-RFXL2F4A.js.map → health-endpoint-UVX6R5N5.js.map} +0 -0
- /package/dist/{init-XRAQZYID.js.map → init-FGTYNGUI.js.map} +0 -0
- /package/dist/{notify-C645PGD5.js.map → migrate-YITCXBLS.js.map} +0 -0
- /package/dist/{orchestrate-YLWQ6KK2.js.map → notify-4HP4GZ2H.js.map} +0 -0
- /package/dist/{onboard-O4IAHJMO.js.map → onboard-BKCYBAVW.js.map} +0 -0
- /package/dist/{parity-56KA2DGR.js.map → orchestrate-JNKCWU5K.js.map} +0 -0
- /package/dist/{pipeline-3AANZFCR.js.map → parity-NBYZUBFU.js.map} +0 -0
- /package/dist/{render-IFOGFB5T.js.map → pipeline-WYTXSLHX.js.map} +0 -0
- /package/dist/{preflight-TNORKGCX.js.map → preflight-IMTYDDD4.js.map} +0 -0
- /package/dist/{prismic-ci-G2AK53VL.js.map → prismic-ci-MY2U6NN7.js.map} +0 -0
- /package/dist/{prismic-models-O6Z3OK3A.js.map → prismic-models-NJN5JORF.js.map} +0 -0
- /package/dist/{render-from-row-BWSOIYDS.js.map → render-VX72AESY.js.map} +0 -0
- /package/dist/{spam-classifier-XLBFCO7G.js.map → render-from-row-DOYJDO2L.js.map} +0 -0
- /package/dist/{replay-C2LXMJZP.js.map → replay-4S6ENYCH.js.map} +0 -0
- /package/dist/{report-R3E3Y7HR.js.map → report-TALY5P3L.js.map} +0 -0
- /package/dist/{self-updating-UCIWESAX.js.map → self-updating-NTCCWJYZ.js.map} +0 -0
- /package/dist/{selftest-VGHWPN72.js.map → selftest-NZTR4SM2.js.map} +0 -0
- /package/dist/{smoke-suite-U3UKD3NS.js.map → smoke-suite-4JFZZYVW.js.map} +0 -0
- /package/dist/{write-audits-to-airtable-CMKHGJNQ.js.map → spam-classifier-T5H4VTP6.js.map} +0 -0
- /package/dist/{submissions-IQEJX6FK.js.map → submissions-TEHPBSZJ.js.map} +0 -0
- /package/dist/{svelte-codemods-GOKXTBHW.js.map → svelte-codemods-QAPDZC6F.js.map} +0 -0
- /package/dist/{sync-configs-SPTLFJCC.js.map → sync-configs-34JIA6KZ.js.map} +0 -0
- /package/dist/{upgrade-W6ZR3FJH.js.map → upgrade-IR2OO3KP.js.map} +0 -0
- /package/dist/{webhook-VOGOW3W6.js.map → webhook-XM6EV4XT.js.map} +0 -0
|
@@ -5,27 +5,27 @@ import {
|
|
|
5
5
|
} from "./chunk-TVL5MVUF.js";
|
|
6
6
|
import {
|
|
7
7
|
resolveSites
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-Q47DU255.js";
|
|
9
9
|
import {
|
|
10
10
|
init
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-K6SLF6GI.js";
|
|
12
|
+
import "./chunk-IYSEC543.js";
|
|
12
13
|
import "./chunk-BQRFQSGY.js";
|
|
13
14
|
import "./chunk-Y53WOQIJ.js";
|
|
14
15
|
import "./chunk-7RJ2HMMJ.js";
|
|
15
16
|
import "./chunk-R53VL3RI.js";
|
|
16
|
-
import "./chunk-XIDUYLSR.js";
|
|
17
|
-
import "./chunk-IYSEC543.js";
|
|
18
17
|
import "./chunk-J7SZQUCW.js";
|
|
18
|
+
import "./chunk-XIDUYLSR.js";
|
|
19
19
|
import "./chunk-7UAYMAKR.js";
|
|
20
20
|
import "./chunk-73UFRZKY.js";
|
|
21
21
|
import "./chunk-3G25KIWW.js";
|
|
22
22
|
import "./chunk-OTGB6YQO.js";
|
|
23
|
-
import "./chunk-
|
|
23
|
+
import "./chunk-B23FFWU4.js";
|
|
24
24
|
import "./chunk-LKGVSM2O.js";
|
|
25
25
|
import "./chunk-GASBX52O.js";
|
|
26
26
|
import "./chunk-XHHMM5HX.js";
|
|
27
|
-
import "./chunk-
|
|
28
|
-
import "./chunk-
|
|
27
|
+
import "./chunk-Z3JXLULD.js";
|
|
28
|
+
import "./chunk-RARREDQE.js";
|
|
29
29
|
import "./chunk-A3WDWNN5.js";
|
|
30
30
|
import "./chunk-2OP4JKIQ.js";
|
|
31
31
|
import "./chunk-XTK5VIQB.js";
|
|
@@ -37,7 +37,7 @@ import {
|
|
|
37
37
|
siteLabel
|
|
38
38
|
} from "./chunk-XXTZBPUY.js";
|
|
39
39
|
import "./chunk-NMAWXBJA.js";
|
|
40
|
-
import "./chunk-
|
|
40
|
+
import "./chunk-O3GT46R2.js";
|
|
41
41
|
|
|
42
42
|
// src/cli/commands/init.ts
|
|
43
43
|
import { resolve } from "path";
|
|
@@ -110,4 +110,4 @@ async function runInitCommand(site, opts) {
|
|
|
110
110
|
export {
|
|
111
111
|
runInitCommand
|
|
112
112
|
};
|
|
113
|
-
//# sourceMappingURL=init-
|
|
113
|
+
//# sourceMappingURL=init-FGTYNGUI.js.map
|
|
@@ -4,14 +4,15 @@ import {
|
|
|
4
4
|
import "./chunk-MNDIED4M.js";
|
|
5
5
|
import {
|
|
6
6
|
writeAuditsToAirtable
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-KMCZA7CH.js";
|
|
8
8
|
import {
|
|
9
9
|
hasRealScores,
|
|
10
10
|
lighthouseScoresFromResult
|
|
11
11
|
} from "./chunk-7BZUOZPU.js";
|
|
12
|
+
import "./chunk-RUPPWAD6.js";
|
|
12
13
|
import {
|
|
13
14
|
resolveSites
|
|
14
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-Q47DU255.js";
|
|
15
16
|
import "./chunk-5L3FPQIJ.js";
|
|
16
17
|
import {
|
|
17
18
|
queueDraft
|
|
@@ -32,8 +33,8 @@ import {
|
|
|
32
33
|
import {
|
|
33
34
|
renderReportHtml,
|
|
34
35
|
resolveCopy
|
|
35
|
-
} from "./chunk-
|
|
36
|
-
import "./chunk-
|
|
36
|
+
} from "./chunk-KJGKZLCT.js";
|
|
37
|
+
import "./chunk-BGTYPVLT.js";
|
|
37
38
|
import {
|
|
38
39
|
listWebsites,
|
|
39
40
|
siteSlug
|
|
@@ -41,12 +42,12 @@ import {
|
|
|
41
42
|
import "./chunk-73UFRZKY.js";
|
|
42
43
|
import {
|
|
43
44
|
runAudits
|
|
44
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-B23FFWU4.js";
|
|
45
46
|
import "./chunk-LKGVSM2O.js";
|
|
46
47
|
import "./chunk-GASBX52O.js";
|
|
47
48
|
import "./chunk-XHHMM5HX.js";
|
|
48
|
-
import "./chunk-
|
|
49
|
-
import "./chunk-
|
|
49
|
+
import "./chunk-Z3JXLULD.js";
|
|
50
|
+
import "./chunk-RARREDQE.js";
|
|
50
51
|
import "./chunk-A3WDWNN5.js";
|
|
51
52
|
import "./chunk-2OP4JKIQ.js";
|
|
52
53
|
import "./chunk-XTK5VIQB.js";
|
|
@@ -59,7 +60,7 @@ import {
|
|
|
59
60
|
} from "./chunk-XXTZBPUY.js";
|
|
60
61
|
import "./chunk-6VAL7XJT.js";
|
|
61
62
|
import "./chunk-NMAWXBJA.js";
|
|
62
|
-
import "./chunk-
|
|
63
|
+
import "./chunk-O3GT46R2.js";
|
|
63
64
|
|
|
64
65
|
// src/cli/commands/launch.ts
|
|
65
66
|
import { resolve } from "path";
|
|
@@ -240,8 +241,8 @@ async function runLaunchCommand(site, opts) {
|
|
|
240
241
|
if (!target) {
|
|
241
242
|
return { output: `No site resolved for "${site}".`, code: 1 };
|
|
242
243
|
}
|
|
243
|
-
const { makeReportMirror } = await import("./report-mirror-
|
|
244
|
-
const { makeSiteMirror } = await import("./site-mirror-
|
|
244
|
+
const { makeReportMirror } = await import("./report-mirror-AAK3MXHY.js");
|
|
245
|
+
const { makeSiteMirror } = await import("./site-mirror-Q763PLGG.js");
|
|
245
246
|
const result = await launch(target, {
|
|
246
247
|
reportMirror: await makeReportMirror(),
|
|
247
248
|
siteMirror: await makeSiteMirror()
|
|
@@ -251,4 +252,4 @@ async function runLaunchCommand(site, opts) {
|
|
|
251
252
|
export {
|
|
252
253
|
runLaunchCommand
|
|
253
254
|
};
|
|
254
|
-
//# sourceMappingURL=launch-
|
|
255
|
+
//# sourceMappingURL=launch-5H7LPEGP.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/commands/launch.ts","../src/recipes/launch.ts"],"sourcesContent":["import { resolve } from \"node:path\";\nimport { launch, type LaunchResult, type LaunchStepResult } from \"../../recipes/launch.js\";\nimport { resolveSites } from \"../fleet/resolve-sites.js\";\n\nexport type LaunchCommandOptions = {\n cwd?: string;\n};\n\nfunction formatStep(name: string, r: LaunchStepResult): string {\n if (r.kind === \"error\") return `${name.padEnd(20)} error: ${r.message}`;\n if (r.kind === \"audit\") {\n const s = r.scores;\n return `${name.padEnd(20)} audited (P=${s.performance} A=${s.accessibility} BP=${s.bestPractices} SEO=${s.seo})`;\n }\n if (r.kind === \"draft\") {\n return `${name.padEnd(20)} drafted ${r.report.reportId}`;\n }\n const rec = r.result;\n if (rec.status === \"noop\") return `${name.padEnd(20)} noop${rec.notes ? ` — ${rec.notes}` : \"\"}`;\n if (rec.status === \"failed\")\n return `${name.padEnd(20)} failed${rec.notes ? ` — ${rec.notes}` : \"\"}`;\n return `${name.padEnd(20)} applied (${rec.commits.length} commit${rec.commits.length === 1 ? \"\" : \"s\"})${rec.notes ? ` — ${rec.notes}` : \"\"}`;\n}\n\nfunction formatResult(r: LaunchResult): string {\n const header = `[${r.site}] launch — ${r.complete ? \"drafted (awaiting approval)\" : \"STOPPED\"}`;\n const body = r.steps.map((s) => formatStep(s.name, s.result)).join(\"\\n\");\n return `${header}\\n${body}`;\n}\n\n/**\n * `launch <site>` — single-site only. Bootstrap (Renovate + protection), first-audit\n * the site, and DRAFT its launch email into the M3 approve queue. Never sends;\n * the operator approves the draft and the next send run delivers the go-live\n * email (flipping Status → maintenance + stamping Launched at).\n */\nexport async function runLaunchCommand(\n site: string,\n opts: LaunchCommandOptions,\n): Promise<{ output: string; code: number }> {\n const cwd = opts.cwd ? resolve(opts.cwd) : process.cwd();\n const sites = await resolveSites({ site, cwd });\n const target = sites[0];\n if (!target) {\n return { output: `No site resolved for \"${site}\".`, code: 1 };\n }\n\n // #539 Phase 5: create-side Turso dual-write, wired at the composition root\n // (see runAnnounceCommand for why it is not defaulted inside the recipe).\n const { makeReportMirror } = await import(\"../../reports/report-mirror.js\");\n const { makeSiteMirror } = await import(\"../../db/site-mirror.js\");\n const result = await launch(target, {\n reportMirror: await makeReportMirror(),\n siteMirror: await makeSiteMirror(),\n });\n return { output: formatResult(result), code: result.complete ? 0 : 1 };\n}\n","import type { AuditResult, RecipeResult, Site } from \"../types.js\";\nimport { siteLabel } from \"../util/site.js\";\nimport { selfUpdating } from \"./self-updating/index.js\";\nimport { runAudits } from \"../audits/index.js\";\nimport { hasRealScores, lighthouseScoresFromResult } from \"../audits/lighthouse-airtable.js\";\nimport { writeAuditsToAirtable } from \"../audits/write-audits-to-airtable.js\";\nimport { openBase, readAirtableConfig } from \"../reports/airtable/client.js\";\nimport type { AirtableBase } from \"../reports/airtable/client.js\";\nimport { listWebsites, siteSlug } from \"../reports/airtable/websites.js\";\nimport type { WebsiteRow } from \"../reports/airtable/websites.js\";\nimport {\n createDraft,\n findReportByPeriod,\n updateReportScores,\n} from \"../reports/airtable/reports.js\";\nimport type { ReportRow } from \"../reports/airtable/reports.js\";\nimport type { ReportMirror } from \"../reports/report-mirror.js\";\nimport type { SiteMirror } from \"../db/site-mirror.js\";\nimport { queueDraft } from \"../reports/queue.js\";\nimport { uploadAttachment } from \"../reports/airtable/attachments.js\";\nimport { renderReportHtml } from \"../reports/render.js\";\nimport { resolveCopy } from \"../reports/copy.js\";\nimport type { LighthouseScores } from \"../reports/types.js\";\n\nexport type LaunchStepResult =\n | { kind: \"recipe\"; result: RecipeResult }\n | { kind: \"audit\"; results: AuditResult[]; scores: LighthouseScores }\n | { kind: \"draft\"; report: ReportRow }\n | { kind: \"error\"; message: string };\n\nexport type LaunchResult = {\n site: string;\n steps: Array<{ name: string; result: LaunchStepResult }>;\n /** True if every step ran (bootstrap + audit + draft); false if a step\n * errored or a recipe `failed` short-circuited the chain. */\n complete: boolean;\n};\n\nexport type LaunchDeps = {\n /** Bootstrap step (Renovate + protection; ci.yml comes from the starter). Defaults to the real `selfUpdating`. */\n bootstrap?: (site: Site) => Promise<RecipeResult>;\n /** Audit step. Defaults to the real `runAudits`. */\n audit?: (site: Site) => Promise<AuditResult[]>;\n /** Airtable handle. Defaults to opening the live base from credentials. */\n base?: AirtableBase;\n /** #539 Phase 5: Turso write-through for everything this recipe writes — the\n * Launch row (or a re-run's refreshed scores), the rendered body, and the\n * queue flag. Wired at the CLI composition root, never defaulted here — the\n * unit suite calls `launch` with a fake base and must not open a real\n * libSQL handle. */\n reportMirror?: ReportMirror;\n /** #539 Phase 5: the Websites-row twin — launch writes the site's FIRST audit\n * results and (on send) its launched status. Injected at the CLI root. */\n siteMirror?: SiteMirror;\n};\n\n/**\n * Launch a site: bootstrap → first-audit → DRAFT a launch email. The M3\n * approve loop is what actually sends; `launch` never sends — it stops at a\n * dashboard-queued draft (`reportType: \"Launch\"`) carrying the just-audited\n * Lighthouse scores, so `sendOne`'s `report.lighthouse` guard passes.\n *\n * Step-chain (mirrors `init`), stopping on the first error or `failed` recipe:\n * 1. selfUpdating — Renovate + protection (platform auto-merge OFF; ci.yml is the starter's).\n * 2. runAudits + write the scores to the site's Websites row (reuses the\n * `audit --write-airtable` writer); the Lighthouse scores feed the draft.\n * 3. createDraft — reportType \"Launch\", today's period, the audited scores.\n */\nexport async function launch(site: Site, deps: LaunchDeps = {}): Promise<LaunchResult> {\n const label = siteLabel(site);\n const bootstrap = deps.bootstrap ?? selfUpdating;\n const audit = deps.audit ?? runAudits;\n const base = deps.base ?? openBase(readAirtableConfig());\n\n const steps: Array<{ name: string; result: LaunchStepResult }> = [];\n const stop = (): LaunchResult => ({ site: label, steps, complete: false });\n\n // 1. Bootstrap.\n let recipe: RecipeResult;\n try {\n recipe = await bootstrap(site);\n } catch (err) {\n steps.push({ name: \"self-updating\", result: errorOf(err) });\n return stop();\n }\n steps.push({ name: \"self-updating\", result: { kind: \"recipe\", result: recipe } });\n if (recipe.status === \"failed\") return stop();\n\n // 2. Audit + write scores back to Airtable.\n let results: AuditResult[];\n try {\n results = await audit(site);\n } catch (err) {\n steps.push({ name: \"audit\", result: errorOf(err) });\n return stop();\n }\n const lhResult = results.find((r) => r.audit === \"lighthouse\");\n if (!lhResult || !hasRealScores(lhResult)) {\n steps.push({\n name: \"audit\",\n result: { kind: \"error\", message: \"lighthouse audit produced no real scores\" },\n });\n return stop();\n }\n // The launch announcement renders a numeric score per category; a metric that\n // errored this run (now null from lighthouseScoresFromResult) keeps the prior\n // 0 behavior here rather than propagating null into the launch-email path. The\n // Airtable write path (write-audits-to-airtable) keeps the null → shows \"—\".\n const rawScores = lighthouseScoresFromResult(lhResult);\n const scores: LighthouseScores = {\n performance: rawScores.performance ?? 0,\n accessibility: rawScores.accessibility ?? 0,\n bestPractices: rawScores.bestPractices ?? 0,\n seo: rawScores.seo ?? 0,\n };\n\n const websites = await listWebsites(base);\n const target = websites.find((w) => siteSlug(w.name) === siteSlug(label));\n if (!target) {\n steps.push({\n name: \"audit\",\n result: { kind: \"error\", message: `no Websites row matched site \"${label}\"` },\n });\n return stop();\n }\n try {\n const auditWrite = await writeAuditsToAirtable({\n base,\n websites,\n slug: siteSlug(target.name),\n results,\n });\n // #539 Phase 5: mirror the first-audit write-back. Launch is the ONE path\n // that writes a brand-new site's health, so without this its row reads empty\n // in the console until the next hourly sync.\n if (auditWrite.siteId && auditWrite.fields) {\n await deps.siteMirror?.health(auditWrite.siteId, auditWrite.fields);\n }\n } catch (err) {\n steps.push({ name: \"audit\", result: errorOf(err) });\n return stop();\n }\n steps.push({ name: \"audit\", result: { kind: \"audit\", results, scores } });\n\n // 3. Draft the launch email (reuses draft.ts's reportId/period scheme). DRAFTS\n // ONLY — the M3 approve loop sends it and flips Status on send.\n const today = new Date();\n const period = today.toISOString().slice(0, 7);\n const slug = siteSlug(target.name);\n\n let report: ReportRow;\n try {\n // Re-run dedupe: reuse an existing Launch row for this (site, period) instead\n // of stacking a second draft. findReportByPeriod is the same idempotency\n // lookup draft.ts documents (dashboard/digest point lookup).\n const existing = await findReportByPeriod(base, target.id, \"Launch\", period);\n if (existing) {\n // Reuse path: the row was created on a prior run with THAT run's scores. This\n // re-run just produced fresh audit scores AND will re-render the preview from\n // them — so refresh the row's Lighthouse cells (+ Completed on) to match,\n // otherwise the sent email (which reads the row) ships stale scores. The\n // create path already writes fresh scores via createDraft.\n await updateReportScores(base, existing.id, scores, today);\n // Mirror the same refresh — see the announce reuse path for why.\n await deps.reportMirror?.patch(existing.id, {\n lighthouse_performance: scores.performance,\n lighthouse_accessibility: scores.accessibility,\n lighthouse_best_practices: scores.bestPractices,\n lighthouse_seo: scores.seo,\n completed_on: today.toISOString().slice(0, 10),\n });\n report = existing;\n } else {\n report = await createDraft(\n base,\n draftInputFor(target, scores, today, period),\n deps.reportMirror?.created,\n );\n }\n } catch (err) {\n steps.push({ name: \"draft\", result: errorOf(err) });\n return stop();\n }\n\n // Mirror draft.ts:135-154 — render → upload \"Rendered HTML\" preview → flip\n // Draft ready. Without setDraftReady the draft never enters the approve queue\n // (every pending-approval gate requires draftReady true), so it can never be\n // approved or sent. The upload is a review convenience; the ready flag is the\n // critical step.\n try {\n const { html } = await renderReportHtml({\n siteName: target.name,\n siteUrl: target.url,\n reportType: \"Launch\",\n completedOn: today,\n lighthouse: scores,\n lastTestedDate: null,\n commentary: null,\n copy: resolveCopy(target),\n headerImageCid: `${slug}-header`,\n });\n // A preview-upload hiccup must NOT fail the launch — log and continue.\n try {\n await uploadAttachment(\n report.id,\n \"Rendered HTML\",\n html,\n `${slug}-${today.toISOString().slice(0, 10)}.html`,\n \"text/html\",\n );\n // The console preview reads the body from Turso, not the attachment.\n await deps.reportMirror?.body(report.id, html);\n } catch (uploadErr) {\n console.warn(\n `⚠ Launch preview upload skipped for ${target.name}: ${\n uploadErr instanceof Error ? uploadErr.message : String(uploadErr)\n }`,\n );\n }\n // Critical: NOT wrapped — a failure here must surface as a failed launch. queueDraft\n // supersedes any lower-tier (Maintenance/Testing) drafts queued for this site; a Launch is\n // top tier so it only stands down if another Launch/Announcement is already queued.\n await queueDraft(\n base,\n { id: report.id, siteId: target.id, reportType: \"Launch\" },\n deps.reportMirror,\n );\n } catch (err) {\n steps.push({ name: \"draft\", result: errorOf(err) });\n return stop();\n }\n\n steps.push({ name: \"draft\", result: { kind: \"draft\", report } });\n\n return { site: label, steps, complete: true };\n}\n\n/** Build the Launch `DraftInput`. reportId/period mirror `draftReportForSite`\n * (draft.ts) — do not invent a new id scheme. `today`/`period` are threaded in\n * from `launch()` so a single timestamp drives the render, the draft, the\n * dedupe lookup, and the preview filename. Launch reports have no period window\n * and no prior maintenance test, so periodStart/periodEnd/completedOn all\n * collapse to \"today\" and `lastTestedDate` is null. */\nfunction draftInputFor(\n target: WebsiteRow,\n scores: LighthouseScores,\n today: Date,\n period: string,\n): Parameters<typeof createDraft>[1] {\n const reportType = \"Launch\" as const;\n const reportId = `${target.name} — ${reportType} — ${today.toISOString().slice(0, 10)}`;\n return {\n reportId,\n siteId: target.id,\n reportType,\n period,\n periodStart: today,\n periodEnd: today,\n completedOn: today,\n lighthouse: scores,\n lastTestedDate: null,\n };\n}\n\nfunction errorOf(err: unknown): LaunchStepResult {\n return { kind: \"error\", message: err instanceof Error ? err.message : String(err) };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/cli/commands/launch.ts","../src/recipes/launch.ts"],"sourcesContent":["import { resolve } from \"node:path\";\nimport { launch, type LaunchResult, type LaunchStepResult } from \"../../recipes/launch.js\";\nimport { resolveSites } from \"../fleet/resolve-sites.js\";\n\nexport type LaunchCommandOptions = {\n cwd?: string;\n};\n\nfunction formatStep(name: string, r: LaunchStepResult): string {\n if (r.kind === \"error\") return `${name.padEnd(20)} error: ${r.message}`;\n if (r.kind === \"audit\") {\n const s = r.scores;\n return `${name.padEnd(20)} audited (P=${s.performance} A=${s.accessibility} BP=${s.bestPractices} SEO=${s.seo})`;\n }\n if (r.kind === \"draft\") {\n return `${name.padEnd(20)} drafted ${r.report.reportId}`;\n }\n const rec = r.result;\n if (rec.status === \"noop\") return `${name.padEnd(20)} noop${rec.notes ? ` — ${rec.notes}` : \"\"}`;\n if (rec.status === \"failed\")\n return `${name.padEnd(20)} failed${rec.notes ? ` — ${rec.notes}` : \"\"}`;\n return `${name.padEnd(20)} applied (${rec.commits.length} commit${rec.commits.length === 1 ? \"\" : \"s\"})${rec.notes ? ` — ${rec.notes}` : \"\"}`;\n}\n\nfunction formatResult(r: LaunchResult): string {\n const header = `[${r.site}] launch — ${r.complete ? \"drafted (awaiting approval)\" : \"STOPPED\"}`;\n const body = r.steps.map((s) => formatStep(s.name, s.result)).join(\"\\n\");\n return `${header}\\n${body}`;\n}\n\n/**\n * `launch <site>` — single-site only. Bootstrap (Renovate + protection), first-audit\n * the site, and DRAFT its launch email into the M3 approve queue. Never sends;\n * the operator approves the draft and the next send run delivers the go-live\n * email (flipping Status → maintenance + stamping Launched at).\n */\nexport async function runLaunchCommand(\n site: string,\n opts: LaunchCommandOptions,\n): Promise<{ output: string; code: number }> {\n const cwd = opts.cwd ? resolve(opts.cwd) : process.cwd();\n const sites = await resolveSites({ site, cwd });\n const target = sites[0];\n if (!target) {\n return { output: `No site resolved for \"${site}\".`, code: 1 };\n }\n\n // #539 Phase 5: create-side Turso dual-write, wired at the composition root\n // (see runAnnounceCommand for why it is not defaulted inside the recipe).\n const { makeReportMirror } = await import(\"../../reports/report-mirror.js\");\n const { makeSiteMirror } = await import(\"../../db/site-mirror.js\");\n const result = await launch(target, {\n reportMirror: await makeReportMirror(),\n siteMirror: await makeSiteMirror(),\n });\n return { output: formatResult(result), code: result.complete ? 0 : 1 };\n}\n","import type { AuditResult, RecipeResult, Site } from \"../types.js\";\nimport { siteLabel } from \"../util/site.js\";\nimport { selfUpdating } from \"./self-updating/index.js\";\nimport { runAudits } from \"../audits/index.js\";\nimport { hasRealScores, lighthouseScoresFromResult } from \"../audits/lighthouse-airtable.js\";\nimport { writeAuditsToAirtable } from \"../audits/write-audits-to-airtable.js\";\nimport { openBase, readAirtableConfig } from \"../reports/airtable/client.js\";\nimport type { AirtableBase } from \"../reports/airtable/client.js\";\nimport { listWebsites, siteSlug } from \"../reports/airtable/websites.js\";\nimport type { WebsiteRow } from \"../reports/airtable/websites.js\";\nimport {\n createDraft,\n findReportByPeriod,\n updateReportScores,\n} from \"../reports/airtable/reports.js\";\nimport type { ReportRow } from \"../reports/airtable/reports.js\";\nimport type { ReportMirror } from \"../reports/report-mirror.js\";\nimport type { SiteMirror } from \"../db/site-mirror.js\";\nimport { queueDraft } from \"../reports/queue.js\";\nimport { uploadAttachment } from \"../reports/airtable/attachments.js\";\nimport { renderReportHtml } from \"../reports/render.js\";\nimport { resolveCopy } from \"../reports/copy.js\";\nimport type { LighthouseScores } from \"../reports/types.js\";\n\nexport type LaunchStepResult =\n | { kind: \"recipe\"; result: RecipeResult }\n | { kind: \"audit\"; results: AuditResult[]; scores: LighthouseScores }\n | { kind: \"draft\"; report: ReportRow }\n | { kind: \"error\"; message: string };\n\nexport type LaunchResult = {\n site: string;\n steps: Array<{ name: string; result: LaunchStepResult }>;\n /** True if every step ran (bootstrap + audit + draft); false if a step\n * errored or a recipe `failed` short-circuited the chain. */\n complete: boolean;\n};\n\nexport type LaunchDeps = {\n /** Bootstrap step (Renovate + protection; ci.yml comes from the starter). Defaults to the real `selfUpdating`. */\n bootstrap?: (site: Site) => Promise<RecipeResult>;\n /** Audit step. Defaults to the real `runAudits`. */\n audit?: (site: Site) => Promise<AuditResult[]>;\n /** Airtable handle. Defaults to opening the live base from credentials. */\n base?: AirtableBase;\n /** #539 Phase 5: Turso write-through for everything this recipe writes — the\n * Launch row (or a re-run's refreshed scores), the rendered body, and the\n * queue flag. Wired at the CLI composition root, never defaulted here — the\n * unit suite calls `launch` with a fake base and must not open a real\n * libSQL handle. */\n reportMirror?: ReportMirror;\n /** #539 Phase 5: the Websites-row twin — launch writes the site's FIRST audit\n * results and (on send) its launched status. Injected at the CLI root. */\n siteMirror?: SiteMirror;\n};\n\n/**\n * Launch a site: bootstrap → first-audit → DRAFT a launch email. The M3\n * approve loop is what actually sends; `launch` never sends — it stops at a\n * dashboard-queued draft (`reportType: \"Launch\"`) carrying the just-audited\n * Lighthouse scores, so `sendOne`'s `report.lighthouse` guard passes.\n *\n * Step-chain (mirrors `init`), stopping on the first error or `failed` recipe:\n * 1. selfUpdating — Renovate + protection (platform auto-merge OFF; ci.yml is the starter's).\n * 2. runAudits + write the scores to the site's Websites row (reuses the\n * `audit --write-airtable` writer); the Lighthouse scores feed the draft.\n * 3. createDraft — reportType \"Launch\", today's period, the audited scores.\n */\nexport async function launch(site: Site, deps: LaunchDeps = {}): Promise<LaunchResult> {\n const label = siteLabel(site);\n const bootstrap = deps.bootstrap ?? selfUpdating;\n const audit = deps.audit ?? runAudits;\n const base = deps.base ?? openBase(readAirtableConfig());\n\n const steps: Array<{ name: string; result: LaunchStepResult }> = [];\n const stop = (): LaunchResult => ({ site: label, steps, complete: false });\n\n // 1. Bootstrap.\n let recipe: RecipeResult;\n try {\n recipe = await bootstrap(site);\n } catch (err) {\n steps.push({ name: \"self-updating\", result: errorOf(err) });\n return stop();\n }\n steps.push({ name: \"self-updating\", result: { kind: \"recipe\", result: recipe } });\n if (recipe.status === \"failed\") return stop();\n\n // 2. Audit + write scores back to Airtable.\n let results: AuditResult[];\n try {\n results = await audit(site);\n } catch (err) {\n steps.push({ name: \"audit\", result: errorOf(err) });\n return stop();\n }\n const lhResult = results.find((r) => r.audit === \"lighthouse\");\n if (!lhResult || !hasRealScores(lhResult)) {\n steps.push({\n name: \"audit\",\n result: { kind: \"error\", message: \"lighthouse audit produced no real scores\" },\n });\n return stop();\n }\n // The launch announcement renders a numeric score per category; a metric that\n // errored this run (now null from lighthouseScoresFromResult) keeps the prior\n // 0 behavior here rather than propagating null into the launch-email path. The\n // Airtable write path (write-audits-to-airtable) keeps the null → shows \"—\".\n const rawScores = lighthouseScoresFromResult(lhResult);\n const scores: LighthouseScores = {\n performance: rawScores.performance ?? 0,\n accessibility: rawScores.accessibility ?? 0,\n bestPractices: rawScores.bestPractices ?? 0,\n seo: rawScores.seo ?? 0,\n };\n\n const websites = await listWebsites(base);\n const target = websites.find((w) => siteSlug(w.name) === siteSlug(label));\n if (!target) {\n steps.push({\n name: \"audit\",\n result: { kind: \"error\", message: `no Websites row matched site \"${label}\"` },\n });\n return stop();\n }\n try {\n const auditWrite = await writeAuditsToAirtable({\n base,\n websites,\n slug: siteSlug(target.name),\n results,\n });\n // #539 Phase 5: mirror the first-audit write-back. Launch is the ONE path\n // that writes a brand-new site's health, so without this its row reads empty\n // in the console until the next hourly sync.\n if (auditWrite.siteId && auditWrite.fields) {\n await deps.siteMirror?.health(auditWrite.siteId, auditWrite.fields);\n }\n } catch (err) {\n steps.push({ name: \"audit\", result: errorOf(err) });\n return stop();\n }\n steps.push({ name: \"audit\", result: { kind: \"audit\", results, scores } });\n\n // 3. Draft the launch email (reuses draft.ts's reportId/period scheme). DRAFTS\n // ONLY — the M3 approve loop sends it and flips Status on send.\n const today = new Date();\n const period = today.toISOString().slice(0, 7);\n const slug = siteSlug(target.name);\n\n let report: ReportRow;\n try {\n // Re-run dedupe: reuse an existing Launch row for this (site, period) instead\n // of stacking a second draft. findReportByPeriod is the same idempotency\n // lookup draft.ts documents (dashboard/digest point lookup).\n const existing = await findReportByPeriod(base, target.id, \"Launch\", period);\n if (existing) {\n // Reuse path: the row was created on a prior run with THAT run's scores. This\n // re-run just produced fresh audit scores AND will re-render the preview from\n // them — so refresh the row's Lighthouse cells (+ Completed on) to match,\n // otherwise the sent email (which reads the row) ships stale scores. The\n // create path already writes fresh scores via createDraft.\n await updateReportScores(base, existing.id, scores, today);\n // Mirror the same refresh — see the announce reuse path for why.\n await deps.reportMirror?.patch(existing.id, {\n lighthouse_performance: scores.performance,\n lighthouse_accessibility: scores.accessibility,\n lighthouse_best_practices: scores.bestPractices,\n lighthouse_seo: scores.seo,\n completed_on: today.toISOString().slice(0, 10),\n });\n report = existing;\n } else {\n report = await createDraft(\n base,\n draftInputFor(target, scores, today, period),\n deps.reportMirror?.created,\n );\n }\n } catch (err) {\n steps.push({ name: \"draft\", result: errorOf(err) });\n return stop();\n }\n\n // Mirror draft.ts:135-154 — render → upload \"Rendered HTML\" preview → flip\n // Draft ready. Without setDraftReady the draft never enters the approve queue\n // (every pending-approval gate requires draftReady true), so it can never be\n // approved or sent. The upload is a review convenience; the ready flag is the\n // critical step.\n try {\n const { html } = await renderReportHtml({\n siteName: target.name,\n siteUrl: target.url,\n reportType: \"Launch\",\n completedOn: today,\n lighthouse: scores,\n lastTestedDate: null,\n commentary: null,\n copy: resolveCopy(target),\n headerImageCid: `${slug}-header`,\n });\n // A preview-upload hiccup must NOT fail the launch — log and continue.\n try {\n await uploadAttachment(\n report.id,\n \"Rendered HTML\",\n html,\n `${slug}-${today.toISOString().slice(0, 10)}.html`,\n \"text/html\",\n );\n // The console preview reads the body from Turso, not the attachment.\n await deps.reportMirror?.body(report.id, html);\n } catch (uploadErr) {\n console.warn(\n `⚠ Launch preview upload skipped for ${target.name}: ${\n uploadErr instanceof Error ? uploadErr.message : String(uploadErr)\n }`,\n );\n }\n // Critical: NOT wrapped — a failure here must surface as a failed launch. queueDraft\n // supersedes any lower-tier (Maintenance/Testing) drafts queued for this site; a Launch is\n // top tier so it only stands down if another Launch/Announcement is already queued.\n await queueDraft(\n base,\n { id: report.id, siteId: target.id, reportType: \"Launch\" },\n deps.reportMirror,\n );\n } catch (err) {\n steps.push({ name: \"draft\", result: errorOf(err) });\n return stop();\n }\n\n steps.push({ name: \"draft\", result: { kind: \"draft\", report } });\n\n return { site: label, steps, complete: true };\n}\n\n/** Build the Launch `DraftInput`. reportId/period mirror `draftReportForSite`\n * (draft.ts) — do not invent a new id scheme. `today`/`period` are threaded in\n * from `launch()` so a single timestamp drives the render, the draft, the\n * dedupe lookup, and the preview filename. Launch reports have no period window\n * and no prior maintenance test, so periodStart/periodEnd/completedOn all\n * collapse to \"today\" and `lastTestedDate` is null. */\nfunction draftInputFor(\n target: WebsiteRow,\n scores: LighthouseScores,\n today: Date,\n period: string,\n): Parameters<typeof createDraft>[1] {\n const reportType = \"Launch\" as const;\n const reportId = `${target.name} — ${reportType} — ${today.toISOString().slice(0, 10)}`;\n return {\n reportId,\n siteId: target.id,\n reportType,\n period,\n periodStart: today,\n periodEnd: today,\n completedOn: today,\n lighthouse: scores,\n lastTestedDate: null,\n };\n}\n\nfunction errorOf(err: unknown): LaunchStepResult {\n return { kind: \"error\", message: err instanceof Error ? err.message : String(err) };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -5,11 +5,11 @@ import {
|
|
|
5
5
|
makeNotify,
|
|
6
6
|
notifySubmission,
|
|
7
7
|
resolveRecipients
|
|
8
|
-
} from "./chunk-
|
|
9
|
-
import "./chunk-
|
|
10
|
-
import "./chunk-
|
|
8
|
+
} from "./chunk-SJOXWJ5Y.js";
|
|
9
|
+
import "./chunk-JRHIFA5R.js";
|
|
10
|
+
import "./chunk-NO74DXDP.js";
|
|
11
11
|
import "./chunk-5ML7FMBD.js";
|
|
12
|
-
import "./chunk-
|
|
12
|
+
import "./chunk-BGTYPVLT.js";
|
|
13
13
|
import "./chunk-2OP4JKIQ.js";
|
|
14
14
|
export {
|
|
15
15
|
buildAutoresponder,
|
|
@@ -19,4 +19,4 @@ export {
|
|
|
19
19
|
notifySubmission,
|
|
20
20
|
resolveRecipients
|
|
21
21
|
};
|
|
22
|
-
//# sourceMappingURL=notify-
|
|
22
|
+
//# sourceMappingURL=notify-4HP4GZ2H.js.map
|
|
@@ -8,15 +8,15 @@ import {
|
|
|
8
8
|
} from "./chunk-TVL5MVUF.js";
|
|
9
9
|
import {
|
|
10
10
|
resolveSites
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-Q47DU255.js";
|
|
12
12
|
import {
|
|
13
13
|
onboard
|
|
14
14
|
} from "./chunk-7RJ2HMMJ.js";
|
|
15
15
|
import "./chunk-3G25KIWW.js";
|
|
16
16
|
import "./chunk-OTGB6YQO.js";
|
|
17
17
|
import "./chunk-LKGVSM2O.js";
|
|
18
|
-
import "./chunk-
|
|
19
|
-
import "./chunk-
|
|
18
|
+
import "./chunk-Z3JXLULD.js";
|
|
19
|
+
import "./chunk-RARREDQE.js";
|
|
20
20
|
import "./chunk-XTK5VIQB.js";
|
|
21
21
|
import "./chunk-LBYOLBW7.js";
|
|
22
22
|
import "./chunk-XXTZBPUY.js";
|
|
@@ -70,4 +70,4 @@ async function runOnboardCommand(site, opts) {
|
|
|
70
70
|
export {
|
|
71
71
|
runOnboardCommand
|
|
72
72
|
};
|
|
73
|
-
//# sourceMappingURL=onboard-
|
|
73
|
+
//# sourceMappingURL=onboard-BKCYBAVW.js.map
|
|
@@ -4,22 +4,22 @@ import {
|
|
|
4
4
|
parseAddresses,
|
|
5
5
|
sendApprovedReports,
|
|
6
6
|
withGlobalCc
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-DGZWFI2G.js";
|
|
8
8
|
import "./chunk-F3JWOPTG.js";
|
|
9
9
|
import "./chunk-VAD43MOR.js";
|
|
10
10
|
import "./chunk-IY6256GK.js";
|
|
11
11
|
import "./chunk-HN6I2XWI.js";
|
|
12
|
-
import "./chunk-
|
|
12
|
+
import "./chunk-XP5WM2LV.js";
|
|
13
13
|
import "./chunk-GECESMVS.js";
|
|
14
|
-
import "./chunk-MT2JINSS.js";
|
|
15
|
-
import "./chunk-DJZWYIPP.js";
|
|
16
14
|
import "./chunk-5UINJNAJ.js";
|
|
15
|
+
import "./chunk-KJGKZLCT.js";
|
|
16
|
+
import "./chunk-BGTYPVLT.js";
|
|
17
17
|
import "./chunk-7NYN2P6I.js";
|
|
18
18
|
import "./chunk-WEKL2HYJ.js";
|
|
19
|
-
import "./chunk-
|
|
20
|
-
import "./chunk-
|
|
21
|
-
import "./chunk-
|
|
22
|
-
import "./chunk-
|
|
19
|
+
import "./chunk-W45FZEGE.js";
|
|
20
|
+
import "./chunk-RARREDQE.js";
|
|
21
|
+
import "./chunk-WS6NU475.js";
|
|
22
|
+
import "./chunk-MFHS7IQ2.js";
|
|
23
23
|
import "./chunk-6VAL7XJT.js";
|
|
24
24
|
export {
|
|
25
25
|
GLOBAL_REPORT_CC,
|
|
@@ -28,4 +28,4 @@ export {
|
|
|
28
28
|
sendApprovedReports,
|
|
29
29
|
withGlobalCc
|
|
30
30
|
};
|
|
31
|
-
//# sourceMappingURL=orchestrate-
|
|
31
|
+
//# sourceMappingURL=orchestrate-JNKCWU5K.js.map
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
checkFleetParity,
|
|
3
3
|
formatParityResult
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-7FFUBF4I.js";
|
|
5
|
+
import "./chunk-GQDDWYU2.js";
|
|
5
6
|
import "./chunk-P6AORG32.js";
|
|
7
|
+
import "./chunk-F3JWOPTG.js";
|
|
6
8
|
import "./chunk-VAD43MOR.js";
|
|
7
9
|
import "./chunk-7NYN2P6I.js";
|
|
8
10
|
export {
|
|
9
11
|
checkFleetParity,
|
|
10
12
|
formatParityResult
|
|
11
13
|
};
|
|
12
|
-
//# sourceMappingURL=parity-
|
|
14
|
+
//# sourceMappingURL=parity-NBYZUBFU.js.map
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// src/prospect/pdf.ts
|
|
2
|
+
var NAVIGATION_TIMEOUT_MS = 6e4;
|
|
3
|
+
async function defaultLaunch() {
|
|
4
|
+
const { chromium } = await import("@playwright/test");
|
|
5
|
+
return chromium.launch({ args: ["--no-sandbox"] });
|
|
6
|
+
}
|
|
7
|
+
async function renderReportPdf(printUrl, deps = {}) {
|
|
8
|
+
const launch = deps.launch ?? defaultLaunch;
|
|
9
|
+
const browser = await launch();
|
|
10
|
+
try {
|
|
11
|
+
const page = await browser.newPage();
|
|
12
|
+
const res = await page.goto(printUrl, {
|
|
13
|
+
waitUntil: "networkidle",
|
|
14
|
+
timeout: NAVIGATION_TIMEOUT_MS
|
|
15
|
+
});
|
|
16
|
+
if (!res || !res.ok()) {
|
|
17
|
+
throw new Error(
|
|
18
|
+
`renderReportPdf: ${printUrl} responded ${res ? res.status() : "no response"}`
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
return await page.pdf({
|
|
22
|
+
// The print route declares `@page { size: A4 }`. Honour it rather than
|
|
23
|
+
// restating the size here, so the document's own stylesheet stays the one
|
|
24
|
+
// place page geometry is decided.
|
|
25
|
+
preferCSSPageSize: true,
|
|
26
|
+
// Without this the callout's fill drops out. It carries a border too, so
|
|
27
|
+
// the emphasis survives either way — but there is no reason to print the
|
|
28
|
+
// degraded version when we control the renderer.
|
|
29
|
+
printBackground: true
|
|
30
|
+
});
|
|
31
|
+
} finally {
|
|
32
|
+
await browser.close();
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export {
|
|
36
|
+
renderReportPdf
|
|
37
|
+
};
|
|
38
|
+
//# sourceMappingURL=pdf-N5QLQ5ZQ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/prospect/pdf.ts"],"sourcesContent":["import type { Browser } from \"@playwright/test\";\n\n/**\n * Render the website's print route to a PDF.\n *\n * The leave-behind is printed from `/audit/{token}/print`, a document designed\n * for paper, not from the interactive report. Printing the interactive page\n * would produce a PDF with its evidence still folded away behind disclosures —\n * worse on paper than the long version it replaced.\n *\n * The page is already live when this runs: the report route reads from the API\n * at request time rather than from a build artifact, so there is no deploy to\n * wait for after the audit persists.\n *\n * The runner already installs Playwright's chromium for the crawl, so this adds\n * no toolchain.\n */\n\nexport type LaunchBrowser = () => Promise<Browser>;\n\nexport type RenderPdfDeps = {\n launch?: LaunchBrowser;\n};\n\n/** Long enough for a cold marketing page plus webfonts, short enough that a\n * wedged render cannot hold the runner open. The audit's own step timeout sits\n * well above it. */\nconst NAVIGATION_TIMEOUT_MS = 60_000;\n\nasync function defaultLaunch(): Promise<Browser> {\n const { chromium } = await import(\"@playwright/test\");\n // --no-sandbox: the runner is already an isolated container, and chromium's\n // own sandbox needs privileges it does not have there.\n return chromium.launch({ args: [\"--no-sandbox\"] });\n}\n\nexport async function renderReportPdf(printUrl: string, deps: RenderPdfDeps = {}): Promise<Buffer> {\n const launch = deps.launch ?? defaultLaunch;\n const browser = await launch();\n try {\n const page = await browser.newPage();\n // `networkidle` rather than `load`: webfonts must settle before we print.\n // A fallback face baked into a client-facing PDF cannot be corrected after\n // the fact — the file is already in somebody's inbox.\n const res = await page.goto(printUrl, {\n waitUntil: \"networkidle\",\n timeout: NAVIGATION_TIMEOUT_MS,\n });\n // `page.goto` resolves for ANY status, and dropping its result meant a 404\n // rendered as a perfectly valid PDF of the marketing site's \"Page not\n // found\" — attached to the email and sent to the prospect. Nothing threw,\n // so no warning was recorded either: a hard failure became silently wrong\n // client-facing content. Throwing here lets the caller's existing catch turn\n // it into the warning it should always have been.\n if (!res || !res.ok()) {\n throw new Error(\n `renderReportPdf: ${printUrl} responded ${res ? res.status() : \"no response\"}`,\n );\n }\n return await page.pdf({\n // The print route declares `@page { size: A4 }`. Honour it rather than\n // restating the size here, so the document's own stylesheet stays the one\n // place page geometry is decided.\n preferCSSPageSize: true,\n // Without this the callout's fill drops out. It carries a border too, so\n // the emphasis survives either way — but there is no reason to print the\n // degraded version when we control the renderer.\n printBackground: true,\n });\n } finally {\n // In `finally`, not after the return: a navigation timeout or a render\n // failure must not leave a chromium process behind on the runner.\n await browser.close();\n }\n}\n"],"mappings":";AA2BA,IAAM,wBAAwB;AAE9B,eAAe,gBAAkC;AAC/C,QAAM,EAAE,SAAS,IAAI,MAAM,OAAO,kBAAkB;AAGpD,SAAO,SAAS,OAAO,EAAE,MAAM,CAAC,cAAc,EAAE,CAAC;AACnD;AAEA,eAAsB,gBAAgB,UAAkB,OAAsB,CAAC,GAAoB;AACjG,QAAM,SAAS,KAAK,UAAU;AAC9B,QAAM,UAAU,MAAM,OAAO;AAC7B,MAAI;AACF,UAAM,OAAO,MAAM,QAAQ,QAAQ;AAInC,UAAM,MAAM,MAAM,KAAK,KAAK,UAAU;AAAA,MACpC,WAAW;AAAA,MACX,SAAS;AAAA,IACX,CAAC;AAOD,QAAI,CAAC,OAAO,CAAC,IAAI,GAAG,GAAG;AACrB,YAAM,IAAI;AAAA,QACR,oBAAoB,QAAQ,cAAc,MAAM,IAAI,OAAO,IAAI,aAAa;AAAA,MAC9E;AAAA,IACF;AACA,WAAO,MAAM,KAAK,IAAI;AAAA;AAAA;AAAA;AAAA,MAIpB,mBAAmB;AAAA;AAAA;AAAA;AAAA,MAInB,iBAAiB;AAAA,IACnB,CAAC;AAAA,EACH,UAAE;AAGA,UAAM,QAAQ,MAAM;AAAA,EACtB;AACF;","names":[]}
|
|
@@ -2,11 +2,11 @@ import {
|
|
|
2
2
|
ANALYZE_SKIPPED,
|
|
3
3
|
PROBES_SKIPPED,
|
|
4
4
|
runProspectAudit
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import "./chunk-
|
|
5
|
+
} from "./chunk-7TMWBXX7.js";
|
|
6
|
+
import "./chunk-RARREDQE.js";
|
|
7
7
|
export {
|
|
8
8
|
ANALYZE_SKIPPED,
|
|
9
9
|
PROBES_SKIPPED,
|
|
10
10
|
runProspectAudit
|
|
11
11
|
};
|
|
12
|
-
//# sourceMappingURL=pipeline-
|
|
12
|
+
//# sourceMappingURL=pipeline-WYTXSLHX.js.map
|
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
import {
|
|
2
2
|
preflight
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-6I6L3CMX.js";
|
|
4
4
|
import "./chunk-PZR4EBPY.js";
|
|
5
|
-
import "./chunk-
|
|
5
|
+
import "./chunk-DGZWFI2G.js";
|
|
6
6
|
import "./chunk-F3JWOPTG.js";
|
|
7
7
|
import "./chunk-VAD43MOR.js";
|
|
8
8
|
import "./chunk-IY6256GK.js";
|
|
9
9
|
import "./chunk-HN6I2XWI.js";
|
|
10
|
-
import "./chunk-
|
|
10
|
+
import "./chunk-XP5WM2LV.js";
|
|
11
11
|
import "./chunk-GECESMVS.js";
|
|
12
|
-
import "./chunk-MT2JINSS.js";
|
|
13
|
-
import "./chunk-DJZWYIPP.js";
|
|
14
12
|
import "./chunk-5UINJNAJ.js";
|
|
13
|
+
import "./chunk-KJGKZLCT.js";
|
|
14
|
+
import "./chunk-BGTYPVLT.js";
|
|
15
15
|
import "./chunk-7NYN2P6I.js";
|
|
16
16
|
import "./chunk-WEKL2HYJ.js";
|
|
17
|
-
import "./chunk-
|
|
18
|
-
import "./chunk-
|
|
19
|
-
import "./chunk-
|
|
20
|
-
import "./chunk-
|
|
17
|
+
import "./chunk-W45FZEGE.js";
|
|
18
|
+
import "./chunk-RARREDQE.js";
|
|
19
|
+
import "./chunk-WS6NU475.js";
|
|
20
|
+
import "./chunk-MFHS7IQ2.js";
|
|
21
21
|
import "./chunk-6VAL7XJT.js";
|
|
22
22
|
|
|
23
23
|
// src/cli/commands/preflight.ts
|
|
@@ -67,4 +67,4 @@ async function runPreflightCommand(site, opts) {
|
|
|
67
67
|
export {
|
|
68
68
|
runPreflightCommand
|
|
69
69
|
};
|
|
70
|
-
//# sourceMappingURL=preflight-
|
|
70
|
+
//# sourceMappingURL=preflight-IMTYDDD4.js.map
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
} from "./chunk-TVL5MVUF.js";
|
|
13
13
|
import {
|
|
14
14
|
resolveSites
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-Q47DU255.js";
|
|
16
16
|
import {
|
|
17
17
|
PRETTIER_FLAG_NOTE,
|
|
18
18
|
formatWithPrettier,
|
|
@@ -24,8 +24,8 @@ import {
|
|
|
24
24
|
import {
|
|
25
25
|
makeGitHub
|
|
26
26
|
} from "./chunk-XHHMM5HX.js";
|
|
27
|
-
import "./chunk-
|
|
28
|
-
import "./chunk-
|
|
27
|
+
import "./chunk-Z3JXLULD.js";
|
|
28
|
+
import "./chunk-RARREDQE.js";
|
|
29
29
|
import {
|
|
30
30
|
branchName,
|
|
31
31
|
checkoutBranch,
|
|
@@ -444,4 +444,4 @@ export {
|
|
|
444
444
|
formatPrismicCiResults,
|
|
445
445
|
runPrismicCiCommand
|
|
446
446
|
};
|
|
447
|
-
//# sourceMappingURL=prismic-ci-
|
|
447
|
+
//# sourceMappingURL=prismic-ci-MY2U6NN7.js.map
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
} from "./chunk-TVL5MVUF.js";
|
|
19
19
|
import {
|
|
20
20
|
resolveSites
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-Q47DU255.js";
|
|
22
22
|
import {
|
|
23
23
|
PRETTIER_FLAG_NOTE,
|
|
24
24
|
formatWithPrettier
|
|
@@ -26,8 +26,8 @@ import {
|
|
|
26
26
|
import {
|
|
27
27
|
siteSlug
|
|
28
28
|
} from "./chunk-7NYN2P6I.js";
|
|
29
|
-
import "./chunk-
|
|
30
|
-
import "./chunk-
|
|
29
|
+
import "./chunk-Z3JXLULD.js";
|
|
30
|
+
import "./chunk-RARREDQE.js";
|
|
31
31
|
import "./chunk-XTK5VIQB.js";
|
|
32
32
|
import {
|
|
33
33
|
makeSpawn
|
|
@@ -169,7 +169,7 @@ var defaultDeps = () => ({
|
|
|
169
169
|
const { listWebsites, updatePrismicModels } = await import("./websites-D6WYFAES.js");
|
|
170
170
|
const base = openBase(readAirtableConfig());
|
|
171
171
|
const websites = await listWebsites(base);
|
|
172
|
-
const { makeSiteMirror } = await import("./site-mirror-
|
|
172
|
+
const { makeSiteMirror } = await import("./site-mirror-Q763PLGG.js");
|
|
173
173
|
const mirror = await makeSiteMirror();
|
|
174
174
|
return {
|
|
175
175
|
websites: websites.map((w) => ({ id: w.id, name: w.name })),
|
|
@@ -769,7 +769,7 @@ async function persistSweep(rows, deps) {
|
|
|
769
769
|
let sink;
|
|
770
770
|
let formatSummary;
|
|
771
771
|
try {
|
|
772
|
-
formatSummary = (await import("./write-audits-to-airtable-
|
|
772
|
+
formatSummary = (await import("./write-audits-to-airtable-OBHGR7DQ.js")).formatFleetWriteSummary;
|
|
773
773
|
sink = await deps.openVerdictSink();
|
|
774
774
|
} catch (e) {
|
|
775
775
|
return {
|
|
@@ -1022,4 +1022,4 @@ export {
|
|
|
1022
1022
|
sweepRowWriteback,
|
|
1023
1023
|
writeSweepToAirtable
|
|
1024
1024
|
};
|
|
1025
|
-
//# sourceMappingURL=prismic-models-
|
|
1025
|
+
//# sourceMappingURL=prismic-models-NJN5JORF.js.map
|
package/dist/prospect/types.d.ts
CHANGED
|
@@ -189,6 +189,20 @@ type ProbeAnswer = {
|
|
|
189
189
|
kind: "branded" | "category" | "competitor";
|
|
190
190
|
domainCited: boolean;
|
|
191
191
|
brandMentioned: boolean;
|
|
192
|
+
/**
|
|
193
|
+
* Did this answer count toward `visibilityScore`?
|
|
194
|
+
*
|
|
195
|
+
* Recorded here rather than re-derived by the renderer, because the gate is
|
|
196
|
+
* not simply `domainCited || brandMentioned` — a mention only counts when the
|
|
197
|
+
* name is distinctive enough for it to mean anything (see `isDistinctiveName`).
|
|
198
|
+
* The report used to re-derive it with the looser rule and printed "You were
|
|
199
|
+
* named in this answer" above a card contributing zero to the number beside it.
|
|
200
|
+
*
|
|
201
|
+
* Optional because reports persisted before this field existed still render;
|
|
202
|
+
* `render.ts` falls back to the old expression for those, which is what those
|
|
203
|
+
* documents already said.
|
|
204
|
+
*/
|
|
205
|
+
countedAsVisible?: boolean;
|
|
192
206
|
citedDomains: string[];
|
|
193
207
|
/** First ~300 chars of the engine's answer — the report's receipt. */
|
|
194
208
|
snippet: string;
|
|
@@ -1,16 +1,23 @@
|
|
|
1
1
|
import {
|
|
2
2
|
hostnameOf,
|
|
3
|
-
isHttpUrl
|
|
4
|
-
|
|
3
|
+
isHttpUrl,
|
|
4
|
+
isPrivateOrLoopbackHost
|
|
5
|
+
} from "./chunk-RARREDQE.js";
|
|
5
6
|
|
|
6
7
|
// src/cli/commands/prospect-audit.ts
|
|
7
8
|
import { mkdir, writeFile } from "fs/promises";
|
|
8
9
|
import { resolve } from "path";
|
|
9
10
|
|
|
10
|
-
// src/
|
|
11
|
-
var
|
|
12
|
-
function
|
|
13
|
-
return (raw?.trim() ||
|
|
11
|
+
// src/prospect/report-url.ts
|
|
12
|
+
var DEFAULT_REPORT_BASE_URL = "https://reddoorla.com";
|
|
13
|
+
function resolveReportBaseUrl(raw) {
|
|
14
|
+
return (raw?.trim() || DEFAULT_REPORT_BASE_URL).replace(/\/$/, "");
|
|
15
|
+
}
|
|
16
|
+
function reportUrl(token, raw = process.env.REPORT_BASE_URL) {
|
|
17
|
+
return `${resolveReportBaseUrl(raw)}/audit/${token}`;
|
|
18
|
+
}
|
|
19
|
+
function reportPrintUrl(token, raw = process.env.REPORT_BASE_URL) {
|
|
20
|
+
return `${reportUrl(token, raw)}/print`;
|
|
14
21
|
}
|
|
15
22
|
|
|
16
23
|
// src/cli/commands/prospect-audit.ts
|
|
@@ -79,13 +86,16 @@ async function runProspectAuditCommand(url, opts) {
|
|
|
79
86
|
if (!isHttpUrl(url)) {
|
|
80
87
|
return fail(`"${url}" is not a URL. Pass the full address, e.g. https://example.com`);
|
|
81
88
|
}
|
|
89
|
+
if (isPrivateOrLoopbackHost(new URL(url).hostname)) {
|
|
90
|
+
return fail(`"${url}" is a private or loopback address \u2014 refusing to audit it.`);
|
|
91
|
+
}
|
|
82
92
|
const canPersist = Boolean(process.env.TURSO_DATABASE_URL);
|
|
83
93
|
if (!canPersist && !opts.out) {
|
|
84
94
|
return fail(
|
|
85
95
|
"No TURSO_DATABASE_URL, so the report cannot be saved or shared. Re-run with --out <file>, or set the Turso credentials."
|
|
86
96
|
);
|
|
87
97
|
}
|
|
88
|
-
const { runProspectAudit } = await import("./pipeline-
|
|
98
|
+
const { runProspectAudit } = await import("./pipeline-WYTXSLHX.js");
|
|
89
99
|
const onStage = (name, status, detail) => {
|
|
90
100
|
if (status === "start") console.error(`\u2026 ${name}`);
|
|
91
101
|
else if (status === "ok") console.error(`\u2713 ${name}`);
|
|
@@ -103,7 +113,7 @@ async function runProspectAuditCommand(url, opts) {
|
|
|
103
113
|
},
|
|
104
114
|
{ ...opts.deps ?? {}, onStage }
|
|
105
115
|
);
|
|
106
|
-
const { renderProspectReport } = await import("./render-
|
|
116
|
+
const { renderProspectReport } = await import("./render-VX72AESY.js");
|
|
107
117
|
const html = renderProspectReport(result);
|
|
108
118
|
const warnings = [];
|
|
109
119
|
let file = null;
|
|
@@ -120,7 +130,7 @@ async function runProspectAuditCommand(url, opts) {
|
|
|
120
130
|
let auditId = null;
|
|
121
131
|
if (canPersist) {
|
|
122
132
|
try {
|
|
123
|
-
const { openDb, readDbConfig } = await import("./client-
|
|
133
|
+
const { openDb, readDbConfig } = await import("./client-JYKPVCJX.js");
|
|
124
134
|
const { createProspectAudit } = await import("./prospect-audits-3PMIO73D.js");
|
|
125
135
|
const db = await openDb(readDbConfig());
|
|
126
136
|
const created = await createProspectAudit(db, {
|
|
@@ -135,7 +145,7 @@ async function runProspectAuditCommand(url, opts) {
|
|
|
135
145
|
});
|
|
136
146
|
auditId = created.id;
|
|
137
147
|
token = created.token;
|
|
138
|
-
link =
|
|
148
|
+
link = reportUrl(token);
|
|
139
149
|
} catch (err) {
|
|
140
150
|
warnings.push(`Could not save to the database: ${errorMessage(err)}`);
|
|
141
151
|
}
|
|
@@ -143,12 +153,21 @@ async function runProspectAuditCommand(url, opts) {
|
|
|
143
153
|
const delivered = file !== null || link !== null;
|
|
144
154
|
const recovery = delivered ? null : await writeRecoveryFiles(result, html);
|
|
145
155
|
const code = delivered ? 0 : 1;
|
|
156
|
+
let pdf = null;
|
|
157
|
+
if (opts.email && token) {
|
|
158
|
+
try {
|
|
159
|
+
const { renderReportPdf } = await import("./pdf-N5QLQ5ZQ.js");
|
|
160
|
+
pdf = await renderReportPdf(reportPrintUrl(token));
|
|
161
|
+
} catch (err) {
|
|
162
|
+
warnings.push(`Could not attach the PDF: ${errorMessage(err)}`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
146
165
|
let email = null;
|
|
147
166
|
if (opts.email) {
|
|
148
167
|
try {
|
|
149
|
-
const { sendAuditEmail, parseProspectAuditRecipients } = await import("./email-
|
|
168
|
+
const { sendAuditEmail, parseProspectAuditRecipients } = await import("./email-SL7464YI.js");
|
|
150
169
|
const recipients = parseProspectAuditRecipients(process.env.PROSPECT_AUDIT_RECIPIENTS);
|
|
151
|
-
email = await sendAuditEmail(result, { link, recipients, auditId });
|
|
170
|
+
email = await sendAuditEmail(result, { link, recipients, auditId, pdf });
|
|
152
171
|
if (!email.sent) {
|
|
153
172
|
warnings.push(`Could not email the audit sheet: ${email.reason}`);
|
|
154
173
|
}
|
|
@@ -171,4 +190,4 @@ async function runProspectAuditCommand(url, opts) {
|
|
|
171
190
|
export {
|
|
172
191
|
runProspectAuditCommand
|
|
173
192
|
};
|
|
174
|
-
//# sourceMappingURL=prospect-audit-
|
|
193
|
+
//# sourceMappingURL=prospect-audit-JMBRVXSG.js.map
|