@reddoorla/maintenance 0.96.0 → 0.98.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (272) hide show
  1. package/README.md +5 -6
  2. package/dist/{announce-45HVP4J4.js → announce-2FH2KBQQ.js} +39 -31
  3. package/dist/announce-2FH2KBQQ.js.map +1 -0
  4. package/dist/attachments-JFGFQRXQ.js +10 -0
  5. package/dist/{blux-RUFMNOUJ.js → blux-NXQLMS4W.js} +5 -5
  6. package/dist/{bump-deps-EL3TKMIL.js → bump-deps-54K4ECP3.js} +6 -6
  7. package/dist/{chunk-IMYL67JV.js → chunk-3RLDX3Q2.js} +5 -5
  8. package/dist/{chunk-EQQ4H6L3.js → chunk-3YALLSBF.js} +2 -2
  9. package/dist/{chunk-LAJ3FF54.js → chunk-5UI4FERC.js} +16 -5
  10. package/dist/chunk-5UI4FERC.js.map +1 -0
  11. package/dist/{chunk-CA6ADGOC.js → chunk-6PGXKN6F.js} +2 -2
  12. package/dist/{chunk-Y5BVR4HW.js → chunk-6THEZQLA.js} +3 -3
  13. package/dist/chunk-ASLDCWBF.js +41 -0
  14. package/dist/chunk-ASLDCWBF.js.map +1 -0
  15. package/dist/{chunk-DVJNYPFR.js → chunk-AYDQQBNG.js} +2 -2
  16. package/dist/{chunk-OTEVKRAH.js → chunk-B2BRFWJY.js} +7 -16
  17. package/dist/chunk-B2BRFWJY.js.map +1 -0
  18. package/dist/{chunk-GEUC5VGM.js → chunk-BINFZQ2T.js} +49 -4
  19. package/dist/chunk-BINFZQ2T.js.map +1 -0
  20. package/dist/{chunk-T76MA2FH.js → chunk-CP6MVZ5X.js} +27 -1
  21. package/dist/{chunk-T76MA2FH.js.map → chunk-CP6MVZ5X.js.map} +1 -1
  22. package/dist/{chunk-72FJZ6LO.js → chunk-DRNZVORX.js} +26 -22
  23. package/dist/chunk-DRNZVORX.js.map +1 -0
  24. package/dist/{chunk-XY7YV2YQ.js → chunk-DXZRWW2F.js} +65 -10
  25. package/dist/chunk-DXZRWW2F.js.map +1 -0
  26. package/dist/{chunk-SHGIDTYF.js → chunk-DYTYPKFN.js} +2 -2
  27. package/dist/chunk-DZZ5KRTB.js +23 -0
  28. package/dist/chunk-DZZ5KRTB.js.map +1 -0
  29. package/dist/{chunk-NVLREB5R.js → chunk-EN6CTBUN.js} +7 -7
  30. package/dist/{chunk-ZH5LOQET.js → chunk-FHFXJ3EM.js} +7 -5
  31. package/dist/chunk-FHFXJ3EM.js.map +1 -0
  32. package/dist/{chunk-3EA43S3R.js → chunk-GRF2RYEO.js} +12 -12
  33. package/dist/{chunk-RRE74VWI.js → chunk-HSMN35LU.js} +2 -2
  34. package/dist/chunk-ICSRWW5Q.js +148 -0
  35. package/dist/chunk-ICSRWW5Q.js.map +1 -0
  36. package/dist/{chunk-XG2A6GIG.js → chunk-IDBPII6G.js} +4 -4
  37. package/dist/{chunk-XG2A6GIG.js.map → chunk-IDBPII6G.js.map} +1 -1
  38. package/dist/{chunk-ECDJDHKT.js → chunk-JHJNNJLG.js} +2 -2
  39. package/dist/{chunk-QFSL2L2B.js → chunk-L5F3WYIY.js} +81 -31
  40. package/dist/chunk-L5F3WYIY.js.map +1 -0
  41. package/dist/{chunk-XED2DNAI.js → chunk-LAG6IP7Y.js} +7 -7
  42. package/dist/{chunk-UIITN37J.js → chunk-LF2TJN4X.js} +2 -2
  43. package/dist/chunk-LF2TJN4X.js.map +1 -0
  44. package/dist/{chunk-SQ4FSNYL.js → chunk-LUF52EIY.js} +2 -2
  45. package/dist/{chunk-MZZDMBDT.js → chunk-LZMAG73U.js} +19 -19
  46. package/dist/chunk-LZMAG73U.js.map +1 -0
  47. package/dist/{chunk-6INOBNRO.js → chunk-MNRWHSFS.js} +2 -2
  48. package/dist/{chunk-CGQZFQAY.js → chunk-MVKNU4QD.js} +2 -3
  49. package/dist/chunk-MVKNU4QD.js.map +1 -0
  50. package/dist/{chunk-62YWOFVN.js → chunk-ORTOMEYR.js} +3 -3
  51. package/dist/{chunk-62YWOFVN.js.map → chunk-ORTOMEYR.js.map} +1 -1
  52. package/dist/{chunk-44SDGPGQ.js → chunk-PZZ6HM5T.js} +3 -3
  53. package/dist/chunk-RQJFGK3A.js +51 -0
  54. package/dist/chunk-RQJFGK3A.js.map +1 -0
  55. package/dist/{chunk-H445EH33.js → chunk-S2PLX4XK.js} +10 -7
  56. package/dist/chunk-S2PLX4XK.js.map +1 -0
  57. package/dist/{chunk-KN52PM63.js → chunk-TC4GANMX.js} +47 -149
  58. package/dist/chunk-TC4GANMX.js.map +1 -0
  59. package/dist/{chunk-F3JWOPTG.js → chunk-TEMQPSCM.js} +45 -105
  60. package/dist/chunk-TEMQPSCM.js.map +1 -0
  61. package/dist/{chunk-4UTJ4G6P.js → chunk-TJLKWQOX.js} +2 -2
  62. package/dist/{chunk-A5QKNOXW.js → chunk-TTT6HYPW.js} +47 -10
  63. package/dist/chunk-TTT6HYPW.js.map +1 -0
  64. package/dist/{chunk-VEIIUCYL.js → chunk-TV76A6GN.js} +2 -2
  65. package/dist/{chunk-D3CTOCUR.js → chunk-TVZ6QCOE.js} +3 -3
  66. package/dist/chunk-UPE6D4AT.js +69 -0
  67. package/dist/chunk-UPE6D4AT.js.map +1 -0
  68. package/dist/{chunk-BIYQN7FH.js → chunk-VCPTOZ56.js} +31 -1
  69. package/dist/{chunk-BIYQN7FH.js.map → chunk-VCPTOZ56.js.map} +1 -1
  70. package/dist/chunk-VQMAAQ5M.js +53 -0
  71. package/dist/chunk-VQMAAQ5M.js.map +1 -0
  72. package/dist/{chunk-EASYCD6F.js → chunk-WMF5S2MB.js} +1 -1
  73. package/dist/{chunk-EASYCD6F.js.map → chunk-WMF5S2MB.js.map} +1 -1
  74. package/dist/{chunk-37B4LVB3.js → chunk-X56LAKPR.js} +3 -3
  75. package/dist/chunk-X56LAKPR.js.map +1 -0
  76. package/dist/{chunk-IY6256GK.js → chunk-YJBSB4LP.js} +6 -1
  77. package/dist/chunk-YJBSB4LP.js.map +1 -0
  78. package/dist/{chunk-P4A6D6HO.js → chunk-ZEE5WQYU.js} +32 -18
  79. package/dist/chunk-ZEE5WQYU.js.map +1 -0
  80. package/dist/cli/bin.js +92 -50
  81. package/dist/cli/bin.js.map +1 -1
  82. package/dist/cli/commands/audit.d.ts +33 -3
  83. package/dist/cli/commands/audit.js +26 -23
  84. package/dist/cli/commands/audit.js.map +1 -1
  85. package/dist/client-3XGSZMLU.js +11 -0
  86. package/dist/{convert-to-pnpm-4DON7IFS.js → convert-to-pnpm-U2CRNKNY.js} +6 -6
  87. package/dist/{db-5K4CDEGJ.js → db-7XYTBIPH.js} +25 -18
  88. package/dist/db-7XYTBIPH.js.map +1 -0
  89. package/dist/{deadletter-G4M3HSVM.js → deadletter-A7RQVNG3.js} +8 -4
  90. package/dist/{digest-5AJGWS33.js → digest-AMXRGWZA.js} +34 -33
  91. package/dist/digest-AMXRGWZA.js.map +1 -0
  92. package/dist/{digest-collectors-MC5NWEUA.js → digest-collectors-CX2NCGS7.js} +15 -12
  93. package/dist/ensure-site-F2WFCWWA.js +70 -0
  94. package/dist/ensure-site-F2WFCWWA.js.map +1 -0
  95. package/dist/ensure-site-JEKV2ODE.js +105 -0
  96. package/dist/ensure-site-JEKV2ODE.js.map +1 -0
  97. package/dist/{ensure-site-XESZHZEB.js → ensure-site-OO4UPWNQ.js} +19 -42
  98. package/dist/ensure-site-OO4UPWNQ.js.map +1 -0
  99. package/dist/fleet-events-CkOZpMVC.d.ts +435 -0
  100. package/dist/{fleet-state-GJWGKTLD.js → fleet-state-RJROYXKO.js} +17 -7
  101. package/dist/{forms-notify-target-4NPLX2UG.js → forms-notify-target-DK5R326N.js} +17 -13
  102. package/dist/forms-notify-target-DK5R326N.js.map +1 -0
  103. package/dist/{github-signals-DMU74SAX.js → github-signals-RGRPYTUB.js} +20 -15
  104. package/dist/github-signals-RGRPYTUB.js.map +1 -0
  105. package/dist/{header-image-BRTOLHJF.js → header-image-43ZIEJKP.js} +13 -17
  106. package/dist/header-image-43ZIEJKP.js.map +1 -0
  107. package/dist/{health-endpoint-UCLMSSCN.js → health-endpoint-K5LXDPGE.js} +7 -7
  108. package/dist/{health-mirror-ONRT4DQ5.js → health-mirror-WZUHWCCV.js} +10 -10
  109. package/dist/{import-airtable-IIK2QUUF.js → import-airtable-UBF5GYAL.js} +3 -3
  110. package/dist/index.d.ts +102 -494
  111. package/dist/index.js +62 -52
  112. package/dist/index.js.map +1 -1
  113. package/dist/{init-3LMZTCVD.js → init-OFITGMOP.js} +16 -16
  114. package/dist/{launch-XTDMC6LD.js → launch-AJY3TGTQ.js} +37 -35
  115. package/dist/launch-AJY3TGTQ.js.map +1 -0
  116. package/dist/{lighthouse-52WSPZ5D.js → lighthouse-RFMFREEX.js} +2 -2
  117. package/dist/lighthouse-airtable-M45OPVRV.js +14 -0
  118. package/dist/{chunk-IHHAYXKY.js → match-harness-CFELJA57.js} +70 -4
  119. package/dist/match-harness-CFELJA57.js.map +1 -0
  120. package/dist/migrate-EZL55AWA.js +7 -0
  121. package/dist/notify-K3WVH3DM.js +1 -1
  122. package/dist/{onboard-CZYBWVWH.js → onboard-F7RTLMDZ.js} +6 -6
  123. package/dist/{orchestrate-TGDFGY52.js → orchestrate-SAIFXZIW.js} +13 -10
  124. package/dist/parity-2JGVUCZD.js +14 -0
  125. package/dist/{pipeline-UUPXOS2J.js → pipeline-TCSNVDQZ.js} +3 -3
  126. package/dist/{preflight-POZZI3GN.js → preflight-6XGVVO2U.js} +35 -11
  127. package/dist/preflight-6XGVVO2U.js.map +1 -0
  128. package/dist/{prismic-ci-AHY5ULJR.js → prismic-ci-XMX7A5E4.js} +11 -11
  129. package/dist/prismic-ci-XMX7A5E4.js.map +1 -0
  130. package/dist/{prismic-models-URYGODNY.js → prismic-models-7GKFAAFA.js} +19 -16
  131. package/dist/prismic-models-7GKFAAFA.js.map +1 -0
  132. package/dist/prospect/types.d.ts +44 -2
  133. package/dist/prospect/types.js +1 -1
  134. package/dist/{prospect-audit-AJEE3Z4L.js → prospect-audit-KWP5P5U2.js} +37 -5
  135. package/dist/prospect-audit-KWP5P5U2.js.map +1 -0
  136. package/dist/{protection-audit-3J3UEOVT.js → protection-audit-YXJKFU6O.js} +3 -3
  137. package/dist/{protection-audit-3J3UEOVT.js.map → protection-audit-YXJKFU6O.js.map} +1 -1
  138. package/dist/recipes/sync-configs.js +3 -3
  139. package/dist/{render-MHUUHPLN.js → render-NWUAX6RN.js} +3 -3
  140. package/dist/{render-from-row-65DC6ZP3.js → render-from-row-75JTED2Z.js} +6 -4
  141. package/dist/{renovate-dispatch-ONJMBUHJ.js → renovate-dispatch-ZZQXT7DA.js} +13 -8
  142. package/dist/{renovate-dispatch-ONJMBUHJ.js.map → renovate-dispatch-ZZQXT7DA.js.map} +1 -1
  143. package/dist/replay-HB44TAII.js +77 -0
  144. package/dist/replay-HB44TAII.js.map +1 -0
  145. package/dist/{report-RC5LGPU3.js → report-MVPWS7WP.js} +102 -58
  146. package/dist/report-MVPWS7WP.js.map +1 -0
  147. package/dist/{report-mirror-KKZZ6RMZ.js → report-mirror-O6IDFDWU.js} +28 -10
  148. package/dist/report-mirror-O6IDFDWU.js.map +1 -0
  149. package/dist/roster-EJ3ILR52.js +19 -0
  150. package/dist/roster-EJ3ILR52.js.map +1 -0
  151. package/dist/{screenouts-7P5GOZMV.js → screenouts-7NQUWHOJ.js} +14 -1
  152. package/dist/screenouts-7NQUWHOJ.js.map +1 -0
  153. package/dist/{self-updating-RKKIYNV4.js → self-updating-KX5FMGEO.js} +7 -7
  154. package/dist/{selftest-AFLR7YV7.js → selftest-KABY2CYJ.js} +21 -17
  155. package/dist/{selftest-AFLR7YV7.js.map → selftest-KABY2CYJ.js.map} +1 -1
  156. package/dist/site-create-ZU3ACBTO.js +45 -0
  157. package/dist/site-create-ZU3ACBTO.js.map +1 -0
  158. package/dist/{site-mirror-H2FYMN55.js → site-mirror-TKTDWYP3.js} +10 -10
  159. package/dist/site-mirror-TKTDWYP3.js.map +1 -0
  160. package/dist/{smoke-suite-BWHR3XX5.js → smoke-suite-QQMV7TNA.js} +7 -7
  161. package/dist/{submissions-JDZP35JM.js → submissions-4I66W6QK.js} +11 -1
  162. package/dist/{submissions-JDZP35JM.js.map → submissions-4I66W6QK.js.map} +1 -1
  163. package/dist/{submissions-II5J35QM.js → submissions-K5UXGZUN.js} +12 -7
  164. package/dist/submissions-K5UXGZUN.js.map +1 -0
  165. package/dist/{svelte-codemods-QWGIRNN6.js → svelte-codemods-YFN4TEGV.js} +6 -6
  166. package/dist/{sync-NKPDCMYW.js → sync-F4USL4K5.js} +6 -6
  167. package/dist/{sync-configs-HGLQV55H.js → sync-configs-HBXS3D7C.js} +6 -6
  168. package/dist/turso-KQKBBQCK.js +24 -0
  169. package/dist/turso-KQKBBQCK.js.map +1 -0
  170. package/dist/{upgrade-WZ44IARG.js → upgrade-XOJMDIT4.js} +6 -6
  171. package/dist/util/git.d.ts +1 -1
  172. package/dist/util/git.js +1 -1
  173. package/dist/{websites-6DHIHJ2D.js → websites-Y6FN2XFD.js} +26 -21
  174. package/dist/{write-audits-to-airtable-BIK6LNVC.js → write-audits-to-airtable-TI3JMWSY.js} +6 -4
  175. package/package.json +1 -1
  176. package/dist/airtable-SJV4ZSMS.js +0 -9
  177. package/dist/announce-45HVP4J4.js.map +0 -1
  178. package/dist/attachments-NLZIJ5NU.js +0 -9
  179. package/dist/chunk-37B4LVB3.js.map +0 -1
  180. package/dist/chunk-72FJZ6LO.js.map +0 -1
  181. package/dist/chunk-74QRWE6G.js +0 -53
  182. package/dist/chunk-74QRWE6G.js.map +0 -1
  183. package/dist/chunk-A5QKNOXW.js.map +0 -1
  184. package/dist/chunk-CGQZFQAY.js.map +0 -1
  185. package/dist/chunk-F3JWOPTG.js.map +0 -1
  186. package/dist/chunk-GEUC5VGM.js.map +0 -1
  187. package/dist/chunk-H445EH33.js.map +0 -1
  188. package/dist/chunk-IHHAYXKY.js.map +0 -1
  189. package/dist/chunk-IY6256GK.js.map +0 -1
  190. package/dist/chunk-KN52PM63.js.map +0 -1
  191. package/dist/chunk-LAJ3FF54.js.map +0 -1
  192. package/dist/chunk-MZZDMBDT.js.map +0 -1
  193. package/dist/chunk-OTEVKRAH.js.map +0 -1
  194. package/dist/chunk-P4A6D6HO.js.map +0 -1
  195. package/dist/chunk-QFSL2L2B.js.map +0 -1
  196. package/dist/chunk-UIITN37J.js.map +0 -1
  197. package/dist/chunk-XY7YV2YQ.js.map +0 -1
  198. package/dist/chunk-YFAXOD7Z.js +0 -42
  199. package/dist/chunk-YFAXOD7Z.js.map +0 -1
  200. package/dist/chunk-ZH5LOQET.js.map +0 -1
  201. package/dist/client-L7NAUG6J.js +0 -11
  202. package/dist/db-5K4CDEGJ.js.map +0 -1
  203. package/dist/digest-5AJGWS33.js.map +0 -1
  204. package/dist/ensure-site-XESZHZEB.js.map +0 -1
  205. package/dist/fleet-events-cF2Om88w.d.ts +0 -24
  206. package/dist/forms-notify-target-4NPLX2UG.js.map +0 -1
  207. package/dist/github-signals-DMU74SAX.js.map +0 -1
  208. package/dist/header-image-BRTOLHJF.js.map +0 -1
  209. package/dist/launch-XTDMC6LD.js.map +0 -1
  210. package/dist/lighthouse-airtable-3NOFB42B.js +0 -12
  211. package/dist/match-harness-OW45CB5H.js +0 -77
  212. package/dist/match-harness-OW45CB5H.js.map +0 -1
  213. package/dist/migrate-NE3DUMTM.js +0 -7
  214. package/dist/parity-AEKYSLN6.js +0 -14
  215. package/dist/preflight-POZZI3GN.js.map +0 -1
  216. package/dist/prismic-ci-AHY5ULJR.js.map +0 -1
  217. package/dist/prismic-models-URYGODNY.js.map +0 -1
  218. package/dist/prospect-audit-AJEE3Z4L.js.map +0 -1
  219. package/dist/replay-4FVFOMHH.js +0 -54
  220. package/dist/replay-4FVFOMHH.js.map +0 -1
  221. package/dist/report-RC5LGPU3.js.map +0 -1
  222. package/dist/report-mirror-KKZZ6RMZ.js.map +0 -1
  223. package/dist/screenouts-7P5GOZMV.js.map +0 -1
  224. package/dist/site-mirror-H2FYMN55.js.map +0 -1
  225. package/dist/submissions-II5J35QM.js.map +0 -1
  226. package/dist/write-audits-to-airtable-BIK6LNVC.js.map +0 -1
  227. /package/dist/{airtable-SJV4ZSMS.js.map → attachments-JFGFQRXQ.js.map} +0 -0
  228. /package/dist/{blux-RUFMNOUJ.js.map → blux-NXQLMS4W.js.map} +0 -0
  229. /package/dist/{bump-deps-EL3TKMIL.js.map → bump-deps-54K4ECP3.js.map} +0 -0
  230. /package/dist/{chunk-IMYL67JV.js.map → chunk-3RLDX3Q2.js.map} +0 -0
  231. /package/dist/{chunk-EQQ4H6L3.js.map → chunk-3YALLSBF.js.map} +0 -0
  232. /package/dist/{chunk-CA6ADGOC.js.map → chunk-6PGXKN6F.js.map} +0 -0
  233. /package/dist/{chunk-Y5BVR4HW.js.map → chunk-6THEZQLA.js.map} +0 -0
  234. /package/dist/{chunk-DVJNYPFR.js.map → chunk-AYDQQBNG.js.map} +0 -0
  235. /package/dist/{chunk-SHGIDTYF.js.map → chunk-DYTYPKFN.js.map} +0 -0
  236. /package/dist/{chunk-NVLREB5R.js.map → chunk-EN6CTBUN.js.map} +0 -0
  237. /package/dist/{chunk-3EA43S3R.js.map → chunk-GRF2RYEO.js.map} +0 -0
  238. /package/dist/{chunk-RRE74VWI.js.map → chunk-HSMN35LU.js.map} +0 -0
  239. /package/dist/{chunk-ECDJDHKT.js.map → chunk-JHJNNJLG.js.map} +0 -0
  240. /package/dist/{chunk-XED2DNAI.js.map → chunk-LAG6IP7Y.js.map} +0 -0
  241. /package/dist/{chunk-SQ4FSNYL.js.map → chunk-LUF52EIY.js.map} +0 -0
  242. /package/dist/{chunk-6INOBNRO.js.map → chunk-MNRWHSFS.js.map} +0 -0
  243. /package/dist/{chunk-44SDGPGQ.js.map → chunk-PZZ6HM5T.js.map} +0 -0
  244. /package/dist/{chunk-4UTJ4G6P.js.map → chunk-TJLKWQOX.js.map} +0 -0
  245. /package/dist/{chunk-VEIIUCYL.js.map → chunk-TV76A6GN.js.map} +0 -0
  246. /package/dist/{chunk-D3CTOCUR.js.map → chunk-TVZ6QCOE.js.map} +0 -0
  247. /package/dist/{attachments-NLZIJ5NU.js.map → client-3XGSZMLU.js.map} +0 -0
  248. /package/dist/{convert-to-pnpm-4DON7IFS.js.map → convert-to-pnpm-U2CRNKNY.js.map} +0 -0
  249. /package/dist/{client-L7NAUG6J.js.map → deadletter-A7RQVNG3.js.map} +0 -0
  250. /package/dist/{deadletter-G4M3HSVM.js.map → digest-collectors-CX2NCGS7.js.map} +0 -0
  251. /package/dist/{digest-collectors-MC5NWEUA.js.map → fleet-state-RJROYXKO.js.map} +0 -0
  252. /package/dist/{health-endpoint-UCLMSSCN.js.map → health-endpoint-K5LXDPGE.js.map} +0 -0
  253. /package/dist/{health-mirror-ONRT4DQ5.js.map → health-mirror-WZUHWCCV.js.map} +0 -0
  254. /package/dist/{fleet-state-GJWGKTLD.js.map → import-airtable-UBF5GYAL.js.map} +0 -0
  255. /package/dist/{init-3LMZTCVD.js.map → init-OFITGMOP.js.map} +0 -0
  256. /package/dist/{import-airtable-IIK2QUUF.js.map → lighthouse-RFMFREEX.js.map} +0 -0
  257. /package/dist/{lighthouse-52WSPZ5D.js.map → lighthouse-airtable-M45OPVRV.js.map} +0 -0
  258. /package/dist/{lighthouse-airtable-3NOFB42B.js.map → migrate-EZL55AWA.js.map} +0 -0
  259. /package/dist/{onboard-CZYBWVWH.js.map → onboard-F7RTLMDZ.js.map} +0 -0
  260. /package/dist/{migrate-NE3DUMTM.js.map → orchestrate-SAIFXZIW.js.map} +0 -0
  261. /package/dist/{orchestrate-TGDFGY52.js.map → parity-2JGVUCZD.js.map} +0 -0
  262. /package/dist/{parity-AEKYSLN6.js.map → pipeline-TCSNVDQZ.js.map} +0 -0
  263. /package/dist/{render-MHUUHPLN.js.map → render-NWUAX6RN.js.map} +0 -0
  264. /package/dist/{pipeline-UUPXOS2J.js.map → render-from-row-75JTED2Z.js.map} +0 -0
  265. /package/dist/{self-updating-RKKIYNV4.js.map → self-updating-KX5FMGEO.js.map} +0 -0
  266. /package/dist/{smoke-suite-BWHR3XX5.js.map → smoke-suite-QQMV7TNA.js.map} +0 -0
  267. /package/dist/{svelte-codemods-QWGIRNN6.js.map → svelte-codemods-YFN4TEGV.js.map} +0 -0
  268. /package/dist/{sync-NKPDCMYW.js.map → sync-F4USL4K5.js.map} +0 -0
  269. /package/dist/{sync-configs-HGLQV55H.js.map → sync-configs-HBXS3D7C.js.map} +0 -0
  270. /package/dist/{upgrade-WZ44IARG.js.map → upgrade-XOJMDIT4.js.map} +0 -0
  271. /package/dist/{render-from-row-65DC6ZP3.js.map → websites-Y6FN2XFD.js.map} +0 -0
  272. /package/dist/{websites-6DHIHJ2D.js.map → write-audits-to-airtable-TI3JMWSY.js.map} +0 -0
@@ -0,0 +1,435 @@
1
+ import * as airtable_lib_airtable_base_js from 'airtable/lib/airtable_base.js';
2
+
3
+ type AirtableConfig = {
4
+ apiKey: string;
5
+ baseId: string;
6
+ };
7
+ type AirtableBase = ReturnType<typeof openBase>;
8
+ declare function openBase(cfg: AirtableConfig): airtable_lib_airtable_base_js.AirtableBase;
9
+
10
+ /**
11
+ * The site-status vocabulary — ONE module owns it (#539 Phase 4).
12
+ *
13
+ * It lived at `src/reports/airtable/site-status.ts` until #539 Phase 6 step 1
14
+ * (#646) moved it here: `canonicalizeStatus` runs on every Turso lead read, so
15
+ * it cannot sit in the directory Phase 6 deletes. The Airtable write seam
16
+ * `toAirtableStatus`, discussed below, stayed behind in that file, which also
17
+ * re-exports everything here.
18
+ *
19
+ * The fleet's lifecycle names were inherited from an Airtable single-select
20
+ * written by hand years ago ("probably not our problem"). The operator approved
21
+ * a canonical vocabulary, and the migration is now COMPLETE in both stores:
22
+ * Airtable's "Status" single-select carries exactly the six canonical options
23
+ * and nothing else. This module no longer knows the old names at all.
24
+ *
25
+ * The retired mapping, kept as the record of what was merged into what:
26
+ *
27
+ * old (retired 2026-08-25) new (canonical)
28
+ * ───────────────────────── ───────────────
29
+ * in development building
30
+ * launch period launching
31
+ * maintenance maintained
32
+ * hosting hosted-only
33
+ * probably not our problem external
34
+ * legacy ┐
35
+ * deprecated ┴ archived ← approved MERGE, many-to-one
36
+ *
37
+ * `legacy` and `deprecated` were already treated identically by every PREDICATE
38
+ * (ARCHIVED_STATUSES held both), so collapsing them changes no *selection* — no
39
+ * fleet op gains or loses a site. It is NOT true that collapsing them changes
40
+ * nothing at all, and one surface proved it: the cockpit's Archived lane LABELS
41
+ * each row with its Status cell, and canonicalizing there rendered all 12 live
42
+ * archived rows as "archived". That lane now labels from `statusRaw`, which is
43
+ * exactly why `WebsiteRow.statusRaw` exists. The rule this leaves behind:
44
+ * canonical values decide BEHAVIOUR; anything DISPLAYING a Status cell, or
45
+ * writing one back, uses the raw cell.
46
+ *
47
+ * The merge had NO clean reverse map while both vocabularies coexisted, which
48
+ * is why `toAirtableStatus` had to pick one archived name deliberately. With the
49
+ * old names retired there is nothing left to pick between, and no code path
50
+ * feeds operator-supplied text through it anyway (see
51
+ * `src/recipes/forms-notify-target.ts`, which writes `--restore` verbatim).
52
+ *
53
+ * THE SHAPE OF THE TRANSITION (three stages):
54
+ *
55
+ * stage 1 (DONE) code speaks the NEW vocabulary internally; reads canonicalize
56
+ * at the two Airtable/Turso seams; writes still emit the OLD
57
+ * Airtable option names. Airtable untouched. No SELECTION
58
+ * change — every predicate picks exactly the sites it picked
59
+ * before (pinned row-by-row in tests/reports/airtable/
60
+ * site-status.test.ts). Displayed labels come from `statusRaw`.
61
+ * stage 2 (DONE) the Airtable "Status" single-select gained the 6 new options
62
+ * and all 44 cells were migrated (verified live: maintained=13,
63
+ * archived=12, external=9, building=6, hosted-only=2,
64
+ * launching=2 — zero old values, zero unrecognized), `db sync`
65
+ * ran clean (mismatches=0), and AIRTABLE_USES_NEW_VOCABULARY
66
+ * flipped to true. Writers now emit canonical names verbatim.
67
+ * The alias map STAYS: the 7 old options still exist in the
68
+ * field, so a human can still pick one in the Airtable UI.
69
+ * stage 3 (DONE) the operator deleted the 7 old options from the Airtable
70
+ * "Status" field on 2026-08-25, which is what made this safe:
71
+ * the gate was always "no old value CAN BE ENTERED", not
72
+ * merely "none is stored". Verified against the live base
73
+ * before any code changed — the field carries exactly the six
74
+ * canonical choices, byte-exact, and all 44 cells still hold a
75
+ * canonical value with ZERO blanks (deleting a single-select
76
+ * option CLEARS the cells using it, so "no cell was blanked"
77
+ * was checked, not assumed). AIRTABLE_STATUS_ALIASES,
78
+ * AIRTABLE_OLD_NAMES and AIRTABLE_USES_NEW_VOCABULARY are
79
+ * gone; both functions reduce to the identity.
80
+ *
81
+ * WHAT CHANGED IN BEHAVIOUR AT STAGE 3, and it is the only thing that did: an
82
+ * old name is no longer translated. `canonicalizeStatus("maintenance")` used to
83
+ * yield `maintained`; it now yields `"maintenance"` verbatim, which
84
+ * `isUnrecognizedStatus` flags and the cockpit surfaces as a watch row. That is
85
+ * intended. The option cannot be selected any more, so a stored old value would
86
+ * mean something went wrong — a restored backup, a scripted write, an API
87
+ * caller with a stale constant — and the fleet should say so rather than absorb
88
+ * it into a status nobody chose.
89
+ *
90
+ * Canonicalization happens on READ, never at rest: `src/db/import-airtable.ts`
91
+ * still stores the raw Airtable cell verbatim in `sites.status`, so the hourly
92
+ * parity check keeps comparing raw-to-raw and the importer stays honest to its
93
+ * source. Both readers — `mapRow` (Airtable) and `rowFromJoined` (Turso) — run
94
+ * the raw value through `canonicalizeStatus`, which is what keeps the #558
95
+ * reader-equivalence instrument green.
96
+ */
97
+ /** The canonical site lifecycle vocabulary. */
98
+ type Status = "building" | "launching" | "maintained" | "hosted-only" | "external" | "archived";
99
+
100
+ /**
101
+ * The fleet's site-row model and its pure, vendor-neutral coercers.
102
+ *
103
+ * `WebsiteRow` is what BOTH readers return — `mapRow` over an Airtable record
104
+ * (`src/reports/airtable/websites.ts`) and `rowFromJoined` over Turso
105
+ * (`src/db/fleet-state.ts`) — and the coercers below are the ONE truth each of
106
+ * them applies to a raw cell/column. They lived in the Airtable module until
107
+ * #539 Phase 6 step 1 (#646) moved them here: they run on every Turso lead read,
108
+ * so they could not stay in the directory Phase 6 deletes. Nothing here touches
109
+ * a store; the doc comments still name Airtable columns because that is where
110
+ * each value was first defined, and the Turso columns carry the same raw values.
111
+ *
112
+ * `src/reports/airtable/websites.ts` re-exports every name, so existing imports
113
+ * resolve unchanged.
114
+ */
115
+
116
+ type Frequency = "None" | "Monthly" | "Quarterly" | "Yearly";
117
+
118
+ /**
119
+ * Per-site notification routing. When present on a `maintained` site, the form
120
+ * notification is addressed by the value of a submission field (`field`, read from
121
+ * `extraFields`) — e.g. route a contact form's `interest` to a different recipient
122
+ * per option, always CC-ing a shared address. Absent (`null`) → the site keeps the
123
+ * default single-POC behavior. Recipients live HERE (server-side Airtable config),
124
+ * never supplied by the submitting site, so the ingest can't be turned into an open
125
+ * relay.
126
+ */
127
+ type NotifyRouting = {
128
+ /** The `extraFields` key whose value selects a route, e.g. "interest". */
129
+ field: string;
130
+ /** Field-value → recipient address(es). */
131
+ routes: Record<string, string | string[]>;
132
+ /** Recipient(s) when the value matches no route. */
133
+ default?: string | string[];
134
+ /** Address(es) CC'd on every routed (maintenance) send. */
135
+ cc?: string[];
136
+ };
137
+ type WebsiteRow = {
138
+ id: string;
139
+ name: string;
140
+ url: string;
141
+ /** Canonical lifecycle status (see ./site-status.ts). Canonicalized at the read
142
+ * boundary, so an old-vocabulary Airtable cell and a new one read identically.
143
+ * A present-but-unrecognized cell survives VERBATIM (blind-cast) rather than
144
+ * becoming null — `isUnrecognizedStatus` flags it, and null would make
145
+ * due.ts/preflight.ts treat the row as eligible-by-default. */
146
+ status: Status | null;
147
+ /** The literal Airtable Status cell behind `status` — same pattern as
148
+ * `maintenanceFreqRaw`. The dashboard status editor round-trips THIS, so its
149
+ * dropdown offers and preselects the values Airtable actually holds while the
150
+ * two vocabularies coexist. Null = blank cell. */
151
+ statusRaw: string | null;
152
+ pointOfContact: string | null;
153
+ maintenanceFreq: Frequency;
154
+ testingFreq: Frequency;
155
+ /** The literal Airtable cell values behind the coerced frequencies. `toFrequency`
156
+ * trims whitespace ("Monthly " reads as Monthly), then maps any still-unrecognized
157
+ * value ("Quaterly") to "None" with a LOUD console.warn so nothing bogus reaches a
158
+ * client email and the drop is never invisible. Preflight validates THESE to surface
159
+ * the same failure as a structured finding. Null = blank cell. */
160
+ maintenanceFreqRaw: string | null;
161
+ testingFreqRaw: string | null;
162
+ /** Last manually-recorded maintenance day (used as fallback when no Reports row exists). */
163
+ maintenanceDay: string | null;
164
+ testingDay: string | null;
165
+ ga4PropertyId: string | null;
166
+ /** Operator-supplied query for the Google search-presence check (e.g. the business name).
167
+ * Null = no query set → the check is skipped for this site. */
168
+ searchQuery: string | null;
169
+ /** Explicit Search Console property for this site (`sc-domain:...` or `https://.../`).
170
+ * Null = auto-resolve from the SA's visible properties by host. */
171
+ searchConsoleProperty: string | null;
172
+ /** ISO timestamp of the last draft run where THIS site's GA/Search enrichment
173
+ * ERRORED (vs a legitimate "not configured" skip). Set by drafting on a soft-fail,
174
+ * cleared (null) on a clean enrichment, so the per-site analytics-failure signal
175
+ * self-heals. Null when the operator-added `Analytics soft-fail at` column is absent. */
176
+ analyticsSoftFailAt: string | null;
177
+ /** GitHub repo identity as `owner/repo`. Null = no git wiring → self-update ops skip
178
+ * (or, for local runs, fall back to the checkout's origin remote). */
179
+ gitRepo: string | null;
180
+ reportRecipientsTo: string | null;
181
+ reportRecipientsCc: string | null;
182
+ acceptedWatchConditions: string[];
183
+ /** First attachment in the Header image field (Airtable's signed URL — fetch before expiry). */
184
+ headerImage: {
185
+ url: string;
186
+ filename: string;
187
+ type: string;
188
+ } | null;
189
+ /** Lighthouse "current state" snapshot, kept fresh by `audit lighthouse --write-back`. */
190
+ pScore: number | null;
191
+ rScore: number | null;
192
+ bpScore: number | null;
193
+ seoScore: number | null;
194
+ /** ISO timestamp set by `audit lighthouse --write-back` when scores were last refreshed. */
195
+ lastLighthouseAuditAt: string | null;
196
+ /** Last-known counts from non-lighthouse audits, written by
197
+ * `audit --write-back`. `null` = never audited (or this audit
198
+ * type was skipped on the last run). 0 = audited, clean. */
199
+ a11yViolations: number | null;
200
+ /** Declared-range drift vs the Reddoor baseline (what package.json asks for). */
201
+ depsDrifted: number | null;
202
+ depsMajorBehind: number | null;
203
+ /** Real installed-version drift: deps behind the registry's latest, from the
204
+ * committed lockfile (`pnpm outdated`). Null = not determined this run. */
205
+ depsOutdated: number | null;
206
+ /** Of {@link depsOutdated}, how many are a *major* version behind the
207
+ * registry's latest — the "majors available on npm" signal, distinct from the
208
+ * baseline-drift {@link depsMajorBehind}. Null = not determined this run. */
209
+ depsMajorOutdated: number | null;
210
+ securityVulnsCritical: number | null;
211
+ securityVulnsHigh: number | null;
212
+ securityVulnsModerate: number | null;
213
+ securityVulnsLow: number | null;
214
+ /** Count of consecutive nightly Renovate auto-fix dispatches for the CURRENT
215
+ * critical/high vuln episode that have NOT yet cleared it. Owned by
216
+ * `renovate-dispatch`: +1 per real dispatch, reset to 0 when vulns clear.
217
+ * Null = field absent / never dispatched → reads as 0. At/above
218
+ * AUTO_FIX_EXHAUSTED_CYCLES the vuln renders as "auto-fix failed". */
219
+ securityAutoFixAttempts: number | null;
220
+ /** ISO timestamp the security audit last ran — gates freshness of the Security Updates auto-tick
221
+ * (clean counts only auto-tick when recent). */
222
+ lastSecurityAuditAt: string | null;
223
+ /** The known advisories behind the counts (severity-sorted, capped), so the dashboard can show
224
+ * WHICH packages are vulnerable, not just the totals. null = never audited / unparseable;
225
+ * empty array = audited clean. Written alongside the counts by the security audit. */
226
+ securityAdvisories: SecurityAdvisory[] | null;
227
+ /** Domain/DNS/SSL probe (the `domain` audit). `certDaysRemaining` is days until the TLS cert
228
+ * expires (null = unresolved or no usable cert); `domainCheckedAt` is when it last ran. */
229
+ certDaysRemaining: number | null;
230
+ domainCheckedAt: string | null;
231
+ /** Netlify site id — the IDENTITY the `netlify-deploy` audit needs to query the
232
+ * Netlify API. Read-only input (operator-set in Airtable); null = not on Netlify
233
+ * (or not wired) → that audit skips. Never derived from the URL. */
234
+ netlifyId: string | null;
235
+ /** Latest PRODUCTION deploy health (the `netlify-deploy` audit). `deployStatus` is
236
+ * Netlify's deploy state lower-cased (`ready`/`error`/`building`/…), null = none / not
237
+ * checked; `lastDeployAt` is when it deployed; `deployLogUrl` links to the deploy/log. */
238
+ deployStatus: string | null;
239
+ lastDeployAt: string | null;
240
+ deployLogUrl: string | null;
241
+ /** When the `netlify-deploy` audit last RAN (freshness stamp for `deployStatus`). The audit
242
+ * already writes "Deploy checked at"; this read-back is the Plan-2 fix so `deployEvidence`
243
+ * (Plan 4) can gate on check time — NOT on `lastDeployAt`, which is deploy time, not check time. */
244
+ deployCheckedAt: string | null;
245
+ /** Function-health verdict (the `function-health` audit): the deployed `/health` function
246
+ * answered `ok:true` (pass) or `ok:false` (fail). Single-select `pass`/`fail`; null = never ran
247
+ * / unreachable (→ Plan 4 maps to unknown/amber). Kept SEPARATE from `deployStatus` so
248
+ * `isFailedDeployStatus` keeps meaning "the build failed". */
249
+ functionHealth: "pass" | "fail" | null;
250
+ /** CMS reachability (server-side), derived from the same `/health` body's `details.prismic ===
251
+ * "ok"`. Single-select `pass`/`fail`; null = never ran. No per-site Prismic token or identity
252
+ * column is ever built — this rides `/health`. */
253
+ cmsReachable: "pass" | "fail" | null;
254
+ /** Does the deployed site's Turnstile widget actually work? Single-select `pass`/`fail`;
255
+ * null = **unverified**, which is the normal state — see below. Freshness gated by
256
+ * `formE2eCheckedAt`, the clock of the audit that writes it. Powers the cockpit Require-Turnstile guardrail: a site with
257
+ * `requireTurnstile` ON but no working widget silently buckets 100% of its real leads.
258
+ *
259
+ * One of the two `"fail"` arms is derived from `/health` (the other is a browser seeing
260
+ * 110200 on the live hostname), whose `forms.turnstile` is a truthiness check
261
+ * on `PUBLIC_TURNSTILE_SITE_KEY` that never contacts Cloudflare (see
262
+ * audits/function-health-airtable.ts for the incident). No key IS proof the widget can't
263
+ * work; a key is NOT proof that it can — a sitekey whose widget is full at Cloudflare's
264
+ * 10-hostname cap sets the var and still mints no token. So a `"pass"` here has to be
265
+ * earned by a real browser rendering the real widget (form-e2e), and until it is, null
266
+ * keeps the site in the cockpit's amber "can't verify" watch rather than claiming health
267
+ * nobody measured. */
268
+ turnstileWidget: "pass" | "fail" | null;
269
+ /** When the `function-health` audit last ran — the freshness gate for `functionHealth`,
270
+ * `cmsReachable`, and `turnstileWidget`. Null = never ran. */
271
+ functionHealthCheckedAt: string | null;
272
+ /** Deployed-URL browser probe (the `browser` audit): cross-engine render OK, mobile render OK,
273
+ * internal-links OK + broken count, and when it last ran (one timestamp gates all three). */
274
+ crossbrowserOk: boolean | null;
275
+ mobileOk: boolean | null;
276
+ linksOk: boolean | null;
277
+ brokenLinks: number | null;
278
+ browserCheckedAt: string | null;
279
+ /** Uptime-reachable verdict (browser audit): every sampled route returned 2xx/3xx. Single-select
280
+ * `pass`/`fail`; null = never ran. Point-in-time. Freshness-gated by `browserCheckedAt`. */
281
+ reachableOk: "pass" | "fail" | null;
282
+ /** Titles & meta verdict (browser audit, chromium): every sampled route has a non-empty `<title>`
283
+ * ≤ 70 chars + a non-empty meta description, and no duplicate titles across the sample.
284
+ * Single-select `pass`/`fail`; null = never ran. Freshness-gated by `browserCheckedAt`. */
285
+ titleMetaOk: "pass" | "fail" | null;
286
+ /** Per-site copy overrides (M6a). Blank → null → the DEFAULT_COPY value. */
287
+ copyIntro: string | null;
288
+ copyContact: string | null;
289
+ copyFooter: string | null;
290
+ /** Go-live timestamp, stamped when a Launch report sends (M6b). Null = not yet launched. */
291
+ launchedAt: string | null;
292
+ /** Optional per-site webhook (e.g. Zapier Catch Hook). When set, the ingest
293
+ * POSTs newsletter-formType submissions here (best-effort). Blank → null. */
294
+ newsletterWebhook: string | null;
295
+ /** Per-site Mailchimp (newsletter). Both must be set for the direct add;
296
+ * blank → skipped. The API key is `key-dc` format; dc is derived from it. */
297
+ mailchimpApiKey: string | null;
298
+ mailchimpAudienceId: string | null;
299
+ /** Per-site Cloudflare Turnstile gate (Airtable checkbox). When true, a submission
300
+ * whose Turnstile token verifies as "fail" (forged) OR "absent" (secret configured
301
+ * centrally but NO token forwarded — the direct-POST-bot signature) is escalated to
302
+ * auto-spam regardless of content score. A present-but-expired token stays
303
+ * "unverifiable" and neutral (a real browser DID render the widget — fail-open).
304
+ * ROLLOUT PRECONDITION: only enable on a site whose DEPLOYED package forwards
305
+ * `_meta.turnstileToken` from EVERY form (widget rendered + `cf-turnstile-response`
306
+ * posted; check the site's `/health` → forms.turnstile:true). A site that never
307
+ * forwards tokens would silently bucket 100% of its real leads — and the form-e2e
308
+ * probe cannot catch that state (testMode bypasses the gate). */
309
+ requireTurnstile: boolean;
310
+ /** GitHub-signals sweep (slice 2a), written nightly by `github-signals --fleet`. */
311
+ renovateFailingCis: number | null;
312
+ defaultBranchCi: string | null;
313
+ lastCommitAt: string | null;
314
+ githubSignalsAt: string | null;
315
+ /** Per-site smoke-suite verdict (the `smoke` audit runs `pnpm test:smoke`).
316
+ * Single-select pass/fail; null = never ran. `lastSmokeAt` gates freshness. */
317
+ smokeOk: "pass" | "fail" | null;
318
+ lastSmokeAt: string | null;
319
+ /** Synthetic form end-to-end verdict (the `form-e2e` audit submits the real prod
320
+ * contact form in test-mode). Single-select pass/fail; null = never ran OR (with
321
+ * a fresh `formE2eCheckedAt`) no contact form → n/a. `formE2eCheckedAt` gates
322
+ * freshness AND encodes the n/a-vs-never-ran distinction. */
323
+ formE2eOk: "pass" | "fail" | null;
324
+ formE2eCheckedAt: string | null;
325
+ /**
326
+ * Nightly Prismic model drift sweep (`prismic-models --fleet --write-back`).
327
+ *
328
+ * FOUR-VALUED, unlike every other verdict column in this table, and the extra
329
+ * state is the point:
330
+ *
331
+ * - `pass` — the repo and its Prismic repository were compared and agree.
332
+ * - `fail` — they were compared and DIVERGE (a model to create/update, or
333
+ * one that exists only in Prismic). A finding for a human.
334
+ * - `unknown` — THE CHECK ITSELF FAILED. Unreadable checkout, broken config,
335
+ * missing/expired token, unreadable remote. Nothing at all was
336
+ * established about this site's models.
337
+ * - `null` — no verdict to hold: the sweep has never run for this site, or
338
+ * it ran and found no Prismic config at all (a repo that simply
339
+ * is not a Prismic site). `prismicModelsCheckedAt` separates
340
+ * those two — fresh timestamp, blank verdict = "checked, and
341
+ * there is nothing here to check".
342
+ *
343
+ * `unknown` exists because the alternatives are both wrong in the dangerous
344
+ * direction. Writing `pass` for a site nobody could read is a green tick over
345
+ * an outage; writing NOTHING (the obvious "leave the last known value alone")
346
+ * leaves yesterday's `pass` standing for a site that has been failing every
347
+ * night since — and nothing ages a stale `pass` out, because the digest's
348
+ * freshness gate only ever examines failures. Both make "I could not read this
349
+ * site" indistinguishable from "this site is fine", in the record the cockpit
350
+ * and the digest read.
351
+ *
352
+ * OPERATOR PRECONDITION: `Prismic Models` is a single select whose options are
353
+ * `pass`, `fail`, `unknown`. Until the three columns exist the sweep's writes
354
+ * fail with UNKNOWN_FIELD_NAME and are collected as soft failures — the feature
355
+ * ships dark rather than reddening the nightly.
356
+ */
357
+ prismicModels: PrismicModelsVerdict | null;
358
+ /** When the sweep last ran for this site — written on EVERY outcome, including
359
+ * `unknown` and blank, so the age of the row is the age of the answer. */
360
+ prismicModelsCheckedAt: string | null;
361
+ /** What the sweep found, verbatim: the drift report for a `fail`, the reason
362
+ * nothing could be established for an `unknown`, the skip reason for a blank,
363
+ * and null for a `pass` (which clears yesterday's finding). */
364
+ prismicModelsDrift: string | null;
365
+ /**
366
+ * An expiry the operator sets to accept a KNOWN, EXPECTED `fail` — most often
367
+ * "I am modelling in Prismic on a branch that has not landed, so Prismic is
368
+ * legitimately ahead of `main`". While this timestamp is in the future the
369
+ * drift item is not raised.
370
+ *
371
+ * It expires on purpose, and nothing renews it automatically. A permanent ack
372
+ * would reproduce this column's own failure mode one step later: once the
373
+ * branch lands, the same acked cell would swallow real drift and "nobody is
374
+ * looking at this" would render as "this is fine". An expiry means the worst
375
+ * case is a silence that ends by itself.
376
+ *
377
+ * Narrow by construction — it mutes only `fail`, the finding the operator
378
+ * actually reviewed. `unknown` (the check could not run) and a verdict too old
379
+ * to be current are never muted by it; see `collectPrismicDriftAlerts`.
380
+ *
381
+ * OPERATOR PRECONDITION: `Prismic Ack Until` is a dateTime column. Until it
382
+ * exists this reads null and nothing is acked, which is the safe direction.
383
+ */
384
+ prismicAckUntil: string | null;
385
+ notifyRouting: NotifyRouting | null;
386
+ /** The RAW `Notify Routing` cell, verbatim. Same reason `statusRaw` exists: the
387
+ * dashboard editor round-trips this JSON, and re-serializing the PARSED object
388
+ * would drop any key the parser ignores and reformat what the operator typed —
389
+ * a silent rewrite of a cell they only opened to look at. */
390
+ notifyRoutingRaw: string | null;
391
+ /** Read-back of the code-owned next-due dates (date-only, written by the
392
+ * nightly `writeNextDueDates`). These exist so the writer can DIFF the
393
+ * freshly-computed dates against what the row already holds and skip the
394
+ * ~31 no-op writes a night the fleet was paying for (#539 Phase 3). Null =
395
+ * cell blank or the operator-added `Next … at` column absent. */
396
+ nextMaintenanceAt: string | null;
397
+ nextTestingAt: string | null;
398
+ };
399
+ /** The `Prismic Models` cell — see {@link WebsiteRow.prismicModels} for why it
400
+ * carries a third state that no other verdict column in this table has. */
401
+ type PrismicModelsVerdict = "pass" | "fail" | "unknown";
402
+ type Severity = "low" | "moderate" | "high" | "critical";
403
+ /** One known vulnerability behind the security counts, as persisted/rendered. */
404
+ type SecurityAdvisory = {
405
+ module: string;
406
+ severity: Severity;
407
+ title: string;
408
+ cves: string[];
409
+ url: string | null;
410
+ /** GitHub Dependabot dependency scope ("runtime" | "development"), when known. Lets the
411
+ * dashboard flag build-time-only ("development") vulns. Omitted for advisories from the
412
+ * lockfile `pnpm audit` fallback, which carries no per-package graph scope. */
413
+ scope?: "runtime" | "development";
414
+ /** GitHub Dependabot dependency-graph relationship, when known. "transitive" means no
415
+ * direct-dep bump can fix it — Renovate's vuln alerts have no fix vehicle until the weekly
416
+ * lockfile-maintenance window. Omitted when GitHub reports "unknown" or for the
417
+ * `pnpm audit` fallback. Drives {@link allActionableVulnsTransitive}. */
418
+ relationship?: "direct" | "transitive";
419
+ };
420
+
421
+ type FleetEventType = "pr_automerged" | "vuln_cleared" | "ci_recovered" | "site_launched" | "fleet_swept" | "cert_renewed" | "report_sent_with_override";
422
+ /** One recorded fleet activity event. `id` is deterministic (see the detectors)
423
+ * so re-runs INSERT OR IGNORE without duplicating. `siteId`/`siteName` are null
424
+ * for fleet-wide rollups; `data` is optional structured detail (e.g. the PR url). */
425
+ type FleetEvent = {
426
+ id: string;
427
+ ts: string;
428
+ type: FleetEventType;
429
+ siteId: string | null;
430
+ siteName: string | null;
431
+ summary: string;
432
+ data: unknown | null;
433
+ };
434
+
435
+ export type { AirtableBase as A, FleetEvent as F, WebsiteRow as W, FleetEventType as a };
@@ -1,11 +1,15 @@
1
1
  import {
2
2
  REPORT_LIST_COLUMNS,
3
+ findReportByMessageId,
3
4
  getReportById,
4
5
  getReportHtml,
5
6
  getSiteById,
6
7
  getSiteBySlug,
8
+ insertReportRow,
9
+ insertSiteRows,
7
10
  listAllReports,
8
11
  listReportsForSite,
12
+ listSendableReports,
9
13
  listSites,
10
14
  mirrorHealthFields,
11
15
  mirrorReportInsert,
@@ -15,20 +19,25 @@ import {
15
19
  mirrorSiteFields,
16
20
  mirrorSiteInsert,
17
21
  siteRowExists,
18
- storeRenderedHtml
19
- } from "./chunk-GEUC5VGM.js";
20
- import "./chunk-UIITN37J.js";
21
- import "./chunk-F3JWOPTG.js";
22
+ storeRenderedHtml,
23
+ updateSiteIdentity
24
+ } from "./chunk-BINFZQ2T.js";
25
+ import "./chunk-LF2TJN4X.js";
26
+ import "./chunk-ASLDCWBF.js";
22
27
  import "./chunk-VAD43MOR.js";
23
- import "./chunk-KN52PM63.js";
28
+ import "./chunk-ICSRWW5Q.js";
24
29
  export {
25
30
  REPORT_LIST_COLUMNS,
31
+ findReportByMessageId,
26
32
  getReportById,
27
33
  getReportHtml,
28
34
  getSiteById,
29
35
  getSiteBySlug,
36
+ insertReportRow,
37
+ insertSiteRows,
30
38
  listAllReports,
31
39
  listReportsForSite,
40
+ listSendableReports,
32
41
  listSites,
33
42
  mirrorHealthFields,
34
43
  mirrorReportInsert,
@@ -38,6 +47,7 @@ export {
38
47
  mirrorSiteFields,
39
48
  mirrorSiteInsert,
40
49
  siteRowExists,
41
- storeRenderedHtml
50
+ storeRenderedHtml,
51
+ updateSiteIdentity
42
52
  };
43
- //# sourceMappingURL=fleet-state-GJWGKTLD.js.map
53
+ //# sourceMappingURL=fleet-state-RJROYXKO.js.map
@@ -2,8 +2,8 @@ import {
2
2
  describeNotifyTarget
3
3
  } from "./chunk-PXRN2MER.js";
4
4
  import "./chunk-Z7FDJ35L.js";
5
- import "./chunk-5ML7FMBD.js";
6
5
  import "./chunk-NO74DXDP.js";
6
+ import "./chunk-5ML7FMBD.js";
7
7
  import "./chunk-I7NHLVVI.js";
8
8
  import {
9
9
  openBase,
@@ -11,12 +11,14 @@ import {
11
11
  } from "./chunk-HN6I2XWI.js";
12
12
  import "./chunk-BGTYPVLT.js";
13
13
  import {
14
- canonicalizeStatus,
15
- listWebsites,
16
- siteSlug,
17
14
  toAirtableStatus,
18
15
  updateSiteField
19
- } from "./chunk-KN52PM63.js";
16
+ } from "./chunk-TC4GANMX.js";
17
+ import {
18
+ canonicalizeStatus,
19
+ siteSlug
20
+ } from "./chunk-ICSRWW5Q.js";
21
+ import "./chunk-RQJFGK3A.js";
20
22
  import "./chunk-2OP4JKIQ.js";
21
23
  import "./chunk-6VAL7XJT.js";
22
24
 
@@ -38,14 +40,14 @@ function findSite(rows, site) {
38
40
  }
39
41
  async function formsNotifyTarget(deps) {
40
42
  const base = deps.base ?? openBase(readAirtableConfig());
41
- const rows = await listWebsites(base);
43
+ const rows = await deps.roster();
42
44
  const row = findSite(rows, deps.site);
43
45
  if (!row) {
44
46
  const needle = siteSlug(deps.site);
45
47
  const near = rows.map((r) => r.name).filter((n) => siteSlug(n).includes(needle) || needle.includes(siteSlug(n)));
46
48
  throw Object.assign(
47
49
  new Error(
48
- `No Websites row matches '${deps.site}'. The Websites NAME is not always the repo slug (Sonder, not gallerysonder).` + (near.length > 0 ? ` Did you mean: ${near.join(", ")}?` : "")
50
+ `No site matches '${deps.site}'. The stored NAME is not always the repo slug (Sonder, not gallerysonder).` + (near.length > 0 ? ` Did you mean: ${near.join(", ")}?` : "")
49
51
  ),
50
52
  { exitCode: 2 }
51
53
  );
@@ -73,10 +75,10 @@ async function formsNotifyTarget(deps) {
73
75
  }
74
76
  const cell = deps.set === "on" ? toAirtableStatus(VERIFY_STATUS) : restoreCell(restoreRaw);
75
77
  await updateSiteField(base, row.id, STATUS_COLUMN, cell);
76
- await deps.siteMirror?.site(row.id, { [STATUS_COLUMN]: cell });
77
- const after = findSite(await listWebsites(base), deps.site);
78
+ await deps.siteMirror.site(row.id, { [STATUS_COLUMN]: cell });
79
+ const after = findSite(await deps.roster(), deps.site);
78
80
  if (!after) {
79
- throw Object.assign(new Error(`${row.name} vanished from Websites during the flip.`), {
81
+ throw Object.assign(new Error(`${row.name} vanished from the fleet during the flip.`), {
80
82
  exitCode: 1
81
83
  });
82
84
  }
@@ -137,15 +139,17 @@ function formatNotifyTarget(r) {
137
139
  }
138
140
  async function runFormsNotifyTargetCommand(site, opts) {
139
141
  if (!site?.trim()) {
140
- return { output: "forms-notify-target requires <site> (slug or Airtable name)", code: 2 };
142
+ return { output: "forms-notify-target requires <site> (slug or site name)", code: 2 };
141
143
  }
142
144
  const set = opts.set?.trim().toLowerCase();
143
145
  if (set !== void 0 && set !== "on" && set !== "off") {
144
146
  return { output: `--set must be 'on' or 'off' (got '${opts.set}')`, code: 2 };
145
147
  }
146
148
  try {
147
- const { makeSiteMirror } = await import("./site-mirror-H2FYMN55.js");
149
+ const { makeSiteMirror } = await import("./site-mirror-TKTDWYP3.js");
150
+ const { readFleetRoster } = await import("./roster-EJ3ILR52.js");
148
151
  const result = await formsNotifyTarget({
152
+ roster: () => readFleetRoster(),
149
153
  siteMirror: await makeSiteMirror(),
150
154
  site: site.trim(),
151
155
  ...set ? { set } : {},
@@ -164,4 +168,4 @@ export {
164
168
  formatNotifyTarget,
165
169
  runFormsNotifyTargetCommand
166
170
  };
167
- //# sourceMappingURL=forms-notify-target-4NPLX2UG.js.map
171
+ //# sourceMappingURL=forms-notify-target-DK5R326N.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/recipes/forms-notify-target.ts","../src/cli/commands/forms-notify-target.ts"],"sourcesContent":["import { openBase, readAirtableConfig } from \"../reports/airtable/client.js\";\nimport type { AirtableBase } from \"../reports/airtable/client.js\";\nimport type { SiteMirror } from \"../db/site-mirror.js\";\nimport {\n siteSlug,\n updateSiteField,\n type Status,\n type WebsiteRow,\n} from \"../reports/airtable/websites.js\";\nimport { canonicalizeStatus, toAirtableStatus } from \"../reports/airtable/site-status.js\";\nimport { describeNotifyTarget, type NotifyTarget } from \"../forms/notify.js\";\n\n/** The Airtable column the pre-launch guard actually lives in. */\nexport const STATUS_COLUMN = \"Status\";\n\n/** The two ends of the verify flip. Deliberately the ONLY transition this\n * performs: a site in any other status is already guarded (or is deliberately\n * something else, like \"hosted-only\"), and silently rewriting that would be the\n * same class of unseen change as the incident. */\nexport const LIVE_STATUS: Status = \"maintained\";\nexport const VERIFY_STATUS: Status = \"launching\";\n\nexport type FormsNotifyTargetDeps = {\n base?: AirtableBase;\n /** Every site in the fleet, read from TURSO (#646 step 4). Required, not\n * defaulted: the unit suite drives this with a fake fleet, and a default would\n * open a real libSQL handle from inside it. The CLI wires `readFleetRoster`.\n *\n * It is called TWICE on a flip — once to find the site, once to read the cell\n * back — and both reads matter: Turso is what `/api/forms/:slug` consults to\n * decide who a submission emails (`getSiteBySlug`, #643), so confirming the\n * Airtable cell would confirm the wrong store, and an Airtable roster cannot\n * see a `site_<ULID>` site at all. */\n roster: () => Promise<WebsiteRow[]>;\n /** Site slug or the stored site NAME (both accepted). */\n site: string;\n /** `on` routes notifications to the operator; `off` restores. Omit to read. */\n set?: \"on\" | \"off\";\n /** Status to restore with `--set off`. Required, never inferred. */\n restore?: string;\n /** The Status write itself (#646 step 4): Turso is the store the form ingest\n * reads, so this is the write the read-back below confirms — the Airtable\n * `updateSiteField` beside it is the shadow, and it skips a `site_` id.\n * Required, and injected at the CLI root for the same reason `roster` is. */\n siteMirror: SiteMirror;\n};\n\nexport type FormsNotifyTargetResult = {\n site: string;\n status: Status | null;\n target: NotifyTarget;\n /** Present only when a flip was attempted. `confirmed` is the whole point:\n * it comes from RE-READING the row, not from the write call returning. */\n flip?: { from: Status | null; to: Status; confirmed: boolean };\n};\n\n/**\n * The exact Airtable cell to write for an operator-supplied `--restore` value:\n * the operator's own string, verbatim.\n *\n * This is the ONE non-revertible surface in the #539 Phase 4 stage-1 rename —\n * every other change is code, and `git revert` undoes code. It cannot undo a\n * rewritten Airtable cell. So the rule here is stricter than everywhere else:\n * substitute only when the substitution is provably lossless, i.e. when\n * canonicalizing and mapping back ROUND-TRIPS to the operator's own string.\n *\n * That condition is, today, never false in a way that changes the answer — which\n * is the point. `toAirtableStatus(canonicalizeStatus(raw))` either equals `raw`\n * (so writing it is writing `raw`) or it does not (so we must write `raw`). The\n * function therefore reduces to \"write raw\", and it is written this way so the\n * reduction is visible rather than assumed. The case that made it matter:\n * `--restore legacy` canonicalizes to `archived`, which maps back to\n * \"deprecated\" — a different, real, operator-visible Airtable option that nobody\n * asked for. `hosting` → `hosted-only` → \"hosting\" round-trips and is safe.\n *\n * Airtable, not this module, is the authority on which option strings the\n * \"Status\" single-select accepts. Writing verbatim delegates to it: a typo is\n * rejected loudly at the API, exactly as it was before the rename.\n */\nexport function restoreCell(raw: string): string {\n const canonical = canonicalizeStatus(raw);\n if (canonical === null) return raw;\n const roundTripped = toAirtableStatus(canonical);\n return roundTripped === raw ? roundTripped : raw;\n}\n\nfunction findSite(rows: WebsiteRow[], site: string): WebsiteRow | undefined {\n const wanted = site.trim().toLowerCase();\n return rows.find(\n (r) => siteSlug(r.name) === siteSlug(site) || r.name.trim().toLowerCase() === wanted,\n );\n}\n\n/**\n * Answer \"who would a form submission on this site email?\" — and optionally\n * flip the pre-launch guard, confirming the flip by reading it back.\n *\n * The guard is a single Airtable `Status` cell. Nothing between \"I intended to\n * flip it\" and \"the client received a test lead\" reported the current state, so\n * on 2026-08-03 a flip that never landed sent a real client a test submission.\n * The fix is not a better intention, it is feedback: this reads the row back\n * after every write and refuses to call the flip confirmed on anything less.\n */\nexport async function formsNotifyTarget(\n deps: FormsNotifyTargetDeps,\n): Promise<FormsNotifyTargetResult> {\n const base = deps.base ?? openBase(readAirtableConfig());\n const rows = await deps.roster();\n const row = findSite(rows, deps.site);\n if (!row) {\n // The Websites NAME is not the repo slug (\"Sonder\", not \"gallerysonder\"),\n // and that mismatch has cost time before — so name the near misses rather\n // than making the operator go read Airtable to find the spelling.\n const needle = siteSlug(deps.site);\n const near = rows\n .map((r) => r.name)\n .filter((n) => siteSlug(n).includes(needle) || needle.includes(siteSlug(n)));\n throw Object.assign(\n new Error(\n `No site matches '${deps.site}'. The stored NAME is not always the repo ` +\n `slug (Sonder, not gallerysonder).` +\n (near.length > 0 ? ` Did you mean: ${near.join(\", \")}?` : \"\"),\n ),\n { exitCode: 2 },\n );\n }\n\n if (!deps.set) {\n return { site: row.name, status: row.status, target: describeNotifyTarget(row) };\n }\n\n // `--restore` is operator free text. It is canonicalized for what this command\n // REPORTS (`flip.to`, and the predicates downstream), but NEVER for what it\n // WRITES — see `restoreCell` below.\n const restoreRaw = deps.restore?.trim();\n const to = deps.set === \"on\" ? VERIFY_STATUS : (canonicalizeStatus(restoreRaw) ?? undefined);\n if (deps.set === \"off\" && !to) {\n throw Object.assign(\n new Error(\n `--set off needs --restore <status>: the status to return to is never inferred. ` +\n `Guessing \"${LIVE_STATUS}\" for a site that was \"hosted-only\" or \"archived\" would start ` +\n `sending real client notifications — the inverse of the failure this command exists ` +\n `to prevent.`,\n ),\n { exitCode: 2 },\n );\n }\n // Only ever flip a LIVE site into verify mode. A site already outside\n // \"maintained\" is guarded already, and rewriting its status would destroy a\n // real value nobody asked us to touch.\n if (deps.set === \"on\" && row.status !== LIVE_STATUS) {\n throw Object.assign(\n new Error(\n `${row.name} is \"${row.status ?? \"blank\"}\", not \"${LIVE_STATUS}\" — notifications ` +\n `already go to the operator only, so there is nothing to flip. Leaving the status ` +\n `untouched.`,\n ),\n { exitCode: 2 },\n );\n }\n\n // `--set on` writes a status this MODULE owns (VERIFY_STATUS), so mapping it to\n // the current Airtable vocabulary is correct. `--set off` writes the operator's\n // own string — see restoreCell.\n const cell = deps.set === \"on\" ? toAirtableStatus(VERIFY_STATUS) : restoreCell(restoreRaw!);\n // The Airtable shadow first, still allowed to fail loudly while it is kept\n // trustworthy; it skips a site id Airtable cannot hold (#646 step 3).\n await updateSiteField(base, row.id, STATUS_COLUMN, cell);\n // The write that DECIDES: `/api/forms/:slug` reads this cell from Turso, and\n // the console reads it there too.\n await deps.siteMirror.site(row.id, { [STATUS_COLUMN]: cell });\n\n // Read it back — from Turso, the store just confirmed to be the one that\n // matters. The write returning is NOT evidence the field changed.\n const after = findSite(await deps.roster(), deps.site);\n if (!after) {\n throw Object.assign(new Error(`${row.name} vanished from the fleet during the flip.`), {\n exitCode: 1,\n });\n }\n return {\n site: after.name,\n status: after.status,\n target: describeNotifyTarget(after),\n // `confirmed` compares the RAW cell against the exact string written, not\n // canonical-to-canonical. Canonical equality is too weak to be a read-back\n // guard here: `legacy` and `deprecated` are the same canonical status, so a\n // cell holding either would confirm a flip to the other. Comparing raw is the\n // only comparison that can actually catch \"the cell is not what I sent\". The\n // canonical check rides along so a reader that stopped canonicalizing is\n // caught too.\n flip: {\n from: row.status,\n to: to!,\n confirmed: after.statusRaw === cell && after.status === to,\n },\n };\n}\n","import {\n formsNotifyTarget,\n LIVE_STATUS,\n VERIFY_STATUS,\n type FormsNotifyTargetResult,\n} from \"../../recipes/forms-notify-target.js\";\n\nexport type FormsNotifyTargetCommandOptions = {\n set?: string;\n restore?: string;\n cwd?: string;\n};\n\nconst AUDIENCE_LABEL = {\n client: \"THE CLIENT\",\n operator: \"OPERATOR ONLY\",\n nobody: \"NOBODY\",\n} as const;\n\n/** The line that decides whether it is safe to test-submit. Deliberately the\n * loudest thing on screen: the incident happened because the answer was\n * invisible, not because it was subtle. */\nexport function formatNotifyTarget(r: FormsNotifyTargetResult): string {\n const lines: string[] = [];\n if (r.flip) {\n const arrow = `${r.flip.from ?? \"blank\"} → ${r.flip.to}`;\n lines.push(\n r.flip.confirmed\n ? `${r.site} Status: ${arrow} ✓ confirmed by read-back`\n : `${r.site} Status: ${arrow} ✗ NOT CONFIRMED — the row still reads \"${r.status ?? \"blank\"}\". Nothing was verified; do not test-submit.`,\n );\n } else {\n lines.push(`${r.site} Status: ${r.status ?? \"blank\"}`);\n }\n\n lines.push(`A submission right now would notify: ${AUDIENCE_LABEL[r.target.audience]}`);\n if (r.target.to.length > 0) lines.push(` to: ${r.target.to.join(\", \")}`);\n if (r.target.cc.length > 0) lines.push(` cc: ${r.target.cc.join(\", \")}`);\n lines.push(` ${r.target.reason}`);\n\n if (r.target.audience === \"client\") {\n lines.push(\n \"\",\n `⚠️ A test submission WILL email the client, and email cannot be recalled.`,\n ` Route it to yourself first: reddoor forms-notify-target ${r.site} --set on`,\n );\n }\n if (r.flip?.confirmed && r.flip.to === VERIFY_STATUS) {\n lines.push(\n \"\",\n `Safe to test. When you are done, restore it:`,\n ` reddoor forms-notify-target ${r.site} --set off --restore ${r.flip.from ?? LIVE_STATUS}`,\n );\n }\n return lines.join(\"\\n\");\n}\n\n/**\n * `forms-notify-target <site>` — show who a form submission would email, and\n * optionally flip the pre-launch guard with a read-back confirmation.\n *\n * Read-only by default: answering the question must never be riskier than not\n * asking it.\n */\nexport async function runFormsNotifyTargetCommand(\n site: string | undefined,\n opts: FormsNotifyTargetCommandOptions,\n): Promise<{ output: string; code: number }> {\n if (!site?.trim()) {\n return { output: \"forms-notify-target requires <site> (slug or site name)\", code: 2 };\n }\n const set = opts.set?.trim().toLowerCase();\n if (set !== undefined && set !== \"on\" && set !== \"off\") {\n return { output: `--set must be 'on' or 'off' (got '${opts.set}')`, code: 2 };\n }\n try {\n // #539 Phase 5: the flip writes Status on the Websites row; mirror it so the\n // console (which reads Turso) shows the new routing immediately.\n const { makeSiteMirror } = await import(\"../../db/site-mirror.js\");\n // #646 step 4: the fleet roster — and the flip's read-back — come from Turso,\n // which is the store `/api/forms/:slug` reads to decide who a submission\n // emails, and the only one that can see a `site_<ULID>` site.\n const { readFleetRoster } = await import(\"../../fleet/roster.js\");\n const result = await formsNotifyTarget({\n roster: () => readFleetRoster(),\n siteMirror: await makeSiteMirror(),\n site: site.trim(),\n ...(set ? { set: set as \"on\" | \"off\" } : {}),\n ...(opts.restore ? { restore: opts.restore } : {}),\n });\n // An unconfirmed flip must not exit 0: a script (or a person skimming) that\n // reads exit status would otherwise take \"I flipped it\" on faith, which is\n // exactly the assumption that sent a client a test lead.\n return {\n output: formatNotifyTarget(result),\n code: result.flip && !result.flip.confirmed ? 1 : 0,\n };\n } catch (err) {\n const e = err as { message?: string; exitCode?: number };\n return { output: e.message ?? String(err), code: e.exitCode ?? 1 };\n }\n}\n"],"mappings":"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","names":[]}