@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.
Files changed (186) hide show
  1. package/dist/airtable-QG5ICI3Y.js +9 -0
  2. package/dist/{announce-I2Z4JN3I.js → announce-GKD5YJNB.js} +9 -9
  3. package/dist/{blux-ZGDSHI3U.js → blux-DN4MI532.js} +5 -5
  4. package/dist/{bump-deps-CGVELRLK.js → bump-deps-KGH5UYSF.js} +4 -4
  5. package/dist/{chunk-SDDPUAWH.js → chunk-6I6L3CMX.js} +2 -2
  6. package/dist/{chunk-ZBDZTJUO.js → chunk-7FFUBF4I.js} +5 -2
  7. package/dist/chunk-7FFUBF4I.js.map +1 -0
  8. package/dist/{chunk-HSI6Q7MI.js → chunk-7TMWBXX7.js} +159 -29
  9. package/dist/chunk-7TMWBXX7.js.map +1 -0
  10. package/dist/{chunk-DEWJMMG3.js → chunk-A2UNJIKH.js} +15 -7
  11. package/dist/chunk-A2UNJIKH.js.map +1 -0
  12. package/dist/{chunk-NCMZMLY7.js → chunk-ANJNTAMM.js} +3 -69
  13. package/dist/chunk-ANJNTAMM.js.map +1 -0
  14. package/dist/{chunk-3JQ2FO3D.js → chunk-B23FFWU4.js} +2 -2
  15. package/dist/{chunk-DJZWYIPP.js → chunk-BGTYPVLT.js} +1 -1
  16. package/dist/chunk-BGTYPVLT.js.map +1 -0
  17. package/dist/chunk-BRYXFH77.js +70 -0
  18. package/dist/chunk-BRYXFH77.js.map +1 -0
  19. package/dist/{chunk-NDWYJLRF.js → chunk-DGZWFI2G.js} +3 -3
  20. package/dist/{chunk-HHMMUR4P.js → chunk-GQDDWYU2.js} +45 -8
  21. package/dist/chunk-GQDDWYU2.js.map +1 -0
  22. package/dist/{chunk-BBUSGEES.js → chunk-J3WEZGIN.js} +6 -6
  23. package/dist/{chunk-BNM5POSJ.js → chunk-JRHIFA5R.js} +2 -2
  24. package/dist/{chunk-TD2NNXLZ.js → chunk-K6SLF6GI.js} +5 -5
  25. package/dist/{chunk-MT2JINSS.js → chunk-KJGKZLCT.js} +3 -3
  26. package/dist/{chunk-NXNPDCF3.js → chunk-KMCZA7CH.js} +11 -1
  27. package/dist/chunk-KMCZA7CH.js.map +1 -0
  28. package/dist/{chunk-3SF7D4DY.js → chunk-MFHS7IQ2.js} +36 -1
  29. package/dist/{chunk-3SF7D4DY.js.map → chunk-MFHS7IQ2.js.map} +1 -1
  30. package/dist/{chunk-SNSTJLQW.js → chunk-NO74DXDP.js} +48 -2
  31. package/dist/chunk-NO74DXDP.js.map +1 -0
  32. package/dist/{chunk-C6B4RHXR.js → chunk-O3GT46R2.js} +8 -2
  33. package/dist/chunk-O3GT46R2.js.map +1 -0
  34. package/dist/{chunk-C6CLRKPV.js → chunk-PR343K7F.js} +2 -2
  35. package/dist/{chunk-CROKUHJB.js → chunk-Q47DU255.js} +4 -4
  36. package/dist/{chunk-EVBCK2KC.js → chunk-RARREDQE.js} +2 -1
  37. package/dist/{chunk-EVBCK2KC.js.map → chunk-RARREDQE.js.map} +1 -1
  38. package/dist/chunk-RUPPWAD6.js +7 -0
  39. package/dist/chunk-RUPPWAD6.js.map +1 -0
  40. package/dist/{chunk-VSBFM7DS.js → chunk-SJOXWJ5Y.js} +3 -3
  41. package/dist/{chunk-HEWSRXYV.js → chunk-ULHPALI5.js} +3 -3
  42. package/dist/{chunk-XUGSZP7Z.js → chunk-W45FZEGE.js} +2 -2
  43. package/dist/{chunk-JHGHLKFS.js → chunk-WS6NU475.js} +2 -2
  44. package/dist/{chunk-ZGBEIWSC.js → chunk-XP5WM2LV.js} +5 -5
  45. package/dist/{chunk-6TWWY7ZU.js → chunk-Z3JXLULD.js} +2 -2
  46. package/dist/cli/bin.js +27 -27
  47. package/dist/cli/bin.js.map +1 -1
  48. package/dist/cli/commands/audit.d.ts +4 -0
  49. package/dist/cli/commands/audit.js +16 -13
  50. package/dist/cli/commands/audit.js.map +1 -1
  51. package/dist/client-JYKPVCJX.js +11 -0
  52. package/dist/configs/playwright-a11y.js +1 -1
  53. package/dist/{convert-to-pnpm-QFJOEP5V.js → convert-to-pnpm-NWB5FCQ2.js} +4 -4
  54. package/dist/{db-UXNIZ2RG.js → db-V6UIS433.js} +121 -26
  55. package/dist/db-V6UIS433.js.map +1 -0
  56. package/dist/{digest-FW6QMZZJ.js → digest-2JEAEJK6.js} +53 -29
  57. package/dist/digest-2JEAEJK6.js.map +1 -0
  58. package/dist/digest-state-CRZRNGDI.js +25 -0
  59. package/dist/digest-state-CRZRNGDI.js.map +1 -0
  60. package/dist/digest-state-F37XUCS5.js +13 -0
  61. package/dist/{dump-P6EBSIOH.js → dump-EPL7AZFR.js} +38 -13
  62. package/dist/dump-EPL7AZFR.js.map +1 -0
  63. package/dist/{email-KJXASVH5.js → email-SL7464YI.js} +16 -6
  64. package/dist/{email-KJXASVH5.js.map → email-SL7464YI.js.map} +1 -1
  65. package/dist/{ensure-site-4DCEBAPM.js → ensure-site-FU6527OU.js} +2 -2
  66. package/dist/{fleet-state-7TJ2GYT2.js → fleet-state-R5LU7IC3.js} +4 -2
  67. package/dist/{forms-notify-target-2EAWCWBW.js → forms-notify-target-SGDGXXK5.js} +6 -6
  68. package/dist/{github-signals-E2WPYTBK.js → github-signals-GWGCKEE2.js} +7 -6
  69. package/dist/{github-signals-E2WPYTBK.js.map → github-signals-GWGCKEE2.js.map} +1 -1
  70. package/dist/{header-image-6IC53W27.js → header-image-7A7XLVEU.js} +2 -2
  71. package/dist/{health-endpoint-RFXL2F4A.js → health-endpoint-UVX6R5N5.js} +4 -4
  72. package/dist/{health-mirror-L5JBEJVA.js → health-mirror-GCDN7BJL.js} +11 -6
  73. package/dist/health-mirror-GCDN7BJL.js.map +1 -0
  74. package/dist/index.js +128 -88
  75. package/dist/index.js.map +1 -1
  76. package/dist/{init-XRAQZYID.js → init-FGTYNGUI.js} +9 -9
  77. package/dist/{launch-IX4Y5JJC.js → launch-5H7LPEGP.js} +12 -11
  78. package/dist/{launch-IX4Y5JJC.js.map → launch-5H7LPEGP.js.map} +1 -1
  79. package/dist/migrate-YITCXBLS.js +7 -0
  80. package/dist/{notify-C645PGD5.js → notify-4HP4GZ2H.js} +5 -5
  81. package/dist/{onboard-O4IAHJMO.js → onboard-BKCYBAVW.js} +4 -4
  82. package/dist/{orchestrate-YLWQ6KK2.js → orchestrate-JNKCWU5K.js} +9 -9
  83. package/dist/{parity-56KA2DGR.js → parity-NBYZUBFU.js} +4 -2
  84. package/dist/pdf-N5QLQ5ZQ.js +38 -0
  85. package/dist/pdf-N5QLQ5ZQ.js.map +1 -0
  86. package/dist/{pipeline-3AANZFCR.js → pipeline-WYTXSLHX.js} +3 -3
  87. package/dist/{preflight-TNORKGCX.js → preflight-IMTYDDD4.js} +10 -10
  88. package/dist/{prismic-ci-G2AK53VL.js → prismic-ci-MY2U6NN7.js} +4 -4
  89. package/dist/{prismic-models-O6Z3OK3A.js → prismic-models-NJN5JORF.js} +6 -6
  90. package/dist/prospect/types.d.ts +14 -0
  91. package/dist/{prospect-audit-KSXUNQ5J.js → prospect-audit-JMBRVXSG.js} +32 -13
  92. package/dist/prospect-audit-JMBRVXSG.js.map +1 -0
  93. package/dist/render-VX72AESY.js +10 -0
  94. package/dist/{render-from-row-BWSOIYDS.js → render-from-row-DOYJDO2L.js} +5 -5
  95. package/dist/{replay-C2LXMJZP.js → replay-4S6ENYCH.js} +3 -3
  96. package/dist/{report-R3E3Y7HR.js → report-TALY5P3L.js} +17 -17
  97. package/dist/{report-mirror-4MNORYQ4.js → report-mirror-AAK3MXHY.js} +12 -6
  98. package/dist/report-mirror-AAK3MXHY.js.map +1 -0
  99. package/dist/schema-75PJECAE.js +18 -0
  100. package/dist/schema-75PJECAE.js.map +1 -0
  101. package/dist/{self-updating-UCIWESAX.js → self-updating-NTCCWJYZ.js} +4 -4
  102. package/dist/{selftest-VGHWPN72.js → selftest-NZTR4SM2.js} +11 -11
  103. package/dist/{site-mirror-NIREX5ME.js → site-mirror-Q763PLGG.js} +17 -7
  104. package/dist/site-mirror-Q763PLGG.js.map +1 -0
  105. package/dist/{smoke-suite-U3UKD3NS.js → smoke-suite-4JFZZYVW.js} +4 -4
  106. package/dist/{spam-classifier-XLBFCO7G.js → spam-classifier-T5H4VTP6.js} +4 -2
  107. package/dist/{submissions-IQEJX6FK.js → submissions-TEHPBSZJ.js} +4 -4
  108. package/dist/{svelte-codemods-GOKXTBHW.js → svelte-codemods-QAPDZC6F.js} +4 -4
  109. package/dist/{sync-CTUVXMCK.js → sync-GBFV45WX.js} +4 -2
  110. package/dist/{sync-CTUVXMCK.js.map → sync-GBFV45WX.js.map} +1 -1
  111. package/dist/{sync-configs-SPTLFJCC.js → sync-configs-34JIA6KZ.js} +4 -4
  112. package/dist/{upgrade-W6ZR3FJH.js → upgrade-IR2OO3KP.js} +4 -4
  113. package/dist/{webhook-VOGOW3W6.js → webhook-XM6EV4XT.js} +2 -2
  114. package/dist/{write-audits-to-airtable-CMKHGJNQ.js → write-audits-to-airtable-OBHGR7DQ.js} +5 -2
  115. package/dist/write-audits-to-airtable-OBHGR7DQ.js.map +1 -0
  116. package/package.json +1 -1
  117. package/dist/airtable-ZBUPQJSC.js +0 -9
  118. package/dist/chunk-C6B4RHXR.js.map +0 -1
  119. package/dist/chunk-DEWJMMG3.js.map +0 -1
  120. package/dist/chunk-DJZWYIPP.js.map +0 -1
  121. package/dist/chunk-HHMMUR4P.js.map +0 -1
  122. package/dist/chunk-HSI6Q7MI.js.map +0 -1
  123. package/dist/chunk-NCMZMLY7.js.map +0 -1
  124. package/dist/chunk-NXNPDCF3.js.map +0 -1
  125. package/dist/chunk-SNSTJLQW.js.map +0 -1
  126. package/dist/chunk-ZBDZTJUO.js.map +0 -1
  127. package/dist/client-AUE3XUPO.js +0 -11
  128. package/dist/db-UXNIZ2RG.js.map +0 -1
  129. package/dist/digest-FW6QMZZJ.js.map +0 -1
  130. package/dist/dump-P6EBSIOH.js.map +0 -1
  131. package/dist/health-mirror-L5JBEJVA.js.map +0 -1
  132. package/dist/migrate-GQH237A6.js +0 -7
  133. package/dist/prospect-audit-KSXUNQ5J.js.map +0 -1
  134. package/dist/render-IFOGFB5T.js +0 -10
  135. package/dist/report-mirror-4MNORYQ4.js.map +0 -1
  136. package/dist/site-mirror-NIREX5ME.js.map +0 -1
  137. /package/dist/{airtable-ZBUPQJSC.js.map → airtable-QG5ICI3Y.js.map} +0 -0
  138. /package/dist/{announce-I2Z4JN3I.js.map → announce-GKD5YJNB.js.map} +0 -0
  139. /package/dist/{blux-ZGDSHI3U.js.map → blux-DN4MI532.js.map} +0 -0
  140. /package/dist/{bump-deps-CGVELRLK.js.map → bump-deps-KGH5UYSF.js.map} +0 -0
  141. /package/dist/{chunk-SDDPUAWH.js.map → chunk-6I6L3CMX.js.map} +0 -0
  142. /package/dist/{chunk-3JQ2FO3D.js.map → chunk-B23FFWU4.js.map} +0 -0
  143. /package/dist/{chunk-NDWYJLRF.js.map → chunk-DGZWFI2G.js.map} +0 -0
  144. /package/dist/{chunk-BBUSGEES.js.map → chunk-J3WEZGIN.js.map} +0 -0
  145. /package/dist/{chunk-BNM5POSJ.js.map → chunk-JRHIFA5R.js.map} +0 -0
  146. /package/dist/{chunk-TD2NNXLZ.js.map → chunk-K6SLF6GI.js.map} +0 -0
  147. /package/dist/{chunk-MT2JINSS.js.map → chunk-KJGKZLCT.js.map} +0 -0
  148. /package/dist/{chunk-C6CLRKPV.js.map → chunk-PR343K7F.js.map} +0 -0
  149. /package/dist/{chunk-CROKUHJB.js.map → chunk-Q47DU255.js.map} +0 -0
  150. /package/dist/{chunk-VSBFM7DS.js.map → chunk-SJOXWJ5Y.js.map} +0 -0
  151. /package/dist/{chunk-HEWSRXYV.js.map → chunk-ULHPALI5.js.map} +0 -0
  152. /package/dist/{chunk-XUGSZP7Z.js.map → chunk-W45FZEGE.js.map} +0 -0
  153. /package/dist/{chunk-JHGHLKFS.js.map → chunk-WS6NU475.js.map} +0 -0
  154. /package/dist/{chunk-ZGBEIWSC.js.map → chunk-XP5WM2LV.js.map} +0 -0
  155. /package/dist/{chunk-6TWWY7ZU.js.map → chunk-Z3JXLULD.js.map} +0 -0
  156. /package/dist/{client-AUE3XUPO.js.map → client-JYKPVCJX.js.map} +0 -0
  157. /package/dist/{convert-to-pnpm-QFJOEP5V.js.map → convert-to-pnpm-NWB5FCQ2.js.map} +0 -0
  158. /package/dist/{fleet-state-7TJ2GYT2.js.map → digest-state-F37XUCS5.js.map} +0 -0
  159. /package/dist/{ensure-site-4DCEBAPM.js.map → ensure-site-FU6527OU.js.map} +0 -0
  160. /package/dist/{migrate-GQH237A6.js.map → fleet-state-R5LU7IC3.js.map} +0 -0
  161. /package/dist/{forms-notify-target-2EAWCWBW.js.map → forms-notify-target-SGDGXXK5.js.map} +0 -0
  162. /package/dist/{header-image-6IC53W27.js.map → header-image-7A7XLVEU.js.map} +0 -0
  163. /package/dist/{health-endpoint-RFXL2F4A.js.map → health-endpoint-UVX6R5N5.js.map} +0 -0
  164. /package/dist/{init-XRAQZYID.js.map → init-FGTYNGUI.js.map} +0 -0
  165. /package/dist/{notify-C645PGD5.js.map → migrate-YITCXBLS.js.map} +0 -0
  166. /package/dist/{orchestrate-YLWQ6KK2.js.map → notify-4HP4GZ2H.js.map} +0 -0
  167. /package/dist/{onboard-O4IAHJMO.js.map → onboard-BKCYBAVW.js.map} +0 -0
  168. /package/dist/{parity-56KA2DGR.js.map → orchestrate-JNKCWU5K.js.map} +0 -0
  169. /package/dist/{pipeline-3AANZFCR.js.map → parity-NBYZUBFU.js.map} +0 -0
  170. /package/dist/{render-IFOGFB5T.js.map → pipeline-WYTXSLHX.js.map} +0 -0
  171. /package/dist/{preflight-TNORKGCX.js.map → preflight-IMTYDDD4.js.map} +0 -0
  172. /package/dist/{prismic-ci-G2AK53VL.js.map → prismic-ci-MY2U6NN7.js.map} +0 -0
  173. /package/dist/{prismic-models-O6Z3OK3A.js.map → prismic-models-NJN5JORF.js.map} +0 -0
  174. /package/dist/{render-from-row-BWSOIYDS.js.map → render-VX72AESY.js.map} +0 -0
  175. /package/dist/{spam-classifier-XLBFCO7G.js.map → render-from-row-DOYJDO2L.js.map} +0 -0
  176. /package/dist/{replay-C2LXMJZP.js.map → replay-4S6ENYCH.js.map} +0 -0
  177. /package/dist/{report-R3E3Y7HR.js.map → report-TALY5P3L.js.map} +0 -0
  178. /package/dist/{self-updating-UCIWESAX.js.map → self-updating-NTCCWJYZ.js.map} +0 -0
  179. /package/dist/{selftest-VGHWPN72.js.map → selftest-NZTR4SM2.js.map} +0 -0
  180. /package/dist/{smoke-suite-U3UKD3NS.js.map → smoke-suite-4JFZZYVW.js.map} +0 -0
  181. /package/dist/{write-audits-to-airtable-CMKHGJNQ.js.map → spam-classifier-T5H4VTP6.js.map} +0 -0
  182. /package/dist/{submissions-IQEJX6FK.js.map → submissions-TEHPBSZJ.js.map} +0 -0
  183. /package/dist/{svelte-codemods-GOKXTBHW.js.map → svelte-codemods-QAPDZC6F.js.map} +0 -0
  184. /package/dist/{sync-configs-SPTLFJCC.js.map → sync-configs-34JIA6KZ.js.map} +0 -0
  185. /package/dist/{upgrade-W6ZR3FJH.js.map → upgrade-IR2OO3KP.js.map} +0 -0
  186. /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-CROKUHJB.js";
8
+ } from "./chunk-Q47DU255.js";
9
9
  import {
10
10
  init
11
- } from "./chunk-TD2NNXLZ.js";
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-3JQ2FO3D.js";
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-6TWWY7ZU.js";
28
- import "./chunk-EVBCK2KC.js";
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-C6B4RHXR.js";
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-XRAQZYID.js.map
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-NXNPDCF3.js";
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-CROKUHJB.js";
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-MT2JINSS.js";
36
- import "./chunk-DJZWYIPP.js";
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-3JQ2FO3D.js";
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-6TWWY7ZU.js";
49
- import "./chunk-EVBCK2KC.js";
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-C6B4RHXR.js";
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-4MNORYQ4.js");
244
- const { makeSiteMirror } = await import("./site-mirror-NIREX5ME.js");
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-IX4Y5JJC.js.map
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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,eAAe;;;ACoExB,eAAsB,OAAO,MAAY,OAAmB,CAAC,GAA0B;AACrF,QAAM,QAAQ,UAAU,IAAI;AAC5B,QAAM,YAAY,KAAK,aAAa;AACpC,QAAM,QAAQ,KAAK,SAAS;AAC5B,QAAM,OAAO,KAAK,QAAQ,SAAS,mBAAmB,CAAC;AAEvD,QAAM,QAA2D,CAAC;AAClE,QAAM,OAAO,OAAqB,EAAE,MAAM,OAAO,OAAO,UAAU,MAAM;AAGxE,MAAI;AACJ,MAAI;AACF,aAAS,MAAM,UAAU,IAAI;AAAA,EAC/B,SAAS,KAAK;AACZ,UAAM,KAAK,EAAE,MAAM,iBAAiB,QAAQ,QAAQ,GAAG,EAAE,CAAC;AAC1D,WAAO,KAAK;AAAA,EACd;AACA,QAAM,KAAK,EAAE,MAAM,iBAAiB,QAAQ,EAAE,MAAM,UAAU,QAAQ,OAAO,EAAE,CAAC;AAChF,MAAI,OAAO,WAAW,SAAU,QAAO,KAAK;AAG5C,MAAI;AACJ,MAAI;AACF,cAAU,MAAM,MAAM,IAAI;AAAA,EAC5B,SAAS,KAAK;AACZ,UAAM,KAAK,EAAE,MAAM,SAAS,QAAQ,QAAQ,GAAG,EAAE,CAAC;AAClD,WAAO,KAAK;AAAA,EACd;AACA,QAAM,WAAW,QAAQ,KAAK,CAAC,MAAM,EAAE,UAAU,YAAY;AAC7D,MAAI,CAAC,YAAY,CAAC,cAAc,QAAQ,GAAG;AACzC,UAAM,KAAK;AAAA,MACT,MAAM;AAAA,MACN,QAAQ,EAAE,MAAM,SAAS,SAAS,2CAA2C;AAAA,IAC/E,CAAC;AACD,WAAO,KAAK;AAAA,EACd;AAKA,QAAM,YAAY,2BAA2B,QAAQ;AACrD,QAAM,SAA2B;AAAA,IAC/B,aAAa,UAAU,eAAe;AAAA,IACtC,eAAe,UAAU,iBAAiB;AAAA,IAC1C,eAAe,UAAU,iBAAiB;AAAA,IAC1C,KAAK,UAAU,OAAO;AAAA,EACxB;AAEA,QAAM,WAAW,MAAM,aAAa,IAAI;AACxC,QAAM,SAAS,SAAS,KAAK,CAAC,MAAM,SAAS,EAAE,IAAI,MAAM,SAAS,KAAK,CAAC;AACxE,MAAI,CAAC,QAAQ;AACX,UAAM,KAAK;AAAA,MACT,MAAM;AAAA,MACN,QAAQ,EAAE,MAAM,SAAS,SAAS,iCAAiC,KAAK,IAAI;AAAA,IAC9E,CAAC;AACD,WAAO,KAAK;AAAA,EACd;AACA,MAAI;AACF,UAAM,aAAa,MAAM,sBAAsB;AAAA,MAC7C;AAAA,MACA;AAAA,MACA,MAAM,SAAS,OAAO,IAAI;AAAA,MAC1B;AAAA,IACF,CAAC;AAID,QAAI,WAAW,UAAU,WAAW,QAAQ;AAC1C,YAAM,KAAK,YAAY,OAAO,WAAW,QAAQ,WAAW,MAAM;AAAA,IACpE;AAAA,EACF,SAAS,KAAK;AACZ,UAAM,KAAK,EAAE,MAAM,SAAS,QAAQ,QAAQ,GAAG,EAAE,CAAC;AAClD,WAAO,KAAK;AAAA,EACd;AACA,QAAM,KAAK,EAAE,MAAM,SAAS,QAAQ,EAAE,MAAM,SAAS,SAAS,OAAO,EAAE,CAAC;AAIxE,QAAM,QAAQ,oBAAI,KAAK;AACvB,QAAM,SAAS,MAAM,YAAY,EAAE,MAAM,GAAG,CAAC;AAC7C,QAAM,OAAO,SAAS,OAAO,IAAI;AAEjC,MAAI;AACJ,MAAI;AAIF,UAAM,WAAW,MAAM,mBAAmB,MAAM,OAAO,IAAI,UAAU,MAAM;AAC3E,QAAI,UAAU;AAMZ,YAAM,mBAAmB,MAAM,SAAS,IAAI,QAAQ,KAAK;AAEzD,YAAM,KAAK,cAAc,MAAM,SAAS,IAAI;AAAA,QAC1C,wBAAwB,OAAO;AAAA,QAC/B,0BAA0B,OAAO;AAAA,QACjC,2BAA2B,OAAO;AAAA,QAClC,gBAAgB,OAAO;AAAA,QACvB,cAAc,MAAM,YAAY,EAAE,MAAM,GAAG,EAAE;AAAA,MAC/C,CAAC;AACD,eAAS;AAAA,IACX,OAAO;AACL,eAAS,MAAM;AAAA,QACb;AAAA,QACA,cAAc,QAAQ,QAAQ,OAAO,MAAM;AAAA,QAC3C,KAAK,cAAc;AAAA,MACrB;AAAA,IACF;AAAA,EACF,SAAS,KAAK;AACZ,UAAM,KAAK,EAAE,MAAM,SAAS,QAAQ,QAAQ,GAAG,EAAE,CAAC;AAClD,WAAO,KAAK;AAAA,EACd;AAOA,MAAI;AACF,UAAM,EAAE,KAAK,IAAI,MAAM,iBAAiB;AAAA,MACtC,UAAU,OAAO;AAAA,MACjB,SAAS,OAAO;AAAA,MAChB,YAAY;AAAA,MACZ,aAAa;AAAA,MACb,YAAY;AAAA,MACZ,gBAAgB;AAAA,MAChB,YAAY;AAAA,MACZ,MAAM,YAAY,MAAM;AAAA,MACxB,gBAAgB,GAAG,IAAI;AAAA,IACzB,CAAC;AAED,QAAI;AACF,YAAM;AAAA,QACJ,OAAO;AAAA,QACP;AAAA,QACA;AAAA,QACA,GAAG,IAAI,IAAI,MAAM,YAAY,EAAE,MAAM,GAAG,EAAE,CAAC;AAAA,QAC3C;AAAA,MACF;AAEA,YAAM,KAAK,cAAc,KAAK,OAAO,IAAI,IAAI;AAAA,IAC/C,SAAS,WAAW;AAClB,cAAQ;AAAA,QACN,4CAAuC,OAAO,IAAI,KAChD,qBAAqB,QAAQ,UAAU,UAAU,OAAO,SAAS,CACnE;AAAA,MACF;AAAA,IACF;AAIA,UAAM;AAAA,MACJ;AAAA,MACA,EAAE,IAAI,OAAO,IAAI,QAAQ,OAAO,IAAI,YAAY,SAAS;AAAA,MACzD,KAAK;AAAA,IACP;AAAA,EACF,SAAS,KAAK;AACZ,UAAM,KAAK,EAAE,MAAM,SAAS,QAAQ,QAAQ,GAAG,EAAE,CAAC;AAClD,WAAO,KAAK;AAAA,EACd;AAEA,QAAM,KAAK,EAAE,MAAM,SAAS,QAAQ,EAAE,MAAM,SAAS,OAAO,EAAE,CAAC;AAE/D,SAAO,EAAE,MAAM,OAAO,OAAO,UAAU,KAAK;AAC9C;AAQA,SAAS,cACP,QACA,QACA,OACA,QACmC;AACnC,QAAM,aAAa;AACnB,QAAM,WAAW,GAAG,OAAO,IAAI,WAAM,UAAU,WAAM,MAAM,YAAY,EAAE,MAAM,GAAG,EAAE,CAAC;AACrF,SAAO;AAAA,IACL;AAAA,IACA,QAAQ,OAAO;AAAA,IACf;AAAA,IACA;AAAA,IACA,aAAa;AAAA,IACb,WAAW;AAAA,IACX,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,gBAAgB;AAAA,EAClB;AACF;AAEA,SAAS,QAAQ,KAAgC;AAC/C,SAAO,EAAE,MAAM,SAAS,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,EAAE;AACpF;;;ADlQA,SAAS,WAAW,MAAc,GAA6B;AAC7D,MAAI,EAAE,SAAS,QAAS,QAAO,GAAG,KAAK,OAAO,EAAE,CAAC,WAAW,EAAE,OAAO;AACrE,MAAI,EAAE,SAAS,SAAS;AACtB,UAAM,IAAI,EAAE;AACZ,WAAO,GAAG,KAAK,OAAO,EAAE,CAAC,eAAe,EAAE,WAAW,MAAM,EAAE,aAAa,OAAO,EAAE,aAAa,QAAQ,EAAE,GAAG;AAAA,EAC/G;AACA,MAAI,EAAE,SAAS,SAAS;AACtB,WAAO,GAAG,KAAK,OAAO,EAAE,CAAC,YAAY,EAAE,OAAO,QAAQ;AAAA,EACxD;AACA,QAAM,MAAM,EAAE;AACd,MAAI,IAAI,WAAW,OAAQ,QAAO,GAAG,KAAK,OAAO,EAAE,CAAC,QAAQ,IAAI,QAAQ,WAAM,IAAI,KAAK,KAAK,EAAE;AAC9F,MAAI,IAAI,WAAW;AACjB,WAAO,GAAG,KAAK,OAAO,EAAE,CAAC,UAAU,IAAI,QAAQ,WAAM,IAAI,KAAK,KAAK,EAAE;AACvE,SAAO,GAAG,KAAK,OAAO,EAAE,CAAC,aAAa,IAAI,QAAQ,MAAM,UAAU,IAAI,QAAQ,WAAW,IAAI,KAAK,GAAG,IAAI,IAAI,QAAQ,WAAM,IAAI,KAAK,KAAK,EAAE;AAC7I;AAEA,SAAS,aAAa,GAAyB;AAC7C,QAAM,SAAS,IAAI,EAAE,IAAI,mBAAc,EAAE,WAAW,gCAAgC,SAAS;AAC7F,QAAM,OAAO,EAAE,MAAM,IAAI,CAAC,MAAM,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,KAAK,IAAI;AACvE,SAAO,GAAG,MAAM;AAAA,EAAK,IAAI;AAC3B;AAQA,eAAsB,iBACpB,MACA,MAC2C;AAC3C,QAAM,MAAM,KAAK,MAAM,QAAQ,KAAK,GAAG,IAAI,QAAQ,IAAI;AACvD,QAAM,QAAQ,MAAM,aAAa,EAAE,MAAM,IAAI,CAAC;AAC9C,QAAM,SAAS,MAAM,CAAC;AACtB,MAAI,CAAC,QAAQ;AACX,WAAO,EAAE,QAAQ,yBAAyB,IAAI,MAAM,MAAM,EAAE;AAAA,EAC9D;AAIA,QAAM,EAAE,iBAAiB,IAAI,MAAM,OAAO,6BAAgC;AAC1E,QAAM,EAAE,eAAe,IAAI,MAAM,OAAO,2BAAyB;AACjE,QAAM,SAAS,MAAM,OAAO,QAAQ;AAAA,IAClC,cAAc,MAAM,iBAAiB;AAAA,IACrC,YAAY,MAAM,eAAe;AAAA,EACnC,CAAC;AACD,SAAO,EAAE,QAAQ,aAAa,MAAM,GAAG,MAAM,OAAO,WAAW,IAAI,EAAE;AACvE;","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":[]}
@@ -0,0 +1,7 @@
1
+ import {
2
+ runMigrations
3
+ } from "./chunk-MFHS7IQ2.js";
4
+ export {
5
+ runMigrations
6
+ };
7
+ //# sourceMappingURL=migrate-YITCXBLS.js.map
@@ -5,11 +5,11 @@ import {
5
5
  makeNotify,
6
6
  notifySubmission,
7
7
  resolveRecipients
8
- } from "./chunk-VSBFM7DS.js";
9
- import "./chunk-BNM5POSJ.js";
10
- import "./chunk-SNSTJLQW.js";
8
+ } from "./chunk-SJOXWJ5Y.js";
9
+ import "./chunk-JRHIFA5R.js";
10
+ import "./chunk-NO74DXDP.js";
11
11
  import "./chunk-5ML7FMBD.js";
12
- import "./chunk-DJZWYIPP.js";
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-C645PGD5.js.map
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-CROKUHJB.js";
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-6TWWY7ZU.js";
19
- import "./chunk-EVBCK2KC.js";
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-O4IAHJMO.js.map
73
+ //# sourceMappingURL=onboard-BKCYBAVW.js.map
@@ -4,22 +4,22 @@ import {
4
4
  parseAddresses,
5
5
  sendApprovedReports,
6
6
  withGlobalCc
7
- } from "./chunk-NDWYJLRF.js";
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-ZGBEIWSC.js";
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-XUGSZP7Z.js";
20
- import "./chunk-EVBCK2KC.js";
21
- import "./chunk-JHGHLKFS.js";
22
- import "./chunk-3SF7D4DY.js";
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-YLWQ6KK2.js.map
31
+ //# sourceMappingURL=orchestrate-JNKCWU5K.js.map
@@ -1,12 +1,14 @@
1
1
  import {
2
2
  checkFleetParity,
3
3
  formatParityResult
4
- } from "./chunk-ZBDZTJUO.js";
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-56KA2DGR.js.map
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-HSI6Q7MI.js";
6
- import "./chunk-EVBCK2KC.js";
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-3AANZFCR.js.map
12
+ //# sourceMappingURL=pipeline-WYTXSLHX.js.map
@@ -1,23 +1,23 @@
1
1
  import {
2
2
  preflight
3
- } from "./chunk-SDDPUAWH.js";
3
+ } from "./chunk-6I6L3CMX.js";
4
4
  import "./chunk-PZR4EBPY.js";
5
- import "./chunk-NDWYJLRF.js";
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-ZGBEIWSC.js";
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-XUGSZP7Z.js";
18
- import "./chunk-EVBCK2KC.js";
19
- import "./chunk-JHGHLKFS.js";
20
- import "./chunk-3SF7D4DY.js";
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-TNORKGCX.js.map
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-CROKUHJB.js";
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-6TWWY7ZU.js";
28
- import "./chunk-EVBCK2KC.js";
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-G2AK53VL.js.map
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-CROKUHJB.js";
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-6TWWY7ZU.js";
30
- import "./chunk-EVBCK2KC.js";
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-NIREX5ME.js");
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-CMKHGJNQ.js")).formatFleetWriteSummary;
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-O6Z3OK3A.js.map
1025
+ //# sourceMappingURL=prismic-models-NJN5JORF.js.map
@@ -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
- } from "./chunk-EVBCK2KC.js";
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/dashboard/handler-helpers.ts
11
- var DEFAULT_DASHBOARD_BASE_URL = "https://reddoor-maintenance.netlify.app";
12
- function resolveDashboardBaseUrl(raw) {
13
- return (raw?.trim() || DEFAULT_DASHBOARD_BASE_URL).replace(/\/$/, "");
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-3AANZFCR.js");
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-IFOGFB5T.js");
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-AUE3XUPO.js");
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 = `${resolveDashboardBaseUrl(process.env.DASHBOARD_BASE_URL)}/r/${token}`;
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-KJXASVH5.js");
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-KSXUNQ5J.js.map
193
+ //# sourceMappingURL=prospect-audit-JMBRVXSG.js.map