* refactor: move lighthouse audits to dataforseo * chore: remove obsolete audit settings modal * refactor: rename psi flows to lighthouse * save * refactor: simplify audit lighthouse storage flow * fix: separate lighthouse metrics from actionable audits * refactor: remove redundant audit project inputs * feat: redesign lighthouse issues screen with score gauges and table layout Replace flat score cards with circular SVG gauges, condense metrics into a compact grid, and switch issue list from cards to an expandable table with fixed column widths. * test: harden lighthouse regression coverage * fix: restore project-scoped audit inputs * refactor: simplify lighthouse payload handling * refactor: inline lighthouse server handlers * refactor: share audit workflow types * refactor: simplify lighthouse payload flows * save * refactor: drop project pagespeed api key * fix: restore lighthouse issues loading with resilient project context * fix: restore audit issues back navigation * refactor: simplify project context and lighthouse error handling * fix: tolerate DataForSEO lighthouse payload drift * refactor: route audit lighthouse through dataforseo client
61 lines
1.7 KiB
TypeScript
61 lines
1.7 KiB
TypeScript
import { env } from "cloudflare:workers";
|
|
import {
|
|
parseDataforseoLighthousePayload,
|
|
requestCategories,
|
|
type LighthouseStrategy,
|
|
} from "@/server/lib/dataforseoLighthousePayload";
|
|
import type { DataforseoApiResponse } from "@/server/lib/dataforseoCost";
|
|
import type { StoredLighthousePayload } from "@/server/lib/lighthouseStoredPayload";
|
|
|
|
const DATAFORSEO_LIGHTHOUSE_ENDPOINT =
|
|
"https://api.dataforseo.com/v3/on_page/lighthouse/live/json";
|
|
|
|
export async function fetchDataforseoLighthouseResultRaw(input: {
|
|
url: string;
|
|
strategy: LighthouseStrategy;
|
|
}): Promise<DataforseoApiResponse<StoredLighthousePayload>> {
|
|
const response = await fetch(DATAFORSEO_LIGHTHOUSE_ENDPOINT, {
|
|
method: "POST",
|
|
headers: {
|
|
Authorization: `Basic ${env.DATAFORSEO_API_KEY?.trim() ?? ""}`,
|
|
"Content-Type": "application/json",
|
|
},
|
|
body: JSON.stringify([
|
|
{
|
|
url: input.url,
|
|
for_mobile: input.strategy === "mobile",
|
|
categories: requestCategories,
|
|
},
|
|
]),
|
|
signal: AbortSignal.timeout(60_000),
|
|
});
|
|
|
|
const rawText = await response.text();
|
|
|
|
if (!response.ok) {
|
|
throw new Error(
|
|
`DataForSEO Lighthouse request failed (${response.status}): ${rawText}`,
|
|
);
|
|
}
|
|
|
|
let payload: unknown;
|
|
try {
|
|
payload = JSON.parse(rawText);
|
|
} catch {
|
|
throw new Error(
|
|
`DataForSEO Lighthouse returned non-JSON content (content-type: ${response.headers.get("content-type") ?? "unknown"}): ${rawText}`,
|
|
);
|
|
}
|
|
|
|
const data = parseDataforseoLighthousePayload(payload, input);
|
|
|
|
return {
|
|
data,
|
|
billing: {
|
|
path: ["v3", "on_page", "lighthouse", "live", "json"],
|
|
costUsd: data.metadata.cost ?? 0,
|
|
resultCount: 1,
|
|
},
|
|
};
|
|
}
|