mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-07-24 04:51:51 +00:00
100 lines
2.9 KiB
TypeScript
100 lines
2.9 KiB
TypeScript
import {
|
|
LIGHTHOUSE_CONTEXT_KIND,
|
|
LIGHTHOUSE_CONTEXT_SOURCE,
|
|
LIGHTHOUSE_CONTEXT_TRANSPORT,
|
|
type LighthouseContextEnvelope,
|
|
type LighthouseContextItem,
|
|
} from "@/types/lighthouse-context";
|
|
|
|
import {
|
|
lighthouseContextEnvelopeSchema,
|
|
lighthouseContextItemSchema,
|
|
} from "./schema";
|
|
import { getApiLighthouseContextByteLength } from "./transport";
|
|
|
|
export const LIGHTHOUSE_CONTEXT_MAX_BYTES = 2 * 1024;
|
|
|
|
export function prepareLighthouseContext(
|
|
value: unknown,
|
|
): LighthouseContextEnvelope | undefined {
|
|
const result = lighthouseContextEnvelopeSchema.safeParse(value);
|
|
if (!result.success) return undefined;
|
|
|
|
const scopeKey = result.data.items[0]?.scopeKey;
|
|
return scopeKey
|
|
? compileLighthouseContext(result.data.items, scopeKey)
|
|
: undefined;
|
|
}
|
|
|
|
export function compileLighthouseContext(
|
|
candidates: unknown[],
|
|
scopeKey: string,
|
|
): LighthouseContextEnvelope | undefined {
|
|
const parsedItems: LighthouseContextItem[] = [];
|
|
|
|
for (const candidate of candidates) {
|
|
if (hasDifferentScope(candidate, scopeKey)) continue;
|
|
const result = lighthouseContextItemSchema.safeParse(candidate);
|
|
if (!result.success) return undefined;
|
|
parsedItems.push(result.data);
|
|
}
|
|
|
|
const seen = new Set<string>();
|
|
const items = parsedItems
|
|
.sort((left, right) => getItemOrder(left) - getItemOrder(right))
|
|
.filter((item) => {
|
|
const key = `${item.kind}:${item.id}`;
|
|
if (seen.has(key)) return false;
|
|
seen.add(key);
|
|
return true;
|
|
});
|
|
|
|
return buildEnvelopeWithProgressiveDegradation(items);
|
|
}
|
|
|
|
function hasDifferentScope(candidate: unknown, scopeKey: string): boolean {
|
|
return (
|
|
typeof candidate === "object" &&
|
|
candidate !== null &&
|
|
"scopeKey" in candidate &&
|
|
typeof candidate.scopeKey === "string" &&
|
|
candidate.scopeKey !== scopeKey
|
|
);
|
|
}
|
|
|
|
function getItemOrder(item: LighthouseContextItem): number {
|
|
if (item.kind === LIGHTHOUSE_CONTEXT_KIND.PAGE) return 0;
|
|
if (item.source === LIGHTHOUSE_CONTEXT_SOURCE.FOCUSED) return 1;
|
|
return item.source === LIGHTHOUSE_CONTEXT_SOURCE.AUTOMATIC ? 3 : 2;
|
|
}
|
|
|
|
function buildEnvelopeWithinLimits(
|
|
items: LighthouseContextItem[],
|
|
): LighthouseContextEnvelope | undefined {
|
|
if (items.length === 0 || items.length > 8) return undefined;
|
|
|
|
const result = lighthouseContextEnvelopeSchema.safeParse({
|
|
schemaVersion: 1,
|
|
transport: LIGHTHOUSE_CONTEXT_TRANSPORT.INLINE,
|
|
items,
|
|
});
|
|
if (!result.success) return undefined;
|
|
|
|
const byteLength = getApiLighthouseContextByteLength(result.data);
|
|
return byteLength <= LIGHTHOUSE_CONTEXT_MAX_BYTES ? result.data : undefined;
|
|
}
|
|
|
|
function buildEnvelopeWithProgressiveDegradation(
|
|
items: LighthouseContextItem[],
|
|
): LighthouseContextEnvelope | undefined {
|
|
const retainedItems = items.slice(0, 8);
|
|
|
|
while (retainedItems.length > 0) {
|
|
const context = buildEnvelopeWithinLimits(retainedItems);
|
|
if (context) return context;
|
|
retainedItems.pop();
|
|
}
|
|
|
|
return undefined;
|
|
}
|