import { z } from "zod"; const WINDOW_MILLISECONDS = 28 * 24 * 60 * 60 * 1000; const nonEmptyString = z.string().trim().min(1); const timestamp = nonEmptyString.refine( (value) => Number.isFinite(Date.parse(value)), "must be an RFC 3339 timestamp", ); const sampleSchema = z .object({ timestamp, consent: z.boolean(), releaseId: nonEmptyString, routeId: nonEmptyString.regex(/^[A-Z][A-Z0-9_]*$/), lcpMs: z.number().finite().nonnegative(), cls: z.number().finite().nonnegative(), inpMs: z.number().finite().nonnegative(), }) .strict(); const fieldEvidenceInputSchema = z .object({ schemaVersion: z.literal(1), environment: z.literal("production"), releaseId: nonEmptyString.refine( (value) => value !== "local-release", "must identify an immutable production release", ), source: z .object({ system: nonEmptyString, exportId: nonEmptyString, }) .strict(), privacy: z .object({ approved: z.literal(true), approvalRef: nonEmptyString, }) .strict(), window: z .object({ start: timestamp, end: timestamp, }) .strict(), thresholdDecision: z .object({ status: z.literal("approved"), minimumEligibleSamples: z.number().int().positive(), owner: nonEmptyString, reviewedAt: timestamp, evidenceRef: nonEmptyString, }) .strict(), samples: z.array(sampleSchema), }) .strict() .superRefine((input, context) => { const start = Date.parse(input.window.start); const end = Date.parse(input.window.end); if (end - start !== WINDOW_MILLISECONDS) { context.addIssue({ code: "custom", path: ["window"], message: "must cover exactly 28 days", }); } }); /** * @param {unknown} input * @param {string | undefined} configuredMinimum * @param {Date} [now] */ export function validateFieldEvidenceInput( input, configuredMinimum, now = new Date(), ) { const parsed = fieldEvidenceInputSchema.safeParse(input); const failures = parsed.success ? [] : parsed.error.issues.map( (issue) => `${issue.path.join(".") || "input"}: ${issue.message}`, ); const minimumEligibleSamples = Number(configuredMinimum); if ( configuredMinimum === undefined || !Number.isInteger(minimumEligibleSamples) || minimumEligibleSamples <= 0 ) { failures.push("MIN_ELIGIBLE_SAMPLES: must be a positive integer"); } if (parsed.success) { if ( parsed.data.thresholdDecision.minimumEligibleSamples !== minimumEligibleSamples ) { failures.push( "MIN_ELIGIBLE_SAMPLES: does not match the approved threshold decision", ); } if (Date.parse(parsed.data.window.end) > now.getTime()) { failures.push("window.end: must not be in the future"); } if (Date.parse(parsed.data.thresholdDecision.reviewedAt) > now.getTime()) { failures.push("thresholdDecision.reviewedAt: must not be in the future"); } } return Object.freeze({ data: parsed.success ? parsed.data : null, failures: Object.freeze(failures), minimumEligibleSamples: Number.isInteger(minimumEligibleSamples) && minimumEligibleSamples > 0 ? minimumEligibleSamples : null, passed: parsed.success && failures.length === 0, }); }