@reddoorla/maintenance 0.97.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.
- package/dist/{announce-5ZD2SBGD.js → announce-2FH2KBQQ.js} +4 -4
- package/dist/{bump-deps-775VLDYB.js → bump-deps-54K4ECP3.js} +2 -2
- package/dist/{chunk-YXWBM26P.js → chunk-3YALLSBF.js} +2 -2
- package/dist/{chunk-LAJ3FF54.js → chunk-5UI4FERC.js} +16 -5
- package/dist/chunk-5UI4FERC.js.map +1 -0
- package/dist/{chunk-VMGHQUTV.js → chunk-B2BRFWJY.js} +2 -2
- package/dist/{chunk-IOTOOTII.js → chunk-CP6MVZ5X.js} +16 -1
- package/dist/{chunk-IOTOOTII.js.map → chunk-CP6MVZ5X.js.map} +1 -1
- package/dist/{chunk-L3S3QZXL.js → chunk-DXZRWW2F.js} +64 -9
- package/dist/chunk-DXZRWW2F.js.map +1 -0
- package/dist/chunk-DZZ5KRTB.js +23 -0
- package/dist/chunk-DZZ5KRTB.js.map +1 -0
- package/dist/{chunk-U2ZI6G7H.js → chunk-GRF2RYEO.js} +2 -2
- package/dist/{chunk-QFSL2L2B.js → chunk-L5F3WYIY.js} +81 -31
- package/dist/chunk-L5F3WYIY.js.map +1 -0
- package/dist/{chunk-MMSMZC7S.js → chunk-MNRWHSFS.js} +2 -2
- package/dist/{chunk-PARKXDXI.js → chunk-ORTOMEYR.js} +2 -2
- package/dist/{chunk-FP6HOW6J.js → chunk-S2PLX4XK.js} +2 -2
- package/dist/{chunk-A5QKNOXW.js → chunk-TTT6HYPW.js} +47 -10
- package/dist/chunk-TTT6HYPW.js.map +1 -0
- package/dist/{chunk-BIYQN7FH.js → chunk-VCPTOZ56.js} +31 -1
- package/dist/{chunk-BIYQN7FH.js.map → chunk-VCPTOZ56.js.map} +1 -1
- package/dist/{chunk-LDHRIQUW.js → chunk-ZEE5WQYU.js} +2 -2
- package/dist/cli/bin.js +27 -27
- package/dist/cli/commands/audit.js +10 -10
- package/dist/client-3XGSZMLU.js +11 -0
- package/dist/{convert-to-pnpm-KLWA53N5.js → convert-to-pnpm-U2CRNKNY.js} +2 -2
- package/dist/{db-II5WAK4D.js → db-7XYTBIPH.js} +20 -13
- package/dist/db-7XYTBIPH.js.map +1 -0
- package/dist/{deadletter-G4M3HSVM.js → deadletter-A7RQVNG3.js} +8 -4
- package/dist/{digest-CWKK2DMR.js → digest-AMXRGWZA.js} +20 -20
- package/dist/{digest-collectors-CYTN2EUX.js → digest-collectors-CX2NCGS7.js} +7 -7
- package/dist/{ensure-site-2QZHFVQ3.js → ensure-site-F2WFCWWA.js} +2 -2
- package/dist/{forms-notify-target-X6UEOI2M.js → forms-notify-target-DK5R326N.js} +3 -3
- package/dist/{github-signals-QIRTHHET.js → github-signals-RGRPYTUB.js} +6 -6
- package/dist/{header-image-H7ZJAV26.js → header-image-43ZIEJKP.js} +3 -3
- package/dist/{health-endpoint-BJ6BKRHF.js → health-endpoint-K5LXDPGE.js} +2 -2
- package/dist/{health-mirror-KU3G7V2Y.js → health-mirror-WZUHWCCV.js} +3 -3
- package/dist/index.js +10 -11
- package/dist/index.js.map +1 -1
- package/dist/{init-GOWDA5QS.js → init-OFITGMOP.js} +5 -5
- package/dist/{launch-7N3X2MXB.js → launch-AJY3TGTQ.js} +7 -7
- package/dist/{lighthouse-52WSPZ5D.js → lighthouse-RFMFREEX.js} +2 -2
- package/dist/{match-harness-GBCDSVPS.js → match-harness-CFELJA57.js} +2 -2
- package/dist/migrate-EZL55AWA.js +7 -0
- package/dist/{onboard-JQQIMQW7.js → onboard-F7RTLMDZ.js} +2 -2
- package/dist/{orchestrate-L2A5BZFY.js → orchestrate-SAIFXZIW.js} +5 -5
- package/dist/{pipeline-UUPXOS2J.js → pipeline-TCSNVDQZ.js} +3 -3
- package/dist/{preflight-O7Q6FWHU.js → preflight-6XGVVO2U.js} +7 -7
- package/dist/{prismic-ci-NAPWOXXD.js → prismic-ci-XMX7A5E4.js} +2 -2
- package/dist/{prismic-models-LL6ORTQ2.js → prismic-models-7GKFAAFA.js} +4 -4
- package/dist/prospect/types.d.ts +44 -2
- package/dist/prospect/types.js +1 -1
- package/dist/{prospect-audit-FMPGQIRQ.js → prospect-audit-KWP5P5U2.js} +37 -5
- package/dist/prospect-audit-KWP5P5U2.js.map +1 -0
- package/dist/{render-MHUUHPLN.js → render-NWUAX6RN.js} +3 -3
- package/dist/{renovate-dispatch-2IHAZDVA.js → renovate-dispatch-ZZQXT7DA.js} +2 -2
- package/dist/replay-HB44TAII.js +77 -0
- package/dist/replay-HB44TAII.js.map +1 -0
- package/dist/{report-IAHXN5CW.js → report-MVPWS7WP.js} +13 -13
- package/dist/{report-mirror-4QM57LMS.js → report-mirror-O6IDFDWU.js} +3 -3
- package/dist/{roster-GDNSIRAK.js → roster-EJ3ILR52.js} +2 -2
- package/dist/{screenouts-7P5GOZMV.js → screenouts-7NQUWHOJ.js} +14 -1
- package/dist/screenouts-7NQUWHOJ.js.map +1 -0
- package/dist/{self-updating-ZUWPGYUP.js → self-updating-KX5FMGEO.js} +2 -2
- package/dist/{selftest-G4W3LIBQ.js → selftest-KABY2CYJ.js} +5 -5
- package/dist/{site-mirror-WR7ACXOV.js → site-mirror-TKTDWYP3.js} +3 -3
- package/dist/{smoke-suite-WAUPI6EJ.js → smoke-suite-QQMV7TNA.js} +2 -2
- package/dist/{submissions-JDZP35JM.js → submissions-4I66W6QK.js} +11 -1
- package/dist/{submissions-JDZP35JM.js.map → submissions-4I66W6QK.js.map} +1 -1
- package/dist/{submissions-2SHCFOKD.js → submissions-K5UXGZUN.js} +4 -4
- package/dist/{svelte-codemods-VOLOKKFI.js → svelte-codemods-YFN4TEGV.js} +2 -2
- package/dist/{sync-configs-OXSWKVZ2.js → sync-configs-HBXS3D7C.js} +2 -2
- package/dist/{upgrade-EVAL3JTO.js → upgrade-XOJMDIT4.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-A5QKNOXW.js.map +0 -1
- package/dist/chunk-L3S3QZXL.js.map +0 -1
- package/dist/chunk-LAJ3FF54.js.map +0 -1
- package/dist/chunk-QFSL2L2B.js.map +0 -1
- package/dist/client-DGTO65WB.js +0 -11
- package/dist/db-II5WAK4D.js.map +0 -1
- package/dist/migrate-XZ7U5DFC.js +0 -7
- package/dist/prospect-audit-FMPGQIRQ.js.map +0 -1
- package/dist/replay-4FVFOMHH.js +0 -54
- package/dist/replay-4FVFOMHH.js.map +0 -1
- package/dist/screenouts-7P5GOZMV.js.map +0 -1
- /package/dist/{announce-5ZD2SBGD.js.map → announce-2FH2KBQQ.js.map} +0 -0
- /package/dist/{bump-deps-775VLDYB.js.map → bump-deps-54K4ECP3.js.map} +0 -0
- /package/dist/{chunk-YXWBM26P.js.map → chunk-3YALLSBF.js.map} +0 -0
- /package/dist/{chunk-VMGHQUTV.js.map → chunk-B2BRFWJY.js.map} +0 -0
- /package/dist/{chunk-U2ZI6G7H.js.map → chunk-GRF2RYEO.js.map} +0 -0
- /package/dist/{chunk-MMSMZC7S.js.map → chunk-MNRWHSFS.js.map} +0 -0
- /package/dist/{chunk-PARKXDXI.js.map → chunk-ORTOMEYR.js.map} +0 -0
- /package/dist/{chunk-FP6HOW6J.js.map → chunk-S2PLX4XK.js.map} +0 -0
- /package/dist/{chunk-LDHRIQUW.js.map → chunk-ZEE5WQYU.js.map} +0 -0
- /package/dist/{client-DGTO65WB.js.map → client-3XGSZMLU.js.map} +0 -0
- /package/dist/{convert-to-pnpm-KLWA53N5.js.map → convert-to-pnpm-U2CRNKNY.js.map} +0 -0
- /package/dist/{deadletter-G4M3HSVM.js.map → deadletter-A7RQVNG3.js.map} +0 -0
- /package/dist/{digest-CWKK2DMR.js.map → digest-AMXRGWZA.js.map} +0 -0
- /package/dist/{digest-collectors-CYTN2EUX.js.map → digest-collectors-CX2NCGS7.js.map} +0 -0
- /package/dist/{ensure-site-2QZHFVQ3.js.map → ensure-site-F2WFCWWA.js.map} +0 -0
- /package/dist/{forms-notify-target-X6UEOI2M.js.map → forms-notify-target-DK5R326N.js.map} +0 -0
- /package/dist/{github-signals-QIRTHHET.js.map → github-signals-RGRPYTUB.js.map} +0 -0
- /package/dist/{header-image-H7ZJAV26.js.map → header-image-43ZIEJKP.js.map} +0 -0
- /package/dist/{health-endpoint-BJ6BKRHF.js.map → health-endpoint-K5LXDPGE.js.map} +0 -0
- /package/dist/{health-mirror-KU3G7V2Y.js.map → health-mirror-WZUHWCCV.js.map} +0 -0
- /package/dist/{init-GOWDA5QS.js.map → init-OFITGMOP.js.map} +0 -0
- /package/dist/{launch-7N3X2MXB.js.map → launch-AJY3TGTQ.js.map} +0 -0
- /package/dist/{lighthouse-52WSPZ5D.js.map → lighthouse-RFMFREEX.js.map} +0 -0
- /package/dist/{match-harness-GBCDSVPS.js.map → match-harness-CFELJA57.js.map} +0 -0
- /package/dist/{migrate-XZ7U5DFC.js.map → migrate-EZL55AWA.js.map} +0 -0
- /package/dist/{onboard-JQQIMQW7.js.map → onboard-F7RTLMDZ.js.map} +0 -0
- /package/dist/{orchestrate-L2A5BZFY.js.map → orchestrate-SAIFXZIW.js.map} +0 -0
- /package/dist/{pipeline-UUPXOS2J.js.map → pipeline-TCSNVDQZ.js.map} +0 -0
- /package/dist/{preflight-O7Q6FWHU.js.map → preflight-6XGVVO2U.js.map} +0 -0
- /package/dist/{prismic-ci-NAPWOXXD.js.map → prismic-ci-XMX7A5E4.js.map} +0 -0
- /package/dist/{prismic-models-LL6ORTQ2.js.map → prismic-models-7GKFAAFA.js.map} +0 -0
- /package/dist/{render-MHUUHPLN.js.map → render-NWUAX6RN.js.map} +0 -0
- /package/dist/{renovate-dispatch-2IHAZDVA.js.map → renovate-dispatch-ZZQXT7DA.js.map} +0 -0
- /package/dist/{report-IAHXN5CW.js.map → report-MVPWS7WP.js.map} +0 -0
- /package/dist/{report-mirror-4QM57LMS.js.map → report-mirror-O6IDFDWU.js.map} +0 -0
- /package/dist/{roster-GDNSIRAK.js.map → roster-EJ3ILR52.js.map} +0 -0
- /package/dist/{self-updating-ZUWPGYUP.js.map → self-updating-KX5FMGEO.js.map} +0 -0
- /package/dist/{selftest-G4W3LIBQ.js.map → selftest-KABY2CYJ.js.map} +0 -0
- /package/dist/{site-mirror-WR7ACXOV.js.map → site-mirror-TKTDWYP3.js.map} +0 -0
- /package/dist/{smoke-suite-WAUPI6EJ.js.map → smoke-suite-QQMV7TNA.js.map} +0 -0
- /package/dist/{submissions-2SHCFOKD.js.map → submissions-K5UXGZUN.js.map} +0 -0
- /package/dist/{svelte-codemods-VOLOKKFI.js.map → svelte-codemods-YFN4TEGV.js.map} +0 -0
- /package/dist/{sync-configs-OXSWKVZ2.js.map → sync-configs-HBXS3D7C.js.map} +0 -0
- /package/dist/{upgrade-EVAL3JTO.js.map → upgrade-XOJMDIT4.js.map} +0 -0
|
@@ -5,10 +5,10 @@ import {
|
|
|
5
5
|
} from "./chunk-DYTYPKFN.js";
|
|
6
6
|
import {
|
|
7
7
|
resolveSites
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-S2PLX4XK.js";
|
|
9
9
|
import {
|
|
10
10
|
init
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-GRF2RYEO.js";
|
|
12
12
|
import "./chunk-EN6CTBUN.js";
|
|
13
13
|
import "./chunk-6PGXKN6F.js";
|
|
14
14
|
import "./chunk-AYDQQBNG.js";
|
|
@@ -21,12 +21,12 @@ import "./chunk-3RLDX3Q2.js";
|
|
|
21
21
|
import "./chunk-SLFG7Y76.js";
|
|
22
22
|
import "./chunk-LUF52EIY.js";
|
|
23
23
|
import "./chunk-OTGB6YQO.js";
|
|
24
|
-
import "./chunk-
|
|
24
|
+
import "./chunk-DXZRWW2F.js";
|
|
25
25
|
import "./chunk-LKGVSM2O.js";
|
|
26
26
|
import "./chunk-MVKNU4QD.js";
|
|
27
27
|
import "./chunk-43SW3FGW.js";
|
|
28
28
|
import "./chunk-Z3JXLULD.js";
|
|
29
|
-
import "./chunk-
|
|
29
|
+
import "./chunk-VCPTOZ56.js";
|
|
30
30
|
import "./chunk-UDRHAQT7.js";
|
|
31
31
|
import "./chunk-PTDMVGKL.js";
|
|
32
32
|
import "./chunk-LBYOLBW7.js";
|
|
@@ -111,4 +111,4 @@ async function runInitCommand(site, opts) {
|
|
|
111
111
|
export {
|
|
112
112
|
runInitCommand
|
|
113
113
|
};
|
|
114
|
-
//# sourceMappingURL=init-
|
|
114
|
+
//# sourceMappingURL=init-OFITGMOP.js.map
|
|
@@ -17,7 +17,7 @@ import "./chunk-WQLNUEZL.js";
|
|
|
17
17
|
import "./chunk-5L3FPQIJ.js";
|
|
18
18
|
import {
|
|
19
19
|
resolveSites
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-S2PLX4XK.js";
|
|
21
21
|
import {
|
|
22
22
|
createReportDraft,
|
|
23
23
|
findReportForPeriod,
|
|
@@ -49,12 +49,12 @@ import "./chunk-RQJFGK3A.js";
|
|
|
49
49
|
import "./chunk-SLFG7Y76.js";
|
|
50
50
|
import {
|
|
51
51
|
runAudits
|
|
52
|
-
} from "./chunk-
|
|
52
|
+
} from "./chunk-DXZRWW2F.js";
|
|
53
53
|
import "./chunk-LKGVSM2O.js";
|
|
54
54
|
import "./chunk-MVKNU4QD.js";
|
|
55
55
|
import "./chunk-43SW3FGW.js";
|
|
56
56
|
import "./chunk-Z3JXLULD.js";
|
|
57
|
-
import "./chunk-
|
|
57
|
+
import "./chunk-VCPTOZ56.js";
|
|
58
58
|
import "./chunk-UDRHAQT7.js";
|
|
59
59
|
import "./chunk-PTDMVGKL.js";
|
|
60
60
|
import "./chunk-LBYOLBW7.js";
|
|
@@ -602,9 +602,9 @@ async function runLaunchCommand(site, opts) {
|
|
|
602
602
|
if (!target) {
|
|
603
603
|
return { output: `No site resolved for "${site}".`, code: 1 };
|
|
604
604
|
}
|
|
605
|
-
const { makeReportMirror } = await import("./report-mirror-
|
|
606
|
-
const { makeSiteMirror } = await import("./site-mirror-
|
|
607
|
-
const { readFleetRoster } = await import("./roster-
|
|
605
|
+
const { makeReportMirror } = await import("./report-mirror-O6IDFDWU.js");
|
|
606
|
+
const { makeSiteMirror } = await import("./site-mirror-TKTDWYP3.js");
|
|
607
|
+
const { readFleetRoster } = await import("./roster-EJ3ILR52.js");
|
|
608
608
|
const result = await launch(target, {
|
|
609
609
|
roster: () => readFleetRoster(),
|
|
610
610
|
reportMirror: await makeReportMirror(),
|
|
@@ -616,4 +616,4 @@ export {
|
|
|
616
616
|
formatStep,
|
|
617
617
|
runLaunchCommand
|
|
618
618
|
};
|
|
619
|
-
//# sourceMappingURL=launch-
|
|
619
|
+
//# sourceMappingURL=launch-AJY3TGTQ.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
lighthouseAudit
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-VCPTOZ56.js";
|
|
4
4
|
import "./chunk-PTDMVGKL.js";
|
|
5
5
|
import "./chunk-LBYOLBW7.js";
|
|
6
6
|
import "./chunk-XXTZBPUY.js";
|
|
@@ -8,4 +8,4 @@ import "./chunk-NMAWXBJA.js";
|
|
|
8
8
|
export {
|
|
9
9
|
lighthouseAudit
|
|
10
10
|
};
|
|
11
|
-
//# sourceMappingURL=lighthouse-
|
|
11
|
+
//# sourceMappingURL=lighthouse-RFMFREEX.js.map
|
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
} from "./chunk-DYTYPKFN.js";
|
|
21
21
|
import {
|
|
22
22
|
resolveSites
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-S2PLX4XK.js";
|
|
24
24
|
import {
|
|
25
25
|
PRETTIER_FLAG_NOTE,
|
|
26
26
|
formatWithPrettier,
|
|
@@ -414,4 +414,4 @@ async function runMatchHarnessCommand(site, opts) {
|
|
|
414
414
|
export {
|
|
415
415
|
runMatchHarnessCommand
|
|
416
416
|
};
|
|
417
|
-
//# sourceMappingURL=match-harness-
|
|
417
|
+
//# sourceMappingURL=match-harness-CFELJA57.js.map
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
} from "./chunk-DYTYPKFN.js";
|
|
9
9
|
import {
|
|
10
10
|
resolveSites
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-S2PLX4XK.js";
|
|
12
12
|
import {
|
|
13
13
|
onboard
|
|
14
14
|
} from "./chunk-6PGXKN6F.js";
|
|
@@ -70,4 +70,4 @@ async function runOnboardCommand(site, opts) {
|
|
|
70
70
|
export {
|
|
71
71
|
runOnboardCommand
|
|
72
72
|
};
|
|
73
|
-
//# sourceMappingURL=onboard-
|
|
73
|
+
//# sourceMappingURL=onboard-F7RTLMDZ.js.map
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
parseAddresses,
|
|
5
5
|
sendApprovedReports,
|
|
6
6
|
withGlobalCc
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-ZEE5WQYU.js";
|
|
8
8
|
import "./chunk-TEMQPSCM.js";
|
|
9
9
|
import "./chunk-ASLDCWBF.js";
|
|
10
10
|
import "./chunk-VAD43MOR.js";
|
|
@@ -19,9 +19,9 @@ import "./chunk-TC4GANMX.js";
|
|
|
19
19
|
import "./chunk-ICSRWW5Q.js";
|
|
20
20
|
import "./chunk-RQJFGK3A.js";
|
|
21
21
|
import "./chunk-WEKL2HYJ.js";
|
|
22
|
-
import "./chunk-
|
|
23
|
-
import "./chunk-
|
|
24
|
-
import "./chunk-
|
|
22
|
+
import "./chunk-3YALLSBF.js";
|
|
23
|
+
import "./chunk-MNRWHSFS.js";
|
|
24
|
+
import "./chunk-CP6MVZ5X.js";
|
|
25
25
|
import "./chunk-RARREDQE.js";
|
|
26
26
|
import "./chunk-6VAL7XJT.js";
|
|
27
27
|
export {
|
|
@@ -31,4 +31,4 @@ export {
|
|
|
31
31
|
sendApprovedReports,
|
|
32
32
|
withGlobalCc
|
|
33
33
|
};
|
|
34
|
-
//# sourceMappingURL=orchestrate-
|
|
34
|
+
//# sourceMappingURL=orchestrate-SAIFXZIW.js.map
|
|
@@ -11,8 +11,8 @@ import {
|
|
|
11
11
|
envEngines,
|
|
12
12
|
mergeFixes,
|
|
13
13
|
runProspectAudit
|
|
14
|
-
} from "./chunk-
|
|
15
|
-
import "./chunk-
|
|
14
|
+
} from "./chunk-L5F3WYIY.js";
|
|
15
|
+
import "./chunk-5UI4FERC.js";
|
|
16
16
|
import "./chunk-T7ZUUOZ2.js";
|
|
17
17
|
import "./chunk-RARREDQE.js";
|
|
18
18
|
export {
|
|
@@ -29,4 +29,4 @@ export {
|
|
|
29
29
|
mergeFixes,
|
|
30
30
|
runProspectAudit
|
|
31
31
|
};
|
|
32
|
-
//# sourceMappingURL=pipeline-
|
|
32
|
+
//# sourceMappingURL=pipeline-TCSNVDQZ.js.map
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
preflight
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-B2BRFWJY.js";
|
|
4
4
|
import "./chunk-PZR4EBPY.js";
|
|
5
|
-
import "./chunk-
|
|
5
|
+
import "./chunk-ZEE5WQYU.js";
|
|
6
6
|
import "./chunk-TEMQPSCM.js";
|
|
7
7
|
import "./chunk-ASLDCWBF.js";
|
|
8
8
|
import "./chunk-VAD43MOR.js";
|
|
@@ -17,9 +17,9 @@ import "./chunk-TC4GANMX.js";
|
|
|
17
17
|
import "./chunk-ICSRWW5Q.js";
|
|
18
18
|
import "./chunk-RQJFGK3A.js";
|
|
19
19
|
import "./chunk-WEKL2HYJ.js";
|
|
20
|
-
import "./chunk-
|
|
21
|
-
import "./chunk-
|
|
22
|
-
import "./chunk-
|
|
20
|
+
import "./chunk-3YALLSBF.js";
|
|
21
|
+
import "./chunk-MNRWHSFS.js";
|
|
22
|
+
import "./chunk-CP6MVZ5X.js";
|
|
23
23
|
import "./chunk-RARREDQE.js";
|
|
24
24
|
import "./chunk-6VAL7XJT.js";
|
|
25
25
|
|
|
@@ -39,7 +39,7 @@ function lazyFleetDb() {
|
|
|
39
39
|
return {
|
|
40
40
|
get: async () => {
|
|
41
41
|
if (!db) {
|
|
42
|
-
const { openDb, readDbConfig } = await import("./client-
|
|
42
|
+
const { openDb, readDbConfig } = await import("./client-3XGSZMLU.js");
|
|
43
43
|
db = await openDb(readDbConfig());
|
|
44
44
|
}
|
|
45
45
|
return db;
|
|
@@ -91,4 +91,4 @@ async function runPreflightCommand(site, opts) {
|
|
|
91
91
|
export {
|
|
92
92
|
runPreflightCommand
|
|
93
93
|
};
|
|
94
|
-
//# sourceMappingURL=preflight-
|
|
94
|
+
//# sourceMappingURL=preflight-6XGVVO2U.js.map
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
} from "./chunk-DYTYPKFN.js";
|
|
13
13
|
import {
|
|
14
14
|
resolveSites
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-S2PLX4XK.js";
|
|
16
16
|
import {
|
|
17
17
|
RESTORED_NOTE,
|
|
18
18
|
refusedByGit,
|
|
@@ -476,4 +476,4 @@ export {
|
|
|
476
476
|
formatPrismicCiResults,
|
|
477
477
|
runPrismicCiCommand
|
|
478
478
|
};
|
|
479
|
-
//# sourceMappingURL=prismic-ci-
|
|
479
|
+
//# sourceMappingURL=prismic-ci-XMX7A5E4.js.map
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
} from "./chunk-DYTYPKFN.js";
|
|
19
19
|
import {
|
|
20
20
|
resolveSites
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-S2PLX4XK.js";
|
|
22
22
|
import {
|
|
23
23
|
PRETTIER_FLAG_NOTE,
|
|
24
24
|
formatWithPrettier
|
|
@@ -169,10 +169,10 @@ var defaultDeps = () => ({
|
|
|
169
169
|
openVerdictSink: async () => {
|
|
170
170
|
const { openBase, readAirtableConfig } = await import("./client-EPVO3FEH.js");
|
|
171
171
|
const { updatePrismicModels } = await import("./websites-Y6FN2XFD.js");
|
|
172
|
-
const { readFleetRoster } = await import("./roster-
|
|
172
|
+
const { readFleetRoster } = await import("./roster-EJ3ILR52.js");
|
|
173
173
|
const base = openBase(readAirtableConfig());
|
|
174
174
|
const websites = await readFleetRoster();
|
|
175
|
-
const { makeSiteMirror } = await import("./site-mirror-
|
|
175
|
+
const { makeSiteMirror } = await import("./site-mirror-TKTDWYP3.js");
|
|
176
176
|
const mirror = await makeSiteMirror();
|
|
177
177
|
return {
|
|
178
178
|
websites: websites.map((w) => ({ id: w.id, name: w.name })),
|
|
@@ -1025,4 +1025,4 @@ export {
|
|
|
1025
1025
|
sweepRowWriteback,
|
|
1026
1026
|
writeSweepToAirtable
|
|
1027
1027
|
};
|
|
1028
|
-
//# sourceMappingURL=prismic-models-
|
|
1028
|
+
//# sourceMappingURL=prismic-models-7GKFAAFA.js.map
|
package/dist/prospect/types.d.ts
CHANGED
|
@@ -38,6 +38,18 @@ type AnswerSpace = {
|
|
|
38
38
|
* that declined to cite anything is a fact about the query, not about the
|
|
39
39
|
* prospect, and folding it into the shares would dilute them with silence. */
|
|
40
40
|
answersWithCitations: number;
|
|
41
|
+
/**
|
|
42
|
+
* Category queries we ASKED — the attempted count, not the returned one.
|
|
43
|
+
*
|
|
44
|
+
* It used to be `answers.filter(kind === "category").length`, i.e. only the
|
|
45
|
+
* probes that came back, which is the identical defect #631 fixed for
|
|
46
|
+
* `visibilityScore` (see `types.ts` — "a flakier run scored HIGHER"): a run
|
|
47
|
+
* where three of five queries timed out reported that we asked two. So this
|
|
48
|
+
* counts every category probe dispatched, whether it answered, answered
|
|
49
|
+
* citing nothing, or never returned at all. `answersWithCitations` is the
|
|
50
|
+
* subset that produced citations; the gap between them is our missing data,
|
|
51
|
+
* and a consumer must read it as ours rather than as the prospect's.
|
|
52
|
+
*/
|
|
41
53
|
queriesAsked: number;
|
|
42
54
|
/** Every citation across every category answer, repeats included. */
|
|
43
55
|
citationsTotal: number;
|
|
@@ -289,7 +301,10 @@ type BasicsCheck = {
|
|
|
289
301
|
* Images loaded over plain http on an https page. Browsers block or refuse to
|
|
290
302
|
* upgrade these, so they are broken images for some visitors and a mixed-
|
|
291
303
|
* content warning for the rest. `measured` is false when the site is not on
|
|
292
|
-
* https at all, in which case `insecureEntry` is the finding instead
|
|
304
|
+
* https at all, in which case `insecureEntry` is the finding instead — and
|
|
305
|
+
* also when the crawl recorded no image sources to look at (an older stored
|
|
306
|
+
* report, replayed), where the honest reading is "not measured" rather than
|
|
307
|
+
* "none found".
|
|
293
308
|
*/
|
|
294
309
|
mixedContent: {
|
|
295
310
|
measured: boolean;
|
|
@@ -394,13 +409,28 @@ type ConsistencyResult = {
|
|
|
394
409
|
/** The newest year found, or null when none was. */
|
|
395
410
|
newestCopyrightYear: number | null;
|
|
396
411
|
/** Pages carrying none of the site's shared navigation links. Empty when
|
|
397
|
-
* there is no shared navigation to compare against — see `sharedNavLinks`.
|
|
412
|
+
* there is no shared navigation to compare against — see `sharedNavLinks`.
|
|
413
|
+
* A page in `pagesWithTruncatedAnchors` can never appear here. */
|
|
398
414
|
pagesOffTemplate: string[];
|
|
399
415
|
/** How many links appear on EVERY page examined. This is the site's shared
|
|
400
416
|
* navigation, derived rather than assumed: no `<nav>` element is required,
|
|
401
417
|
* because plenty of sites do not use one. */
|
|
402
418
|
sharedNavLinks: number;
|
|
403
419
|
pagesExamined: number;
|
|
420
|
+
/**
|
|
421
|
+
* Pages whose anchor list hit `MAX_ANCHORS`, so we read only its first 300
|
|
422
|
+
* links (see `anchorsTruncated`).
|
|
423
|
+
*
|
|
424
|
+
* They take no part in the template comparison in EITHER direction, and that
|
|
425
|
+
* is the difference from the journey graph, where a truncated page's links
|
|
426
|
+
* stay in as edges. Shared navigation is derived by MAJORITY VOTE, and a link
|
|
427
|
+
* that fell past the cap is indistinguishable from a link the page does not
|
|
428
|
+
* have — so an incomplete page silently votes "absent" for every one of them
|
|
429
|
+
* and can push a genuine nav link below the threshold. It is not purely
|
|
430
|
+
* positive evidence here the way an edge is there, so it is excluded from the
|
|
431
|
+
* derivation as well as from the finding.
|
|
432
|
+
*/
|
|
433
|
+
pagesWithTruncatedAnchors: string[];
|
|
404
434
|
};
|
|
405
435
|
|
|
406
436
|
/**
|
|
@@ -1087,6 +1117,18 @@ type JourneyMap = {
|
|
|
1087
1117
|
* page on the site being a dead end.
|
|
1088
1118
|
*/
|
|
1089
1119
|
anchorsMeasured: boolean;
|
|
1120
|
+
/**
|
|
1121
|
+
* Pages whose anchor list hit `MAX_ANCHORS`, so we read only its first 300
|
|
1122
|
+
* links (see `anchorsTruncated`).
|
|
1123
|
+
*
|
|
1124
|
+
* These pages are still in the graph and their links are still edges — a link
|
|
1125
|
+
* we read is a real link, and the evidence is only ever additive in that
|
|
1126
|
+
* direction. What they can never be is `deadEnds`: that finding is drawn from
|
|
1127
|
+
* ABSENCE, and a list we cut off establishes nothing about what came after
|
|
1128
|
+
* the cut. Reported rather than silently withheld, so "we could not judge
|
|
1129
|
+
* this page" is a visible claim rather than an unexplained gap.
|
|
1130
|
+
*/
|
|
1131
|
+
pagesWithTruncatedAnchors: string[];
|
|
1090
1132
|
};
|
|
1091
1133
|
|
|
1092
1134
|
/** Every pipeline stage resolves to this. A failed stage degrades its report
|
package/dist/prospect/types.js
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DAILY_CAP_LOOKBACK,
|
|
3
|
+
PROSPECT_AUDIT_DAILY_CAP,
|
|
4
|
+
countAuditsInDailyWindow,
|
|
5
|
+
dailyCapMessage,
|
|
6
|
+
isOverDailyCap
|
|
7
|
+
} from "./chunk-DZZ5KRTB.js";
|
|
1
8
|
import {
|
|
2
9
|
hostnameOf,
|
|
3
10
|
isHttpUrl,
|
|
@@ -96,6 +103,25 @@ function summarize(result, link, file, warnings, recovery, email) {
|
|
|
96
103
|
}
|
|
97
104
|
return lines.join("\n");
|
|
98
105
|
}
|
|
106
|
+
var NO_DB_CAP_WARNING = `No TURSO_DATABASE_URL, so prior audits cannot be counted \u2014 the 24h runaway brake (cap ${PROSPECT_AUDIT_DAILY_CAP}) is NOT protecting this run.`;
|
|
107
|
+
async function checkDailyCap(canPersist, opts) {
|
|
108
|
+
const now = (opts.now ?? (() => /* @__PURE__ */ new Date()))();
|
|
109
|
+
const listRecent = opts.listRecent ?? (canPersist ? async (limit) => {
|
|
110
|
+
const { openDb, readDbConfig } = await import("./client-3XGSZMLU.js");
|
|
111
|
+
const { listRecentProspectAudits } = await import("./prospect-audits-IZVQY3OQ.js");
|
|
112
|
+
return listRecentProspectAudits(await openDb(readDbConfig()), limit);
|
|
113
|
+
} : null);
|
|
114
|
+
if (listRecent === null) return { kind: "unchecked", warning: NO_DB_CAP_WARNING };
|
|
115
|
+
try {
|
|
116
|
+
const count = countAuditsInDailyWindow(await listRecent(DAILY_CAP_LOOKBACK), now);
|
|
117
|
+
return isOverDailyCap(count) ? { kind: "over", count } : { kind: "under", count };
|
|
118
|
+
} catch (err) {
|
|
119
|
+
return {
|
|
120
|
+
kind: "unchecked",
|
|
121
|
+
warning: `Could not read recent audits, so the 24h runaway brake (cap ${PROSPECT_AUDIT_DAILY_CAP}) is NOT protecting this run: ${errorMessage(err)}`
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
}
|
|
99
125
|
async function runProspectAuditCommand(url, opts) {
|
|
100
126
|
if (!isHttpUrl(url)) {
|
|
101
127
|
return fail(`"${url}" is not a URL. Pass the full address, e.g. https://example.com`);
|
|
@@ -109,7 +135,14 @@ async function runProspectAuditCommand(url, opts) {
|
|
|
109
135
|
"No TURSO_DATABASE_URL, so the report cannot be saved or shared. Re-run with --out <file>, or set the Turso credentials."
|
|
110
136
|
);
|
|
111
137
|
}
|
|
112
|
-
const
|
|
138
|
+
const warnings = [];
|
|
139
|
+
const cap = await checkDailyCap(canPersist, opts);
|
|
140
|
+
if (cap.kind === "over") return fail(dailyCapMessage(cap.count));
|
|
141
|
+
if (cap.kind === "unchecked") {
|
|
142
|
+
warnings.push(cap.warning);
|
|
143
|
+
console.error(`! ${cap.warning}`);
|
|
144
|
+
}
|
|
145
|
+
const { runProspectAudit } = await import("./pipeline-TCSNVDQZ.js");
|
|
113
146
|
const onStage = (name, status, detail) => {
|
|
114
147
|
if (status === "start") console.error(`\u2026 ${name}`);
|
|
115
148
|
else if (status === "ok") console.error(`\u2713 ${name}`);
|
|
@@ -140,9 +173,8 @@ async function runProspectAuditCommand(url, opts) {
|
|
|
140
173
|
},
|
|
141
174
|
{ ...opts.deps ?? {}, onStage }
|
|
142
175
|
);
|
|
143
|
-
const { renderProspectReport } = await import("./render-
|
|
176
|
+
const { renderProspectReport } = await import("./render-NWUAX6RN.js");
|
|
144
177
|
const html = renderProspectReport(result);
|
|
145
|
-
const warnings = [];
|
|
146
178
|
let file = null;
|
|
147
179
|
if (opts.out) {
|
|
148
180
|
try {
|
|
@@ -157,7 +189,7 @@ async function runProspectAuditCommand(url, opts) {
|
|
|
157
189
|
let auditId = null;
|
|
158
190
|
if (canPersist) {
|
|
159
191
|
try {
|
|
160
|
-
const { openDb, readDbConfig } = await import("./client-
|
|
192
|
+
const { openDb, readDbConfig } = await import("./client-3XGSZMLU.js");
|
|
161
193
|
const { createProspectAudit } = await import("./prospect-audits-IZVQY3OQ.js");
|
|
162
194
|
const db = await openDb(readDbConfig());
|
|
163
195
|
const created = await createProspectAudit(db, {
|
|
@@ -222,4 +254,4 @@ export {
|
|
|
222
254
|
GOALS,
|
|
223
255
|
runProspectAuditCommand
|
|
224
256
|
};
|
|
225
|
-
//# sourceMappingURL=prospect-audit-
|
|
257
|
+
//# sourceMappingURL=prospect-audit-KWP5P5U2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/commands/prospect-audit.ts","../src/prospect/report-url.ts"],"sourcesContent":["import { mkdir, writeFile } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport { hostnameOf, isHttpUrl, isPrivateOrLoopbackHost } from \"../../util/url.js\";\nimport { reportUrl, reportPrintUrl } from \"../../prospect/report-url.js\";\nimport type { ProspectAuditStatus } from \"../../db/prospect-audits.js\";\nimport type { PipelineDeps, StageName } from \"../../prospect/pipeline.js\";\nimport type { ProspectAuditResult } from \"../../prospect/types.js\";\nimport type { SendAuditEmailResult } from \"../../prospect/email.js\";\nimport type { SiteGoal } from \"../../prospect/goals.js\";\nimport {\n PROSPECT_AUDIT_DAILY_CAP,\n DAILY_CAP_LOOKBACK,\n countAuditsInDailyWindow,\n isOverDailyCap,\n dailyCapMessage,\n type DatedAudit,\n} from \"../../prospect/daily-cap.js\";\n\n/** The operator-selectable goals, in the order the dispatch dropdown lists\n * them. `unknown` is deliberately absent: it is a finding the audit can reach\n * on its own, never something an operator would choose. */\nexport const GOALS = [\n \"book\",\n \"enquire\",\n \"call\",\n \"visit\",\n \"buy\",\n \"demo\",\n \"partner\",\n] as const satisfies readonly SiteGoal[];\n\nfunction isSiteGoal(value: string): value is SiteGoal {\n return (GOALS as readonly string[]).includes(value);\n}\n\nexport type ProspectAuditCliOptions = {\n business?: string;\n /**\n * The one action the site should produce from a visitor, chosen by the\n * operator instead of inferred from the site.\n *\n * Worth overriding because the operator knows things the site does not say.\n * A practice that wants online bookings but has never built one reads as\n * \"call\" from its own pages, and grading it as \"call\" would score it well for\n * doing the thing they are trying to stop doing.\n */\n goal?: string;\n /** Comma-separated competitor domains. */\n competitors?: string;\n /** cac sets this false for `--no-probes`. */\n probes?: boolean;\n out?: string;\n json?: boolean;\n /**\n * Email the internal sheet (scores, what wasn't measured and why, top\n * fixes, and the shareable link) to `PROSPECT_AUDIT_RECIPIENTS`, once the\n * report is rendered and the `--out`/Turso delivery attempts finish. A\n * missing/empty recipients var, or a Resend failure, is a warning — never a\n * crash — because by the time this runs the audit is already delivered (or\n * recovered) by the code above it.\n */\n email?: boolean;\n /**\n * #676. Search terms and buyer questions chosen by hand, comma-separated.\n *\n * Blank generates them, exactly as before — this is an override for a client\n * we already know, and for a comparison over time, where the terms have to\n * stay fixed between runs.\n */\n terms?: string;\n questions?: string;\n /** Test seam: injected pipeline deps. Never set from the CLI. */\n deps?: PipelineDeps;\n /**\n * Test seam: newest-first recent audits for the daily cap. Never set from the\n * CLI — the real implementation opens Turso below. Same injection shape\n * `ProspectAuditTriggerDeps.listRecent` uses on the dashboard side, so both\n * paths' cap tests drive the brake the same way and neither needs a database.\n */\n listRecent?: (limit: number) => Promise<DatedAudit[]>;\n /** Test seam: injectable clock for the cap's 24h window. */\n now?: () => Date;\n};\n\ntype RecoveryWrite = { htmlPath: string; jsonPath: string };\n\nfunction fail(message: string): { output: string; code: number } {\n return { output: message, code: 2 };\n}\n\nfunction errorMessage(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\nfunction scoreLine(label: string, value: number | null): string {\n return `${label.padEnd(14)} ${value === null ? \"not measured\" : String(value).padStart(3)}`;\n}\n\n/** Item 3: the `status` column exists to answer, without deserializing the\n * whole result_json, whether this was a clean run or a degraded one. crawl\n * is excluded — it's the one fatal stage (see pipeline.ts), so by the time a\n * ProspectAuditResult exists it was always ok. Every other stage's\n * StageResult already collapses \"failed\" and \"deliberately skipped\"\n * (--no-probes, the checks→analyze cascade) into the same `ok: false` — both\n * mean the report has a \"not measured\" section, so both count as partial\n * here too. */\nfunction auditStatus(result: ProspectAuditResult): ProspectAuditStatus {\n const allStagesOk =\n result.checks.ok && result.lighthouse.ok && result.analyze.ok && result.probes.ok;\n return allStagesOk ? \"complete\" : \"partial\";\n}\n\n/** Filesystem-safe, never empty. Collapses anything outside [a-z0-9.-] to a\n * single dash so a hostname becomes a sane filename fragment. */\nfunction slugify(s: string): string {\n const slug = s\n .toLowerCase()\n .replace(/[^a-z0-9.-]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\");\n return slug || \"prospect\";\n}\n\n/**\n * Last-resort write when NEITHER `--out` nor the database persist made it —\n * the one situation a paid, already-run audit must never end in silently. Lands\n * in `reports/`, mirroring header-image.ts's own convention for CLI-written\n * artifacts (mkdir -p, resolved against cwd), rather than a bare file dropped\n * into whatever directory the operator happened to be standing in when they\n * ran the command — often unrelated to this repo at all in fleet-tool usage.\n */\nasync function writeRecoveryFiles(\n result: ProspectAuditResult,\n html: string,\n): Promise<RecoveryWrite> {\n const dir = resolve(\"reports\");\n await mkdir(dir, { recursive: true });\n const stamp = new Date().toISOString().replace(/[:.]/g, \"-\");\n const base = `prospect-audit-${slugify(hostnameOf(result.url))}-${stamp}`;\n const htmlPath = resolve(dir, `${base}.html`);\n const jsonPath = resolve(dir, `${base}.json`);\n await writeFile(htmlPath, html, \"utf-8\");\n await writeFile(jsonPath, JSON.stringify(result, null, 2), \"utf-8\");\n return { htmlPath, jsonPath };\n}\n\nfunction summarize(\n result: ProspectAuditResult,\n link: string | null,\n file: string | null,\n warnings: string[],\n recovery: RecoveryWrite | null,\n email: SendAuditEmailResult | null,\n): string {\n const lines = [\n `Prospect audit — ${result.businessName ?? result.url}`,\n \"\",\n scoreLine(\"Findability\", result.scores.findability),\n scoreLine(\"Readability\", result.scores.readability),\n scoreLine(\"Answers\", result.scores.answers),\n // No AI Visibility line: the score was removed from every presentation\n // surface (web, print, email, here) — the measurement lives on as the\n // report's receipts section, not as a number that reads as ours to move.\n ];\n for (const [name, stage] of [\n [\"checks\", result.checks],\n [\"lighthouse\", result.lighthouse],\n [\"analyze\", result.analyze],\n [\"probes\", result.probes],\n ] as const) {\n if (!stage.ok) lines.push(` ! ${name} not measured — ${stage.error}`);\n }\n if (file) lines.push(\"\", `Report written to ${file}`);\n if (link) lines.push(\"\", `Shareable link: ${link}`);\n if (email?.sent) {\n lines.push(\"\", `Emailed to ${email.recipients.join(\", \")} (${email.messageId})`);\n }\n for (const w of warnings) lines.push(\"\", `! ${w}`);\n if (recovery) {\n lines.push(\n \"\",\n \"Neither --out nor the database took this report — wrote a recovery copy instead:\",\n ` ${recovery.htmlPath}`,\n ` ${recovery.jsonPath}`,\n );\n }\n return lines.join(\"\\n\");\n}\n\n/** What the runaway brake concluded before any money was spent. */\ntype DailyCapCheck =\n | { kind: \"under\"; count: number }\n | { kind: \"over\"; count: number }\n /** The brake could not be applied at all — carries the sentence the operator\n * must see, because a guard that quietly abstains is worse than none. */\n | { kind: \"unchecked\"; warning: string };\n\nconst NO_DB_CAP_WARNING =\n \"No TURSO_DATABASE_URL, so prior audits cannot be counted — the 24h runaway brake \" +\n `(cap ${PROSPECT_AUDIT_DAILY_CAP}) is NOT protecting this run.`;\n\n/**\n * MED-15 (2026-09-02): the daily cap was enforced only in the dashboard\n * dispatch path, and every batch to date — including the 29-site corpus — ran\n * through this CLI, which had none. #618 fixed exactly this shape for the\n * private-host guard twenty lines above, and its comment describes the guard it\n * did NOT fix: \"one layer at the far end of the chain — so anyone running the\n * CLI directly, or any future second caller, had none.\"\n *\n * Counted, not re-implemented: the window, the threshold and the wording all\n * come from `src/prospect/daily-cap.ts`, which the dashboard path uses too.\n *\n * **When there is no database, this WARNS and lets the run proceed.** A run with\n * no persistence cannot count prior audits, and refusing would break the\n * documented `--out`-only local path — which is also, by construction, a\n * one-off: an unpersisted run is invisible to every later count, so it is not\n * the automated path the brake exists for. What it must never do is pass in\n * silence, so the sentence goes to stderr AND into the run's warnings, where\n * `--json` consumers see it too. Same answer if the count itself throws: a\n * Turso blip must not block a legitimate audit, but must not look like a\n * passed check either.\n */\nasync function checkDailyCap(\n canPersist: boolean,\n opts: ProspectAuditCliOptions,\n): Promise<DailyCapCheck> {\n const now = (opts.now ?? (() => new Date()))();\n const listRecent =\n opts.listRecent ??\n (canPersist\n ? async (limit: number): Promise<DatedAudit[]> => {\n const { openDb, readDbConfig } = await import(\"../../db/client.js\");\n const { listRecentProspectAudits } = await import(\"../../db/prospect-audits.js\");\n return listRecentProspectAudits(await openDb(readDbConfig()), limit);\n }\n : null);\n if (listRecent === null) return { kind: \"unchecked\", warning: NO_DB_CAP_WARNING };\n\n try {\n const count = countAuditsInDailyWindow(await listRecent(DAILY_CAP_LOOKBACK), now);\n return isOverDailyCap(count) ? { kind: \"over\", count } : { kind: \"under\", count };\n } catch (err) {\n return {\n kind: \"unchecked\",\n warning:\n `Could not read recent audits, so the 24h runaway brake (cap ${PROSPECT_AUDIT_DAILY_CAP}) ` +\n `is NOT protecting this run: ${errorMessage(err)}`,\n };\n }\n}\n\n/**\n * Run one prospect audit end to end. Progress goes to stderr so `--json` stdout\n * stays pipeable. Persistence needs Turso; without it `--out` is mandatory,\n * because an audit nobody can read afterwards is just a bill.\n *\n * By the time `runProspectAudit` resolves, the money is already spent — only\n * the crawl is fatal, every other stage degrades rather than throwing. So the\n * `--out` write and the database persist below are each wrapped in their own\n * try/catch and attempted independently: a bad `--out` path must not cost a\n * working Turso persist (or vice versa), and if BOTH fail — or persist fails\n * with no `--out` given at all — a recovery copy goes to `reports/` rather\n * than the run ending with nothing anywhere. `--json` only changes the SHAPE\n * of stdout; it still runs the same `--out`/persist/recovery logic beneath it.\n */\nexport async function runProspectAuditCommand(\n url: string,\n opts: ProspectAuditCliOptions,\n): Promise<{ output: string; code: number }> {\n if (!isHttpUrl(url)) {\n return fail(`\"${url}\" is not a URL. Pass the full address, e.g. https://example.com`);\n }\n // #612 review: this validated only the SHAPE. The sole private-address guard\n // was in `triggerProspectAudit` — one layer at the far end of the chain — so\n // anyone running the CLI directly, or any future second caller, had none.\n // `crawlSite` now refuses too; this keeps the refusal a clean message instead\n // of a thrown crawl error.\n if (isPrivateOrLoopbackHost(new URL(url).hostname)) {\n return fail(`\"${url}\" is a private or loopback address — refusing to audit it.`);\n }\n const canPersist = Boolean(process.env.TURSO_DATABASE_URL);\n if (!canPersist && !opts.out) {\n return fail(\n \"No TURSO_DATABASE_URL, so the report cannot be saved or shared. Re-run with --out <file>, or set the Turso credentials.\",\n );\n }\n\n // Collected from here on, so the brake's verdict can be recorded BEFORE the\n // pipeline runs — a warning printed only in the summary arrives after the\n // money is spent.\n const warnings: string[] = [];\n\n // MED-15. The last refusal before anything is spent (see checkDailyCap).\n const cap = await checkDailyCap(canPersist, opts);\n if (cap.kind === \"over\") return fail(dailyCapMessage(cap.count));\n if (cap.kind === \"unchecked\") {\n warnings.push(cap.warning);\n console.error(`! ${cap.warning}`);\n }\n\n const { runProspectAudit } = await import(\"../../prospect/pipeline.js\");\n const onStage = (name: StageName, status: \"start\" | \"ok\" | \"fail\", detail?: string): void => {\n if (status === \"start\") console.error(`… ${name}`);\n else if (status === \"ok\") console.error(`✓ ${name}`);\n else console.error(`! ${name} — ${detail ?? \"failed\"}`);\n };\n\n const business = opts.business?.trim();\n const goal = opts.goal?.trim();\n // #676. Comma-separated on a flag (a newline is not typeable in one); the\n // cockpit's textareas split on newlines instead. Both drop blanks, and both\n // treat \"nothing usable\" as \"generate\".\n const splitList = (v: string | undefined): string[] =>\n (v ?? \"\")\n .split(\",\")\n .map((x) => x.trim())\n .filter((x) => x !== \"\");\n const chosenTerms = splitList(opts.terms);\n const chosenQuestions = splitList(opts.questions);\n if (goal !== undefined && goal !== \"\" && !isSiteGoal(goal)) {\n return fail(`--goal must be one of: ${GOALS.join(\", \")}`);\n }\n\n const result = await runProspectAudit(\n url,\n {\n ...(business ? { business } : {}),\n // An empty string is what a blank dispatch field sends; it must read as\n // \"not supplied\" so the model's own inference still runs, rather than\n // overriding it with nothing.\n ...(goal ? { goal } : {}),\n ...(opts.competitors\n ? {\n competitors: opts.competitors\n .split(\",\")\n .map((c) => c.trim())\n .filter(Boolean),\n }\n : {}),\n ...(opts.probes === false ? { probes: false } : {}),\n ...(chosenTerms.length > 0 ? { terms: chosenTerms } : {}),\n ...(chosenQuestions.length > 0 ? { questions: chosenQuestions } : {}),\n },\n { ...(opts.deps ?? {}), onStage },\n );\n\n const { renderProspectReport } = await import(\"../../prospect/render.js\");\n const html = renderProspectReport(result);\n\n let file: string | null = null;\n if (opts.out) {\n try {\n await writeFile(opts.out, html, \"utf-8\");\n file = opts.out;\n } catch (err) {\n warnings.push(`Could not write --out (${opts.out}): ${errorMessage(err)}`);\n }\n }\n\n let link: string | null = null;\n let token: string | null = null;\n let auditId: string | null = null;\n if (canPersist) {\n try {\n const { openDb, readDbConfig } = await import(\"../../db/client.js\");\n const { createProspectAudit } = await import(\"../../db/prospect-audits.js\");\n const db = await openDb(readDbConfig());\n const created = await createProspectAudit(db, {\n url: result.url,\n // Map at the boundary: ProspectAuditResult.businessName is the field\n // name (Item 2 — it's a resolved NAME, not a description); the\n // `prospect_audits.business` column keeps its existing name, since\n // renaming a column needs its own migration for no benefit here.\n business: result.businessName,\n status: auditStatus(result),\n resultJson: JSON.stringify(result),\n // #676: on the ROW, not only in result_json — a re-run reuses them and\n // the /audits listing marks them without reading the blob.\n chosenTerms: chosenTerms.length > 0 ? chosenTerms : null,\n chosenQuestions: chosenQuestions.length > 0 ? chosenQuestions : null,\n });\n auditId = created.id;\n token = created.token;\n link = reportUrl(token);\n } catch (err) {\n warnings.push(`Could not save to the database: ${errorMessage(err)}`);\n }\n }\n\n const delivered = file !== null || link !== null;\n const recovery = delivered ? null : await writeRecoveryFiles(result, html);\n const code = delivered ? 0 : 1;\n\n // The audit is already delivered (or recovered) above — an email failure\n // must never take that away. Same independent try/catch shape as the\n // --out write and the Turso persist: record a warning, keep going, never\n // touch `code`. Dynamically imported for the same reason db/client.js and\n // prospect/render.js are above: it reaches `resend` (a devDependency) and\n // must stay out of bin.js's static import graph (see bin.ts's\n // central-dep-blocker comment).\n // The PDF leave-behind, printed from the website's print route — a document\n // designed for paper, not the interactive report with its evidence folded\n // away behind disclosures.\n //\n // Best-effort by design. Every other stage in this pipeline degrades rather\n // than throwing, and an attachment is not worth losing a delivered report\n // over: if this fails the email still goes, with the link, and a warning says\n // the PDF is missing. It also needs a token — with no persisted report there\n // is no page to print.\n let pdf: Buffer | null = null;\n if (opts.email && token) {\n try {\n const { renderReportPdf } = await import(\"../../prospect/pdf.js\");\n pdf = await renderReportPdf(reportPrintUrl(token));\n } catch (err) {\n warnings.push(`Could not attach the PDF: ${errorMessage(err)}`);\n }\n }\n\n let email: SendAuditEmailResult | null = null;\n if (opts.email) {\n try {\n const { sendAuditEmail, parseProspectAuditRecipients } =\n await import(\"../../prospect/email.js\");\n const recipients = parseProspectAuditRecipients(process.env.PROSPECT_AUDIT_RECIPIENTS);\n email = await sendAuditEmail(result, { link, recipients, auditId, pdf });\n if (!email.sent) {\n warnings.push(`Could not email the audit sheet: ${email.reason}`);\n }\n } catch (err) {\n warnings.push(`Could not email the audit sheet: ${errorMessage(err)}`);\n }\n }\n\n if (opts.json) {\n return {\n output: JSON.stringify(\n { result, out: file, link, token, recovery, warnings, email },\n null,\n 2,\n ),\n code,\n };\n }\n\n return { output: summarize(result, link, file, warnings, recovery, email), code };\n}\n","/** Where the prospect-facing report lives now: a real, branded route on the\n * marketing site rather than generated HTML on the ops app's domain. */\nexport const DEFAULT_REPORT_BASE_URL = \"https://reddoorla.com\";\n\n/**\n * Resolve the public report origin.\n *\n * Deliberately its own variable rather than reusing `DASHBOARD_BASE_URL`. That\n * one addresses operators and points at the ops app; this one addresses a\n * prospect and points at reddoorla.com. They are different audiences on\n * different domains, and sharing a variable would mean one of them silently\n * moving the day the other is repointed.\n */\nexport function resolveReportBaseUrl(raw: string | undefined): string {\n return (raw?.trim() || DEFAULT_REPORT_BASE_URL).replace(/\\/$/, \"\");\n}\n\n/** The link a prospect opens. */\nexport function reportUrl(token: string, raw = process.env.REPORT_BASE_URL): string {\n return `${resolveReportBaseUrl(raw)}/audit/${token}`;\n}\n\n/** The print-designed variant, which the runner renders to a PDF. Same token,\n * same guards — a separate document, not a stylesheet over the page. */\nexport function reportPrintUrl(token: string, raw = process.env.REPORT_BASE_URL): string {\n return `${reportUrl(token, raw)}/print`;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -3,8 +3,8 @@ import {
|
|
|
3
3
|
PROBES_SKIPPED,
|
|
4
4
|
domainOf,
|
|
5
5
|
resolveBusinessName
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-L5F3WYIY.js";
|
|
7
|
+
import "./chunk-5UI4FERC.js";
|
|
8
8
|
import {
|
|
9
9
|
escapeHtml,
|
|
10
10
|
safeUrl
|
|
@@ -328,4 +328,4 @@ function renderProspectReport(result) {
|
|
|
328
328
|
export {
|
|
329
329
|
renderProspectReport
|
|
330
330
|
};
|
|
331
|
-
//# sourceMappingURL=render-
|
|
331
|
+
//# sourceMappingURL=render-NWUAX6RN.js.map
|
|
@@ -109,7 +109,7 @@ async function runRenovateDispatchCommand(opts) {
|
|
|
109
109
|
}
|
|
110
110
|
const base = opts.base ?? openBase(readAirtableConfig());
|
|
111
111
|
const websites = await (opts.roster ?? (async () => {
|
|
112
|
-
const { readFleetRoster } = await import("./roster-
|
|
112
|
+
const { readFleetRoster } = await import("./roster-EJ3ILR52.js");
|
|
113
113
|
return readFleetRoster();
|
|
114
114
|
}))();
|
|
115
115
|
const targets = selectRenovateTargets(websites);
|
|
@@ -146,4 +146,4 @@ async function runRenovateDispatchCommand(opts) {
|
|
|
146
146
|
export {
|
|
147
147
|
runRenovateDispatchCommand
|
|
148
148
|
};
|
|
149
|
-
//# sourceMappingURL=renovate-dispatch-
|
|
149
|
+
//# sourceMappingURL=renovate-dispatch-ZZQXT7DA.js.map
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import {
|
|
2
|
+
markDeadLetterReplayed,
|
|
3
|
+
readUnreplayedDeadLetters
|
|
4
|
+
} from "./chunk-TTT6HYPW.js";
|
|
5
|
+
import {
|
|
6
|
+
ingestSubmission
|
|
7
|
+
} from "./chunk-Z7FDJ35L.js";
|
|
8
|
+
import "./chunk-NO74DXDP.js";
|
|
9
|
+
import "./chunk-I7NHLVVI.js";
|
|
10
|
+
import "./chunk-2OP4JKIQ.js";
|
|
11
|
+
|
|
12
|
+
// src/forms/replay.ts
|
|
13
|
+
async function replayDeadLetters(db, deps) {
|
|
14
|
+
const queue = await readUnreplayedDeadLetters(db);
|
|
15
|
+
const result = {
|
|
16
|
+
replayed: [],
|
|
17
|
+
stillFailing: [],
|
|
18
|
+
unmarked: [],
|
|
19
|
+
unreadable: [...queue.unreadable]
|
|
20
|
+
};
|
|
21
|
+
for (const row of queue.rows) {
|
|
22
|
+
let outcome;
|
|
23
|
+
try {
|
|
24
|
+
outcome = await replayOne(db, deps, row);
|
|
25
|
+
} catch (err) {
|
|
26
|
+
result.stillFailing.push({ id: row.id, error: `replay threw: ${String(err)}` });
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
if (outcome.terminal) {
|
|
30
|
+
result.replayed.push({
|
|
31
|
+
id: row.id,
|
|
32
|
+
outcome: outcome.outcome,
|
|
33
|
+
submissionId: outcome.submissionId
|
|
34
|
+
});
|
|
35
|
+
} else if (outcome.unmarked) {
|
|
36
|
+
result.unmarked.push({
|
|
37
|
+
id: row.id,
|
|
38
|
+
outcome: outcome.outcome,
|
|
39
|
+
submissionId: outcome.submissionId,
|
|
40
|
+
error: outcome.error
|
|
41
|
+
});
|
|
42
|
+
} else {
|
|
43
|
+
result.stillFailing.push({ id: row.id, error: outcome.error });
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return result;
|
|
47
|
+
}
|
|
48
|
+
async function markTerminal(db, row, outcome, submissionId, now) {
|
|
49
|
+
try {
|
|
50
|
+
await markDeadLetterReplayed(db, row.id, outcome, submissionId, now);
|
|
51
|
+
} catch (err) {
|
|
52
|
+
return { terminal: false, unmarked: true, outcome, submissionId, error: String(err) };
|
|
53
|
+
}
|
|
54
|
+
return { terminal: true, outcome, submissionId };
|
|
55
|
+
}
|
|
56
|
+
async function replayOne(db, deps, row) {
|
|
57
|
+
const { deadLetter: _stripped, ...safeDeps } = deps;
|
|
58
|
+
void _stripped;
|
|
59
|
+
let res;
|
|
60
|
+
try {
|
|
61
|
+
res = await ingestSubmission(safeDeps, row.siteSlug, row.payload, row.turnstile);
|
|
62
|
+
} catch (err) {
|
|
63
|
+
return { terminal: false, error: String(err) };
|
|
64
|
+
}
|
|
65
|
+
const now = deps.now();
|
|
66
|
+
if (res.status === "accepted") {
|
|
67
|
+
return markTerminal(db, row, "accepted", res.submissionId, now);
|
|
68
|
+
}
|
|
69
|
+
if (res.status === "unknown-site") {
|
|
70
|
+
return { terminal: false, error: `unknown-site: no fleet row for '${row.siteSlug}'` };
|
|
71
|
+
}
|
|
72
|
+
return markTerminal(db, row, `rejected:${res.reason}`, null, now);
|
|
73
|
+
}
|
|
74
|
+
export {
|
|
75
|
+
replayDeadLetters
|
|
76
|
+
};
|
|
77
|
+
//# sourceMappingURL=replay-HB44TAII.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/forms/replay.ts"],"sourcesContent":["import type { Db } from \"../db/client.js\";\nimport {\n readUnreplayedDeadLetters,\n markDeadLetterReplayed,\n type DeadLetterRow,\n type UnreadableDeadLetterRow,\n} from \"../db/deadletter.js\";\nimport { ingestSubmission, type IngestDeps } from \"./ingest.js\";\n\nexport type ReplayResult = {\n /** Terminal outcomes this run: the row will never be picked up again. */\n replayed: Array<{ id: string; outcome: string; submissionId: string | null }>;\n /** Rows whose lookup threw AGAIN — left unreplayed for the next run. */\n stillFailing: Array<{ id: string; error: string }>;\n /** MED-10(b). Rows that DID re-ingest — a real submission exists for them —\n * but whose terminal mark could not be written. Distinct from `stillFailing`\n * on purpose: that bucket means \"nothing was written, retry freely\", which is\n * the one thing nobody may believe about these. Re-running replay before the\n * row is reconciled WILL mint a duplicate submission, so each entry names the\n * submission that already exists. */\n unmarked: Array<{ id: string; outcome: string; submissionId: string | null; error: string }>;\n /** MED-10(c). Rows whose stored JSON could not be decoded — they cannot be\n * replayed at all until a human looks. Reported so they are visible; still\n * queued, so nothing is destroyed by reporting them. */\n unreadable: UnreadableDeadLetterRow[];\n};\n\n/**\n * Run every unreplayed dead-letter back through `ingestSubmission` — the SAME\n * pipeline a live submission takes, so a replayed lead gets real spam\n * classification, notify, and fan-out, not a bespoke re-implementation.\n *\n * Each row replays with the Turnstile verification computed at receipt (tokens\n * expire in 300s; re-verifying is impossible by design, see deadletter.ts).\n *\n * `deps` must NOT wire `deadLetter`: a lookup that throws during replay would\n * otherwise dead-letter the SAME lead a second time while the original row stays\n * unreplayed — every retry would mint a duplicate. Enforced here by stripping the\n * key rather than trusting the caller. A thrown lookup leaves the row untouched\n * for the next run; `accepted` and `rejected` are terminal — re-running cannot\n * improve on an answer the store actually gave. `unknown-site` USED to be\n * terminal too and no longer is: see replayOne below (#645).\n *\n * Oldest-first (listUnreplayedDeadLetters orders by received_at) so the\n * duplicate/velocity spam signals see submissions in arrival order.\n */\nexport async function replayDeadLetters(\n db: Db,\n deps: Omit<IngestDeps, \"deadLetter\">,\n): Promise<ReplayResult> {\n const queue = await readUnreplayedDeadLetters(db);\n const result: ReplayResult = {\n replayed: [],\n stillFailing: [],\n unmarked: [],\n unreadable: [...queue.unreadable],\n };\n\n for (const row of queue.rows) {\n // MED-10(b). One row's failure must never abort the ones behind it. Every\n // outcome replayOne can reach is already a return value; this catch is the\n // backstop for anything it cannot anticipate (a `deps.now()` that throws, a\n // dep wired wrong), so a surprise costs one lead's run, not the queue's.\n let outcome: Awaited<ReturnType<typeof replayOne>>;\n try {\n outcome = await replayOne(db, deps, row);\n } catch (err) {\n result.stillFailing.push({ id: row.id, error: `replay threw: ${String(err)}` });\n continue;\n }\n if (outcome.terminal) {\n result.replayed.push({\n id: row.id,\n outcome: outcome.outcome,\n submissionId: outcome.submissionId,\n });\n } else if (outcome.unmarked) {\n result.unmarked.push({\n id: row.id,\n outcome: outcome.outcome,\n submissionId: outcome.submissionId,\n error: outcome.error,\n });\n } else {\n result.stillFailing.push({ id: row.id, error: outcome.error });\n }\n }\n return result;\n}\n\n/**\n * MED-10(b). Write the terminal mark, and never let its failure escape.\n *\n * ORDERING. Ingest-then-mark is kept, because the alternative (mark first) turns\n * every ingest failure into a lead marked replayed that no submission exists\n * for — silent loss, which is strictly worse than a duplicate the operator can\n * see. What changes is what a failed mark MEANS: it is no longer an exception\n * that unwinds `replayDeadLetters` with the row looking like an ordinary retry.\n * It is its own outcome, naming the submission that already exists, and it\n * cannot touch the rows behind it.\n *\n * RESIDUAL, stated honestly: the mark is a durable write and its failure means\n * the store refused a write. Nothing in-process can persist the fact, so the\n * row IS still queued and the next unattended run will re-ingest it and mint a\n * duplicate. That is why this is not retried quietly and not folded into\n * `stillFailing`: the run's output is the only record that exists, so it has to\n * be loud enough to reach a person before the next run does.\n */\nasync function markTerminal(\n db: Db,\n row: DeadLetterRow,\n outcome: string,\n submissionId: string | null,\n now: Date,\n): Promise<ReplayOutcome> {\n try {\n await markDeadLetterReplayed(db, row.id, outcome, submissionId, now);\n } catch (err) {\n return { terminal: false, unmarked: true, outcome, submissionId, error: String(err) };\n }\n return { terminal: true, outcome, submissionId };\n}\n\ntype ReplayOutcome =\n | { terminal: true; outcome: string; submissionId: string | null }\n | { terminal: false; unmarked?: false; error: string }\n | {\n terminal: false;\n unmarked: true;\n outcome: string;\n submissionId: string | null;\n error: string;\n };\n\nasync function replayOne(\n db: Db,\n deps: Omit<IngestDeps, \"deadLetter\">,\n row: DeadLetterRow,\n): Promise<ReplayOutcome> {\n // Strip deadLetter defensively even though the type forbids it — a structurally\n // wider object passed through `as` must not re-arm the duplicate loop.\n const { deadLetter: _stripped, ...safeDeps } = deps as IngestDeps;\n void _stripped;\n let res;\n try {\n res = await ingestSubmission(safeDeps, row.siteSlug, row.payload, row.turnstile);\n } catch (err) {\n return { terminal: false, error: String(err) };\n }\n const now = deps.now();\n if (res.status === \"accepted\") {\n return markTerminal(db, row, \"accepted\", res.submissionId, now);\n }\n // #645. `unknown-site` is NO LONGER terminal. It used to be, on the reasoning\n // that a slug the store rejects \"can never improve\" — true while nothing could\n // create the missing row. `ensure-site` can now heal one (#645 item 1), and\n // `ingestSubmission` now dead-letters `unknown-site` leads instead of dropping\n // them, so this queue holds real client leads whose site is merely absent.\n //\n // Terminality would then be an ORDERING TRAP: replay-before-heal marks every\n // such lead replayed-and-lost, and that is the order a person reaches for\n // first. Leaving the row queued makes both orders safe.\n //\n // The cost is a slug that is genuinely gone piling up rows and holding this\n // command at exit 1. Deliberate: loud and recoverable beats silent and not.\n if (res.status === \"unknown-site\") {\n return { terminal: false, error: `unknown-site: no fleet row for '${row.siteSlug}'` };\n }\n return markTerminal(db, row, `rejected:${res.reason}`, null, now);\n}\n"],"mappings":";;;;;;;;;;;;AA8CA,eAAsB,kBACpB,IACA,MACuB;AACvB,QAAM,QAAQ,MAAM,0BAA0B,EAAE;AAChD,QAAM,SAAuB;AAAA,IAC3B,UAAU,CAAC;AAAA,IACX,cAAc,CAAC;AAAA,IACf,UAAU,CAAC;AAAA,IACX,YAAY,CAAC,GAAG,MAAM,UAAU;AAAA,EAClC;AAEA,aAAW,OAAO,MAAM,MAAM;AAK5B,QAAI;AACJ,QAAI;AACF,gBAAU,MAAM,UAAU,IAAI,MAAM,GAAG;AAAA,IACzC,SAAS,KAAK;AACZ,aAAO,aAAa,KAAK,EAAE,IAAI,IAAI,IAAI,OAAO,iBAAiB,OAAO,GAAG,CAAC,GAAG,CAAC;AAC9E;AAAA,IACF;AACA,QAAI,QAAQ,UAAU;AACpB,aAAO,SAAS,KAAK;AAAA,QACnB,IAAI,IAAI;AAAA,QACR,SAAS,QAAQ;AAAA,QACjB,cAAc,QAAQ;AAAA,MACxB,CAAC;AAAA,IACH,WAAW,QAAQ,UAAU;AAC3B,aAAO,SAAS,KAAK;AAAA,QACnB,IAAI,IAAI;AAAA,QACR,SAAS,QAAQ;AAAA,QACjB,cAAc,QAAQ;AAAA,QACtB,OAAO,QAAQ;AAAA,MACjB,CAAC;AAAA,IACH,OAAO;AACL,aAAO,aAAa,KAAK,EAAE,IAAI,IAAI,IAAI,OAAO,QAAQ,MAAM,CAAC;AAAA,IAC/D;AAAA,EACF;AACA,SAAO;AACT;AAoBA,eAAe,aACb,IACA,KACA,SACA,cACA,KACwB;AACxB,MAAI;AACF,UAAM,uBAAuB,IAAI,IAAI,IAAI,SAAS,cAAc,GAAG;AAAA,EACrE,SAAS,KAAK;AACZ,WAAO,EAAE,UAAU,OAAO,UAAU,MAAM,SAAS,cAAc,OAAO,OAAO,GAAG,EAAE;AAAA,EACtF;AACA,SAAO,EAAE,UAAU,MAAM,SAAS,aAAa;AACjD;AAaA,eAAe,UACb,IACA,MACA,KACwB;AAGxB,QAAM,EAAE,YAAY,WAAW,GAAG,SAAS,IAAI;AAC/C,OAAK;AACL,MAAI;AACJ,MAAI;AACF,UAAM,MAAM,iBAAiB,UAAU,IAAI,UAAU,IAAI,SAAS,IAAI,SAAS;AAAA,EACjF,SAAS,KAAK;AACZ,WAAO,EAAE,UAAU,OAAO,OAAO,OAAO,GAAG,EAAE;AAAA,EAC/C;AACA,QAAM,MAAM,KAAK,IAAI;AACrB,MAAI,IAAI,WAAW,YAAY;AAC7B,WAAO,aAAa,IAAI,KAAK,YAAY,IAAI,cAAc,GAAG;AAAA,EAChE;AAaA,MAAI,IAAI,WAAW,gBAAgB;AACjC,WAAO,EAAE,UAAU,OAAO,OAAO,mCAAmC,IAAI,QAAQ,IAAI;AAAA,EACtF;AACA,SAAO,aAAa,IAAI,KAAK,YAAY,IAAI,MAAM,IAAI,MAAM,GAAG;AAClE;","names":[]}
|