@reddoorla/maintenance 0.87.0 → 0.88.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/airtable-QG5ICI3Y.js +9 -0
- package/dist/{announce-I2Z4JN3I.js → announce-GKD5YJNB.js} +9 -9
- package/dist/{blux-ZGDSHI3U.js → blux-DN4MI532.js} +5 -5
- package/dist/{bump-deps-CGVELRLK.js → bump-deps-KGH5UYSF.js} +4 -4
- package/dist/{chunk-SDDPUAWH.js → chunk-6I6L3CMX.js} +2 -2
- package/dist/{chunk-ZBDZTJUO.js → chunk-7FFUBF4I.js} +5 -2
- package/dist/chunk-7FFUBF4I.js.map +1 -0
- package/dist/{chunk-HSI6Q7MI.js → chunk-7TMWBXX7.js} +159 -29
- package/dist/chunk-7TMWBXX7.js.map +1 -0
- package/dist/{chunk-DEWJMMG3.js → chunk-A2UNJIKH.js} +15 -7
- package/dist/chunk-A2UNJIKH.js.map +1 -0
- package/dist/{chunk-NCMZMLY7.js → chunk-ANJNTAMM.js} +3 -69
- package/dist/chunk-ANJNTAMM.js.map +1 -0
- package/dist/{chunk-3JQ2FO3D.js → chunk-B23FFWU4.js} +2 -2
- package/dist/{chunk-DJZWYIPP.js → chunk-BGTYPVLT.js} +1 -1
- package/dist/chunk-BGTYPVLT.js.map +1 -0
- package/dist/chunk-BRYXFH77.js +70 -0
- package/dist/chunk-BRYXFH77.js.map +1 -0
- package/dist/{chunk-NDWYJLRF.js → chunk-DGZWFI2G.js} +3 -3
- package/dist/{chunk-HHMMUR4P.js → chunk-GQDDWYU2.js} +45 -8
- package/dist/chunk-GQDDWYU2.js.map +1 -0
- package/dist/{chunk-BBUSGEES.js → chunk-J3WEZGIN.js} +6 -6
- package/dist/{chunk-BNM5POSJ.js → chunk-JRHIFA5R.js} +2 -2
- package/dist/{chunk-TD2NNXLZ.js → chunk-K6SLF6GI.js} +5 -5
- package/dist/{chunk-MT2JINSS.js → chunk-KJGKZLCT.js} +3 -3
- package/dist/{chunk-NXNPDCF3.js → chunk-KMCZA7CH.js} +11 -1
- package/dist/chunk-KMCZA7CH.js.map +1 -0
- package/dist/{chunk-3SF7D4DY.js → chunk-MFHS7IQ2.js} +36 -1
- package/dist/{chunk-3SF7D4DY.js.map → chunk-MFHS7IQ2.js.map} +1 -1
- package/dist/{chunk-SNSTJLQW.js → chunk-NO74DXDP.js} +48 -2
- package/dist/chunk-NO74DXDP.js.map +1 -0
- package/dist/{chunk-C6B4RHXR.js → chunk-O3GT46R2.js} +8 -2
- package/dist/chunk-O3GT46R2.js.map +1 -0
- package/dist/{chunk-C6CLRKPV.js → chunk-PR343K7F.js} +2 -2
- package/dist/{chunk-CROKUHJB.js → chunk-Q47DU255.js} +4 -4
- package/dist/{chunk-EVBCK2KC.js → chunk-RARREDQE.js} +2 -1
- package/dist/{chunk-EVBCK2KC.js.map → chunk-RARREDQE.js.map} +1 -1
- package/dist/chunk-RUPPWAD6.js +7 -0
- package/dist/chunk-RUPPWAD6.js.map +1 -0
- package/dist/{chunk-VSBFM7DS.js → chunk-SJOXWJ5Y.js} +3 -3
- package/dist/{chunk-HEWSRXYV.js → chunk-ULHPALI5.js} +3 -3
- package/dist/{chunk-XUGSZP7Z.js → chunk-W45FZEGE.js} +2 -2
- package/dist/{chunk-JHGHLKFS.js → chunk-WS6NU475.js} +2 -2
- package/dist/{chunk-ZGBEIWSC.js → chunk-XP5WM2LV.js} +5 -5
- package/dist/{chunk-6TWWY7ZU.js → chunk-Z3JXLULD.js} +2 -2
- package/dist/cli/bin.js +27 -27
- package/dist/cli/bin.js.map +1 -1
- package/dist/cli/commands/audit.d.ts +4 -0
- package/dist/cli/commands/audit.js +16 -13
- package/dist/cli/commands/audit.js.map +1 -1
- package/dist/client-JYKPVCJX.js +11 -0
- package/dist/configs/playwright-a11y.js +1 -1
- package/dist/{convert-to-pnpm-QFJOEP5V.js → convert-to-pnpm-NWB5FCQ2.js} +4 -4
- package/dist/{db-UXNIZ2RG.js → db-V6UIS433.js} +121 -26
- package/dist/db-V6UIS433.js.map +1 -0
- package/dist/{digest-FW6QMZZJ.js → digest-2JEAEJK6.js} +53 -29
- package/dist/digest-2JEAEJK6.js.map +1 -0
- package/dist/digest-state-CRZRNGDI.js +25 -0
- package/dist/digest-state-CRZRNGDI.js.map +1 -0
- package/dist/digest-state-F37XUCS5.js +13 -0
- package/dist/{dump-P6EBSIOH.js → dump-EPL7AZFR.js} +38 -13
- package/dist/dump-EPL7AZFR.js.map +1 -0
- package/dist/{email-KJXASVH5.js → email-SL7464YI.js} +16 -6
- package/dist/{email-KJXASVH5.js.map → email-SL7464YI.js.map} +1 -1
- package/dist/{ensure-site-4DCEBAPM.js → ensure-site-FU6527OU.js} +2 -2
- package/dist/{fleet-state-7TJ2GYT2.js → fleet-state-R5LU7IC3.js} +4 -2
- package/dist/{forms-notify-target-2EAWCWBW.js → forms-notify-target-SGDGXXK5.js} +6 -6
- package/dist/{github-signals-E2WPYTBK.js → github-signals-GWGCKEE2.js} +7 -6
- package/dist/{github-signals-E2WPYTBK.js.map → github-signals-GWGCKEE2.js.map} +1 -1
- package/dist/{header-image-6IC53W27.js → header-image-7A7XLVEU.js} +2 -2
- package/dist/{health-endpoint-RFXL2F4A.js → health-endpoint-UVX6R5N5.js} +4 -4
- package/dist/{health-mirror-L5JBEJVA.js → health-mirror-GCDN7BJL.js} +11 -6
- package/dist/health-mirror-GCDN7BJL.js.map +1 -0
- package/dist/index.js +128 -88
- package/dist/index.js.map +1 -1
- package/dist/{init-XRAQZYID.js → init-FGTYNGUI.js} +9 -9
- package/dist/{launch-IX4Y5JJC.js → launch-5H7LPEGP.js} +12 -11
- package/dist/{launch-IX4Y5JJC.js.map → launch-5H7LPEGP.js.map} +1 -1
- package/dist/migrate-YITCXBLS.js +7 -0
- package/dist/{notify-C645PGD5.js → notify-4HP4GZ2H.js} +5 -5
- package/dist/{onboard-O4IAHJMO.js → onboard-BKCYBAVW.js} +4 -4
- package/dist/{orchestrate-YLWQ6KK2.js → orchestrate-JNKCWU5K.js} +9 -9
- package/dist/{parity-56KA2DGR.js → parity-NBYZUBFU.js} +4 -2
- package/dist/pdf-N5QLQ5ZQ.js +38 -0
- package/dist/pdf-N5QLQ5ZQ.js.map +1 -0
- package/dist/{pipeline-3AANZFCR.js → pipeline-WYTXSLHX.js} +3 -3
- package/dist/{preflight-TNORKGCX.js → preflight-IMTYDDD4.js} +10 -10
- package/dist/{prismic-ci-G2AK53VL.js → prismic-ci-MY2U6NN7.js} +4 -4
- package/dist/{prismic-models-O6Z3OK3A.js → prismic-models-NJN5JORF.js} +6 -6
- package/dist/prospect/types.d.ts +14 -0
- package/dist/{prospect-audit-KSXUNQ5J.js → prospect-audit-JMBRVXSG.js} +32 -13
- package/dist/prospect-audit-JMBRVXSG.js.map +1 -0
- package/dist/render-VX72AESY.js +10 -0
- package/dist/{render-from-row-BWSOIYDS.js → render-from-row-DOYJDO2L.js} +5 -5
- package/dist/{replay-C2LXMJZP.js → replay-4S6ENYCH.js} +3 -3
- package/dist/{report-R3E3Y7HR.js → report-TALY5P3L.js} +17 -17
- package/dist/{report-mirror-4MNORYQ4.js → report-mirror-AAK3MXHY.js} +12 -6
- package/dist/report-mirror-AAK3MXHY.js.map +1 -0
- package/dist/schema-75PJECAE.js +18 -0
- package/dist/schema-75PJECAE.js.map +1 -0
- package/dist/{self-updating-UCIWESAX.js → self-updating-NTCCWJYZ.js} +4 -4
- package/dist/{selftest-VGHWPN72.js → selftest-NZTR4SM2.js} +11 -11
- package/dist/{site-mirror-NIREX5ME.js → site-mirror-Q763PLGG.js} +17 -7
- package/dist/site-mirror-Q763PLGG.js.map +1 -0
- package/dist/{smoke-suite-U3UKD3NS.js → smoke-suite-4JFZZYVW.js} +4 -4
- package/dist/{spam-classifier-XLBFCO7G.js → spam-classifier-T5H4VTP6.js} +4 -2
- package/dist/{submissions-IQEJX6FK.js → submissions-TEHPBSZJ.js} +4 -4
- package/dist/{svelte-codemods-GOKXTBHW.js → svelte-codemods-QAPDZC6F.js} +4 -4
- package/dist/{sync-CTUVXMCK.js → sync-GBFV45WX.js} +4 -2
- package/dist/{sync-CTUVXMCK.js.map → sync-GBFV45WX.js.map} +1 -1
- package/dist/{sync-configs-SPTLFJCC.js → sync-configs-34JIA6KZ.js} +4 -4
- package/dist/{upgrade-W6ZR3FJH.js → upgrade-IR2OO3KP.js} +4 -4
- package/dist/{webhook-VOGOW3W6.js → webhook-XM6EV4XT.js} +2 -2
- package/dist/{write-audits-to-airtable-CMKHGJNQ.js → write-audits-to-airtable-OBHGR7DQ.js} +5 -2
- package/dist/write-audits-to-airtable-OBHGR7DQ.js.map +1 -0
- package/package.json +1 -1
- package/dist/airtable-ZBUPQJSC.js +0 -9
- package/dist/chunk-C6B4RHXR.js.map +0 -1
- package/dist/chunk-DEWJMMG3.js.map +0 -1
- package/dist/chunk-DJZWYIPP.js.map +0 -1
- package/dist/chunk-HHMMUR4P.js.map +0 -1
- package/dist/chunk-HSI6Q7MI.js.map +0 -1
- package/dist/chunk-NCMZMLY7.js.map +0 -1
- package/dist/chunk-NXNPDCF3.js.map +0 -1
- package/dist/chunk-SNSTJLQW.js.map +0 -1
- package/dist/chunk-ZBDZTJUO.js.map +0 -1
- package/dist/client-AUE3XUPO.js +0 -11
- package/dist/db-UXNIZ2RG.js.map +0 -1
- package/dist/digest-FW6QMZZJ.js.map +0 -1
- package/dist/dump-P6EBSIOH.js.map +0 -1
- package/dist/health-mirror-L5JBEJVA.js.map +0 -1
- package/dist/migrate-GQH237A6.js +0 -7
- package/dist/prospect-audit-KSXUNQ5J.js.map +0 -1
- package/dist/render-IFOGFB5T.js +0 -10
- package/dist/report-mirror-4MNORYQ4.js.map +0 -1
- package/dist/site-mirror-NIREX5ME.js.map +0 -1
- /package/dist/{airtable-ZBUPQJSC.js.map → airtable-QG5ICI3Y.js.map} +0 -0
- /package/dist/{announce-I2Z4JN3I.js.map → announce-GKD5YJNB.js.map} +0 -0
- /package/dist/{blux-ZGDSHI3U.js.map → blux-DN4MI532.js.map} +0 -0
- /package/dist/{bump-deps-CGVELRLK.js.map → bump-deps-KGH5UYSF.js.map} +0 -0
- /package/dist/{chunk-SDDPUAWH.js.map → chunk-6I6L3CMX.js.map} +0 -0
- /package/dist/{chunk-3JQ2FO3D.js.map → chunk-B23FFWU4.js.map} +0 -0
- /package/dist/{chunk-NDWYJLRF.js.map → chunk-DGZWFI2G.js.map} +0 -0
- /package/dist/{chunk-BBUSGEES.js.map → chunk-J3WEZGIN.js.map} +0 -0
- /package/dist/{chunk-BNM5POSJ.js.map → chunk-JRHIFA5R.js.map} +0 -0
- /package/dist/{chunk-TD2NNXLZ.js.map → chunk-K6SLF6GI.js.map} +0 -0
- /package/dist/{chunk-MT2JINSS.js.map → chunk-KJGKZLCT.js.map} +0 -0
- /package/dist/{chunk-C6CLRKPV.js.map → chunk-PR343K7F.js.map} +0 -0
- /package/dist/{chunk-CROKUHJB.js.map → chunk-Q47DU255.js.map} +0 -0
- /package/dist/{chunk-VSBFM7DS.js.map → chunk-SJOXWJ5Y.js.map} +0 -0
- /package/dist/{chunk-HEWSRXYV.js.map → chunk-ULHPALI5.js.map} +0 -0
- /package/dist/{chunk-XUGSZP7Z.js.map → chunk-W45FZEGE.js.map} +0 -0
- /package/dist/{chunk-JHGHLKFS.js.map → chunk-WS6NU475.js.map} +0 -0
- /package/dist/{chunk-ZGBEIWSC.js.map → chunk-XP5WM2LV.js.map} +0 -0
- /package/dist/{chunk-6TWWY7ZU.js.map → chunk-Z3JXLULD.js.map} +0 -0
- /package/dist/{client-AUE3XUPO.js.map → client-JYKPVCJX.js.map} +0 -0
- /package/dist/{convert-to-pnpm-QFJOEP5V.js.map → convert-to-pnpm-NWB5FCQ2.js.map} +0 -0
- /package/dist/{fleet-state-7TJ2GYT2.js.map → digest-state-F37XUCS5.js.map} +0 -0
- /package/dist/{ensure-site-4DCEBAPM.js.map → ensure-site-FU6527OU.js.map} +0 -0
- /package/dist/{migrate-GQH237A6.js.map → fleet-state-R5LU7IC3.js.map} +0 -0
- /package/dist/{forms-notify-target-2EAWCWBW.js.map → forms-notify-target-SGDGXXK5.js.map} +0 -0
- /package/dist/{header-image-6IC53W27.js.map → header-image-7A7XLVEU.js.map} +0 -0
- /package/dist/{health-endpoint-RFXL2F4A.js.map → health-endpoint-UVX6R5N5.js.map} +0 -0
- /package/dist/{init-XRAQZYID.js.map → init-FGTYNGUI.js.map} +0 -0
- /package/dist/{notify-C645PGD5.js.map → migrate-YITCXBLS.js.map} +0 -0
- /package/dist/{orchestrate-YLWQ6KK2.js.map → notify-4HP4GZ2H.js.map} +0 -0
- /package/dist/{onboard-O4IAHJMO.js.map → onboard-BKCYBAVW.js.map} +0 -0
- /package/dist/{parity-56KA2DGR.js.map → orchestrate-JNKCWU5K.js.map} +0 -0
- /package/dist/{pipeline-3AANZFCR.js.map → parity-NBYZUBFU.js.map} +0 -0
- /package/dist/{render-IFOGFB5T.js.map → pipeline-WYTXSLHX.js.map} +0 -0
- /package/dist/{preflight-TNORKGCX.js.map → preflight-IMTYDDD4.js.map} +0 -0
- /package/dist/{prismic-ci-G2AK53VL.js.map → prismic-ci-MY2U6NN7.js.map} +0 -0
- /package/dist/{prismic-models-O6Z3OK3A.js.map → prismic-models-NJN5JORF.js.map} +0 -0
- /package/dist/{render-from-row-BWSOIYDS.js.map → render-VX72AESY.js.map} +0 -0
- /package/dist/{spam-classifier-XLBFCO7G.js.map → render-from-row-DOYJDO2L.js.map} +0 -0
- /package/dist/{replay-C2LXMJZP.js.map → replay-4S6ENYCH.js.map} +0 -0
- /package/dist/{report-R3E3Y7HR.js.map → report-TALY5P3L.js.map} +0 -0
- /package/dist/{self-updating-UCIWESAX.js.map → self-updating-NTCCWJYZ.js.map} +0 -0
- /package/dist/{selftest-VGHWPN72.js.map → selftest-NZTR4SM2.js.map} +0 -0
- /package/dist/{smoke-suite-U3UKD3NS.js.map → smoke-suite-4JFZZYVW.js.map} +0 -0
- /package/dist/{write-audits-to-airtable-CMKHGJNQ.js.map → spam-classifier-T5H4VTP6.js.map} +0 -0
- /package/dist/{submissions-IQEJX6FK.js.map → submissions-TEHPBSZJ.js.map} +0 -0
- /package/dist/{svelte-codemods-GOKXTBHW.js.map → svelte-codemods-QAPDZC6F.js.map} +0 -0
- /package/dist/{sync-configs-SPTLFJCC.js.map → sync-configs-34JIA6KZ.js.map} +0 -0
- /package/dist/{upgrade-W6ZR3FJH.js.map → upgrade-IR2OO3KP.js.map} +0 -0
- /package/dist/{webhook-VOGOW3W6.js.map → webhook-XM6EV4XT.js.map} +0 -0
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
scoresFromRow
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-ULHPALI5.js";
|
|
4
4
|
import {
|
|
5
5
|
fetchGaUsers,
|
|
6
6
|
fetchSearch,
|
|
7
7
|
readGaConfig,
|
|
8
8
|
refreshHeaderImage
|
|
9
|
-
} from "./chunk-
|
|
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-
|
|
34
|
-
import "./chunk-
|
|
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-
|
|
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-
|
|
207
|
-
const { makeSiteMirror } = await import("./site-mirror-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
17
|
-
import "./chunk-
|
|
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-
|
|
60
|
+
//# sourceMappingURL=bump-deps-KGH5UYSF.js.map
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
import {
|
|
6
6
|
isProbablyEmail,
|
|
7
7
|
parseAddresses
|
|
8
|
-
} from "./chunk-
|
|
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-
|
|
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").
|
|
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-
|
|
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-
|
|
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
|
-
|
|
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:
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
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
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
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 =
|
|
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
|
|
943
|
-
|
|
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
|
-
|
|
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
|
-
|
|
969
|
-
|
|
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
|
-
|
|
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
|
|
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-
|
|
1368
|
+
//# sourceMappingURL=chunk-7TMWBXX7.js.map
|