@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
@@ -0,0 +1,9 @@
1
+ import {
2
+ fromAirtableBase
3
+ } from "./chunk-PR343K7F.js";
4
+ import "./chunk-7NYN2P6I.js";
5
+ import "./chunk-RARREDQE.js";
6
+ export {
7
+ fromAirtableBase
8
+ };
9
+ //# sourceMappingURL=airtable-QG5ICI3Y.js.map
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  scoresFromRow
3
- } from "./chunk-HEWSRXYV.js";
3
+ } from "./chunk-ULHPALI5.js";
4
4
  import {
5
5
  fetchGaUsers,
6
6
  fetchSearch,
7
7
  readGaConfig,
8
8
  refreshHeaderImage
9
- } from "./chunk-BBUSGEES.js";
9
+ } from "./chunk-J3WEZGIN.js";
10
10
  import {
11
11
  queueDraft
12
12
  } from "./chunk-YFAXOD7Z.js";
@@ -26,19 +26,19 @@ import {
26
26
  import {
27
27
  defaultReportSubject
28
28
  } from "./chunk-GECESMVS.js";
29
+ import "./chunk-5UINJNAJ.js";
29
30
  import {
30
31
  announcementSiteExtras,
31
32
  renderReportHtml,
32
33
  resolveCopy
33
- } from "./chunk-MT2JINSS.js";
34
- import "./chunk-DJZWYIPP.js";
35
- import "./chunk-5UINJNAJ.js";
34
+ } from "./chunk-KJGKZLCT.js";
35
+ import "./chunk-BGTYPVLT.js";
36
36
  import {
37
37
  listWebsites,
38
38
  siteSlug,
39
39
  updateAnalyticsHealth
40
40
  } from "./chunk-7NYN2P6I.js";
41
- import "./chunk-EVBCK2KC.js";
41
+ import "./chunk-RARREDQE.js";
42
42
  import "./chunk-6VAL7XJT.js";
43
43
 
44
44
  // src/recipes/announce.ts
@@ -203,8 +203,8 @@ function formatAnnounceResult(result) {
203
203
  return result.results.map(formatSiteResult).join("\n");
204
204
  }
205
205
  async function runAnnounceCommand(site, _opts) {
206
- const { makeReportMirror } = await import("./report-mirror-4MNORYQ4.js");
207
- const { makeSiteMirror } = await import("./site-mirror-NIREX5ME.js");
206
+ const { makeReportMirror } = await import("./report-mirror-AAK3MXHY.js");
207
+ const { makeSiteMirror } = await import("./site-mirror-Q763PLGG.js");
208
208
  const reportMirror = await makeReportMirror();
209
209
  const siteMirror = await makeSiteMirror();
210
210
  const result = await announce({ ...site ? { site } : {}, reportMirror, siteMirror });
@@ -215,4 +215,4 @@ export {
215
215
  formatAnnounceResult,
216
216
  runAnnounceCommand
217
217
  };
218
- //# sourceMappingURL=announce-I2Z4JN3I.js.map
218
+ //# sourceMappingURL=announce-GKD5YJNB.js.map
@@ -1,13 +1,13 @@
1
- import {
2
- assetRef,
3
- richText
4
- } from "./chunk-UWJZXL2D.js";
5
1
  import {
6
2
  FROZEN_PAGE_TYPE,
7
3
  extractMapConfig,
8
4
  frozenPageCustomType,
9
5
  makeIsMapMount
10
6
  } from "./chunk-DRDAEELJ.js";
7
+ import {
8
+ assetRef,
9
+ richText
10
+ } from "./chunk-UWJZXL2D.js";
11
11
  import {
12
12
  CDN_HOSTS,
13
13
  collectAssetUrls
@@ -4767,4 +4767,4 @@ ${lines.join("\n")}`,
4767
4767
  export {
4768
4768
  runBluxCommand
4769
4769
  };
4770
- //# sourceMappingURL=blux-ZGDSHI3U.js.map
4770
+ //# sourceMappingURL=blux-DN4MI532.js.map
@@ -8,13 +8,13 @@ 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
  bumpDeps
14
14
  } from "./chunk-2NJQLSEU.js";
15
15
  import "./chunk-3G25KIWW.js";
16
- import "./chunk-6TWWY7ZU.js";
17
- import "./chunk-EVBCK2KC.js";
16
+ import "./chunk-Z3JXLULD.js";
17
+ import "./chunk-RARREDQE.js";
18
18
  import "./chunk-XTK5VIQB.js";
19
19
  import "./chunk-LBYOLBW7.js";
20
20
  import "./chunk-XXTZBPUY.js";
@@ -57,4 +57,4 @@ async function runBumpDepsCommand(site, opts) {
57
57
  export {
58
58
  runBumpDepsCommand
59
59
  };
60
- //# sourceMappingURL=bump-deps-CGVELRLK.js.map
60
+ //# sourceMappingURL=bump-deps-KGH5UYSF.js.map
@@ -5,7 +5,7 @@ import {
5
5
  import {
6
6
  isProbablyEmail,
7
7
  parseAddresses
8
- } from "./chunk-NDWYJLRF.js";
8
+ } from "./chunk-DGZWFI2G.js";
9
9
  import {
10
10
  listAllReports
11
11
  } from "./chunk-F3JWOPTG.js";
@@ -341,4 +341,4 @@ export {
341
341
  preflight,
342
342
  approveBlockers
343
343
  };
344
- //# sourceMappingURL=chunk-SDDPUAWH.js.map
344
+ //# sourceMappingURL=chunk-6I6L3CMX.js.map
@@ -1,3 +1,6 @@
1
+ import {
2
+ REPORT_LIST_COLUMNS
3
+ } from "./chunk-GQDDWYU2.js";
1
4
  import {
2
5
  mapReportRecord,
3
6
  mapWebsiteRecord
@@ -82,7 +85,7 @@ async function checkFleetParity(db, io) {
82
85
  }
83
86
  const reports = await io.listReportRecords();
84
87
  const reportRows = byId(
85
- await db.selectFrom("reports").selectAll().execute(),
88
+ await db.selectFrom("reports").select(REPORT_LIST_COLUMNS).execute(),
86
89
  "id"
87
90
  );
88
91
  for (const rec of reports) {
@@ -126,4 +129,4 @@ export {
126
129
  checkFleetParity,
127
130
  formatParityResult
128
131
  };
129
- //# sourceMappingURL=chunk-ZBDZTJUO.js.map
132
+ //# sourceMappingURL=chunk-7FFUBF4I.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/db/parity.ts"],"sourcesContent":["import type { Db } from \"./client.js\";\nimport { mapWebsiteRecord, mapReportRecord, type RawRecord } from \"./import-airtable.js\";\nimport { REPORT_LIST_COLUMNS } from \"./fleet-state.js\";\n\n/**\n * Phase 1.4 of #539: the instrument the cutover depends on. Reads BOTH stores\n * and diffs field-by-field, using the importer's own mapping functions — so\n * \"what parity expects\" is definitionally \"what the importer writes\", and the\n * two cannot drift apart.\n *\n * Per the repo's standing rule, this harness must be shown to PASS GREEN on the\n * pre-cutover state (immediately after an import, when the stores genuinely\n * agree) before any mismatch it reports is treated as a finding. A harness that\n * has only ever failed is not evidence.\n *\n * Deliberately NOT compared:\n * - `site_schedule.computed_at` — an import stamp, different by construction.\n * - `sites.header_image*` — Airtable stopped being the source (design D5).\n * - `reports.rendered_html` — comparing it would re-download every attachment\n * on every run against URLs that expire; presence is checked at import time\n * and the body never changes after a send.\n */\n\nexport type ParityMismatch = {\n table: \"sites\" | \"site_health\" | \"site_schedule\" | \"reports\";\n id: string;\n column: string;\n airtable: string;\n turso: string;\n};\n\nexport type ParityResult = {\n compared: Record<\"sites\" | \"site_health\" | \"site_schedule\" | \"reports\", number>;\n mismatches: ParityMismatch[];\n};\n\nconst SKIP_COLUMNS: ReadonlySet<string> = new Set([\n \"computed_at\",\n \"header_image\",\n \"header_image_filename\",\n \"header_image_type\",\n \"header_image_generated_at\",\n \"rendered_html\",\n]);\n\nconst show = (v: unknown): string => {\n if (v === null || v === undefined) return \"∅\";\n const str = typeof v === \"string\" ? v : JSON.stringify(v);\n return str.length > 80 ? `${str.slice(0, 77)}…` : str;\n};\n\nfunction diffRows(\n table: ParityMismatch[\"table\"],\n id: string,\n expected: Record<string, unknown>,\n actual: Record<string, unknown> | undefined,\n out: ParityMismatch[],\n): void {\n if (!actual) {\n out.push({ table, id, column: \"(row)\", airtable: \"present\", turso: \"ABSENT\" });\n return;\n }\n for (const [col, want] of Object.entries(expected)) {\n if (SKIP_COLUMNS.has(col)) continue;\n const got = actual[col] ?? null;\n const wantNorm = want ?? null;\n if (String(wantNorm ?? \"\") !== String(got ?? \"\") && !(wantNorm === null && got === null)) {\n out.push({ table, id, column: col, airtable: show(wantNorm), turso: show(got) });\n }\n }\n}\n\nexport type ParityIo = {\n listWebsiteRecords: () => Promise<RawRecord[]>;\n listReportRecords: () => Promise<RawRecord[]>;\n now: () => Date;\n};\n\nexport async function checkFleetParity(db: Db, io: ParityIo): Promise<ParityResult> {\n const computedAt = io.now().toISOString();\n const mismatches: ParityMismatch[] = [];\n\n const websites = await io.listWebsiteRecords();\n const mapped = websites.map((r) => mapWebsiteRecord(r, computedAt));\n\n const [sites, health, schedule] = await Promise.all([\n db.selectFrom(\"sites\").selectAll().execute(),\n db.selectFrom(\"site_health\").selectAll().execute(),\n db.selectFrom(\"site_schedule\").selectAll().execute(),\n ]);\n const byId = <T extends { [k: string]: unknown }>(rows: T[], key: string): Map<string, T> =>\n new Map(rows.map((r) => [String(r[key]), r]));\n const sitesById = byId(sites as Array<Record<string, unknown>>, \"id\");\n const healthById = byId(health as Array<Record<string, unknown>>, \"site_id\");\n const scheduleById = byId(schedule as Array<Record<string, unknown>>, \"site_id\");\n\n for (const m of mapped) {\n diffRows(\n \"sites\",\n m.site.id,\n m.site as unknown as Record<string, unknown>,\n sitesById.get(m.site.id),\n mismatches,\n );\n diffRows(\n \"site_health\",\n m.health.site_id,\n m.health as unknown as Record<string, unknown>,\n healthById.get(m.health.site_id),\n mismatches,\n );\n diffRows(\n \"site_schedule\",\n m.schedule.site_id,\n m.schedule as unknown as Record<string, unknown>,\n scheduleById.get(m.schedule.site_id),\n mismatches,\n );\n }\n // A Turso site Airtable no longer has is as much a divergence as a missing one.\n const airtableIds = new Set(mapped.map((m) => m.site.id));\n for (const row of sitesById.keys()) {\n if (!airtableIds.has(row)) {\n mismatches.push({\n table: \"sites\",\n id: row,\n column: \"(row)\",\n airtable: \"ABSENT\",\n turso: \"present\",\n });\n }\n }\n\n const reports = await io.listReportRecords();\n // Every reports column EXCEPT rendered_html, which `SKIP_COLUMNS` discards\n // anyway — a selectAll pulled all 16 stored bodies (1.17 MB live) across the\n // wire on every hourly run, 24×/day, purely to throw them away. Same list the\n // read layer uses, so the lockstep test covers this too.\n const reportRows = byId(\n (await db.selectFrom(\"reports\").select(REPORT_LIST_COLUMNS).execute()) as Array<\n Record<string, unknown>\n >,\n \"id\",\n );\n for (const rec of reports) {\n const expected = mapReportRecord(rec, null) as unknown as Record<string, unknown>;\n diffRows(\"reports\", rec.id, expected, reportRows.get(rec.id), mismatches);\n }\n const reportIds = new Set(reports.map((r) => r.id));\n for (const row of reportRows.keys()) {\n if (!reportIds.has(row)) {\n mismatches.push({\n table: \"reports\",\n id: row,\n column: \"(row)\",\n airtable: \"ABSENT\",\n turso: \"present\",\n });\n }\n }\n\n return {\n compared: {\n sites: mapped.length,\n site_health: mapped.length,\n site_schedule: mapped.length,\n reports: reports.length,\n },\n mismatches,\n };\n}\n\n/** Render for CLI/CI. Emits the machine-parseable `FLEET_PARITY` line on every\n * run, count=0 included — an absent line must mean \"the harness never ran\",\n * never \"it ran clean\" (same contract as FLEET_SMOKE_UNMEASURED, same reason). */\nexport function formatParityResult(r: ParityResult): string {\n const lines: string[] = [];\n for (const m of r.mismatches) {\n lines.push(`✗ ${m.table} ${m.id} ${m.column}: airtable=${m.airtable} turso=${m.turso}`);\n }\n lines.push(\n `FLEET_PARITY sites=${r.compared.sites} health=${r.compared.site_health} ` +\n `schedule=${r.compared.site_schedule} reports=${r.compared.reports} ` +\n `mismatches=${r.mismatches.length}`,\n );\n return lines.join(\"\\n\");\n}\n"],"mappings":"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","names":[]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  isPrivateOrLoopbackHost
3
- } from "./chunk-EVBCK2KC.js";
3
+ } from "./chunk-RARREDQE.js";
4
4
 
5
5
  // src/prospect/crawl.ts
6
6
  import { parse as parse2, NodeType as NodeType2 } from "node-html-parser";
@@ -264,6 +264,17 @@ function decodeXmlText(s) {
264
264
  function parseSitemapLocs(xml) {
265
265
  return [...xml.matchAll(/<(?:[\w-]+:)?loc\b[^>]*>([\s\S]*?)<\/(?:[\w-]+:)?loc>/gi)].map((m) => decodeXmlText(m[1] ?? "").trim()).filter(Boolean);
266
266
  }
267
+ function isSafeNestedSitemap(child, origin) {
268
+ let url;
269
+ try {
270
+ url = new URL(child, origin);
271
+ } catch {
272
+ return false;
273
+ }
274
+ if (url.protocol !== "https:" && url.protocol !== "http:") return false;
275
+ if (url.origin !== origin) return false;
276
+ return !isPrivateOrLoopbackHost(url.hostname);
277
+ }
267
278
  function isSitemapIndex(xml) {
268
279
  return /<(?:[\w-]+:)?sitemapindex[\s>]/i.test(xml);
269
280
  }
@@ -347,7 +358,8 @@ async function fetchSidecars(origin, deps) {
347
358
  if (sitemap.res && /<(urlset|sitemapindex)[\s>]/i.test(sitemap.res.body)) {
348
359
  sitemapPresent = true;
349
360
  if (isSitemapIndex(sitemap.res.body)) {
350
- for (const child of parseSitemapLocs(sitemap.res.body).slice(0, 3)) {
361
+ const children = parseSitemapLocs(sitemap.res.body).filter((child) => isSafeNestedSitemap(child, origin)).slice(0, 3);
362
+ for (const child of children) {
351
363
  const nested = await optional(deps, child);
352
364
  if (nested.res) sitemapUrls.push(...parseSitemapLocs(nested.res.body));
353
365
  }
@@ -369,6 +381,14 @@ async function crawlSite(rawUrl, deps) {
369
381
  start.hash = "";
370
382
  start.username = "";
371
383
  start.password = "";
384
+ if (isPrivateOrLoopbackHost(start.hostname)) {
385
+ throw Object.assign(
386
+ new Error(
387
+ `${start.toString()} is a private address (${start.hostname}) \u2014 refusing to crawl it.`
388
+ ),
389
+ { exitCode: 1 }
390
+ );
391
+ }
372
392
  let home;
373
393
  try {
374
394
  home = await deps.fetchUrl(start.toString());
@@ -787,10 +807,16 @@ Return:
787
807
  the site answers it (yes/partial/no), whether there is a passage an AI could quote verbatim, the page
788
808
  it lives on, and the evidence quote. evidence must be an EXACT substring of that page's quoted text \u2014
789
809
  copied verbatim, never paraphrased or invented \u2014 or null when no exact quote supports the answer.
790
- - categoryQueries: 3-5 searches a buyer types BEFORE they have heard of this company, chosen so that
791
- this company deserves to appear in the results. Each one is sent verbatim to a live answer engine on
792
- its own, with no other context, so it must stand alone: name the service and the place or the
793
- qualifier a buyer would use ("packaging design agency Los Angeles", "how much does a rebrand cost").
810
+ - categoryQueries: 5 searches a buyer types BEFORE they have heard of this company, chosen so that this
811
+ company could PLAUSIBLY RANK for them today \u2014 not ones it arguably deserves. A broad head term
812
+ ("branding agency Los Angeles") returns directories and listicles, which is where small firms are
813
+ aggregated rather than surfaced, so a query like that measures nothing about this company. Give a
814
+ spread: at most ONE head term, and at least THREE that are long-tail \u2014 a specific service, a
815
+ narrower niche or industry, a smaller locality, or a question phrased the way a buyer types it.
816
+ Prefer the specific over the impressive. Each one is sent verbatim to a live answer engine on its
817
+ own, with no other context, so it must stand alone: name the service and the place or the qualifier
818
+ a buyer would use ("trade show booth design for medical device companies", "how much does a rebrand
819
+ cost for a B2B company", "packaging design studio San Antonio").
794
820
  Never refer to the company \u2014 not by name, and not as "this agency", "they", "them" or "you". A query
795
821
  that names the company measures nothing (the engine just echoes the name back); a query that points
796
822
  at it with a pronoun has no antecedent and the engine will answer that it does not know who is meant.
@@ -902,16 +928,19 @@ function verifyEvidence(result, crawl) {
902
928
  if (view) textByUrl.set(p.url, view.text);
903
929
  }
904
930
  const buyerQuestions = result.buyerQuestions.map((q) => {
905
- if (q.page === null) {
906
- return q.evidence === null ? q : { ...q, evidence: null };
907
- }
908
- if (!crawledUrls.has(q.page)) {
909
- return { ...q, page: null, evidence: null };
910
- }
911
- if (q.evidence === null) return q;
912
- const pageText = textByUrl.get(q.page) ?? "";
913
- const verified = normalizeWhitespace(pageText).includes(normalizeWhitespace(q.evidence));
914
- return verified ? q : { ...q, evidence: null };
931
+ const verified = (() => {
932
+ if (q.page === null) {
933
+ return q.evidence === null ? q : { ...q, evidence: null };
934
+ }
935
+ if (!crawledUrls.has(q.page)) {
936
+ return { ...q, page: null, evidence: null };
937
+ }
938
+ if (q.evidence === null) return q;
939
+ const pageText = textByUrl.get(q.page) ?? "";
940
+ const quoted = normalizeWhitespace(pageText).includes(normalizeWhitespace(q.evidence));
941
+ return quoted ? q : { ...q, evidence: null };
942
+ })();
943
+ return verified.evidence === null && verified.answered !== "no" ? { ...verified, answered: "no" } : verified;
915
944
  });
916
945
  return { ...result, buyerQuestions };
917
946
  }
@@ -922,7 +951,7 @@ async function analyzeSite(url, crawl, checks, deps = defaultAnalyzeDeps()) {
922
951
  }
923
952
 
924
953
  // src/prospect/probes.ts
925
- var MAX_QUERIES = 8;
954
+ var MAX_QUERIES = 9;
926
955
  var SNIPPET_CHARS = 300;
927
956
  var PROBE_MODEL = "claude-sonnet-5";
928
957
  function domainOf(raw) {
@@ -937,11 +966,13 @@ function isSameSite(cited, prospect) {
937
966
  return cited === prospect || cited.endsWith(`.${prospect}`) || prospect.endsWith(`.${cited}`);
938
967
  }
939
968
  var MAX_NAME_CHARS = 60;
969
+ var NAME_ABBREVIATIONS = /\b(st|mt|ft|dr|mr|mrs|ms|jr|sr|co|inc|ltd|llc|corp|assoc|bros|dept|ave|blvd|rd)\.\s/gi;
970
+ var INITIALS = /\b[a-z]\.\s/gi;
940
971
  function resolveBusinessName(business, url) {
941
972
  const trimmed = business.trim();
942
- if (!trimmed || trimmed.length > MAX_NAME_CHARS || /\.\s/.test(trimmed)) {
943
- return domainOf(url);
944
- }
973
+ if (!trimmed || trimmed.length > MAX_NAME_CHARS) return domainOf(url);
974
+ const withoutAbbreviations = trimmed.replace(NAME_ABBREVIATIONS, "").replace(INITIALS, "");
975
+ if (/\.\s/.test(withoutAbbreviations)) return domainOf(url);
945
976
  return trimmed;
946
977
  }
947
978
  function buildQueries(input) {
@@ -949,7 +980,11 @@ function buildQueries(input) {
949
980
  const candidates = [
950
981
  { query: `who is ${name}`, kind: "branded" },
951
982
  { query: `${name} reviews`, kind: "branded" },
952
- ...input.categoryQueries.slice(0, 3).map((query) => ({ query, kind: "category" })),
983
+ // All five, not three. The schema asks the model for up to five and we were
984
+ // paying to generate them, then discarding two — which also pinned the
985
+ // denominator at 3, making visibilityScore a four-valued {0,33,67,100}
986
+ // rendered on a 0-100 card. Five halves the step to 20 points.
987
+ ...input.categoryQueries.slice(0, 5).map((query) => ({ query, kind: "category" })),
953
988
  ...input.competitors.slice(0, 2).map((c) => ({ query: `${name} vs ${c}`, kind: "competitor" }))
954
989
  ];
955
990
  const seen = /* @__PURE__ */ new Set();
@@ -964,12 +999,106 @@ function buildQueries(input) {
964
999
  function escapeRegExp(s) {
965
1000
  return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
966
1001
  }
1002
+ var LEGAL_SUFFIX = /\b(llc|inc|incorporated|ltd|limited|corp|corporation|plc|llp|lp|pllc|pc)\b/g;
1003
+ function normalizeForMatch(s) {
1004
+ return s.toLowerCase().replace(/&/g, " and ").replace(/[‐-―]/g, " ").replace(/[^a-z0-9]+/g, " ").replace(LEGAL_SUFFIX, " ").replace(/\s+/g, " ").trim();
1005
+ }
967
1006
  function mentionsBrand(answer, brand) {
968
- if (!brand) return false;
969
- return new RegExp(`(^|[^a-z0-9])${escapeRegExp(brand)}($|[^a-z0-9])`, "i").test(answer);
1007
+ const needle = normalizeForMatch(brand);
1008
+ if (!needle) return false;
1009
+ return new RegExp(`(^| )${escapeRegExp(needle)}( |$)`).test(normalizeForMatch(answer));
970
1010
  }
1011
+ var CATEGORY_WORDS = /* @__PURE__ */ new Set([
1012
+ // articles and joiners
1013
+ "the",
1014
+ "a",
1015
+ "an",
1016
+ "and",
1017
+ "of",
1018
+ "for",
1019
+ "at",
1020
+ "by",
1021
+ // company words
1022
+ "co",
1023
+ "company",
1024
+ "group",
1025
+ "collective",
1026
+ "partners",
1027
+ "associates",
1028
+ "works",
1029
+ "lab",
1030
+ "labs",
1031
+ "studio",
1032
+ "studios",
1033
+ "agency",
1034
+ "agencies",
1035
+ "firm",
1036
+ "practice",
1037
+ "shop",
1038
+ "house",
1039
+ "office",
1040
+ // sector words
1041
+ "design",
1042
+ "designs",
1043
+ "creative",
1044
+ "creatives",
1045
+ "brand",
1046
+ "branding",
1047
+ "marketing",
1048
+ "media",
1049
+ "digital",
1050
+ "solutions",
1051
+ "services",
1052
+ "consulting",
1053
+ "consultants",
1054
+ "advisors",
1055
+ "strategy",
1056
+ "dental",
1057
+ "dentistry",
1058
+ "orthodontics",
1059
+ "law",
1060
+ "legal",
1061
+ "clinic",
1062
+ "care",
1063
+ "health",
1064
+ "medical",
1065
+ "roofing",
1066
+ "construction",
1067
+ "builders",
1068
+ "contracting",
1069
+ "plumbing",
1070
+ "electric",
1071
+ "landscaping",
1072
+ "interiors",
1073
+ "architects",
1074
+ "photography",
1075
+ "films",
1076
+ "productions",
1077
+ "printing",
1078
+ "packaging",
1079
+ // adjectives that market rather than identify
1080
+ "modern",
1081
+ "premier",
1082
+ "elite",
1083
+ "first",
1084
+ "best",
1085
+ "local",
1086
+ "family",
1087
+ "advanced",
1088
+ "complete",
1089
+ "quality",
1090
+ "professional",
1091
+ "trusted",
1092
+ "expert",
1093
+ "affordable",
1094
+ "custom",
1095
+ "creative"
1096
+ ]);
971
1097
  function isDistinctiveName(brand) {
972
- return /\s/.test(brand) || brand.includes(".");
1098
+ if (brand.includes(".")) return true;
1099
+ const tokens = normalizeForMatch(brand).split(" ").filter(Boolean);
1100
+ if (tokens.length < 2) return false;
1101
+ return tokens.some((t) => !CATEGORY_WORDS.has(t));
973
1102
  }
974
1103
  function isRateLimited(err) {
975
1104
  const message = err instanceof Error ? err.message : String(err);
@@ -983,6 +1112,7 @@ async function runVisibilityProbes(input, engines, opts = {}) {
983
1112
  const queries = buildQueries(input);
984
1113
  const prospect = domainOf(input.url);
985
1114
  const brand = resolveBusinessName(input.business, input.url).toLowerCase();
1115
+ const nameIsDistinctive = isDistinctiveName(brand);
986
1116
  const answers = [];
987
1117
  const competitorCounts = /* @__PURE__ */ new Map();
988
1118
  for (const engine of engines) {
@@ -1015,6 +1145,8 @@ async function runVisibilityProbes(input, engines, opts = {}) {
1015
1145
  kind,
1016
1146
  domainCited,
1017
1147
  brandMentioned,
1148
+ // The same expression the score uses below — written once, read twice.
1149
+ countedAsVisible: domainCited || brandMentioned && nameIsDistinctive,
1018
1150
  citedDomains,
1019
1151
  snippet: reply.answer.slice(0, SNIPPET_CHARS),
1020
1152
  truncated: reply.answer.length > SNIPPET_CHARS,
@@ -1028,10 +1160,7 @@ async function runVisibilityProbes(input, engines, opts = {}) {
1028
1160
  throw new Error("no visibility engine returned an answer");
1029
1161
  }
1030
1162
  const categoryAnswers = answers.filter((a) => a.kind === "category");
1031
- const nameIsDistinctive = isDistinctiveName(brand);
1032
- const visibleCategory = categoryAnswers.filter(
1033
- (a) => a.domainCited || a.brandMentioned && nameIsDistinctive
1034
- ).length;
1163
+ const visibleCategory = categoryAnswers.filter((a) => a.countedAsVisible).length;
1035
1164
  const visibilityScore = categoryAnswers.length === 0 ? null : Math.round(visibleCategory / categoryAnswers.length * 100);
1036
1165
  const brandedRecognized = answers.some((a) => a.kind === "branded" && a.domainCited);
1037
1166
  return {
@@ -1231,8 +1360,9 @@ async function runProspectAudit(url, opts, deps = {}) {
1231
1360
  }
1232
1361
 
1233
1362
  export {
1363
+ resolveBusinessName,
1234
1364
  PROBES_SKIPPED,
1235
1365
  ANALYZE_SKIPPED,
1236
1366
  runProspectAudit
1237
1367
  };
1238
- //# sourceMappingURL=chunk-HSI6Q7MI.js.map
1368
+ //# sourceMappingURL=chunk-7TMWBXX7.js.map