import { type NormalizedMaxStale, type NormalizedParams, type NormalizedProducerResult, type NormalizedProducerResultResource, type NormalizedVary, type NormalizeParamName, type NormalizeParamValue, } from '../types/06_Normalization.js'; import { type AnyParams, type AnyParamValue, type AnyValidators, type ProducerResult, type ProducerResultResource, type Vary, } from '../types/index.js'; export function normalizeProducerResult< Content, Validators extends AnyValidators, Params extends AnyParams, >( normalizeVary: (vary: Vary) => NormalizedVary, it: ProducerResult, fallbackProducedAt?: Date, ): NormalizedProducerResult { const { supplementalResources, ...rest } = it; return { ...normalizeProducerResultResource(normalizeVary, rest, fallbackProducedAt), supplementalResources: supplementalResources?.map((it) => normalizeProducerResultResource(normalizeVary, it, fallbackProducedAt), ), }; } export function normalizeProducerResultResource< Content, Validators extends AnyValidators, Params extends AnyParams, >( normalizeVary: (vary: Vary) => NormalizedVary, resourceResult: ProducerResultResource, fallbackProducedAt?: Date, ): NormalizedProducerResultResource { const { maxStale, ...otherDirectives } = resourceResult.directives; return { ...resourceResult, initialAge: Math.max(resourceResult.initialAge ?? 0, 0), vary: normalizeVary(resourceResult.vary ?? {}), directives: { ...otherDirectives, ...(maxStale != null ? { maxStale: normalizeMaxStale(maxStale) } : {}), }, validators: resourceResult.validators ?? {}, date: resourceResult.date ?? fallbackProducedAt ?? new Date(), }; } export function normalizeParams( normalizeParamName: NormalizeParamName, normalizeParamValue: NormalizeParamValue, params: Partial, ): NormalizedParams { const entries = Object.entries(params) satisfies [string, any][] as [ keyof Params & string, Params[keyof Params] | undefined, ][]; const normalizedEntries = entries .filter(([_, v]) => v !== undefined) .map(([k, v]) => { const finalName = normalizeParamName(k); const finalVal = normalizeParamValue(finalName, v!); return [finalName, finalVal] as const; }); return Object.fromEntries(normalizedEntries) satisfies { [k: string]: Params[keyof Params] & AnyParamValue; } as unknown as NormalizedParams; } /** * This is identical to `normalizeParams`, except that param values in `vary` * can be explicitly null, to indicate that the producer relied on the param * being missing. */ export function normalizeVary( normalizeParamName: NormalizeParamName, normalizeParamValue: NormalizeParamValue, vary: Vary, ): NormalizedVary { const entries = Object.entries(vary) satisfies [string, any][] as [ keyof Params & string, Params[keyof Params] | undefined, ][]; const normalizedEntries = entries .filter(([_, v]) => v !== undefined) .map(([k, v]) => { const finalName = normalizeParamName(k); const finalVal = v === null ? v : normalizeParamValue(finalName, v!); return [finalName, finalVal] as const; }); return Object.fromEntries(normalizedEntries) satisfies { [k: string]: (Params[keyof Params] & AnyParamValue) | null; } as unknown as NormalizedVary; } /** * Takes a provided maxStale directive value and normalizes it into its * canonical, valid form, namely by making sure that each number is >= the * previous one. */ export function normalizeMaxStale(maxStale: [number, number, number]) { return maxStale.reduce((acc, it) => { acc.push(Math.max(acc[acc.length - 1] || 0, it)); return acc; }, [] as number[]) as NormalizedMaxStale; }