@reddoorla/maintenance 0.85.1 → 0.86.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/README.md +8 -0
- package/dist/airtable-G7WBQQMI.js +9 -0
- package/dist/{announce-GIAYN67S.js → announce-MXTUQ6C7.js} +26 -19
- package/dist/announce-MXTUQ6C7.js.map +1 -0
- package/dist/{bump-deps-SWJB6H5V.js → bump-deps-EC74CPLS.js} +9 -9
- package/dist/chunk-2EVEFOZY.js +129 -0
- package/dist/chunk-2EVEFOZY.js.map +1 -0
- package/dist/{chunk-COZPL62X.js → chunk-2NDRHXMR.js} +25 -17
- package/dist/chunk-2NDRHXMR.js.map +1 -0
- package/dist/{chunk-SDUJIANJ.js → chunk-2NJQLSEU.js} +3 -3
- package/dist/chunk-2NQUCS7O.js +243 -0
- package/dist/chunk-2NQUCS7O.js.map +1 -0
- package/dist/{chunk-QRDB4NLB.js → chunk-2ZPT7GLV.js} +43 -404
- package/dist/chunk-2ZPT7GLV.js.map +1 -0
- package/dist/{chunk-ZTPPCHDB.js → chunk-3G25KIWW.js} +4 -4
- package/dist/chunk-3SF7D4DY.js +359 -0
- package/dist/chunk-3SF7D4DY.js.map +1 -0
- package/dist/{chunk-Q276MZ7E.js → chunk-3VQWSE3F.js} +4 -4
- package/dist/{chunk-37S6L6G4.js → chunk-5UINJNAJ.js} +72 -2
- package/dist/chunk-5UINJNAJ.js.map +1 -0
- package/dist/{chunk-THEFTZ7F.js → chunk-62CMMGEO.js} +5 -5
- package/dist/{chunk-FDIFTIXC.js → chunk-6TWWY7ZU.js} +2 -2
- package/dist/{chunk-UYCAF77E.js → chunk-7RJ2HMMJ.js} +3 -3
- package/dist/chunk-ACBRLLFT.js +198 -0
- package/dist/chunk-ACBRLLFT.js.map +1 -0
- package/dist/chunk-BNM5POSJ.js +284 -0
- package/dist/chunk-BNM5POSJ.js.map +1 -0
- package/dist/{chunk-R6FPFMOS.js → chunk-BQRFQSGY.js} +3 -3
- package/dist/{chunk-MGR2H7F4.js → chunk-BYK66EWO.js} +19 -12
- package/dist/chunk-BYK66EWO.js.map +1 -0
- package/dist/{chunk-N4MOEF32.js → chunk-C6B4RHXR.js} +36 -8
- package/dist/chunk-C6B4RHXR.js.map +1 -0
- package/dist/{chunk-6QRLRT3P.js → chunk-CQR4LIM7.js} +12 -265
- package/dist/chunk-CQR4LIM7.js.map +1 -0
- package/dist/{chunk-SEEA6RXF.js → chunk-DJZWYIPP.js} +2 -2
- package/dist/chunk-DJZWYIPP.js.map +1 -0
- package/dist/chunk-EVBCK2KC.js +68 -0
- package/dist/chunk-EVBCK2KC.js.map +1 -0
- package/dist/{chunk-TP5M2NQB.js → chunk-F5KM4LEQ.js} +3 -3
- package/dist/{chunk-62VF32IC.js → chunk-ILUNZHYV.js} +2 -2
- package/dist/chunk-ITIOFN7A.js +396 -0
- package/dist/chunk-ITIOFN7A.js.map +1 -0
- package/dist/{chunk-LS6QPANO.js → chunk-IYSEC543.js} +2 -2
- package/dist/{chunk-DC5H7KEQ.js → chunk-JHGHLKFS.js} +2 -2
- package/dist/{chunk-PBWDDDQH.js → chunk-KTH5ZODA.js} +2 -2
- package/dist/{chunk-4DHQCN5H.js → chunk-LBYOLBW7.js} +17 -2
- package/dist/chunk-LBYOLBW7.js.map +1 -0
- package/dist/{chunk-577HCGZO.js → chunk-LDWZSLSU.js} +38 -23
- package/dist/chunk-LDWZSLSU.js.map +1 -0
- package/dist/{chunk-LTB6KVJW.js → chunk-N45M3FDK.js} +13 -11
- package/dist/{chunk-LTB6KVJW.js.map → chunk-N45M3FDK.js.map} +1 -1
- package/dist/chunk-NYUYNYQL.js +48 -0
- package/dist/chunk-NYUYNYQL.js.map +1 -0
- package/dist/{chunk-7J53SUT6.js → chunk-P2FE5AI6.js} +4 -4
- package/dist/{chunk-3YXDSCM6.js → chunk-PPE5KZJK.js} +29 -11
- package/dist/chunk-PPE5KZJK.js.map +1 -0
- package/dist/chunk-PTDMVGKL.js +31 -0
- package/dist/chunk-PTDMVGKL.js.map +1 -0
- package/dist/{chunk-D4FVAIEJ.js → chunk-PZR4EBPY.js} +5 -2
- package/dist/chunk-PZR4EBPY.js.map +1 -0
- package/dist/{chunk-NWB4O5EY.js → chunk-SLUQ7R6I.js} +3 -3
- package/dist/chunk-SLUQ7R6I.js.map +1 -0
- package/dist/{chunk-GZNBCHAZ.js → chunk-TERE5SDF.js} +4 -4
- package/dist/{chunk-ZMIPG6TR.js → chunk-TVL5MVUF.js} +4 -4
- package/dist/chunk-UDRHAQT7.js +172 -0
- package/dist/chunk-UDRHAQT7.js.map +1 -0
- package/dist/chunk-VAD43MOR.js +72 -0
- package/dist/chunk-VAD43MOR.js.map +1 -0
- package/dist/chunk-VSBFM7DS.js +229 -0
- package/dist/chunk-VSBFM7DS.js.map +1 -0
- package/dist/chunk-W7Z3BGCI.js +274 -0
- package/dist/chunk-W7Z3BGCI.js.map +1 -0
- package/dist/chunk-X3B723J4.js +1209 -0
- package/dist/chunk-X3B723J4.js.map +1 -0
- package/dist/{chunk-VRWUL4TR.js → chunk-XHHMM5HX.js} +2 -2
- package/dist/{chunk-RJB3QUSP.js → chunk-XIDUYLSR.js} +3 -3
- package/dist/{chunk-QG6OSL4M.js → chunk-XUGSZP7Z.js} +2 -2
- package/dist/{chunk-R4AB6GCT.js → chunk-Y53WOQIJ.js} +7 -4
- package/dist/{chunk-R4AB6GCT.js.map → chunk-Y53WOQIJ.js.map} +1 -1
- package/dist/{chunk-ICXV25N7.js → chunk-Z3KYFUN6.js} +3 -3
- package/dist/{chunk-MPBXOJ3N.js → chunk-Z7AXYKQB.js} +33 -2
- package/dist/chunk-Z7AXYKQB.js.map +1 -0
- package/dist/{chunk-6V7565O2.js → chunk-ZKXSX4LO.js} +11 -11
- package/dist/cli/bin.js +46 -28
- package/dist/cli/bin.js.map +1 -1
- package/dist/cli/commands/audit.d.ts +30 -1
- package/dist/cli/commands/audit.js +63 -31
- package/dist/cli/commands/audit.js.map +1 -1
- package/dist/client-AUE3XUPO.js +11 -0
- package/dist/configs/playwright-a11y.js +1 -1
- package/dist/configs/svelte.d.ts +30 -1
- package/dist/configs/svelte.js +9 -1
- package/dist/configs/svelte.js.map +1 -1
- package/dist/{convert-to-pnpm-AT52NWZB.js → convert-to-pnpm-6L6P74WR.js} +9 -9
- package/dist/db-B35OGV3G.js +217 -0
- package/dist/db-B35OGV3G.js.map +1 -0
- package/dist/{digest-UVHYZUYE.js → digest-BL6UJYKH.js} +23 -20
- package/dist/{digest-UVHYZUYE.js.map → digest-BL6UJYKH.js.map} +1 -1
- package/dist/dump-P6EBSIOH.js +68 -0
- package/dist/dump-P6EBSIOH.js.map +1 -0
- package/dist/email-VTTTKKL5.js +195 -0
- package/dist/email-VTTTKKL5.js.map +1 -0
- package/dist/{ensure-site-S25MDDHW.js → ensure-site-DFTB7MN3.js} +8 -7
- package/dist/ensure-site-DFTB7MN3.js.map +1 -0
- package/dist/fleet-events-cF2Om88w.d.ts +24 -0
- package/dist/{forms-notify-target-TWN4EH6K.js → forms-notify-target-75U6OU7L.js} +38 -132
- package/dist/forms-notify-target-75U6OU7L.js.map +1 -0
- package/dist/{github-signals-G4ILZAJ6.js → github-signals-IJUPGCUX.js} +40 -19
- package/dist/github-signals-IJUPGCUX.js.map +1 -0
- package/dist/{header-image-T7XD37JL.js → header-image-AWLLQA4L.js} +34 -11
- package/dist/header-image-AWLLQA4L.js.map +1 -0
- package/dist/header-images-335L2AKB.js +68 -0
- package/dist/header-images-335L2AKB.js.map +1 -0
- package/dist/{health-endpoint-242WG2OJ.js → health-endpoint-WJC2UMYS.js} +9 -9
- package/dist/health-mirror-4B2L7T2Y.js +75 -0
- package/dist/health-mirror-4B2L7T2Y.js.map +1 -0
- package/dist/import-airtable-HE43FB4H.js +35 -0
- package/dist/index.d.ts +175 -21
- package/dist/index.js +116 -74
- package/dist/index.js.map +1 -1
- package/dist/{init-TFVAN5OY.js → init-NJEOEO7I.js} +21 -18
- package/dist/{init-TFVAN5OY.js.map → init-NJEOEO7I.js.map} +1 -1
- package/dist/{launch-DWY2MF54.js → launch-XNAX427U.js} +32 -26
- package/dist/{launch-DWY2MF54.js.map → launch-XNAX427U.js.map} +1 -1
- package/dist/lighthouse-VHI77PFB.js +11 -0
- package/dist/{lighthouse-airtable-BIPM26SZ.js → lighthouse-airtable-LBVIYYP5.js} +3 -3
- package/dist/mailchimp-XYCTEEJY.js +72 -0
- package/dist/mailchimp-XYCTEEJY.js.map +1 -0
- package/dist/migrate-GQH237A6.js +7 -0
- package/dist/notify-C645PGD5.js +22 -0
- package/dist/{onboard-53CITIM7.js → onboard-GK4PHPNI.js} +9 -9
- package/dist/orchestrate-77UO4BYJ.js +30 -0
- package/dist/orchestrate-77UO4BYJ.js.map +1 -0
- package/dist/parity-MWS24A3H.js +12 -0
- package/dist/parity-MWS24A3H.js.map +1 -0
- package/dist/pipeline-S6CVHDGB.js +12 -0
- package/dist/pipeline-S6CVHDGB.js.map +1 -0
- package/dist/{preflight-3XPDUHFJ.js → preflight-6WBNU2GZ.js} +16 -13
- package/dist/{preflight-3XPDUHFJ.js.map → preflight-6WBNU2GZ.js.map} +1 -1
- package/dist/{prismic-ci-UTQ6LRR3.js → prismic-ci-3RHOZUUT.js} +15 -15
- package/dist/{prismic-models-PVES6R5V.js → prismic-models-QBGUT2Q3.js} +10 -10
- package/dist/prospect-audit-IUNCJ2LV.js +174 -0
- package/dist/prospect-audit-IUNCJ2LV.js.map +1 -0
- package/dist/prospect-audits-3PMIO73D.js +19 -0
- package/dist/prospect-audits-3PMIO73D.js.map +1 -0
- package/dist/{protection-audit-64PLLBLI.js → protection-audit-SJO53MEQ.js} +3 -3
- package/dist/recipes/sync-configs.js +3 -3
- package/dist/render-AQAVQDPZ.js +10 -0
- package/dist/render-AQAVQDPZ.js.map +1 -0
- package/dist/{renovate-dispatch-ICJGSFCE.js → renovate-dispatch-QJY75ODR.js} +8 -8
- package/dist/replay-C2LXMJZP.js +66 -0
- package/dist/replay-C2LXMJZP.js.map +1 -0
- package/dist/{report-6CKSWJNG.js → report-4EVNDHOZ.js} +55 -29
- package/dist/report-4EVNDHOZ.js.map +1 -0
- package/dist/reports/header-image/assets/headline-announcement.png +0 -0
- package/dist/reports/header-image/assets/headline-launch.png +0 -0
- package/dist/reports/header-image/assets/headline-maintenance.png +0 -0
- package/dist/reports/header-image/assets/headline-testing.png +0 -0
- package/dist/reports/header-image/assets/plate-clean.png +0 -0
- package/dist/{self-updating-PPQVV6UA.js → self-updating-6DWI2Z56.js} +9 -9
- package/dist/{selftest-CQ6NOX52.js → selftest-RC36MTKP.js} +25 -20
- package/dist/selftest-RC36MTKP.js.map +1 -0
- package/dist/smoke-B2GQOSIZ.js +20 -0
- package/dist/smoke-B2GQOSIZ.js.map +1 -0
- package/dist/{smoke-suite-OBWNPALQ.js → smoke-suite-VYY2LXM2.js} +9 -9
- package/dist/{submissions-GJ6ITBRH.js → submissions-Q7DRFOCD.js} +3 -3
- package/dist/{svelte-codemods-ZOBDHIES.js → svelte-codemods-25J2FO22.js} +9 -9
- package/dist/sync-34HNZZ56.js +44 -0
- package/dist/sync-34HNZZ56.js.map +1 -0
- package/dist/{sync-configs-CJXUX6MD.js → sync-configs-3SE6PSCO.js} +9 -9
- package/dist/{upgrade-WLX27UPC.js → upgrade-WBRQ62FX.js} +9 -9
- package/dist/{webflow-624FEBFD.js → webflow-IRKOIT7S.js} +4 -4
- package/dist/webhook-VOGOW3W6.js +38 -0
- package/dist/webhook-VOGOW3W6.js.map +1 -0
- package/dist/{websites-SADZR4XQ.js → websites-SXWTP72S.js} +6 -2
- package/dist/websites-SXWTP72S.js.map +1 -0
- package/dist/{write-audits-to-airtable-7PH75YWY.js → write-audits-to-airtable-MBEILLPU.js} +4 -4
- package/dist/write-audits-to-airtable-MBEILLPU.js.map +1 -0
- package/package.json +5 -2
- package/dist/airtable-HRKSA7V4.js +0 -9
- package/dist/announce-GIAYN67S.js.map +0 -1
- package/dist/chunk-37S6L6G4.js.map +0 -1
- package/dist/chunk-3YXDSCM6.js.map +0 -1
- package/dist/chunk-4DHQCN5H.js.map +0 -1
- package/dist/chunk-4SOCPK7A.js +0 -108
- package/dist/chunk-4SOCPK7A.js.map +0 -1
- package/dist/chunk-577HCGZO.js.map +0 -1
- package/dist/chunk-6QRLRT3P.js.map +0 -1
- package/dist/chunk-COZPL62X.js.map +0 -1
- package/dist/chunk-D4FVAIEJ.js.map +0 -1
- package/dist/chunk-MGR2H7F4.js.map +0 -1
- package/dist/chunk-MPBXOJ3N.js.map +0 -1
- package/dist/chunk-N4MOEF32.js.map +0 -1
- package/dist/chunk-NWB4O5EY.js.map +0 -1
- package/dist/chunk-QRDB4NLB.js.map +0 -1
- package/dist/chunk-SEEA6RXF.js.map +0 -1
- package/dist/chunk-U5SZ4FOP.js +0 -26
- package/dist/chunk-U5SZ4FOP.js.map +0 -1
- package/dist/client-X5WUJWDE.js +0 -11
- package/dist/db-JSIZYT23.js +0 -23
- package/dist/db-JSIZYT23.js.map +0 -1
- package/dist/ensure-site-S25MDDHW.js.map +0 -1
- package/dist/forms-notify-target-TWN4EH6K.js.map +0 -1
- package/dist/github-signals-G4ILZAJ6.js.map +0 -1
- package/dist/header-image-T7XD37JL.js.map +0 -1
- package/dist/migrate-LJUFGXQZ.js +0 -7
- package/dist/orchestrate-KDNXZQX7.js +0 -27
- package/dist/report-6CKSWJNG.js.map +0 -1
- package/dist/reports/header-image/assets/plate.png +0 -0
- package/dist/selftest-CQ6NOX52.js.map +0 -1
- /package/dist/{airtable-HRKSA7V4.js.map → airtable-G7WBQQMI.js.map} +0 -0
- /package/dist/{bump-deps-SWJB6H5V.js.map → bump-deps-EC74CPLS.js.map} +0 -0
- /package/dist/{chunk-SDUJIANJ.js.map → chunk-2NJQLSEU.js.map} +0 -0
- /package/dist/{chunk-ZTPPCHDB.js.map → chunk-3G25KIWW.js.map} +0 -0
- /package/dist/{chunk-Q276MZ7E.js.map → chunk-3VQWSE3F.js.map} +0 -0
- /package/dist/{chunk-THEFTZ7F.js.map → chunk-62CMMGEO.js.map} +0 -0
- /package/dist/{chunk-FDIFTIXC.js.map → chunk-6TWWY7ZU.js.map} +0 -0
- /package/dist/{chunk-UYCAF77E.js.map → chunk-7RJ2HMMJ.js.map} +0 -0
- /package/dist/{chunk-R6FPFMOS.js.map → chunk-BQRFQSGY.js.map} +0 -0
- /package/dist/{chunk-TP5M2NQB.js.map → chunk-F5KM4LEQ.js.map} +0 -0
- /package/dist/{chunk-62VF32IC.js.map → chunk-ILUNZHYV.js.map} +0 -0
- /package/dist/{chunk-LS6QPANO.js.map → chunk-IYSEC543.js.map} +0 -0
- /package/dist/{chunk-DC5H7KEQ.js.map → chunk-JHGHLKFS.js.map} +0 -0
- /package/dist/{chunk-PBWDDDQH.js.map → chunk-KTH5ZODA.js.map} +0 -0
- /package/dist/{chunk-7J53SUT6.js.map → chunk-P2FE5AI6.js.map} +0 -0
- /package/dist/{chunk-GZNBCHAZ.js.map → chunk-TERE5SDF.js.map} +0 -0
- /package/dist/{chunk-ZMIPG6TR.js.map → chunk-TVL5MVUF.js.map} +0 -0
- /package/dist/{chunk-VRWUL4TR.js.map → chunk-XHHMM5HX.js.map} +0 -0
- /package/dist/{chunk-RJB3QUSP.js.map → chunk-XIDUYLSR.js.map} +0 -0
- /package/dist/{chunk-QG6OSL4M.js.map → chunk-XUGSZP7Z.js.map} +0 -0
- /package/dist/{chunk-ICXV25N7.js.map → chunk-Z3KYFUN6.js.map} +0 -0
- /package/dist/{chunk-6V7565O2.js.map → chunk-ZKXSX4LO.js.map} +0 -0
- /package/dist/{client-X5WUJWDE.js.map → client-AUE3XUPO.js.map} +0 -0
- /package/dist/{convert-to-pnpm-AT52NWZB.js.map → convert-to-pnpm-6L6P74WR.js.map} +0 -0
- /package/dist/{health-endpoint-242WG2OJ.js.map → health-endpoint-WJC2UMYS.js.map} +0 -0
- /package/dist/{lighthouse-airtable-BIPM26SZ.js.map → import-airtable-HE43FB4H.js.map} +0 -0
- /package/dist/{migrate-LJUFGXQZ.js.map → lighthouse-VHI77PFB.js.map} +0 -0
- /package/dist/{orchestrate-KDNXZQX7.js.map → lighthouse-airtable-LBVIYYP5.js.map} +0 -0
- /package/dist/{websites-SADZR4XQ.js.map → migrate-GQH237A6.js.map} +0 -0
- /package/dist/{write-audits-to-airtable-7PH75YWY.js.map → notify-C645PGD5.js.map} +0 -0
- /package/dist/{onboard-53CITIM7.js.map → onboard-GK4PHPNI.js.map} +0 -0
- /package/dist/{prismic-ci-UTQ6LRR3.js.map → prismic-ci-3RHOZUUT.js.map} +0 -0
- /package/dist/{prismic-models-PVES6R5V.js.map → prismic-models-QBGUT2Q3.js.map} +0 -0
- /package/dist/{protection-audit-64PLLBLI.js.map → protection-audit-SJO53MEQ.js.map} +0 -0
- /package/dist/{renovate-dispatch-ICJGSFCE.js.map → renovate-dispatch-QJY75ODR.js.map} +0 -0
- /package/dist/{self-updating-PPQVV6UA.js.map → self-updating-6DWI2Z56.js.map} +0 -0
- /package/dist/{smoke-suite-OBWNPALQ.js.map → smoke-suite-VYY2LXM2.js.map} +0 -0
- /package/dist/{submissions-GJ6ITBRH.js.map → submissions-Q7DRFOCD.js.map} +0 -0
- /package/dist/{svelte-codemods-ZOBDHIES.js.map → svelte-codemods-25J2FO22.js.map} +0 -0
- /package/dist/{sync-configs-CJXUX6MD.js.map → sync-configs-3SE6PSCO.js.map} +0 -0
- /package/dist/{upgrade-WLX27UPC.js.map → upgrade-WBRQ62FX.js.map} +0 -0
- /package/dist/{webflow-624FEBFD.js.map → webflow-IRKOIT7S.js.map} +0 -0
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { a as AuditResult, S as Site, A as AuditName, b as RecipeResult, R as RecipeName, I as InventoryProvider } from './types-OIQZ5hWN.js';
|
|
2
2
|
export { C as ConfigName } from './types-OIQZ5hWN.js';
|
|
3
|
-
import
|
|
3
|
+
import { A as AirtableBase, a as FleetEventType } from './fleet-events-cF2Om88w.js';
|
|
4
4
|
import { F as FormType } from './types-RXY-vY-5.js';
|
|
5
5
|
export { SyncConfigsOptions, syncConfigs } from './recipes/sync-configs.js';
|
|
6
|
+
import 'airtable/lib/airtable_base.js';
|
|
6
7
|
|
|
7
8
|
type SpawnResult = {
|
|
8
9
|
code: number;
|
|
@@ -119,7 +120,15 @@ type FormSubmitOutcome = {
|
|
|
119
120
|
formPresent: true;
|
|
120
121
|
success: boolean;
|
|
121
122
|
detail?: string;
|
|
123
|
+
/** Click → success banner VISIBLE. A user-experience number: it includes the
|
|
124
|
+
* browser's own render of the banner, which no server budget governs. */
|
|
122
125
|
elapsedMs?: number;
|
|
126
|
+
/** Click → the action's POST response arrives. This is the span the site's
|
|
127
|
+
* `INGEST_TIMEOUT_MS` abort budget actually governs (it wraps the
|
|
128
|
+
* site→central fetch, which is nested inside this POST), so it — not
|
|
129
|
+
* `elapsedMs` — is what the budget check must compare against. Undefined
|
|
130
|
+
* when no POST was observed. */
|
|
131
|
+
postElapsedMs?: number;
|
|
123
132
|
} | {
|
|
124
133
|
testModeUndeclared: true;
|
|
125
134
|
};
|
|
@@ -388,13 +397,6 @@ declare function localPath(path: string, opts?: LocalPathOptions): InventoryProv
|
|
|
388
397
|
|
|
389
398
|
declare function fromJsonFile(path: string): InventoryProvider;
|
|
390
399
|
|
|
391
|
-
type AirtableConfig = {
|
|
392
|
-
apiKey: string;
|
|
393
|
-
baseId: string;
|
|
394
|
-
};
|
|
395
|
-
type AirtableBase = ReturnType<typeof openBase>;
|
|
396
|
-
declare function openBase(cfg: AirtableConfig): airtable_lib_airtable_base_js.AirtableBase;
|
|
397
|
-
|
|
398
400
|
type AirtableInventoryOptions = {
|
|
399
401
|
/**
|
|
400
402
|
* Local workdir to compute each site's path as `{workdir}/{slug}`.
|
|
@@ -407,21 +409,105 @@ type AirtableInventoryOptions = {
|
|
|
407
409
|
* Read sites from the Airtable Websites table as an InventoryProvider.
|
|
408
410
|
* Each row becomes one Site; `path` is computed as `{workdir}/{slug}`.
|
|
409
411
|
* Only LIVE `maintenance` sites that have a `url` are included — pre-launch
|
|
410
|
-
* stages ("
|
|
412
|
+
* stages ("launching" / "building", via isPreLaunch) are excluded so a
|
|
411
413
|
* not-yet-live site is never audited as production (its deploy/domain/uptime/CMS
|
|
412
414
|
* audits would fail against nothing and red its Airtable row) nor swept by other
|
|
413
415
|
* `--fleet airtable` ops; it re-enters the fleet when a Launch report flips its
|
|
414
|
-
* Status to "
|
|
416
|
+
* Status to "maintained". The production URL is exposed as `Site.deployedUrl` so
|
|
415
417
|
* the lighthouse audit can run against it with no checkout. `repoUrl` is
|
|
416
418
|
* intentionally NOT set from `url` — a clone source must come from `gitRepo`
|
|
417
419
|
* (`owner/repo`), never the production URL.
|
|
418
420
|
*/
|
|
419
421
|
declare function fromAirtableBase(base: AirtableBase, opts?: AirtableInventoryOptions): InventoryProvider;
|
|
420
422
|
|
|
423
|
+
/**
|
|
424
|
+
* The site-status vocabulary — ONE module owns it (#539 Phase 4).
|
|
425
|
+
*
|
|
426
|
+
* The fleet's lifecycle names were inherited from an Airtable single-select
|
|
427
|
+
* written by hand years ago ("probably not our problem"). The operator approved
|
|
428
|
+
* a canonical vocabulary, and the migration is now COMPLETE in both stores:
|
|
429
|
+
* Airtable's "Status" single-select carries exactly the six canonical options
|
|
430
|
+
* and nothing else. This module no longer knows the old names at all.
|
|
431
|
+
*
|
|
432
|
+
* The retired mapping, kept as the record of what was merged into what:
|
|
433
|
+
*
|
|
434
|
+
* old (retired 2026-08-25) new (canonical)
|
|
435
|
+
* ───────────────────────── ───────────────
|
|
436
|
+
* in development building
|
|
437
|
+
* launch period launching
|
|
438
|
+
* maintenance maintained
|
|
439
|
+
* hosting hosted-only
|
|
440
|
+
* probably not our problem external
|
|
441
|
+
* legacy ┐
|
|
442
|
+
* deprecated ┴ archived ← approved MERGE, many-to-one
|
|
443
|
+
*
|
|
444
|
+
* `legacy` and `deprecated` were already treated identically by every PREDICATE
|
|
445
|
+
* (ARCHIVED_STATUSES held both), so collapsing them changes no *selection* — no
|
|
446
|
+
* fleet op gains or loses a site. It is NOT true that collapsing them changes
|
|
447
|
+
* nothing at all, and one surface proved it: the cockpit's Archived lane LABELS
|
|
448
|
+
* each row with its Status cell, and canonicalizing there rendered all 12 live
|
|
449
|
+
* archived rows as "archived". That lane now labels from `statusRaw`, which is
|
|
450
|
+
* exactly why `WebsiteRow.statusRaw` exists. The rule this leaves behind:
|
|
451
|
+
* canonical values decide BEHAVIOUR; anything DISPLAYING a Status cell, or
|
|
452
|
+
* writing one back, uses the raw cell.
|
|
453
|
+
*
|
|
454
|
+
* The merge had NO clean reverse map while both vocabularies coexisted, which
|
|
455
|
+
* is why `toAirtableStatus` had to pick one archived name deliberately. With the
|
|
456
|
+
* old names retired there is nothing left to pick between, and no code path
|
|
457
|
+
* feeds operator-supplied text through it anyway (see
|
|
458
|
+
* `src/recipes/forms-notify-target.ts`, which writes `--restore` verbatim).
|
|
459
|
+
*
|
|
460
|
+
* THE SHAPE OF THE TRANSITION (three stages):
|
|
461
|
+
*
|
|
462
|
+
* stage 1 (DONE) code speaks the NEW vocabulary internally; reads canonicalize
|
|
463
|
+
* at the two Airtable/Turso seams; writes still emit the OLD
|
|
464
|
+
* Airtable option names. Airtable untouched. No SELECTION
|
|
465
|
+
* change — every predicate picks exactly the sites it picked
|
|
466
|
+
* before (pinned row-by-row in tests/reports/airtable/
|
|
467
|
+
* site-status.test.ts). Displayed labels come from `statusRaw`.
|
|
468
|
+
* stage 2 (DONE) the Airtable "Status" single-select gained the 6 new options
|
|
469
|
+
* and all 44 cells were migrated (verified live: maintained=13,
|
|
470
|
+
* archived=12, external=9, building=6, hosted-only=2,
|
|
471
|
+
* launching=2 — zero old values, zero unrecognized), `db sync`
|
|
472
|
+
* ran clean (mismatches=0), and AIRTABLE_USES_NEW_VOCABULARY
|
|
473
|
+
* flipped to true. Writers now emit canonical names verbatim.
|
|
474
|
+
* The alias map STAYS: the 7 old options still exist in the
|
|
475
|
+
* field, so a human can still pick one in the Airtable UI.
|
|
476
|
+
* stage 3 (DONE) the operator deleted the 7 old options from the Airtable
|
|
477
|
+
* "Status" field on 2026-08-25, which is what made this safe:
|
|
478
|
+
* the gate was always "no old value CAN BE ENTERED", not
|
|
479
|
+
* merely "none is stored". Verified against the live base
|
|
480
|
+
* before any code changed — the field carries exactly the six
|
|
481
|
+
* canonical choices, byte-exact, and all 44 cells still hold a
|
|
482
|
+
* canonical value with ZERO blanks (deleting a single-select
|
|
483
|
+
* option CLEARS the cells using it, so "no cell was blanked"
|
|
484
|
+
* was checked, not assumed). AIRTABLE_STATUS_ALIASES,
|
|
485
|
+
* AIRTABLE_OLD_NAMES and AIRTABLE_USES_NEW_VOCABULARY are
|
|
486
|
+
* gone; both functions reduce to the identity.
|
|
487
|
+
*
|
|
488
|
+
* WHAT CHANGED IN BEHAVIOUR AT STAGE 3, and it is the only thing that did: an
|
|
489
|
+
* old name is no longer translated. `canonicalizeStatus("maintenance")` used to
|
|
490
|
+
* yield `maintained`; it now yields `"maintenance"` verbatim, which
|
|
491
|
+
* `isUnrecognizedStatus` flags and the cockpit surfaces as a watch row. That is
|
|
492
|
+
* intended. The option cannot be selected any more, so a stored old value would
|
|
493
|
+
* mean something went wrong — a restored backup, a scripted write, an API
|
|
494
|
+
* caller with a stale constant — and the fleet should say so rather than absorb
|
|
495
|
+
* it into a status nobody chose.
|
|
496
|
+
*
|
|
497
|
+
* Canonicalization happens on READ, never at rest: `src/db/import-airtable.ts`
|
|
498
|
+
* still stores the raw Airtable cell verbatim in `sites.status`, so the hourly
|
|
499
|
+
* parity check keeps comparing raw-to-raw and the importer stays honest to its
|
|
500
|
+
* source. Both readers — `mapRow` (Airtable) and `rowFromJoined` (Turso) — run
|
|
501
|
+
* the raw value through `canonicalizeStatus`, which is what keeps the #558
|
|
502
|
+
* reader-equivalence instrument green.
|
|
503
|
+
*/
|
|
504
|
+
/** The canonical site lifecycle vocabulary. */
|
|
505
|
+
type Status = "building" | "launching" | "maintained" | "hosted-only" | "external" | "archived";
|
|
506
|
+
|
|
421
507
|
type Frequency = "None" | "Monthly" | "Quarterly" | "Yearly";
|
|
422
|
-
|
|
508
|
+
|
|
423
509
|
/**
|
|
424
|
-
* Per-site notification routing. When present on a `
|
|
510
|
+
* Per-site notification routing. When present on a `maintained` site, the form
|
|
425
511
|
* notification is addressed by the value of a submission field (`field`, read from
|
|
426
512
|
* `extraFields`) — e.g. route a contact form's `interest` to a different recipient
|
|
427
513
|
* per option, always CC-ing a shared address. Absent (`null`) → the site keeps the
|
|
@@ -443,7 +529,17 @@ type WebsiteRow = {
|
|
|
443
529
|
id: string;
|
|
444
530
|
name: string;
|
|
445
531
|
url: string;
|
|
532
|
+
/** Canonical lifecycle status (see ./site-status.ts). Canonicalized at the read
|
|
533
|
+
* boundary, so an old-vocabulary Airtable cell and a new one read identically.
|
|
534
|
+
* A present-but-unrecognized cell survives VERBATIM (blind-cast) rather than
|
|
535
|
+
* becoming null — `isUnrecognizedStatus` flags it, and null would make
|
|
536
|
+
* due.ts/preflight.ts treat the row as eligible-by-default. */
|
|
446
537
|
status: Status | null;
|
|
538
|
+
/** The literal Airtable Status cell behind `status` — same pattern as
|
|
539
|
+
* `maintenanceFreqRaw`. The dashboard status editor round-trips THIS, so its
|
|
540
|
+
* dropdown offers and preselects the values Airtable actually holds while the
|
|
541
|
+
* two vocabularies coexist. Null = blank cell. */
|
|
542
|
+
statusRaw: string | null;
|
|
447
543
|
pointOfContact: string | null;
|
|
448
544
|
maintenanceFreq: Frequency;
|
|
449
545
|
testingFreq: Frequency;
|
|
@@ -670,6 +766,18 @@ type WebsiteRow = {
|
|
|
670
766
|
*/
|
|
671
767
|
prismicAckUntil: string | null;
|
|
672
768
|
notifyRouting: NotifyRouting | null;
|
|
769
|
+
/** The RAW `Notify Routing` cell, verbatim. Same reason `statusRaw` exists: the
|
|
770
|
+
* dashboard editor round-trips this JSON, and re-serializing the PARSED object
|
|
771
|
+
* would drop any key the parser ignores and reformat what the operator typed —
|
|
772
|
+
* a silent rewrite of a cell they only opened to look at. */
|
|
773
|
+
notifyRoutingRaw: string | null;
|
|
774
|
+
/** Read-back of the code-owned next-due dates (date-only, written by the
|
|
775
|
+
* nightly `writeNextDueDates`). These exist so the writer can DIFF the
|
|
776
|
+
* freshly-computed dates against what the row already holds and skip the
|
|
777
|
+
* ~31 no-op writes a night the fleet was paying for (#539 Phase 3). Null =
|
|
778
|
+
* cell blank or the operator-added `Next … at` column absent. */
|
|
779
|
+
nextMaintenanceAt: string | null;
|
|
780
|
+
nextTestingAt: string | null;
|
|
673
781
|
};
|
|
674
782
|
/** The `Prismic Models` cell — see {@link WebsiteRow.prismicModels} for why it
|
|
675
783
|
* carries a third state that no other verdict column in this table has. */
|
|
@@ -884,7 +992,9 @@ type RefreshHeaderDeps = {
|
|
|
884
992
|
url: string;
|
|
885
993
|
slug?: string;
|
|
886
994
|
}) => Promise<GeneratedHeaderImage>;
|
|
887
|
-
upload?: (recordId: string, field: string, bytes: Uint8Array, filename: string, contentType: string
|
|
995
|
+
upload?: (recordId: string, field: string, bytes: Uint8Array, filename: string, contentType: string, opts?: {
|
|
996
|
+
replaceIn?: string;
|
|
997
|
+
}) => Promise<void>;
|
|
888
998
|
};
|
|
889
999
|
type DraftOptions = {
|
|
890
1000
|
/** Where to write the local preview HTML when `previewOnly`. Defaults to `reports/<slug>/draft.html`. */
|
|
@@ -1145,8 +1255,6 @@ type AttentionItem = {
|
|
|
1145
1255
|
autoFixExhausted?: boolean;
|
|
1146
1256
|
};
|
|
1147
1257
|
|
|
1148
|
-
type FleetEventType = "pr_automerged" | "vuln_cleared" | "ci_recovered" | "site_launched" | "fleet_swept" | "cert_renewed" | "report_sent_with_override";
|
|
1149
|
-
|
|
1150
1258
|
type Tier = "attention" | "watch" | "healthy" | "pre-launch";
|
|
1151
1259
|
type SiteCard = {
|
|
1152
1260
|
site: WebsiteRow;
|
|
@@ -1191,7 +1299,7 @@ type CockpitSummary = {
|
|
|
1191
1299
|
attention: number;
|
|
1192
1300
|
watch: number;
|
|
1193
1301
|
healthy: number;
|
|
1194
|
-
/** Count of pre-live "
|
|
1302
|
+
/** Count of pre-live "launching" sites still muted as expected pre-launch
|
|
1195
1303
|
* conditions. A piercing alarm (piercesPreLaunchMute) re-tiers such a site to
|
|
1196
1304
|
* attention, so it counts there instead — muted never means "hidden if broken". */
|
|
1197
1305
|
preLaunch: number;
|
|
@@ -1221,7 +1329,15 @@ type RecentEntry = {
|
|
|
1221
1329
|
ts: string;
|
|
1222
1330
|
};
|
|
1223
1331
|
/** A Websites row surfaced OUTSIDE the fleet cards: archived (legacy/deprecated)
|
|
1224
|
-
* or holding an unrecognized Status cell.
|
|
1332
|
+
* or holding an unrecognized Status cell.
|
|
1333
|
+
*
|
|
1334
|
+
* `status` is the RAW Airtable cell, not the canonical status (#539 Phase 4).
|
|
1335
|
+
* These two lanes exist to mirror what Airtable holds so a row can never
|
|
1336
|
+
* silently vanish, and both of them survive on the distinction the canonical
|
|
1337
|
+
* vocabulary erases: `legacy` and `deprecated` both canonicalize to `archived`,
|
|
1338
|
+
* so labelling the lane canonically would render 12 live rows identically and
|
|
1339
|
+
* disagree with the cell the operator is looking at. Everything else about
|
|
1340
|
+
* these rows — which lane they land in — is decided canonically. */
|
|
1225
1341
|
type OffFleetSiteEntry = {
|
|
1226
1342
|
name: string;
|
|
1227
1343
|
slug: string;
|
|
@@ -1268,7 +1384,7 @@ type SiteAlarmContext = {
|
|
|
1268
1384
|
* fetches data, then hands it here. Easier to unit-test, easier to render
|
|
1269
1385
|
* a static preview from CLI later.
|
|
1270
1386
|
*/
|
|
1271
|
-
declare function renderSiteDashboardHtml(site: WebsiteRow, reports: ReportRow[], submissions?: SubmissionRow[], spamTotals?: ScreenOutTotals | null, now?: Date, alarm?: SiteAlarmContext | null): string;
|
|
1387
|
+
declare function renderSiteDashboardHtml(site: WebsiteRow, reports: ReportRow[], submissions?: SubmissionRow[], spamTotals?: ScreenOutTotals | null, now?: Date, alarm?: SiteAlarmContext | null, operatorEmail?: string | null): string;
|
|
1272
1388
|
|
|
1273
1389
|
/**
|
|
1274
1390
|
* Render the fleet cockpit as a single HTML document. Pure function: no Airtable
|
|
@@ -1277,7 +1393,7 @@ declare function renderSiteDashboardHtml(site: WebsiteRow, reports: ReportRow[],
|
|
|
1277
1393
|
* and hands it here. Renders the doc shell + verdict bar + the per-site Needs-you
|
|
1278
1394
|
* feed + the collapsed Fleet browse panel (one flat, filterable card grid).
|
|
1279
1395
|
*/
|
|
1280
|
-
declare function renderCockpitHtml(model: CockpitModel): string;
|
|
1396
|
+
declare function renderCockpitHtml(model: CockpitModel, operatorEmail?: string | null): string;
|
|
1281
1397
|
|
|
1282
1398
|
/**
|
|
1283
1399
|
* Verify an `Authorization: Basic <base64>` header against the configured
|
|
@@ -1300,7 +1416,45 @@ declare function renderCockpitHtml(model: CockpitModel): string;
|
|
|
1300
1416
|
*/
|
|
1301
1417
|
declare function verifyBasicAuth(authHeader: string | null | undefined, expectedPassword: string | null): boolean;
|
|
1302
1418
|
|
|
1303
|
-
/**
|
|
1419
|
+
/** Per-report-type headline overlays, stamped over the CLEAN plate at send time
|
|
1420
|
+
* (see orchestrate.ts). Types with no entry go out on the clean plate.
|
|
1421
|
+
*
|
|
1422
|
+
* Source: Figma "Web-Maintenance-Email" (mQ3hy2d9JnOG9ljCzbZS8j) —
|
|
1423
|
+
* Maintenance is node 158:15, Testing is 153:721 ("maintenance & testing",
|
|
1424
|
+
* which is what a Testing report actually covers). Export each at 4x; Figma
|
|
1425
|
+
* crops a text export to its ink box, which is why these are 1328x660 /
|
|
1426
|
+
* 1715x664 rather than the 1840x720 text box.
|
|
1427
|
+
*
|
|
1428
|
+
* ⚠️ A Figma MCP `download_assets` export arrives FLATTENED — never
|
|
1429
|
+
* transparent — and it flattens onto WHATEVER SITS BEHIND THE NODE, which is
|
|
1430
|
+
* not one fixed colour: Maintenance/Testing live inside a white Header frame
|
|
1431
|
+
* and come back on white, while Announcement/Launch sit on the bare canvas and
|
|
1432
|
+
* come back on Figma's canvas grey (30,30,30). Stamping either unprocessed
|
|
1433
|
+
* paints a solid slab over the paper texture — that, not a bad design file, is
|
|
1434
|
+
* what made the 2026-08-20 Testing asset unusable.
|
|
1435
|
+
*
|
|
1436
|
+
* Recover the alpha instead of re-exporting by hand: for ink C over backdrop B,
|
|
1437
|
+
* a = (px - B) / (C - B). DETECT B (the export's most common colour) rather
|
|
1438
|
+
* than assuming white, and pick the channel with the largest |C - B| — green
|
|
1439
|
+
* separates the brand red from white by 221 levels but from canvas grey by only
|
|
1440
|
+
* 4, which would quantise the alpha to noise. Verified against the known-good
|
|
1441
|
+
* Maintenance asset at mean abs alpha diff 0.022, 0.0037% of pixels off by
|
|
1442
|
+
* more than 8.
|
|
1443
|
+
*
|
|
1444
|
+
* Editing this copy needs Figma desktop, not the Plugin API: `characters`
|
|
1445
|
+
* requires loadFontAsync and the MCP font environment carries no Helvetica at
|
|
1446
|
+
* all, so the licensed Helvetica Neue LT Std can never load there. */
|
|
1447
|
+
declare const HEADLINE_FILES: {
|
|
1448
|
+
readonly Maintenance: "headline-maintenance.png";
|
|
1449
|
+
readonly Testing: "headline-testing.png";
|
|
1450
|
+
readonly Announcement: "headline-announcement.png";
|
|
1451
|
+
readonly Launch: "headline-launch.png";
|
|
1452
|
+
};
|
|
1453
|
+
type HeadlineKind = keyof typeof HEADLINE_FILES;
|
|
1454
|
+
/** Read the bundled 2400x3200 CLEAN plate (no headline — the report type's
|
|
1455
|
+
* headline is stamped at send time, so one stored image serves every type). */
|
|
1304
1456
|
declare function loadPlate(): Promise<Uint8Array>;
|
|
1457
|
+
/** Read a headline overlay (transparent PNG, ink-box cropped). */
|
|
1458
|
+
declare function loadHeadline(kind: HeadlineKind): Promise<Uint8Array>;
|
|
1305
1459
|
|
|
1306
|
-
export { ALL_AUDIT_NAMES, ALL_RECIPE_NAMES, type AirtableInventoryOptions, AuditName, AuditResult, BLURRED_CID, type BumpDepsOptions, type BundledImage, CHECK_CID, type ConvertToPnpmOptions, DEFAULT_INIT_STEPS, type DraftOptions, type DraftResult, type DueItem, type GenerateInput, type GeneratedHeaderImage, type HeaderImage, type InitOptions, type InitResult, type InitStep, type InitStepResult, InventoryProvider, type LighthouseScores, type LocalPathOptions, type OnboardAudit, type OnboardOptions, type OrchestrateOptions, RecipeName, RecipeResult, type RefreshHeaderDeps, type RenderResult, type ReportData, type ReportType, Site, type UpgradeSvelte4to5Options, a11yAudit, a11yFixturesPage, bumpDeps, convertToPnpm, depsAudit, domainFromUrl, draftReportForSite, findDueReports, fromAirtableBase, fromJsonFile, generateHeaderImage, init, isRecipeName, lighthouseAudit, lintAudit, loadBundledImages, loadPlate, localPath, onboard, renderCockpitHtml, renderReportHtml, renderSiteDashboardHtml, runAudits, runAuditsAcross, securityAudit, selfCaretRange, selfPackageVersion, sendApprovedReports, svelteCodemods, upgradeSvelte4to5, verifyBasicAuth };
|
|
1460
|
+
export { ALL_AUDIT_NAMES, ALL_RECIPE_NAMES, type AirtableInventoryOptions, AuditName, AuditResult, BLURRED_CID, type BumpDepsOptions, type BundledImage, CHECK_CID, type ConvertToPnpmOptions, DEFAULT_INIT_STEPS, type DraftOptions, type DraftResult, type DueItem, type GenerateInput, type GeneratedHeaderImage, type HeaderImage, type InitOptions, type InitResult, type InitStep, type InitStepResult, InventoryProvider, type LighthouseScores, type LocalPathOptions, type OnboardAudit, type OnboardOptions, type OrchestrateOptions, RecipeName, RecipeResult, type RefreshHeaderDeps, type RenderResult, type ReportData, type ReportType, Site, type UpgradeSvelte4to5Options, a11yAudit, a11yFixturesPage, bumpDeps, convertToPnpm, depsAudit, domainFromUrl, draftReportForSite, findDueReports, fromAirtableBase, fromJsonFile, generateHeaderImage, init, isRecipeName, lighthouseAudit, lintAudit, loadBundledImages, loadHeadline, loadPlate, localPath, onboard, renderCockpitHtml, renderReportHtml, renderSiteDashboardHtml, runAudits, runAuditsAcross, securityAudit, selfCaretRange, selfPackageVersion, sendApprovedReports, svelteCodemods, upgradeSvelte4to5, verifyBasicAuth };
|
package/dist/index.js
CHANGED
|
@@ -1,113 +1,125 @@
|
|
|
1
1
|
import "./chunk-2SLED3NB.js";
|
|
2
|
-
import "./chunk-
|
|
2
|
+
import "./chunk-F5KM4LEQ.js";
|
|
3
3
|
import {
|
|
4
|
-
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import {
|
|
7
|
-
DEFAULT_INIT_STEPS,
|
|
8
|
-
a11yFixturesPage,
|
|
9
|
-
init
|
|
10
|
-
} from "./chunk-6V7565O2.js";
|
|
4
|
+
draftReportForSite
|
|
5
|
+
} from "./chunk-BYK66EWO.js";
|
|
11
6
|
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
selfPackageVersion
|
|
15
|
-
} from "./chunk-UYCAF77E.js";
|
|
7
|
+
approveBlockers
|
|
8
|
+
} from "./chunk-N45M3FDK.js";
|
|
16
9
|
import {
|
|
17
10
|
findDueReports
|
|
18
|
-
} from "./chunk-
|
|
19
|
-
import {
|
|
20
|
-
draftReportForSite
|
|
21
|
-
} from "./chunk-MGR2H7F4.js";
|
|
22
|
-
import "./chunk-62VF32IC.js";
|
|
23
|
-
import {
|
|
24
|
-
domainFromUrl,
|
|
25
|
-
generateHeaderImage,
|
|
26
|
-
loadPlate
|
|
27
|
-
} from "./chunk-37S6L6G4.js";
|
|
11
|
+
} from "./chunk-PZR4EBPY.js";
|
|
28
12
|
import {
|
|
29
13
|
upgradeSvelte4to5
|
|
30
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-Z3KYFUN6.js";
|
|
15
|
+
import {
|
|
16
|
+
DEFAULT_INIT_STEPS,
|
|
17
|
+
a11yFixturesPage,
|
|
18
|
+
init
|
|
19
|
+
} from "./chunk-ZKXSX4LO.js";
|
|
31
20
|
import {
|
|
32
21
|
convertToPnpm
|
|
33
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-XIDUYLSR.js";
|
|
34
23
|
import {
|
|
35
24
|
svelteCodemods
|
|
36
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-IYSEC543.js";
|
|
37
26
|
import "./chunk-J7SZQUCW.js";
|
|
38
|
-
import "./chunk-
|
|
39
|
-
import "./chunk-
|
|
27
|
+
import "./chunk-BQRFQSGY.js";
|
|
28
|
+
import "./chunk-Y53WOQIJ.js";
|
|
29
|
+
import {
|
|
30
|
+
onboard,
|
|
31
|
+
selfCaretRange,
|
|
32
|
+
selfPackageVersion
|
|
33
|
+
} from "./chunk-7RJ2HMMJ.js";
|
|
34
|
+
import "./chunk-ILUNZHYV.js";
|
|
35
|
+
import {
|
|
36
|
+
bumpDeps
|
|
37
|
+
} from "./chunk-2NJQLSEU.js";
|
|
40
38
|
import "./chunk-R53VL3RI.js";
|
|
39
|
+
import {
|
|
40
|
+
fromAirtableBase
|
|
41
|
+
} from "./chunk-SLUQ7R6I.js";
|
|
41
42
|
import {
|
|
42
43
|
parseAddresses,
|
|
43
44
|
sendApprovedReports,
|
|
44
45
|
withGlobalCc
|
|
45
|
-
} from "./chunk-
|
|
46
|
+
} from "./chunk-2NDRHXMR.js";
|
|
46
47
|
import "./chunk-GECESMVS.js";
|
|
48
|
+
import {
|
|
49
|
+
domainFromUrl,
|
|
50
|
+
generateHeaderImage,
|
|
51
|
+
loadHeadline,
|
|
52
|
+
loadPlate
|
|
53
|
+
} from "./chunk-5UINJNAJ.js";
|
|
47
54
|
import {
|
|
48
55
|
BLURRED_CID,
|
|
49
56
|
CHECK_CID,
|
|
50
|
-
checklistFor,
|
|
51
|
-
gatingFields,
|
|
52
|
-
isHealthGateClear,
|
|
53
|
-
isPendingApproval,
|
|
54
57
|
loadBundledImages,
|
|
55
58
|
renderReportHtml
|
|
56
|
-
} from "./chunk-
|
|
57
|
-
import "./chunk-
|
|
59
|
+
} from "./chunk-CQR4LIM7.js";
|
|
60
|
+
import "./chunk-Z7AXYKQB.js";
|
|
58
61
|
import {
|
|
59
62
|
escapeHtml,
|
|
60
63
|
safeUrl
|
|
61
|
-
} from "./chunk-
|
|
62
|
-
import "./chunk-WEKL2HYJ.js";
|
|
64
|
+
} from "./chunk-DJZWYIPP.js";
|
|
63
65
|
import {
|
|
64
|
-
|
|
65
|
-
} from "./chunk-
|
|
66
|
+
isPendingApproval
|
|
67
|
+
} from "./chunk-ACBRLLFT.js";
|
|
68
|
+
import {
|
|
69
|
+
checklistFor,
|
|
70
|
+
gatingFields,
|
|
71
|
+
isHealthGateClear
|
|
72
|
+
} from "./chunk-VAD43MOR.js";
|
|
73
|
+
import "./chunk-HN6I2XWI.js";
|
|
74
|
+
import "./chunk-WEKL2HYJ.js";
|
|
75
|
+
import "./chunk-NYUYNYQL.js";
|
|
66
76
|
import {
|
|
67
77
|
syncConfigs
|
|
68
|
-
} from "./chunk-
|
|
78
|
+
} from "./chunk-3VQWSE3F.js";
|
|
79
|
+
import "./chunk-3G25KIWW.js";
|
|
69
80
|
import "./chunk-73UFRZKY.js";
|
|
70
|
-
import "./chunk-ZTPPCHDB.js";
|
|
71
81
|
import "./chunk-OTGB6YQO.js";
|
|
72
82
|
import {
|
|
73
83
|
ALL_AUDIT_NAMES,
|
|
74
84
|
a11yAudit,
|
|
75
85
|
depsAudit,
|
|
76
|
-
lighthouseAudit,
|
|
77
86
|
lintAudit,
|
|
78
87
|
runAudits,
|
|
79
88
|
runAuditsAcross,
|
|
80
89
|
securityAudit
|
|
81
|
-
} from "./chunk-
|
|
90
|
+
} from "./chunk-2ZPT7GLV.js";
|
|
82
91
|
import "./chunk-LKGVSM2O.js";
|
|
83
92
|
import "./chunk-GASBX52O.js";
|
|
84
|
-
import "./chunk-
|
|
85
|
-
import "./chunk-QG6OSL4M.js";
|
|
86
|
-
import "./chunk-DC5H7KEQ.js";
|
|
87
|
-
import "./chunk-4SOCPK7A.js";
|
|
93
|
+
import "./chunk-XHHMM5HX.js";
|
|
88
94
|
import {
|
|
89
95
|
fromJsonFile,
|
|
90
96
|
localPath
|
|
91
|
-
} from "./chunk-
|
|
92
|
-
import "./chunk-
|
|
97
|
+
} from "./chunk-6TWWY7ZU.js";
|
|
98
|
+
import "./chunk-XUGSZP7Z.js";
|
|
99
|
+
import "./chunk-EVBCK2KC.js";
|
|
100
|
+
import "./chunk-JHGHLKFS.js";
|
|
101
|
+
import "./chunk-3SF7D4DY.js";
|
|
93
102
|
import "./chunk-A3WDWNN5.js";
|
|
94
103
|
import {
|
|
95
104
|
isLeadFormType
|
|
96
105
|
} from "./chunk-2OP4JKIQ.js";
|
|
97
|
-
import "./chunk-XXTZBPUY.js";
|
|
98
106
|
import "./chunk-XTK5VIQB.js";
|
|
99
107
|
import {
|
|
100
|
-
|
|
101
|
-
} from "./chunk-
|
|
102
|
-
import "./chunk-
|
|
108
|
+
lighthouseAudit
|
|
109
|
+
} from "./chunk-2NQUCS7O.js";
|
|
110
|
+
import "./chunk-UDRHAQT7.js";
|
|
111
|
+
import "./chunk-PTDMVGKL.js";
|
|
112
|
+
import "./chunk-LBYOLBW7.js";
|
|
113
|
+
import "./chunk-XXTZBPUY.js";
|
|
103
114
|
import {
|
|
115
|
+
CANONICAL_STATUSES,
|
|
104
116
|
SEVERITY_RANK,
|
|
105
|
-
siteSlug
|
|
106
|
-
|
|
107
|
-
|
|
117
|
+
siteSlug,
|
|
118
|
+
toAirtableStatus
|
|
119
|
+
} from "./chunk-LDWZSLSU.js";
|
|
108
120
|
import "./chunk-6VAL7XJT.js";
|
|
109
121
|
import "./chunk-NMAWXBJA.js";
|
|
110
|
-
import "./chunk-
|
|
122
|
+
import "./chunk-C6B4RHXR.js";
|
|
111
123
|
|
|
112
124
|
// src/recipes/index.ts
|
|
113
125
|
var ALL_RECIPE_NAMES = [
|
|
@@ -128,6 +140,16 @@ function isRecipeName(value) {
|
|
|
128
140
|
return ALL_RECIPE_NAMES.includes(value);
|
|
129
141
|
}
|
|
130
142
|
|
|
143
|
+
// src/dashboard/favicon.ts
|
|
144
|
+
var REDDOOR_FAVICON_PNG_BASE64 = "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAACXBIWXMAAAAnAAAAJwEqCZFPAAAAk1BMVEVHcEzkGTfjGDbjGTfjGTfjGTfjGTfjGDbjGDbjGTfjGTfjGTfkGTfjGTfjGDbjGDbkGTfjGDbjGDbjGTfjGTfjGDbjGTfjGDbjGTfjGDbjGTfjGTfjGDbjGDbjGDbjGDbjGTfjGTbjGDbjGDbjGDbjGDbjGTfjGTfjGTfjGDbjGDbjGTfjGDbjGDbjGTfjGTbkGTfxxbwzAAAALXRSTlMA4DABMOD8cOBwDltwi+bFLMlk54/BDVPk/I61/u2cFaBw9nqO1izBIQE+Becdo6eEAAABBElEQVQ4y91SCVYCMQwt4kxbcEHFfUFFcMGf9P6nM0kXEPEAmtdJs+cnU+f+He2fIIEAYuVgkmvDfTG9Rh+6LoRBUBqE7gi09l9eAeeTrZJoFd5uQWfj4VbPvRqwmj9zfzP6CYpyi48F6HW5A3WuMHsEPsfvO8cSkMPTe+pfRr/MTckdg+4enqL3PkYf/YFIqiiP8VAw6EZkH6QEO0xJLUhmdbY5+TjHkCVohprlcpzlnJw9GlNkrZC16uCmWIaAZItNrT4xV0T2yxrIWoNKy4rdVXOq0MycWp4r43FOMQWciibMYaOHCXKSPhapqTupGFAnwHoVuUUZq7jaSkqDb0/uD9MXqvJMDtU7lL0AAAAASUVORK5CYII=";
|
|
145
|
+
var FAVICON_LINK = `<link rel="icon" type="image/png" href="data:image/png;base64,${REDDOOR_FAVICON_PNG_BASE64}" />`;
|
|
146
|
+
|
|
147
|
+
// src/dashboard/auth/render.ts
|
|
148
|
+
function renderAuthChrome(email) {
|
|
149
|
+
if (!email) return "";
|
|
150
|
+
return `<div style="float:right;font-size:0.8rem;color:#666">${escapeHtml(email)} \xB7 <a href="/auth/logout">sign out</a></div>`;
|
|
151
|
+
}
|
|
152
|
+
|
|
131
153
|
// src/dashboard/relative-time.ts
|
|
132
154
|
function relativeTimeFromNow(iso, now = /* @__PURE__ */ new Date()) {
|
|
133
155
|
if (!iso) return "\u2014";
|
|
@@ -147,10 +169,6 @@ function relativeTimeFromNow(iso, now = /* @__PURE__ */ new Date()) {
|
|
|
147
169
|
return `${months}mo ago`;
|
|
148
170
|
}
|
|
149
171
|
|
|
150
|
-
// src/dashboard/favicon.ts
|
|
151
|
-
var REDDOOR_FAVICON_PNG_BASE64 = "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAACXBIWXMAAAAnAAAAJwEqCZFPAAAAk1BMVEVHcEzkGTfjGDbjGTfjGTfjGTfjGTfjGDbjGDbjGTfjGTfjGTfkGTfjGTfjGDbjGDbkGTfjGDbjGDbjGTfjGTfjGDbjGTfjGDbjGTfjGDbjGTfjGTfjGDbjGDbjGDbjGDbjGTfjGTbjGDbjGDbjGDbjGDbjGTfjGTfjGTfjGDbjGDbjGTfjGDbjGDbjGTfjGTbkGTfxxbwzAAAALXRSTlMA4DABMOD8cOBwDltwi+bFLMlk54/BDVPk/I61/u2cFaBw9nqO1izBIQE+Becdo6eEAAABBElEQVQ4y91SCVYCMQwt4kxbcEHFfUFFcMGf9P6nM0kXEPEAmtdJs+cnU+f+He2fIIEAYuVgkmvDfTG9Rh+6LoRBUBqE7gi09l9eAeeTrZJoFd5uQWfj4VbPvRqwmj9zfzP6CYpyi48F6HW5A3WuMHsEPsfvO8cSkMPTe+pfRr/MTckdg+4enqL3PkYf/YFIqiiP8VAw6EZkH6QEO0xJLUhmdbY5+TjHkCVohprlcpzlnJw9GlNkrZC16uCmWIaAZItNrT4xV0T2yxrIWoNKy4rdVXOq0MycWp4r43FOMQWciibMYaOHCXKSPhapqTupGFAnwHoVuUUZq7jaSkqDb0/uD9MXqvJMDtU7lL0AAAAASUVORK5CYII=";
|
|
152
|
-
var FAVICON_LINK = `<link rel="icon" type="image/png" href="data:image/png;base64,${REDDOOR_FAVICON_PNG_BASE64}" />`;
|
|
153
|
-
|
|
154
172
|
// src/dashboard/onboarding.ts
|
|
155
173
|
function isNonEmpty(s) {
|
|
156
174
|
return typeof s === "string" && s.trim().length > 0;
|
|
@@ -294,14 +312,7 @@ var SUBMISSION_STATUS_SCRIPT = `document.querySelectorAll("button.subm-status").
|
|
|
294
312
|
});`;
|
|
295
313
|
|
|
296
314
|
// src/dashboard/site-details.ts
|
|
297
|
-
var SITE_STATUS_OPTIONS =
|
|
298
|
-
"in development",
|
|
299
|
-
"launch period",
|
|
300
|
-
"maintenance",
|
|
301
|
-
"hosting",
|
|
302
|
-
"probably not our problem",
|
|
303
|
-
"deprecated"
|
|
304
|
-
];
|
|
315
|
+
var SITE_STATUS_OPTIONS = CANONICAL_STATUSES.map(toAirtableStatus);
|
|
305
316
|
var FREQ_OPTIONS = ["None", "Monthly", "Quarterly", "Yearly"];
|
|
306
317
|
|
|
307
318
|
// src/dashboard/render.ts
|
|
@@ -476,8 +487,8 @@ function gaUsersCell(r) {
|
|
|
476
487
|
const current = String(r.gaUsersCurrent);
|
|
477
488
|
if (r.gaUsersPrevious === null) return escapeHtml(current);
|
|
478
489
|
const delta = r.gaUsersCurrent - r.gaUsersPrevious;
|
|
479
|
-
const
|
|
480
|
-
return `${escapeHtml(current)} <span class="muted">(${escapeHtml(`${
|
|
490
|
+
const sign2 = delta > 0 ? "+" : "";
|
|
491
|
+
return `${escapeHtml(current)} <span class="muted">(${escapeHtml(`${sign2}${delta}`)})</span>`;
|
|
481
492
|
}
|
|
482
493
|
function searchCell(r) {
|
|
483
494
|
if (r.searchFoundPage1 && r.searchPosition !== null) {
|
|
@@ -575,6 +586,9 @@ function selectRow(label, field, options, current, url) {
|
|
|
575
586
|
function inputRow(label, field, value, url) {
|
|
576
587
|
return `<div class="detail"><dt><label for="detail-${field}">${escapeHtml(label)}</label></dt><dd><input type="text" id="detail-${field}" data-detail-field="${field}" data-details-url="${url}" value="${escapeHtml(value ?? "")}" />${savedSpan(field)}</dd></div>`;
|
|
577
588
|
}
|
|
589
|
+
function dateRow(label, field, value, url) {
|
|
590
|
+
return `<div class="detail"><dt><label for="detail-${field}">${escapeHtml(label)}</label></dt><dd><input type="date" id="detail-${field}" data-detail-field="${field}" data-details-url="${url}" value="${escapeHtml(value ?? "")}" />${savedSpan(field)}</dd></div>`;
|
|
591
|
+
}
|
|
578
592
|
function textareaRow(label, field, value, url) {
|
|
579
593
|
return `<div class="detail wide"><dt><label for="detail-${field}">${escapeHtml(label)}</label></dt><dd><textarea id="detail-${field}" data-detail-field="${field}" data-details-url="${url}">${escapeHtml(value ?? "")}</textarea>${savedSpan(field)}</dd></div>`;
|
|
580
594
|
}
|
|
@@ -582,7 +596,11 @@ function siteDetailsSection(site) {
|
|
|
582
596
|
const url = `/api/sites/${escapeHtml(siteSlug(site.name))}/details`;
|
|
583
597
|
const lastCommit = site.lastCommitAt ? `${relativeTimeFromNow(site.lastCommitAt)}` : null;
|
|
584
598
|
const rows = [
|
|
585
|
-
|
|
599
|
+
// `statusRaw`, not `status`: this select's options ARE the Airtable cell
|
|
600
|
+
// values (see SITE_STATUS_OPTIONS), so it must preselect against the raw cell.
|
|
601
|
+
// Comparing the canonical value would mis-preselect every site, and would show
|
|
602
|
+
// a "legacy" site as "deprecated" instead of the placeholder.
|
|
603
|
+
selectRow("Status", "status", SITE_STATUS_OPTIONS, site.statusRaw, url),
|
|
586
604
|
selectRow("Maintenance cadence", "maintenanceFreq", FREQ_OPTIONS, site.maintenanceFreq, url),
|
|
587
605
|
selectRow("Testing cadence", "testingFreq", FREQ_OPTIONS, site.testingFreq, url),
|
|
588
606
|
inputRow("Report recipients (To)", "reportRecipientsTo", site.reportRecipientsTo, url),
|
|
@@ -591,6 +609,18 @@ function siteDetailsSection(site) {
|
|
|
591
609
|
inputRow("GA4 property", "ga4PropertyId", site.ga4PropertyId, url),
|
|
592
610
|
inputRow("Search query", "searchQuery", site.searchQuery, url),
|
|
593
611
|
inputRow("Git repo", "gitRepo", site.gitRepo, url),
|
|
612
|
+
// #539 Phase 4 — the fields nothing rendered before. `Mailchimp API Key` is
|
|
613
|
+
// the one field in that group still absent, and deliberately: it is a live
|
|
614
|
+
// credential and every row here emits its stored value into the page.
|
|
615
|
+
inputRow("Netlify ID", "netlifyId", site.netlifyId, url),
|
|
616
|
+
inputRow("Search Console property", "searchConsoleProperty", site.searchConsoleProperty, url),
|
|
617
|
+
inputRow("Newsletter webhook", "newsletterWebhook", site.newsletterWebhook, url),
|
|
618
|
+
inputRow("Mailchimp audience ID", "mailchimpAudienceId", site.mailchimpAudienceId, url),
|
|
619
|
+
dateRow("Last maintenance day", "maintenanceDay", site.maintenanceDay, url),
|
|
620
|
+
dateRow("Last testing day", "testingDay", site.testingDay, url),
|
|
621
|
+
// Raw JSON, and shown as the raw cell rather than the parsed object: what the
|
|
622
|
+
// operator edits has to be the thing `parseNotifyRouting` will read back.
|
|
623
|
+
textareaRow("Notify routing (JSON)", "notifyRouting", site.notifyRoutingRaw, url),
|
|
594
624
|
textareaRow("Copy \u2014 Intro", "copyIntro", site.copyIntro, url),
|
|
595
625
|
textareaRow("Copy \u2014 Contact", "copyContact", site.copyContact, url),
|
|
596
626
|
textareaRow("Copy \u2014 Footer", "copyFooter", site.copyFooter, url),
|
|
@@ -754,7 +784,7 @@ button.trigger-renovate:disabled { opacity: 0.6; cursor: default; }
|
|
|
754
784
|
.chip.accepted { background: transparent; border: 1px dashed #bbb; color: #888; }
|
|
755
785
|
@media (prefers-color-scheme: dark) { .chip.accepted { border-color: #444; } .chip.critical { background: #2a0f0d; color: #ff8a80; } }
|
|
756
786
|
`;
|
|
757
|
-
function renderSiteDashboardHtml(site, reports, submissions = [], spamTotals = null, now = /* @__PURE__ */ new Date(), alarm = null) {
|
|
787
|
+
function renderSiteDashboardHtml(site, reports, submissions = [], spamTotals = null, now = /* @__PURE__ */ new Date(), alarm = null, operatorEmail = null) {
|
|
758
788
|
const name = escapeHtml(site.name);
|
|
759
789
|
const urlSafe = safeUrl(site.url);
|
|
760
790
|
const allScoresNull = site.pScore === null && site.rScore === null && site.bpScore === null && site.seoScore === null;
|
|
@@ -787,6 +817,7 @@ function renderSiteDashboardHtml(site, reports, submissions = [], spamTotals = n
|
|
|
787
817
|
<style>${STYLES}${SUBMISSION_STYLES}</style>
|
|
788
818
|
</head>
|
|
789
819
|
<body>
|
|
820
|
+
${renderAuthChrome(operatorEmail)}
|
|
790
821
|
<a class="home" href="/">\u2190 Fleet home</a>
|
|
791
822
|
<h1>${name}</h1>
|
|
792
823
|
<div class="meta"><a href="${escapeHtml(urlSafe)}">${escapeHtml(site.url)}</a></div>
|
|
@@ -1612,7 +1643,7 @@ var AUDIT_SCRIPT = `<script>
|
|
|
1612
1643
|
} catch(e){}
|
|
1613
1644
|
})();
|
|
1614
1645
|
</script>`;
|
|
1615
|
-
function renderCockpitHtml(model) {
|
|
1646
|
+
function renderCockpitHtml(model, operatorEmail = null) {
|
|
1616
1647
|
const total = model.cards.length;
|
|
1617
1648
|
const feed = buildNeedsYouFeed(model);
|
|
1618
1649
|
return `<!doctype html>
|
|
@@ -1625,8 +1656,9 @@ function renderCockpitHtml(model) {
|
|
|
1625
1656
|
<style>${STYLES2}</style>
|
|
1626
1657
|
</head>
|
|
1627
1658
|
<body>
|
|
1659
|
+
${renderAuthChrome(operatorEmail)}
|
|
1628
1660
|
<h1>Reddoor fleet cockpit</h1>
|
|
1629
|
-
<div class="meta">${total} site${total === 1 ? "" : "s"} on the Reddoor stack
|
|
1661
|
+
<div class="meta">${total} site${total === 1 ? "" : "s"} on the Reddoor stack. <a href="/fleet">Fleet table \u2192</a></div>
|
|
1630
1662
|
${verdictBar(model, feed)}
|
|
1631
1663
|
${renderNeedsYouFeed(feed)}
|
|
1632
1664
|
${renderFleetBrowsePanel(model)}
|
|
@@ -1659,6 +1691,15 @@ function verifyBasicAuth(authHeader, expectedPassword) {
|
|
|
1659
1691
|
if (a.length !== b.length) return false;
|
|
1660
1692
|
return timingSafeEqual(a, b);
|
|
1661
1693
|
}
|
|
1694
|
+
|
|
1695
|
+
// src/dashboard/auth/signing.ts
|
|
1696
|
+
import { createHmac, timingSafeEqual as timingSafeEqual2 } from "crypto";
|
|
1697
|
+
|
|
1698
|
+
// src/dashboard/auth/session.ts
|
|
1699
|
+
var SESSION_TTL_SECONDS = 30 * 24 * 60 * 60;
|
|
1700
|
+
|
|
1701
|
+
// src/dashboard/prospect-audit-trigger.ts
|
|
1702
|
+
var PROSPECT_AUDIT_DUPLICATE_WINDOW_MS = 10 * 60 * 1e3;
|
|
1662
1703
|
export {
|
|
1663
1704
|
ALL_AUDIT_NAMES,
|
|
1664
1705
|
ALL_RECIPE_NAMES,
|
|
@@ -1681,6 +1722,7 @@ export {
|
|
|
1681
1722
|
lighthouseAudit,
|
|
1682
1723
|
lintAudit,
|
|
1683
1724
|
loadBundledImages,
|
|
1725
|
+
loadHeadline,
|
|
1684
1726
|
loadPlate,
|
|
1685
1727
|
localPath,
|
|
1686
1728
|
onboard,
|