/** * Contract Headers - Dynamic Version & Canonical Fingerprint * * NO HARDCODING: Version comes from package.json, fingerprint from canonical schemas */ import { createHash } from "crypto"; import pkg from "../package.json"; /** * Emit contract headers with dynamic version and fingerprint * SINGLE SOURCE OF TRUTH: No hardcoded values */ export function emitContractHeaders(): Record { const version = pkg.version; // <- Single source of truth from package.json // Try to get fingerprint from generated file, fallback to package version let fingerprint: string; try { const { CONTRACTS_FINGERPRINT } = require('./fingerprint'); fingerprint = CONTRACTS_FINGERPRINT; } catch { // Fallback during development/testing before fingerprint is generated fingerprint = `${version}:development`; } return { "X-Contracts-Version": version, "X-Contracts-Fingerprint": fingerprint, }; } /** * Validate that headers match package version (for testing) */ export function validateHeadersMatchPackage(): { valid: boolean; errors: string[] } { const errors: string[] = []; const headers = emitContractHeaders(); if (headers["X-Contracts-Version"] !== pkg.version) { errors.push(`Header version ${headers["X-Contracts-Version"]} !== package version ${pkg.version}`); } if (!headers["X-Contracts-Fingerprint"].startsWith(`${pkg.version}:`)) { errors.push(`Fingerprint doesn't start with package version: ${headers["X-Contracts-Fingerprint"]}`); } return { valid: errors.length === 0, errors }; }