Mirror of https://github.com/roostorg/coop
github.com/roostorg/coop
1import {
2 type NormalizedMaxStale,
3 type NormalizedParams,
4 type NormalizedProducerResult,
5 type NormalizedProducerResultResource,
6 type NormalizedVary,
7 type NormalizeParamName,
8 type NormalizeParamValue,
9} from "../types/06_Normalization.js";
10import {
11 type AnyParams,
12 type AnyParamValue,
13 type AnyValidators,
14 type ProducerResult,
15 type ProducerResultResource,
16 type Vary,
17} from "../types/index.js";
18
19export function normalizeProducerResult<
20 Content,
21 Validators extends AnyValidators,
22 Params extends AnyParams,
23>(
24 normalizeVary: (vary: Vary<Params>) => NormalizedVary<Params>,
25 it: ProducerResult<Content, Validators, Params>,
26 fallbackProducedAt?: Date,
27): NormalizedProducerResult<Content, Validators, Params> {
28 const { supplementalResources, ...rest } = it;
29 return {
30 ...normalizeProducerResultResource(normalizeVary, rest, fallbackProducedAt),
31 supplementalResources: supplementalResources?.map((it) =>
32 normalizeProducerResultResource(normalizeVary, it, fallbackProducedAt),
33 ),
34 };
35}
36
37export function normalizeProducerResultResource<
38 Content,
39 Validators extends AnyValidators,
40 Params extends AnyParams,
41>(
42 normalizeVary: (vary: Vary<Params>) => NormalizedVary<Params>,
43 resourceResult: ProducerResultResource<Content, Validators, Params>,
44 fallbackProducedAt?: Date,
45): NormalizedProducerResultResource<Content, Validators, Params> {
46 const { maxStale, ...otherDirectives } = resourceResult.directives;
47
48 return {
49 ...resourceResult,
50 initialAge: Math.max(resourceResult.initialAge ?? 0, 0),
51 vary: normalizeVary(resourceResult.vary ?? {}),
52 directives: {
53 ...otherDirectives,
54 ...(maxStale != null ? { maxStale: normalizeMaxStale(maxStale) } : {}),
55 },
56 validators: resourceResult.validators ?? {},
57 date: resourceResult.date ?? fallbackProducedAt ?? new Date(),
58 };
59}
60
61export function normalizeParams<Params extends AnyParams>(
62 normalizeParamName: NormalizeParamName<Params>,
63 normalizeParamValue: NormalizeParamValue<Params>,
64 params: Partial<Params>,
65): NormalizedParams<Params> {
66 const entries = Object.entries(params) satisfies [string, any][] as [
67 keyof Params & string,
68 Params[keyof Params] | undefined,
69 ][];
70
71 const normalizedEntries = entries
72 .filter(([_, v]) => v !== undefined)
73 .map(([k, v]) => {
74 const finalName = normalizeParamName(k);
75 const finalVal = normalizeParamValue(finalName, v!);
76 return [finalName, finalVal] as const;
77 });
78
79 return Object.fromEntries(normalizedEntries) satisfies {
80 [k: string]: Params[keyof Params] & AnyParamValue;
81 } as unknown as NormalizedParams<Params>;
82}
83
84/**
85 * This is identical to `normalizeParams`, except that param values in `vary`
86 * can be explicitly null, to indicate that the producer relied on the param
87 * being missing.
88 */
89export function normalizeVary<Params extends AnyParams>(
90 normalizeParamName: NormalizeParamName<Params>,
91 normalizeParamValue: NormalizeParamValue<Params>,
92 vary: Vary<Params>,
93): NormalizedVary<Params> {
94 const entries = Object.entries(vary) satisfies [string, any][] as [
95 keyof Params & string,
96 Params[keyof Params] | undefined,
97 ][];
98
99 const normalizedEntries = entries
100 .filter(([_, v]) => v !== undefined)
101 .map(([k, v]) => {
102 const finalName = normalizeParamName(k);
103 const finalVal = v === null ? v : normalizeParamValue(finalName, v!);
104 return [finalName, finalVal] as const;
105 });
106
107 return Object.fromEntries(normalizedEntries) satisfies {
108 [k: string]: (Params[keyof Params] & AnyParamValue) | null;
109 } as unknown as NormalizedVary<Params>;
110}
111
112/**
113 * Takes a provided maxStale directive value and normalizes it into its
114 * canonical, valid form, namely by making sure that each number is >= the
115 * previous one.
116 */
117export function normalizeMaxStale(maxStale: [number, number, number]) {
118 return maxStale.reduce((acc, it) => {
119 acc.push(Math.max(acc[acc.length - 1] || 0, it));
120 return acc;
121 }, [] as number[]) as NormalizedMaxStale;
122}