@reddoorla/maintenance 0.61.0 → 0.62.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/airtable-HHAWHBNM.js +9 -0
- package/dist/{announce-Q2DXP5OO.js → announce-N6VWO5QZ.js} +16 -6
- package/dist/announce-N6VWO5QZ.js.map +1 -0
- package/dist/{bump-deps-RYHQIKW4.js → bump-deps-2U6GIHM5.js} +2 -2
- package/dist/{chunk-D3LFQNJK.js → chunk-3HM4S422.js} +2 -2
- package/dist/{chunk-LMXIZITU.js → chunk-4REUHZAW.js} +40 -4
- package/dist/chunk-4REUHZAW.js.map +1 -0
- package/dist/chunk-5L3FPQIJ.js +92 -0
- package/dist/chunk-5L3FPQIJ.js.map +1 -0
- package/dist/{client-JA6QLEDW.js → chunk-6ZKM7OIJ.js} +5 -4
- package/dist/{chunk-L4ULXHIN.js → chunk-BLD6AYJO.js} +15 -1
- package/dist/chunk-BLD6AYJO.js.map +1 -0
- package/dist/{chunk-VDBENQUA.js → chunk-BMDBOPN3.js} +2 -2
- package/dist/{chunk-KC4HU7BC.js → chunk-DXRKWALS.js} +31 -6
- package/dist/chunk-DXRKWALS.js.map +1 -0
- package/dist/{chunk-HB7QPECR.js → chunk-KTPPKO2C.js} +6 -6
- package/dist/chunk-L5F664ZA.js +45 -0
- package/dist/chunk-L5F664ZA.js.map +1 -0
- package/dist/{chunk-TZN2G6FD.js → chunk-NPJFHBAX.js} +3 -3
- package/dist/{chunk-XB6T4ETK.js → chunk-OSRFDGQM.js} +21 -1
- package/dist/chunk-OSRFDGQM.js.map +1 -0
- package/dist/{chunk-6CSCLBAA.js → chunk-SAOCVNX7.js} +2 -2
- package/dist/{chunk-5PHCZ6L5.js → chunk-SS7BKOIX.js} +89 -2
- package/dist/chunk-SS7BKOIX.js.map +1 -0
- package/dist/{chunk-BWLUNY7L.js → chunk-U3MF6RCS.js} +40 -21
- package/dist/chunk-U3MF6RCS.js.map +1 -0
- package/dist/{chunk-HG5DTFNF.js → chunk-XKKTK6WA.js} +17 -1
- package/dist/chunk-XKKTK6WA.js.map +1 -0
- package/dist/{chunk-JNXCDUYB.js → chunk-XVR7UM6Z.js} +4 -4
- package/dist/{chunk-HPSGCDWY.js → chunk-YYUY2OVP.js} +2 -2
- package/dist/{chunk-TLZ4V2BE.js → chunk-ZEX2T6JH.js} +3 -2
- package/dist/{chunk-TLZ4V2BE.js.map → chunk-ZEX2T6JH.js.map} +1 -1
- package/dist/cli/bin.js +16 -15
- package/dist/cli/bin.js.map +1 -1
- package/dist/cli/commands/audit.d.ts +3 -2
- package/dist/cli/commands/audit.js +29 -8
- package/dist/cli/commands/audit.js.map +1 -1
- package/dist/client-GTMJTXBK.js +11 -0
- package/dist/{convert-to-pnpm-KNCXU6FM.js → convert-to-pnpm-JG3767ZQ.js} +2 -2
- package/dist/{db-AXKMRTVA.js → db-Y6BVTNH7.js} +3 -3
- package/dist/{digest-WAS3EJNC.js → digest-ABJROO4H.js} +3 -3
- package/dist/{github-signals-UL2BBS3Q.js → github-signals-XTJLKOXJ.js} +26 -5
- package/dist/github-signals-XTJLKOXJ.js.map +1 -0
- package/dist/index.d.ts +60 -3
- package/dist/index.js +86 -21
- package/dist/index.js.map +1 -1
- package/dist/{init-KD56UENX.js → init-DMAIKUQE.js} +8 -8
- package/dist/{launch-UWCI3JRM.js → launch-IBP23PNY.js} +10 -9
- package/dist/{launch-UWCI3JRM.js.map → launch-IBP23PNY.js.map} +1 -1
- package/dist/{lighthouse-airtable-N3KCBPVA.js → lighthouse-airtable-HTEW6BBT.js} +3 -3
- package/dist/migrate-BFOG2OCP.js +7 -0
- package/dist/{onboard-SCZ3UKZ2.js → onboard-TTIC3YZI.js} +2 -2
- package/dist/{orchestrate-D72PB6NG.js → orchestrate-I3KAJGFB.js} +7 -4
- package/dist/recipes/sync-configs.d.ts +1 -1
- package/dist/recipes/sync-configs.js +2 -2
- package/dist/{renovate-dispatch-NG5KUQKY.js → renovate-dispatch-QDDMTATD.js} +3 -3
- package/dist/{report-EPHXV2T2.js → report-PY6O3YMX.js} +6 -6
- package/dist/{self-updating-CFHXJSAX.js → self-updating-2RLUP4AA.js} +4 -4
- package/dist/{svelte-codemods-HNITLWQM.js → svelte-codemods-BPLKSVIA.js} +2 -2
- package/dist/{sync-configs-BZXBYKTI.js → sync-configs-VFRV3TJ4.js} +4 -4
- package/dist/{types-QG-QhCYh.d.ts → types-Dg4mHvyf.d.ts} +6 -1
- package/dist/{upgrade-6YDUELFA.js → upgrade-WCFD2TRN.js} +2 -2
- package/dist/{websites-IYP7IGLU.js → websites-HM2NMZMR.js} +2 -2
- package/dist/{write-audits-to-airtable-VDGHCZGQ.js → write-audits-to-airtable-QF26PCAR.js} +5 -4
- package/dist/write-audits-to-airtable-QF26PCAR.js.map +1 -0
- package/package.json +1 -1
- package/dist/airtable-YZ6VMSQZ.js +0 -9
- package/dist/announce-Q2DXP5OO.js.map +0 -1
- package/dist/chunk-5PHCZ6L5.js.map +0 -1
- package/dist/chunk-BWLUNY7L.js.map +0 -1
- package/dist/chunk-HG5DTFNF.js.map +0 -1
- package/dist/chunk-KC4HU7BC.js.map +0 -1
- package/dist/chunk-L4ULXHIN.js.map +0 -1
- package/dist/chunk-LMXIZITU.js.map +0 -1
- package/dist/chunk-XB6T4ETK.js.map +0 -1
- package/dist/github-signals-UL2BBS3Q.js.map +0 -1
- package/dist/migrate-P2LS4WXI.js +0 -7
- /package/dist/{airtable-YZ6VMSQZ.js.map → airtable-HHAWHBNM.js.map} +0 -0
- /package/dist/{bump-deps-RYHQIKW4.js.map → bump-deps-2U6GIHM5.js.map} +0 -0
- /package/dist/{chunk-D3LFQNJK.js.map → chunk-3HM4S422.js.map} +0 -0
- /package/dist/{client-JA6QLEDW.js.map → chunk-6ZKM7OIJ.js.map} +0 -0
- /package/dist/{chunk-VDBENQUA.js.map → chunk-BMDBOPN3.js.map} +0 -0
- /package/dist/{chunk-HB7QPECR.js.map → chunk-KTPPKO2C.js.map} +0 -0
- /package/dist/{chunk-TZN2G6FD.js.map → chunk-NPJFHBAX.js.map} +0 -0
- /package/dist/{chunk-6CSCLBAA.js.map → chunk-SAOCVNX7.js.map} +0 -0
- /package/dist/{chunk-JNXCDUYB.js.map → chunk-XVR7UM6Z.js.map} +0 -0
- /package/dist/{chunk-HPSGCDWY.js.map → chunk-YYUY2OVP.js.map} +0 -0
- /package/dist/{lighthouse-airtable-N3KCBPVA.js.map → client-GTMJTXBK.js.map} +0 -0
- /package/dist/{convert-to-pnpm-KNCXU6FM.js.map → convert-to-pnpm-JG3767ZQ.js.map} +0 -0
- /package/dist/{db-AXKMRTVA.js.map → db-Y6BVTNH7.js.map} +0 -0
- /package/dist/{digest-WAS3EJNC.js.map → digest-ABJROO4H.js.map} +0 -0
- /package/dist/{init-KD56UENX.js.map → init-DMAIKUQE.js.map} +0 -0
- /package/dist/{migrate-P2LS4WXI.js.map → lighthouse-airtable-HTEW6BBT.js.map} +0 -0
- /package/dist/{orchestrate-D72PB6NG.js.map → migrate-BFOG2OCP.js.map} +0 -0
- /package/dist/{onboard-SCZ3UKZ2.js.map → onboard-TTIC3YZI.js.map} +0 -0
- /package/dist/{websites-IYP7IGLU.js.map → orchestrate-I3KAJGFB.js.map} +0 -0
- /package/dist/{renovate-dispatch-NG5KUQKY.js.map → renovate-dispatch-QDDMTATD.js.map} +0 -0
- /package/dist/{report-EPHXV2T2.js.map → report-PY6O3YMX.js.map} +0 -0
- /package/dist/{self-updating-CFHXJSAX.js.map → self-updating-2RLUP4AA.js.map} +0 -0
- /package/dist/{svelte-codemods-HNITLWQM.js.map → svelte-codemods-BPLKSVIA.js.map} +0 -0
- /package/dist/{sync-configs-BZXBYKTI.js.map → sync-configs-VFRV3TJ4.js.map} +0 -0
- /package/dist/{upgrade-6YDUELFA.js.map → upgrade-WCFD2TRN.js.map} +0 -0
- /package/dist/{write-audits-to-airtable-VDGHCZGQ.js.map → websites-HM2NMZMR.js.map} +0 -0
|
@@ -5,19 +5,19 @@ import {
|
|
|
5
5
|
} from "./chunk-4NAOR44V.js";
|
|
6
6
|
import {
|
|
7
7
|
resolveSites
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-SAOCVNX7.js";
|
|
9
9
|
import {
|
|
10
10
|
init
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-KTPPKO2C.js";
|
|
12
|
+
import "./chunk-2X322ZES.js";
|
|
12
13
|
import "./chunk-FUD4I2ZW.js";
|
|
13
|
-
import "./chunk-ZYBOT5PM.js";
|
|
14
14
|
import "./chunk-OQPMZ6BM.js";
|
|
15
|
-
import "./chunk-
|
|
16
|
-
import "./chunk-
|
|
17
|
-
import "./chunk-CASCWQQX.js";
|
|
15
|
+
import "./chunk-ZYBOT5PM.js";
|
|
16
|
+
import "./chunk-XVR7UM6Z.js";
|
|
18
17
|
import "./chunk-XKOZUVK2.js";
|
|
18
|
+
import "./chunk-CASCWQQX.js";
|
|
19
19
|
import "./chunk-OTGB6YQO.js";
|
|
20
|
-
import "./chunk-
|
|
20
|
+
import "./chunk-SS7BKOIX.js";
|
|
21
21
|
import "./chunk-LKGVSM2O.js";
|
|
22
22
|
import "./chunk-FDIFTIXC.js";
|
|
23
23
|
import "./chunk-HVOOCK6L.js";
|
|
@@ -82,4 +82,4 @@ async function runInitCommand(site, opts) {
|
|
|
82
82
|
export {
|
|
83
83
|
runInitCommand
|
|
84
84
|
};
|
|
85
|
-
//# sourceMappingURL=init-
|
|
85
|
+
//# sourceMappingURL=init-DMAIKUQE.js.map
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
2
|
writeAuditsToAirtable
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-4REUHZAW.js";
|
|
4
4
|
import {
|
|
5
5
|
hasRealScores,
|
|
6
6
|
lighthouseScoresFromResult
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-YYUY2OVP.js";
|
|
8
8
|
import {
|
|
9
9
|
selfUpdating
|
|
10
|
-
} from "./chunk-
|
|
11
|
-
import "./chunk-
|
|
10
|
+
} from "./chunk-3HM4S422.js";
|
|
11
|
+
import "./chunk-OSRFDGQM.js";
|
|
12
|
+
import "./chunk-5L3FPQIJ.js";
|
|
12
13
|
import {
|
|
13
14
|
resolveSites
|
|
14
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-SAOCVNX7.js";
|
|
15
16
|
import {
|
|
16
17
|
queueDraft
|
|
17
18
|
} from "./chunk-6LIWDIXU.js";
|
|
@@ -19,7 +20,7 @@ import {
|
|
|
19
20
|
renderReportHtml,
|
|
20
21
|
resolveCopy,
|
|
21
22
|
uploadAttachment
|
|
22
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-U3MF6RCS.js";
|
|
23
24
|
import {
|
|
24
25
|
createDraft,
|
|
25
26
|
findReportByPeriod,
|
|
@@ -28,7 +29,7 @@ import {
|
|
|
28
29
|
import "./chunk-CASCWQQX.js";
|
|
29
30
|
import {
|
|
30
31
|
runAudits
|
|
31
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-SS7BKOIX.js";
|
|
32
33
|
import "./chunk-LKGVSM2O.js";
|
|
33
34
|
import "./chunk-FDIFTIXC.js";
|
|
34
35
|
import "./chunk-HVOOCK6L.js";
|
|
@@ -40,7 +41,7 @@ import "./chunk-U5SZ4FOP.js";
|
|
|
40
41
|
import {
|
|
41
42
|
listWebsites,
|
|
42
43
|
siteSlug
|
|
43
|
-
} from "./chunk-
|
|
44
|
+
} from "./chunk-BLD6AYJO.js";
|
|
44
45
|
import {
|
|
45
46
|
openBase,
|
|
46
47
|
readAirtableConfig
|
|
@@ -210,4 +211,4 @@ async function runLaunchCommand(site, opts) {
|
|
|
210
211
|
export {
|
|
211
212
|
runLaunchCommand
|
|
212
213
|
};
|
|
213
|
-
//# sourceMappingURL=launch-
|
|
214
|
+
//# sourceMappingURL=launch-IBP23PNY.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/commands/launch.ts","../src/recipes/launch.ts"],"sourcesContent":["import { resolve } from \"node:path\";\nimport { launch, type LaunchResult, type LaunchStepResult } from \"../../recipes/launch.js\";\nimport { resolveSites } from \"../fleet/resolve-sites.js\";\n\nexport type LaunchCommandOptions = {\n cwd?: string;\n};\n\nfunction formatStep(name: string, r: LaunchStepResult): string {\n if (r.kind === \"error\") return `${name.padEnd(20)} error: ${r.message}`;\n if (r.kind === \"audit\") {\n const s = r.scores;\n return `${name.padEnd(20)} audited (P=${s.performance} A=${s.accessibility} BP=${s.bestPractices} SEO=${s.seo})`;\n }\n if (r.kind === \"draft\") {\n return `${name.padEnd(20)} drafted ${r.report.reportId}`;\n }\n const rec = r.result;\n if (rec.status === \"noop\") return `${name.padEnd(20)} noop${rec.notes ? ` — ${rec.notes}` : \"\"}`;\n if (rec.status === \"failed\")\n return `${name.padEnd(20)} failed${rec.notes ? ` — ${rec.notes}` : \"\"}`;\n return `${name.padEnd(20)} applied (${rec.commits.length} commit${rec.commits.length === 1 ? \"\" : \"s\"})${rec.notes ? ` — ${rec.notes}` : \"\"}`;\n}\n\nfunction formatResult(r: LaunchResult): string {\n const header = `[${r.site}] launch — ${r.complete ? \"drafted (awaiting approval)\" : \"STOPPED\"}`;\n const body = r.steps.map((s) => formatStep(s.name, s.result)).join(\"\\n\");\n return `${header}\\n${body}`;\n}\n\n/**\n * `launch <site>` — single-site only. Bootstrap (CI + Renovate), first-audit\n * the site, and DRAFT its launch email into the M3 approve queue. Never sends;\n * the operator approves the draft and the next send run delivers the go-live\n * email (flipping Status → maintenance + stamping Launched at).\n */\nexport async function runLaunchCommand(\n site: string,\n opts: LaunchCommandOptions,\n): Promise<{ output: string; code: number }> {\n const cwd = opts.cwd ? resolve(opts.cwd) : process.cwd();\n const sites = await resolveSites({ site, cwd });\n const target = sites[0];\n if (!target) {\n return { output: `No site resolved for \"${site}\".`, code: 1 };\n }\n\n const result = await launch(target);\n return { output: formatResult(result), code: result.complete ? 0 : 1 };\n}\n","import type { AuditResult, RecipeResult, Site } from \"../types.js\";\nimport { siteLabel } from \"../util/site.js\";\nimport { selfUpdating } from \"./self-updating/index.js\";\nimport { runAudits } from \"../audits/index.js\";\nimport { hasRealScores, lighthouseScoresFromResult } from \"../audits/lighthouse-airtable.js\";\nimport { writeAuditsToAirtable } from \"../audits/write-audits-to-airtable.js\";\nimport { openBase, readAirtableConfig } from \"../reports/airtable/client.js\";\nimport type { AirtableBase } from \"../reports/airtable/client.js\";\nimport { listWebsites, siteSlug } from \"../reports/airtable/websites.js\";\nimport type { WebsiteRow } from \"../reports/airtable/websites.js\";\nimport {\n createDraft,\n findReportByPeriod,\n updateReportScores,\n} from \"../reports/airtable/reports.js\";\nimport type { ReportRow } from \"../reports/airtable/reports.js\";\nimport { queueDraft } from \"../reports/queue.js\";\nimport { uploadAttachment } from \"../reports/airtable/attachments.js\";\nimport { renderReportHtml } from \"../reports/render.js\";\nimport { resolveCopy } from \"../reports/copy.js\";\nimport type { LighthouseScores } from \"../reports/types.js\";\n\nexport type LaunchStepResult =\n | { kind: \"recipe\"; result: RecipeResult }\n | { kind: \"audit\"; results: AuditResult[]; scores: LighthouseScores }\n | { kind: \"draft\"; report: ReportRow }\n | { kind: \"error\"; message: string };\n\nexport type LaunchResult = {\n site: string;\n steps: Array<{ name: string; result: LaunchStepResult }>;\n /** True if every step ran (bootstrap + audit + draft); false if a step\n * errored or a recipe `failed` short-circuited the chain. */\n complete: boolean;\n};\n\nexport type LaunchDeps = {\n /** Bootstrap step (CI + Renovate). Defaults to the real `selfUpdating`. */\n bootstrap?: (site: Site) => Promise<RecipeResult>;\n /** Audit step. Defaults to the real `runAudits`. */\n audit?: (site: Site) => Promise<AuditResult[]>;\n /** Airtable handle. Defaults to opening the live base from credentials. */\n base?: AirtableBase;\n};\n\n/**\n * Launch a site: bootstrap → first-audit → DRAFT a launch email. The M3\n * approve loop is what actually sends; `launch` never sends — it stops at a\n * dashboard-queued draft (`reportType: \"Launch\"`) carrying the just-audited\n * Lighthouse scores, so `sendOne`'s `report.lighthouse` guard passes.\n *\n * Step-chain (mirrors `init`), stopping on the first error or `failed` recipe:\n * 1. selfUpdating — CI + Renovate + auto-merge.\n * 2. runAudits + write the scores to the site's Websites row (reuses the\n * `audit --write-airtable` writer); the Lighthouse scores feed the draft.\n * 3. createDraft — reportType \"Launch\", today's period, the audited scores.\n */\nexport async function launch(site: Site, deps: LaunchDeps = {}): Promise<LaunchResult> {\n const label = siteLabel(site);\n const bootstrap = deps.bootstrap ?? selfUpdating;\n const audit = deps.audit ?? runAudits;\n const base = deps.base ?? openBase(readAirtableConfig());\n\n const steps: Array<{ name: string; result: LaunchStepResult }> = [];\n const stop = (): LaunchResult => ({ site: label, steps, complete: false });\n\n // 1. Bootstrap.\n let recipe: RecipeResult;\n try {\n recipe = await bootstrap(site);\n } catch (err) {\n steps.push({ name: \"self-updating\", result: errorOf(err) });\n return stop();\n }\n steps.push({ name: \"self-updating\", result: { kind: \"recipe\", result: recipe } });\n if (recipe.status === \"failed\") return stop();\n\n // 2. Audit + write scores back to Airtable.\n let results: AuditResult[];\n try {\n results = await audit(site);\n } catch (err) {\n steps.push({ name: \"audit\", result: errorOf(err) });\n return stop();\n }\n const lhResult = results.find((r) => r.audit === \"lighthouse\");\n if (!lhResult || !hasRealScores(lhResult)) {\n steps.push({\n name: \"audit\",\n result: { kind: \"error\", message: \"lighthouse audit produced no real scores\" },\n });\n return stop();\n }\n // The launch announcement renders a numeric score per category; a metric that\n // errored this run (now null from lighthouseScoresFromResult) keeps the prior\n // 0 behavior here rather than propagating null into the launch-email path. The\n // Airtable write path (write-audits-to-airtable) keeps the null → shows \"—\".\n const rawScores = lighthouseScoresFromResult(lhResult);\n const scores: LighthouseScores = {\n performance: rawScores.performance ?? 0,\n accessibility: rawScores.accessibility ?? 0,\n bestPractices: rawScores.bestPractices ?? 0,\n seo: rawScores.seo ?? 0,\n };\n\n const websites = await listWebsites(base);\n const target = websites.find((w) => siteSlug(w.name) === siteSlug(label));\n if (!target) {\n steps.push({\n name: \"audit\",\n result: { kind: \"error\", message: `no Websites row matched site \"${label}\"` },\n });\n return stop();\n }\n try {\n await writeAuditsToAirtable({ base, websites, slug: siteSlug(target.name), results });\n } catch (err) {\n steps.push({ name: \"audit\", result: errorOf(err) });\n return stop();\n }\n steps.push({ name: \"audit\", result: { kind: \"audit\", results, scores } });\n\n // 3. Draft the launch email (reuses draft.ts's reportId/period scheme). DRAFTS\n // ONLY — the M3 approve loop sends it and flips Status on send.\n const today = new Date();\n const period = today.toISOString().slice(0, 7);\n const slug = siteSlug(target.name);\n\n let report: ReportRow;\n try {\n // Re-run dedupe: reuse an existing Launch row for this (site, period) instead\n // of stacking a second draft. findReportByPeriod is the same idempotency\n // lookup draft.ts documents (dashboard/digest point lookup).\n const existing = await findReportByPeriod(base, target.id, \"Launch\", period);\n if (existing) {\n // Reuse path: the row was created on a prior run with THAT run's scores. This\n // re-run just produced fresh audit scores AND will re-render the preview from\n // them — so refresh the row's Lighthouse cells (+ Completed on) to match,\n // otherwise the sent email (which reads the row) ships stale scores. The\n // create path already writes fresh scores via createDraft.\n await updateReportScores(base, existing.id, scores, today);\n report = existing;\n } else {\n report = await createDraft(base, draftInputFor(target, scores, today, period));\n }\n } catch (err) {\n steps.push({ name: \"draft\", result: errorOf(err) });\n return stop();\n }\n\n // Mirror draft.ts:135-154 — render → upload \"Rendered HTML\" preview → flip\n // Draft ready. Without setDraftReady the draft never enters the approve queue\n // (every pending-approval gate requires draftReady true), so it can never be\n // approved or sent. The upload is a review convenience; the ready flag is the\n // critical step.\n try {\n const { html } = await renderReportHtml({\n siteName: target.name,\n siteUrl: target.url,\n reportType: \"Launch\",\n completedOn: today,\n lighthouse: scores,\n lastTestedDate: null,\n commentary: null,\n copy: resolveCopy(target),\n headerImageCid: `${slug}-header`,\n });\n // A preview-upload hiccup must NOT fail the launch — log and continue.\n try {\n await uploadAttachment(\n report.id,\n \"Rendered HTML\",\n html,\n `${slug}-${today.toISOString().slice(0, 10)}.html`,\n \"text/html\",\n );\n } catch (uploadErr) {\n console.warn(\n `⚠ Launch preview upload skipped for ${target.name}: ${\n uploadErr instanceof Error ? uploadErr.message : String(uploadErr)\n }`,\n );\n }\n // Critical: NOT wrapped — a failure here must surface as a failed launch. queueDraft\n // supersedes any lower-tier (Maintenance/Testing) drafts queued for this site; a Launch is\n // top tier so it only stands down if another Launch/Announcement is already queued.\n await queueDraft(base, { id: report.id, siteId: target.id, reportType: \"Launch\" });\n } catch (err) {\n steps.push({ name: \"draft\", result: errorOf(err) });\n return stop();\n }\n\n steps.push({ name: \"draft\", result: { kind: \"draft\", report } });\n\n return { site: label, steps, complete: true };\n}\n\n/** Build the Launch `DraftInput`. reportId/period mirror `draftReportForSite`\n * (draft.ts) — do not invent a new id scheme. `today`/`period` are threaded in\n * from `launch()` so a single timestamp drives the render, the draft, the\n * dedupe lookup, and the preview filename. Launch reports have no period window\n * and no prior maintenance test, so periodStart/periodEnd/completedOn all\n * collapse to \"today\" and `lastTestedDate` is null. */\nfunction draftInputFor(\n target: WebsiteRow,\n scores: LighthouseScores,\n today: Date,\n period: string,\n): Parameters<typeof createDraft>[1] {\n const reportType = \"Launch\" as const;\n const reportId = `${target.name} — ${reportType} — ${today.toISOString().slice(0, 10)}`;\n return {\n reportId,\n siteId: target.id,\n reportType,\n period,\n periodStart: today,\n periodEnd: today,\n completedOn: today,\n lighthouse: scores,\n lastTestedDate: null,\n };\n}\n\nfunction errorOf(err: unknown): LaunchStepResult {\n return { kind: \"error\", message: err instanceof Error ? err.message : String(err) };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/cli/commands/launch.ts","../src/recipes/launch.ts"],"sourcesContent":["import { resolve } from \"node:path\";\nimport { launch, type LaunchResult, type LaunchStepResult } from \"../../recipes/launch.js\";\nimport { resolveSites } from \"../fleet/resolve-sites.js\";\n\nexport type LaunchCommandOptions = {\n cwd?: string;\n};\n\nfunction formatStep(name: string, r: LaunchStepResult): string {\n if (r.kind === \"error\") return `${name.padEnd(20)} error: ${r.message}`;\n if (r.kind === \"audit\") {\n const s = r.scores;\n return `${name.padEnd(20)} audited (P=${s.performance} A=${s.accessibility} BP=${s.bestPractices} SEO=${s.seo})`;\n }\n if (r.kind === \"draft\") {\n return `${name.padEnd(20)} drafted ${r.report.reportId}`;\n }\n const rec = r.result;\n if (rec.status === \"noop\") return `${name.padEnd(20)} noop${rec.notes ? ` — ${rec.notes}` : \"\"}`;\n if (rec.status === \"failed\")\n return `${name.padEnd(20)} failed${rec.notes ? ` — ${rec.notes}` : \"\"}`;\n return `${name.padEnd(20)} applied (${rec.commits.length} commit${rec.commits.length === 1 ? \"\" : \"s\"})${rec.notes ? ` — ${rec.notes}` : \"\"}`;\n}\n\nfunction formatResult(r: LaunchResult): string {\n const header = `[${r.site}] launch — ${r.complete ? \"drafted (awaiting approval)\" : \"STOPPED\"}`;\n const body = r.steps.map((s) => formatStep(s.name, s.result)).join(\"\\n\");\n return `${header}\\n${body}`;\n}\n\n/**\n * `launch <site>` — single-site only. Bootstrap (CI + Renovate), first-audit\n * the site, and DRAFT its launch email into the M3 approve queue. Never sends;\n * the operator approves the draft and the next send run delivers the go-live\n * email (flipping Status → maintenance + stamping Launched at).\n */\nexport async function runLaunchCommand(\n site: string,\n opts: LaunchCommandOptions,\n): Promise<{ output: string; code: number }> {\n const cwd = opts.cwd ? resolve(opts.cwd) : process.cwd();\n const sites = await resolveSites({ site, cwd });\n const target = sites[0];\n if (!target) {\n return { output: `No site resolved for \"${site}\".`, code: 1 };\n }\n\n const result = await launch(target);\n return { output: formatResult(result), code: result.complete ? 0 : 1 };\n}\n","import type { AuditResult, RecipeResult, Site } from \"../types.js\";\nimport { siteLabel } from \"../util/site.js\";\nimport { selfUpdating } from \"./self-updating/index.js\";\nimport { runAudits } from \"../audits/index.js\";\nimport { hasRealScores, lighthouseScoresFromResult } from \"../audits/lighthouse-airtable.js\";\nimport { writeAuditsToAirtable } from \"../audits/write-audits-to-airtable.js\";\nimport { openBase, readAirtableConfig } from \"../reports/airtable/client.js\";\nimport type { AirtableBase } from \"../reports/airtable/client.js\";\nimport { listWebsites, siteSlug } from \"../reports/airtable/websites.js\";\nimport type { WebsiteRow } from \"../reports/airtable/websites.js\";\nimport {\n createDraft,\n findReportByPeriod,\n updateReportScores,\n} from \"../reports/airtable/reports.js\";\nimport type { ReportRow } from \"../reports/airtable/reports.js\";\nimport { queueDraft } from \"../reports/queue.js\";\nimport { uploadAttachment } from \"../reports/airtable/attachments.js\";\nimport { renderReportHtml } from \"../reports/render.js\";\nimport { resolveCopy } from \"../reports/copy.js\";\nimport type { LighthouseScores } from \"../reports/types.js\";\n\nexport type LaunchStepResult =\n | { kind: \"recipe\"; result: RecipeResult }\n | { kind: \"audit\"; results: AuditResult[]; scores: LighthouseScores }\n | { kind: \"draft\"; report: ReportRow }\n | { kind: \"error\"; message: string };\n\nexport type LaunchResult = {\n site: string;\n steps: Array<{ name: string; result: LaunchStepResult }>;\n /** True if every step ran (bootstrap + audit + draft); false if a step\n * errored or a recipe `failed` short-circuited the chain. */\n complete: boolean;\n};\n\nexport type LaunchDeps = {\n /** Bootstrap step (CI + Renovate). Defaults to the real `selfUpdating`. */\n bootstrap?: (site: Site) => Promise<RecipeResult>;\n /** Audit step. Defaults to the real `runAudits`. */\n audit?: (site: Site) => Promise<AuditResult[]>;\n /** Airtable handle. Defaults to opening the live base from credentials. */\n base?: AirtableBase;\n};\n\n/**\n * Launch a site: bootstrap → first-audit → DRAFT a launch email. The M3\n * approve loop is what actually sends; `launch` never sends — it stops at a\n * dashboard-queued draft (`reportType: \"Launch\"`) carrying the just-audited\n * Lighthouse scores, so `sendOne`'s `report.lighthouse` guard passes.\n *\n * Step-chain (mirrors `init`), stopping on the first error or `failed` recipe:\n * 1. selfUpdating — CI + Renovate + auto-merge.\n * 2. runAudits + write the scores to the site's Websites row (reuses the\n * `audit --write-airtable` writer); the Lighthouse scores feed the draft.\n * 3. createDraft — reportType \"Launch\", today's period, the audited scores.\n */\nexport async function launch(site: Site, deps: LaunchDeps = {}): Promise<LaunchResult> {\n const label = siteLabel(site);\n const bootstrap = deps.bootstrap ?? selfUpdating;\n const audit = deps.audit ?? runAudits;\n const base = deps.base ?? openBase(readAirtableConfig());\n\n const steps: Array<{ name: string; result: LaunchStepResult }> = [];\n const stop = (): LaunchResult => ({ site: label, steps, complete: false });\n\n // 1. Bootstrap.\n let recipe: RecipeResult;\n try {\n recipe = await bootstrap(site);\n } catch (err) {\n steps.push({ name: \"self-updating\", result: errorOf(err) });\n return stop();\n }\n steps.push({ name: \"self-updating\", result: { kind: \"recipe\", result: recipe } });\n if (recipe.status === \"failed\") return stop();\n\n // 2. Audit + write scores back to Airtable.\n let results: AuditResult[];\n try {\n results = await audit(site);\n } catch (err) {\n steps.push({ name: \"audit\", result: errorOf(err) });\n return stop();\n }\n const lhResult = results.find((r) => r.audit === \"lighthouse\");\n if (!lhResult || !hasRealScores(lhResult)) {\n steps.push({\n name: \"audit\",\n result: { kind: \"error\", message: \"lighthouse audit produced no real scores\" },\n });\n return stop();\n }\n // The launch announcement renders a numeric score per category; a metric that\n // errored this run (now null from lighthouseScoresFromResult) keeps the prior\n // 0 behavior here rather than propagating null into the launch-email path. The\n // Airtable write path (write-audits-to-airtable) keeps the null → shows \"—\".\n const rawScores = lighthouseScoresFromResult(lhResult);\n const scores: LighthouseScores = {\n performance: rawScores.performance ?? 0,\n accessibility: rawScores.accessibility ?? 0,\n bestPractices: rawScores.bestPractices ?? 0,\n seo: rawScores.seo ?? 0,\n };\n\n const websites = await listWebsites(base);\n const target = websites.find((w) => siteSlug(w.name) === siteSlug(label));\n if (!target) {\n steps.push({\n name: \"audit\",\n result: { kind: \"error\", message: `no Websites row matched site \"${label}\"` },\n });\n return stop();\n }\n try {\n await writeAuditsToAirtable({ base, websites, slug: siteSlug(target.name), results });\n } catch (err) {\n steps.push({ name: \"audit\", result: errorOf(err) });\n return stop();\n }\n steps.push({ name: \"audit\", result: { kind: \"audit\", results, scores } });\n\n // 3. Draft the launch email (reuses draft.ts's reportId/period scheme). DRAFTS\n // ONLY — the M3 approve loop sends it and flips Status on send.\n const today = new Date();\n const period = today.toISOString().slice(0, 7);\n const slug = siteSlug(target.name);\n\n let report: ReportRow;\n try {\n // Re-run dedupe: reuse an existing Launch row for this (site, period) instead\n // of stacking a second draft. findReportByPeriod is the same idempotency\n // lookup draft.ts documents (dashboard/digest point lookup).\n const existing = await findReportByPeriod(base, target.id, \"Launch\", period);\n if (existing) {\n // Reuse path: the row was created on a prior run with THAT run's scores. This\n // re-run just produced fresh audit scores AND will re-render the preview from\n // them — so refresh the row's Lighthouse cells (+ Completed on) to match,\n // otherwise the sent email (which reads the row) ships stale scores. The\n // create path already writes fresh scores via createDraft.\n await updateReportScores(base, existing.id, scores, today);\n report = existing;\n } else {\n report = await createDraft(base, draftInputFor(target, scores, today, period));\n }\n } catch (err) {\n steps.push({ name: \"draft\", result: errorOf(err) });\n return stop();\n }\n\n // Mirror draft.ts:135-154 — render → upload \"Rendered HTML\" preview → flip\n // Draft ready. Without setDraftReady the draft never enters the approve queue\n // (every pending-approval gate requires draftReady true), so it can never be\n // approved or sent. The upload is a review convenience; the ready flag is the\n // critical step.\n try {\n const { html } = await renderReportHtml({\n siteName: target.name,\n siteUrl: target.url,\n reportType: \"Launch\",\n completedOn: today,\n lighthouse: scores,\n lastTestedDate: null,\n commentary: null,\n copy: resolveCopy(target),\n headerImageCid: `${slug}-header`,\n });\n // A preview-upload hiccup must NOT fail the launch — log and continue.\n try {\n await uploadAttachment(\n report.id,\n \"Rendered HTML\",\n html,\n `${slug}-${today.toISOString().slice(0, 10)}.html`,\n \"text/html\",\n );\n } catch (uploadErr) {\n console.warn(\n `⚠ Launch preview upload skipped for ${target.name}: ${\n uploadErr instanceof Error ? uploadErr.message : String(uploadErr)\n }`,\n );\n }\n // Critical: NOT wrapped — a failure here must surface as a failed launch. queueDraft\n // supersedes any lower-tier (Maintenance/Testing) drafts queued for this site; a Launch is\n // top tier so it only stands down if another Launch/Announcement is already queued.\n await queueDraft(base, { id: report.id, siteId: target.id, reportType: \"Launch\" });\n } catch (err) {\n steps.push({ name: \"draft\", result: errorOf(err) });\n return stop();\n }\n\n steps.push({ name: \"draft\", result: { kind: \"draft\", report } });\n\n return { site: label, steps, complete: true };\n}\n\n/** Build the Launch `DraftInput`. reportId/period mirror `draftReportForSite`\n * (draft.ts) — do not invent a new id scheme. `today`/`period` are threaded in\n * from `launch()` so a single timestamp drives the render, the draft, the\n * dedupe lookup, and the preview filename. Launch reports have no period window\n * and no prior maintenance test, so periodStart/periodEnd/completedOn all\n * collapse to \"today\" and `lastTestedDate` is null. */\nfunction draftInputFor(\n target: WebsiteRow,\n scores: LighthouseScores,\n today: Date,\n period: string,\n): Parameters<typeof createDraft>[1] {\n const reportType = \"Launch\" as const;\n const reportId = `${target.name} — ${reportType} — ${today.toISOString().slice(0, 10)}`;\n return {\n reportId,\n siteId: target.id,\n reportType,\n period,\n periodStart: today,\n periodEnd: today,\n completedOn: today,\n lighthouse: scores,\n lastTestedDate: null,\n };\n}\n\nfunction errorOf(err: unknown): LaunchStepResult {\n return { kind: \"error\", message: err instanceof Error ? err.message : String(err) };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,eAAe;;;ACyDxB,eAAsB,OAAO,MAAY,OAAmB,CAAC,GAA0B;AACrF,QAAM,QAAQ,UAAU,IAAI;AAC5B,QAAM,YAAY,KAAK,aAAa;AACpC,QAAM,QAAQ,KAAK,SAAS;AAC5B,QAAM,OAAO,KAAK,QAAQ,SAAS,mBAAmB,CAAC;AAEvD,QAAM,QAA2D,CAAC;AAClE,QAAM,OAAO,OAAqB,EAAE,MAAM,OAAO,OAAO,UAAU,MAAM;AAGxE,MAAI;AACJ,MAAI;AACF,aAAS,MAAM,UAAU,IAAI;AAAA,EAC/B,SAAS,KAAK;AACZ,UAAM,KAAK,EAAE,MAAM,iBAAiB,QAAQ,QAAQ,GAAG,EAAE,CAAC;AAC1D,WAAO,KAAK;AAAA,EACd;AACA,QAAM,KAAK,EAAE,MAAM,iBAAiB,QAAQ,EAAE,MAAM,UAAU,QAAQ,OAAO,EAAE,CAAC;AAChF,MAAI,OAAO,WAAW,SAAU,QAAO,KAAK;AAG5C,MAAI;AACJ,MAAI;AACF,cAAU,MAAM,MAAM,IAAI;AAAA,EAC5B,SAAS,KAAK;AACZ,UAAM,KAAK,EAAE,MAAM,SAAS,QAAQ,QAAQ,GAAG,EAAE,CAAC;AAClD,WAAO,KAAK;AAAA,EACd;AACA,QAAM,WAAW,QAAQ,KAAK,CAAC,MAAM,EAAE,UAAU,YAAY;AAC7D,MAAI,CAAC,YAAY,CAAC,cAAc,QAAQ,GAAG;AACzC,UAAM,KAAK;AAAA,MACT,MAAM;AAAA,MACN,QAAQ,EAAE,MAAM,SAAS,SAAS,2CAA2C;AAAA,IAC/E,CAAC;AACD,WAAO,KAAK;AAAA,EACd;AAKA,QAAM,YAAY,2BAA2B,QAAQ;AACrD,QAAM,SAA2B;AAAA,IAC/B,aAAa,UAAU,eAAe;AAAA,IACtC,eAAe,UAAU,iBAAiB;AAAA,IAC1C,eAAe,UAAU,iBAAiB;AAAA,IAC1C,KAAK,UAAU,OAAO;AAAA,EACxB;AAEA,QAAM,WAAW,MAAM,aAAa,IAAI;AACxC,QAAM,SAAS,SAAS,KAAK,CAAC,MAAM,SAAS,EAAE,IAAI,MAAM,SAAS,KAAK,CAAC;AACxE,MAAI,CAAC,QAAQ;AACX,UAAM,KAAK;AAAA,MACT,MAAM;AAAA,MACN,QAAQ,EAAE,MAAM,SAAS,SAAS,iCAAiC,KAAK,IAAI;AAAA,IAC9E,CAAC;AACD,WAAO,KAAK;AAAA,EACd;AACA,MAAI;AACF,UAAM,sBAAsB,EAAE,MAAM,UAAU,MAAM,SAAS,OAAO,IAAI,GAAG,QAAQ,CAAC;AAAA,EACtF,SAAS,KAAK;AACZ,UAAM,KAAK,EAAE,MAAM,SAAS,QAAQ,QAAQ,GAAG,EAAE,CAAC;AAClD,WAAO,KAAK;AAAA,EACd;AACA,QAAM,KAAK,EAAE,MAAM,SAAS,QAAQ,EAAE,MAAM,SAAS,SAAS,OAAO,EAAE,CAAC;AAIxE,QAAM,QAAQ,oBAAI,KAAK;AACvB,QAAM,SAAS,MAAM,YAAY,EAAE,MAAM,GAAG,CAAC;AAC7C,QAAM,OAAO,SAAS,OAAO,IAAI;AAEjC,MAAI;AACJ,MAAI;AAIF,UAAM,WAAW,MAAM,mBAAmB,MAAM,OAAO,IAAI,UAAU,MAAM;AAC3E,QAAI,UAAU;AAMZ,YAAM,mBAAmB,MAAM,SAAS,IAAI,QAAQ,KAAK;AACzD,eAAS;AAAA,IACX,OAAO;AACL,eAAS,MAAM,YAAY,MAAM,cAAc,QAAQ,QAAQ,OAAO,MAAM,CAAC;AAAA,IAC/E;AAAA,EACF,SAAS,KAAK;AACZ,UAAM,KAAK,EAAE,MAAM,SAAS,QAAQ,QAAQ,GAAG,EAAE,CAAC;AAClD,WAAO,KAAK;AAAA,EACd;AAOA,MAAI;AACF,UAAM,EAAE,KAAK,IAAI,MAAM,iBAAiB;AAAA,MACtC,UAAU,OAAO;AAAA,MACjB,SAAS,OAAO;AAAA,MAChB,YAAY;AAAA,MACZ,aAAa;AAAA,MACb,YAAY;AAAA,MACZ,gBAAgB;AAAA,MAChB,YAAY;AAAA,MACZ,MAAM,YAAY,MAAM;AAAA,MACxB,gBAAgB,GAAG,IAAI;AAAA,IACzB,CAAC;AAED,QAAI;AACF,YAAM;AAAA,QACJ,OAAO;AAAA,QACP;AAAA,QACA;AAAA,QACA,GAAG,IAAI,IAAI,MAAM,YAAY,EAAE,MAAM,GAAG,EAAE,CAAC;AAAA,QAC3C;AAAA,MACF;AAAA,IACF,SAAS,WAAW;AAClB,cAAQ;AAAA,QACN,4CAAuC,OAAO,IAAI,KAChD,qBAAqB,QAAQ,UAAU,UAAU,OAAO,SAAS,CACnE;AAAA,MACF;AAAA,IACF;AAIA,UAAM,WAAW,MAAM,EAAE,IAAI,OAAO,IAAI,QAAQ,OAAO,IAAI,YAAY,SAAS,CAAC;AAAA,EACnF,SAAS,KAAK;AACZ,UAAM,KAAK,EAAE,MAAM,SAAS,QAAQ,QAAQ,GAAG,EAAE,CAAC;AAClD,WAAO,KAAK;AAAA,EACd;AAEA,QAAM,KAAK,EAAE,MAAM,SAAS,QAAQ,EAAE,MAAM,SAAS,OAAO,EAAE,CAAC;AAE/D,SAAO,EAAE,MAAM,OAAO,OAAO,UAAU,KAAK;AAC9C;AAQA,SAAS,cACP,QACA,QACA,OACA,QACmC;AACnC,QAAM,aAAa;AACnB,QAAM,WAAW,GAAG,OAAO,IAAI,WAAM,UAAU,WAAM,MAAM,YAAY,EAAE,MAAM,GAAG,EAAE,CAAC;AACrF,SAAO;AAAA,IACL;AAAA,IACA,QAAQ,OAAO;AAAA,IACf;AAAA,IACA;AAAA,IACA,aAAa;AAAA,IACb,WAAW;AAAA,IACX,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,gBAAgB;AAAA,EAClB;AACF;AAEA,SAAS,QAAQ,KAAgC;AAC/C,SAAO,EAAE,MAAM,SAAS,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,EAAE;AACpF;;;AD1NA,SAAS,WAAW,MAAc,GAA6B;AAC7D,MAAI,EAAE,SAAS,QAAS,QAAO,GAAG,KAAK,OAAO,EAAE,CAAC,WAAW,EAAE,OAAO;AACrE,MAAI,EAAE,SAAS,SAAS;AACtB,UAAM,IAAI,EAAE;AACZ,WAAO,GAAG,KAAK,OAAO,EAAE,CAAC,eAAe,EAAE,WAAW,MAAM,EAAE,aAAa,OAAO,EAAE,aAAa,QAAQ,EAAE,GAAG;AAAA,EAC/G;AACA,MAAI,EAAE,SAAS,SAAS;AACtB,WAAO,GAAG,KAAK,OAAO,EAAE,CAAC,YAAY,EAAE,OAAO,QAAQ;AAAA,EACxD;AACA,QAAM,MAAM,EAAE;AACd,MAAI,IAAI,WAAW,OAAQ,QAAO,GAAG,KAAK,OAAO,EAAE,CAAC,QAAQ,IAAI,QAAQ,WAAM,IAAI,KAAK,KAAK,EAAE;AAC9F,MAAI,IAAI,WAAW;AACjB,WAAO,GAAG,KAAK,OAAO,EAAE,CAAC,UAAU,IAAI,QAAQ,WAAM,IAAI,KAAK,KAAK,EAAE;AACvE,SAAO,GAAG,KAAK,OAAO,EAAE,CAAC,aAAa,IAAI,QAAQ,MAAM,UAAU,IAAI,QAAQ,WAAW,IAAI,KAAK,GAAG,IAAI,IAAI,QAAQ,WAAM,IAAI,KAAK,KAAK,EAAE;AAC7I;AAEA,SAAS,aAAa,GAAyB;AAC7C,QAAM,SAAS,IAAI,EAAE,IAAI,mBAAc,EAAE,WAAW,gCAAgC,SAAS;AAC7F,QAAM,OAAO,EAAE,MAAM,IAAI,CAAC,MAAM,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,KAAK,IAAI;AACvE,SAAO,GAAG,MAAM;AAAA,EAAK,IAAI;AAC3B;AAQA,eAAsB,iBACpB,MACA,MAC2C;AAC3C,QAAM,MAAM,KAAK,MAAM,QAAQ,KAAK,GAAG,IAAI,QAAQ,IAAI;AACvD,QAAM,QAAQ,MAAM,aAAa,EAAE,MAAM,IAAI,CAAC;AAC9C,QAAM,SAAS,MAAM,CAAC;AACtB,MAAI,CAAC,QAAQ;AACX,WAAO,EAAE,QAAQ,yBAAyB,IAAI,MAAM,MAAM,EAAE;AAAA,EAC9D;AAEA,QAAM,SAAS,MAAM,OAAO,MAAM;AAClC,SAAO,EAAE,QAAQ,aAAa,MAAM,GAAG,MAAM,OAAO,WAAW,IAAI,EAAE;AACvE;","names":[]}
|
|
@@ -2,11 +2,11 @@ import {
|
|
|
2
2
|
hasRealScores,
|
|
3
3
|
lighthouseScoresFromResult,
|
|
4
4
|
resolveSlugFromCwd
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import "./chunk-
|
|
5
|
+
} from "./chunk-YYUY2OVP.js";
|
|
6
|
+
import "./chunk-BLD6AYJO.js";
|
|
7
7
|
export {
|
|
8
8
|
hasRealScores,
|
|
9
9
|
lighthouseScoresFromResult,
|
|
10
10
|
resolveSlugFromCwd
|
|
11
11
|
};
|
|
12
|
-
//# sourceMappingURL=lighthouse-airtable-
|
|
12
|
+
//# sourceMappingURL=lighthouse-airtable-HTEW6BBT.js.map
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
} from "./chunk-4NAOR44V.js";
|
|
6
6
|
import {
|
|
7
7
|
resolveSites
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-SAOCVNX7.js";
|
|
9
9
|
import {
|
|
10
10
|
onboard
|
|
11
11
|
} from "./chunk-ZYBOT5PM.js";
|
|
@@ -66,4 +66,4 @@ async function runOnboardCommand(site, opts) {
|
|
|
66
66
|
export {
|
|
67
67
|
runOnboardCommand
|
|
68
68
|
};
|
|
69
|
-
//# sourceMappingURL=onboard-
|
|
69
|
+
//# sourceMappingURL=onboard-TTIC3YZI.js.map
|
|
@@ -4,12 +4,15 @@ import {
|
|
|
4
4
|
parseAddresses,
|
|
5
5
|
sendApprovedReports,
|
|
6
6
|
withGlobalCc
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-DXRKWALS.js";
|
|
8
|
+
import "./chunk-U3MF6RCS.js";
|
|
8
9
|
import "./chunk-OGGRFBL4.js";
|
|
9
|
-
import "./chunk-BWLUNY7L.js";
|
|
10
10
|
import "./chunk-OCS7SZUZ.js";
|
|
11
|
+
import "./chunk-L5F664ZA.js";
|
|
12
|
+
import "./chunk-6ZKM7OIJ.js";
|
|
13
|
+
import "./chunk-XKKTK6WA.js";
|
|
11
14
|
import "./chunk-U5SZ4FOP.js";
|
|
12
|
-
import "./chunk-
|
|
15
|
+
import "./chunk-BLD6AYJO.js";
|
|
13
16
|
import "./chunk-HN6I2XWI.js";
|
|
14
17
|
import "./chunk-WEKL2HYJ.js";
|
|
15
18
|
import "./chunk-6VAL7XJT.js";
|
|
@@ -20,4 +23,4 @@ export {
|
|
|
20
23
|
sendApprovedReports,
|
|
21
24
|
withGlobalCc
|
|
22
25
|
};
|
|
23
|
-
//# sourceMappingURL=orchestrate-
|
|
26
|
+
//# sourceMappingURL=orchestrate-I3KAJGFB.js.map
|
|
@@ -2,9 +2,9 @@ import {
|
|
|
2
2
|
ALL_CONFIG_NAMES,
|
|
3
3
|
isConfigName,
|
|
4
4
|
syncConfigs
|
|
5
|
-
} from "../chunk-
|
|
6
|
-
import "../chunk-CASCWQQX.js";
|
|
5
|
+
} from "../chunk-XVR7UM6Z.js";
|
|
7
6
|
import "../chunk-XKOZUVK2.js";
|
|
7
|
+
import "../chunk-CASCWQQX.js";
|
|
8
8
|
import "../chunk-XXTZBPUY.js";
|
|
9
9
|
import "../chunk-XTK5VIQB.js";
|
|
10
10
|
export {
|
|
@@ -3,13 +3,13 @@ import {
|
|
|
3
3
|
} from "./chunk-PZQ3WED2.js";
|
|
4
4
|
import {
|
|
5
5
|
makeGitHub
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-OSRFDGQM.js";
|
|
7
7
|
import "./chunk-HVOOCK6L.js";
|
|
8
8
|
import {
|
|
9
9
|
isDashboardVisible,
|
|
10
10
|
listWebsites,
|
|
11
11
|
updateAutoFixAttempts
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-BLD6AYJO.js";
|
|
13
13
|
import {
|
|
14
14
|
openBase,
|
|
15
15
|
readAirtableConfig
|
|
@@ -136,4 +136,4 @@ No active repo-backed sites with critical/high vulnerabilities \u2014 nothing to
|
|
|
136
136
|
export {
|
|
137
137
|
runRenovateDispatchCommand
|
|
138
138
|
};
|
|
139
|
-
//# sourceMappingURL=renovate-dispatch-
|
|
139
|
+
//# sourceMappingURL=renovate-dispatch-QDDMTATD.js.map
|
|
@@ -5,11 +5,11 @@ import {
|
|
|
5
5
|
import {
|
|
6
6
|
draftReportForSite,
|
|
7
7
|
readGaConfig
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-NPJFHBAX.js";
|
|
9
9
|
import {
|
|
10
10
|
reportTier
|
|
11
11
|
} from "./chunk-6LIWDIXU.js";
|
|
12
|
-
import "./chunk-
|
|
12
|
+
import "./chunk-U3MF6RCS.js";
|
|
13
13
|
import {
|
|
14
14
|
escapeHtml,
|
|
15
15
|
listAllReports
|
|
@@ -18,7 +18,7 @@ import "./chunk-U5SZ4FOP.js";
|
|
|
18
18
|
import {
|
|
19
19
|
listWebsites,
|
|
20
20
|
siteSlug
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-BLD6AYJO.js";
|
|
22
22
|
import {
|
|
23
23
|
openBase,
|
|
24
24
|
readAirtableConfig
|
|
@@ -68,11 +68,11 @@ function dashboardBaseUrl() {
|
|
|
68
68
|
}
|
|
69
69
|
async function runReportCommand(slug, opts) {
|
|
70
70
|
if (opts.digest) {
|
|
71
|
-
const { runDigest } = await import("./digest-
|
|
71
|
+
const { runDigest } = await import("./digest-ABJROO4H.js");
|
|
72
72
|
return runDigest({ baseUrl: dashboardBaseUrl() });
|
|
73
73
|
}
|
|
74
74
|
if (opts.sendReady) {
|
|
75
|
-
const { sendApprovedReports } = await import("./orchestrate-
|
|
75
|
+
const { sendApprovedReports } = await import("./orchestrate-I3KAJGFB.js");
|
|
76
76
|
return sendApprovedReports();
|
|
77
77
|
}
|
|
78
78
|
if (opts.due) {
|
|
@@ -237,4 +237,4 @@ export {
|
|
|
237
237
|
parseSingleSiteReportType,
|
|
238
238
|
runReportCommand
|
|
239
239
|
};
|
|
240
|
-
//# sourceMappingURL=report-
|
|
240
|
+
//# sourceMappingURL=report-PY6O3YMX.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
selfUpdating
|
|
3
|
-
} from "./chunk-
|
|
4
|
-
import "./chunk-
|
|
3
|
+
} from "./chunk-3HM4S422.js";
|
|
4
|
+
import "./chunk-OSRFDGQM.js";
|
|
5
5
|
import {
|
|
6
6
|
appendSkipNotice,
|
|
7
7
|
fleetWorkdir,
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
} from "./chunk-4NAOR44V.js";
|
|
10
10
|
import {
|
|
11
11
|
resolveSites
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-SAOCVNX7.js";
|
|
13
13
|
import "./chunk-CASCWQQX.js";
|
|
14
14
|
import "./chunk-FDIFTIXC.js";
|
|
15
15
|
import "./chunk-HVOOCK6L.js";
|
|
@@ -58,4 +58,4 @@ async function runSelfUpdatingCommand(site, opts) {
|
|
|
58
58
|
export {
|
|
59
59
|
runSelfUpdatingCommand
|
|
60
60
|
};
|
|
61
|
-
//# sourceMappingURL=self-updating-
|
|
61
|
+
//# sourceMappingURL=self-updating-2RLUP4AA.js.map
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
} from "./chunk-4NAOR44V.js";
|
|
6
6
|
import {
|
|
7
7
|
resolveSites
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-SAOCVNX7.js";
|
|
9
9
|
import {
|
|
10
10
|
svelteCodemods
|
|
11
11
|
} from "./chunk-FUD4I2ZW.js";
|
|
@@ -48,4 +48,4 @@ async function runSvelteCodemodsCommand(site, opts) {
|
|
|
48
48
|
export {
|
|
49
49
|
runSvelteCodemodsCommand
|
|
50
50
|
};
|
|
51
|
-
//# sourceMappingURL=svelte-codemods-
|
|
51
|
+
//# sourceMappingURL=svelte-codemods-BPLKSVIA.js.map
|
|
@@ -5,19 +5,19 @@ import {
|
|
|
5
5
|
} from "./chunk-4NAOR44V.js";
|
|
6
6
|
import {
|
|
7
7
|
resolveSites
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-SAOCVNX7.js";
|
|
9
9
|
import {
|
|
10
10
|
ALL_CONFIG_NAMES,
|
|
11
11
|
CANONICAL_GITIGNORE_ENTRIES,
|
|
12
12
|
isConfigName,
|
|
13
13
|
mergeGitignore,
|
|
14
14
|
syncConfigs
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-XVR7UM6Z.js";
|
|
16
|
+
import "./chunk-XKOZUVK2.js";
|
|
16
17
|
import {
|
|
17
18
|
ALL_TEMPLATES,
|
|
18
19
|
templatesByName
|
|
19
20
|
} from "./chunk-CASCWQQX.js";
|
|
20
|
-
import "./chunk-XKOZUVK2.js";
|
|
21
21
|
import "./chunk-FDIFTIXC.js";
|
|
22
22
|
import "./chunk-HVOOCK6L.js";
|
|
23
23
|
import "./chunk-XXTZBPUY.js";
|
|
@@ -106,4 +106,4 @@ async function runSyncConfigsCommand(site, opts) {
|
|
|
106
106
|
export {
|
|
107
107
|
runSyncConfigsCommand
|
|
108
108
|
};
|
|
109
|
-
//# sourceMappingURL=sync-configs-
|
|
109
|
+
//# sourceMappingURL=sync-configs-VFRV3TJ4.js.map
|
|
@@ -7,9 +7,14 @@ type Site = {
|
|
|
7
7
|
/** Deployed/production URL. When set, the lighthouse audit runs against this
|
|
8
8
|
* URL directly (no checkout, no dev server) instead of a local vite server. */
|
|
9
9
|
deployedUrl?: string;
|
|
10
|
+
/** Netlify site id (the API `id`/`site_id`, e.g. a UUID), when known (from
|
|
11
|
+
* Airtable). The `netlify-deploy` audit needs it to query the Netlify API;
|
|
12
|
+
* absent → that audit skips. NOT derived from the URL — it's an explicit
|
|
13
|
+
* identity column on the Websites row. */
|
|
14
|
+
netlifyId?: string;
|
|
10
15
|
meta?: Record<string, unknown>;
|
|
11
16
|
};
|
|
12
|
-
type AuditName = "deps" | "lighthouse" | "a11y" | "security" | "lint" | "domain" | "browser";
|
|
17
|
+
type AuditName = "deps" | "lighthouse" | "a11y" | "security" | "lint" | "domain" | "browser" | "netlify-deploy";
|
|
13
18
|
type RecipeName = "sync-configs" | "bump-deps" | "svelte-4-to-5" | "svelte-codemods" | "convert-to-pnpm" | "onboard" | "a11y-fixtures-page" | "self-updating" | "init";
|
|
14
19
|
type ConfigName = "lighthouse" | "eslint" | "prettier" | "prettier-ignore" | "playwright-a11y" | "svelte" | "gitignore" | "ci" | "renovate-action" | "renovate-config" | "netlify";
|
|
15
20
|
type AuditResult = {
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
} from "./chunk-4NAOR44V.js";
|
|
6
6
|
import {
|
|
7
7
|
resolveSites
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-SAOCVNX7.js";
|
|
9
9
|
import {
|
|
10
10
|
upgradeSvelte4to5
|
|
11
11
|
} from "./chunk-O65I7G7G.js";
|
|
@@ -61,4 +61,4 @@ async function runUpgradeCommand(upgradeName, site, opts = {}) {
|
|
|
61
61
|
export {
|
|
62
62
|
runUpgradeCommand
|
|
63
63
|
};
|
|
64
|
-
//# sourceMappingURL=upgrade-
|
|
64
|
+
//# sourceMappingURL=upgrade-WCFD2TRN.js.map
|
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
updateScores,
|
|
21
21
|
updateSecurityCounts,
|
|
22
22
|
updateSiteField
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-BLD6AYJO.js";
|
|
24
24
|
export {
|
|
25
25
|
ACTIVE_STATUSES,
|
|
26
26
|
SEVERITY_RANK,
|
|
@@ -44,4 +44,4 @@ export {
|
|
|
44
44
|
updateSecurityCounts,
|
|
45
45
|
updateSiteField
|
|
46
46
|
};
|
|
47
|
-
//# sourceMappingURL=websites-
|
|
47
|
+
//# sourceMappingURL=websites-HM2NMZMR.js.map
|
|
@@ -2,12 +2,13 @@ import {
|
|
|
2
2
|
formatFleetWriteSummary,
|
|
3
3
|
writeAuditsToAirtable,
|
|
4
4
|
writeFleetAuditsToAirtable
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import "./chunk-
|
|
7
|
-
import "./chunk-
|
|
5
|
+
} from "./chunk-4REUHZAW.js";
|
|
6
|
+
import "./chunk-YYUY2OVP.js";
|
|
7
|
+
import "./chunk-5L3FPQIJ.js";
|
|
8
|
+
import "./chunk-BLD6AYJO.js";
|
|
8
9
|
export {
|
|
9
10
|
formatFleetWriteSummary,
|
|
10
11
|
writeAuditsToAirtable,
|
|
11
12
|
writeFleetAuditsToAirtable
|
|
12
13
|
};
|
|
13
|
-
//# sourceMappingURL=write-audits-to-airtable-
|
|
14
|
+
//# sourceMappingURL=write-audits-to-airtable-QF26PCAR.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/recipes/announce.ts","../src/cli/commands/announce.ts"],"sourcesContent":["import { openBase, readAirtableConfig } from \"../reports/airtable/client.js\";\nimport type { AirtableBase } from \"../reports/airtable/client.js\";\nimport { listWebsites, siteSlug } from \"../reports/airtable/websites.js\";\nimport type { WebsiteRow } from \"../reports/airtable/websites.js\";\nimport {\n createDraft,\n findReportByPeriod,\n updateReportScores,\n type ReportEnrichment,\n} from \"../reports/airtable/reports.js\";\nimport { queueDraft } from \"../reports/queue.js\";\nimport { uploadAttachment } from \"../reports/airtable/attachments.js\";\nimport { renderReportHtml } from \"../reports/render.js\";\nimport { resolveCopy } from \"../reports/copy.js\";\nimport { fetchGaUsers, fetchSearch } from \"../reports/draft.js\";\nimport { announcementSiteExtras } from \"../reports/announcement-email/template.js\";\nimport type { LighthouseScores } from \"../reports/types.js\";\n\nexport type AnnounceSiteResult =\n | {\n site: string;\n status: \"drafted\" | \"reused\";\n reportId: string;\n recipientMissing: boolean;\n /** False when a higher-or-equal-tier report was already queued (single-queue rule). */\n queued: boolean;\n }\n | { site: string; status: \"skipped-no-scores\" }\n | { site: string; status: \"error\"; message: string };\n\nexport type AnnounceResult = { results: AnnounceSiteResult[] };\n\nexport type AnnounceDeps = {\n /** Airtable handle. Defaults to opening the live base from credentials. */\n base?: AirtableBase;\n /** When set, restrict to the single site whose slug matches. Default: all maintenance sites. */\n site?: string;\n /** Single timestamp driving the period key, render, draft, and preview filename. */\n now?: Date;\n};\n\n/**\n * Draft the monthly-report ANNOUNCEMENT email for every `maintenance` site (or one,\n * via `deps.site`). Airtable-driven and fleet-wide: unlike `launch`, it runs no audits\n * and takes no `Site`/inventory object — it reads the Lighthouse scores already stored\n * on each Websites row. DRAFTS ONLY; the M3 approve loop sends.\n *\n * One bad site must never abort the run: each site is wrapped in its own try/catch that\n * records an `error` result and continues.\n */\nexport async function announce(deps?: AnnounceDeps): Promise<AnnounceResult> {\n const base = deps?.base ?? openBase(readAirtableConfig());\n const now = deps?.now ?? new Date();\n\n const websites = await listWebsites(base);\n let targets = websites.filter((w) => w.status === \"maintenance\");\n if (deps?.site) {\n const wanted = siteSlug(deps.site);\n targets = targets.filter((w) => siteSlug(w.name) === wanted);\n }\n\n const period = now.toISOString().slice(0, 7);\n const results: AnnounceSiteResult[] = [];\n\n for (const w of targets) {\n try {\n const scores = scoresFromRow(w);\n if (scores === null) {\n results.push({ site: w.name, status: \"skipped-no-scores\" });\n continue;\n }\n\n // Traffic + search snapshot over a ~30-day window ending now (fetchPeriodUsers derives\n // the equal-length previous window for the trend). Reuses the report pipeline's\n // soft-failing enrichment: GA/search unconfigured or an API error leaves the numbers\n // null and the email simply omits the traffic section — it never blocks the draft.\n const periodEnd = now;\n const periodStart = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);\n const gaUsers = (await fetchGaUsers(w, periodStart, periodEnd)).value;\n const search = (await fetchSearch(w, periodStart, periodEnd)).value;\n const enrichment: ReportEnrichment = {\n ...(gaUsers ? { gaUsersCurrent: gaUsers.current, gaUsersPrevious: gaUsers.previous } : {}),\n ...(search ? { searchFoundPage1: search.foundOnPage1 } : {}),\n ...(search?.foundOnPage1 && search.position !== null\n ? { searchPosition: search.position }\n : {}),\n };\n\n // Dedupe: reuse an existing Announcement row for this (site, period) rather than\n // stacking a second draft. The reuse path refreshes the stored scores + traffic/search\n // (and Completed on) so the eventually-sent email — which reads the row — isn't stale.\n // The create path writes them via createDraft.\n let report;\n let statusKind: \"drafted\" | \"reused\";\n const existing = await findReportByPeriod(base, w.id, \"Announcement\", period);\n if (existing) {\n await updateReportScores(base, existing.id, scores, now, enrichment);\n report = existing;\n statusKind = \"reused\";\n } else {\n report = await createDraft(base, draftInputFor(w, scores, now, period, enrichment));\n statusKind = \"drafted\";\n }\n\n const slug = siteSlug(w.name);\n const { html } = await renderReportHtml({\n siteName: w.name,\n siteUrl: w.url,\n reportType: \"Announcement\",\n completedOn: now,\n lighthouse: scores,\n gaUsersCurrent: gaUsers?.current,\n gaUsersPrevious: gaUsers?.previous,\n searchPosition: search?.foundOnPage1 ? (search.position ?? undefined) : undefined,\n lastTestedDate: null,\n commentary: null,\n copy: resolveCopy(w),\n headerImageCid: `${slug}-header`,\n // cadence (the client's go-forward pace, \"None\" omitted) + default-on improvement\n // callouts. Shared with the send re-render via announcementSiteExtras so the sent\n // email matches this reviewed preview.\n ...announcementSiteExtras(w),\n });\n\n // A preview-upload hiccup must NOT fail the site — log and continue.\n try {\n await uploadAttachment(\n report.id,\n \"Rendered HTML\",\n html,\n `${slug}-${now.toISOString().slice(0, 10)}.html`,\n \"text/html\",\n );\n } catch (uploadErr) {\n console.warn(\n `⚠ Announcement preview upload skipped for ${w.name}: ${\n uploadErr instanceof Error ? uploadErr.message : String(uploadErr)\n }`,\n );\n }\n\n // Critical: NOT wrapped — without queueing, the draft never enters the approve queue,\n // so a failure here must surface as an error result for the site. queueDraft also\n // supersedes any lower-tier (Maintenance/Testing) drafts queued for this site, and\n // stands down if an equal-or-higher report is already queued (single-queue rule).\n const queue = await queueDraft(base, {\n id: report.id,\n siteId: w.id,\n reportType: \"Announcement\",\n });\n\n const recipientMissing = !(w.reportRecipientsTo && w.reportRecipientsTo.trim());\n results.push({\n site: w.name,\n status: statusKind,\n reportId: report.id,\n recipientMissing,\n queued: queue.queued,\n });\n } catch (err) {\n results.push({\n site: w.name,\n status: \"error\",\n message: err instanceof Error ? err.message : String(err),\n });\n }\n }\n\n return { results };\n}\n\n/** The four stored Lighthouse scores off a Websites row, or null if ANY is missing. */\nfunction scoresFromRow(w: WebsiteRow): LighthouseScores | null {\n if (w.pScore === null || w.rScore === null || w.bpScore === null || w.seoScore === null) {\n return null;\n }\n return {\n performance: w.pScore,\n accessibility: w.rScore,\n bestPractices: w.bpScore,\n seo: w.seoScore,\n };\n}\n\n/** Build the Announcement `DraftInput`. Announcements have no period window and no prior\n * maintenance test, so periodStart/periodEnd/completedOn all collapse to `now` and\n * `lastTestedDate` is null. The subject override gives the email a purpose-built line. */\nfunction draftInputFor(\n w: WebsiteRow,\n scores: LighthouseScores,\n now: Date,\n period: string,\n enrichment: ReportEnrichment,\n): Parameters<typeof createDraft>[1] {\n return {\n reportId: `${w.name} — Announcement — ${now.toISOString().slice(0, 10)}`,\n siteId: w.id,\n reportType: \"Announcement\",\n period,\n periodStart: now,\n periodEnd: now,\n completedOn: now,\n lighthouse: scores,\n lastTestedDate: null,\n subjectOverride: `Your testing & maintenance schedule for ${w.name}`,\n ...enrichment,\n };\n}\n","import { announce, type AnnounceResult, type AnnounceSiteResult } from \"../../recipes/announce.js\";\n\nexport type AnnounceCommandOptions = {\n cwd?: string;\n};\n\nfunction formatSiteResult(r: AnnounceSiteResult): string {\n if (r.status === \"skipped-no-scores\") return `[${r.site}] skipped-no-scores`;\n if (r.status === \"error\") return `[${r.site}] error: ${r.message}`;\n const note = r.recipientMissing ? \" ⚠ recipient missing\" : \"\";\n return `[${r.site}] ${r.status}${note}`;\n}\n\nexport function formatAnnounceResult(result: AnnounceResult): string {\n if (result.results.length === 0) return \"No maintenance sites to announce.\";\n return result.results.map(formatSiteResult).join(\"\\n\");\n}\n\n/**\n * `announce [site]` — Airtable-driven and fleet-wide. Draft the monthly-report\n * announcement email for every `maintenance` site (or one, when `site` is given) into\n * the M3 approve queue. Never sends; the operator approves each draft and the next send\n * run delivers it. Reads the Lighthouse scores already stored on each Websites row —\n * no audits are run.\n */\nexport async function runAnnounceCommand(\n site: string | undefined,\n _opts: AnnounceCommandOptions,\n): Promise<{ output: string; code: number }> {\n const result = await announce(site ? { site } : {});\n const hadError = result.results.some((r) => r.status === \"error\");\n return { output: formatAnnounceResult(result), code: hadError ? 1 : 0 };\n}\n"],"mappings":"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","names":[]}
|