File size: 3,738 Bytes
fa9c65f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | export type BootstrapR2RumTier = 'fast' | 'slow';
export type BootstrapR2RumOutcome = 'success' | 'abort';
export type BootstrapR2RumRejectReason =
| 'missing-server-timing'
| 'invalid-server-timing'
| 'missing-vercel-cache-status'
| 'vercel-not-miss'
| 'cloudflare-cache-hit'
| 'cached-age'
| 'invalid-duration';
export interface BootstrapR2RumSample {
bootstrap_tier: BootstrapR2RumTier;
device_class: 'mobile' | 'desktop';
total_duration_ms: number;
redis_duration_ms: number;
non_r2_overhead_ms: number;
outcome: BootstrapR2RumOutcome;
}
export type BootstrapR2RumResult =
| { accepted: true; sample: BootstrapR2RumSample }
| { accepted: false; reason: BootstrapR2RumRejectReason };
const SERVER_TIMING_RE = /(?:^|,)\s*wm_bootstrap_redis\s*;\s*dur\s*=\s*(\d+(?:\.\d+)?)\s*(?:,|$)/i;
const REDIS_DURATION_RE = /^\d+(?:\.\d+)?$/;
const REDIS_DURATION_HEADER = 'x-worldmonitor-bootstrap-redis-duration';
const CLOUDFLARE_ORIGIN_STATES = new Set(['DYNAMIC', 'BYPASS', 'MISS']);
export function selectBootstrapR2RumTier(rng: () => number = Math.random): BootstrapR2RumTier {
return rng() < 0.5 ? 'fast' : 'slow';
}
function readRedisDuration(headers: Headers): number | null | 'invalid' {
const rawPlatformSafeDuration = headers.get(REDIS_DURATION_HEADER);
if (rawPlatformSafeDuration !== null) {
const platformSafeDuration = rawPlatformSafeDuration.trim();
if (!REDIS_DURATION_RE.test(platformSafeDuration)) return 'invalid';
const duration = Number(platformSafeDuration);
return Number.isFinite(duration) && duration >= 0 ? duration : 'invalid';
}
const raw = headers.get('server-timing');
if (!raw) return null;
const match = raw.match(SERVER_TIMING_RE);
if (!match) return 'invalid';
const duration = Number(match[1]);
return Number.isFinite(duration) && duration >= 0 ? duration : 'invalid';
}
/**
* Conservative candidate classifier for the U3a purge -> MISS -> HIT proof.
* Production evidence must validate the accepted header tuple before any
* sample is admitted to C_happy; unknown or conflicting states fail closed.
*/
export function buildBootstrapR2RumSample(
tier: BootstrapR2RumTier,
outcome: BootstrapR2RumOutcome,
totalDurationMs: number,
headers: Headers,
deviceClass: 'mobile' | 'desktop',
): BootstrapR2RumResult {
const redisDurationMs = readRedisDuration(headers);
if (redisDurationMs === null) return { accepted: false, reason: 'missing-server-timing' };
if (redisDurationMs === 'invalid') return { accepted: false, reason: 'invalid-server-timing' };
const vercelCache = headers.get('x-vercel-cache')?.trim().toUpperCase();
if (!vercelCache) return { accepted: false, reason: 'missing-vercel-cache-status' };
if (vercelCache !== 'MISS') return { accepted: false, reason: 'vercel-not-miss' };
const cloudflareCache = headers.get('cf-cache-status')?.trim().toUpperCase();
if (cloudflareCache && !CLOUDFLARE_ORIGIN_STATES.has(cloudflareCache)) {
return { accepted: false, reason: 'cloudflare-cache-hit' };
}
const rawAge = headers.get('age');
if (rawAge != null && rawAge.trim() !== '') {
const age = rawAge.trim();
if (!/^\d+$/.test(age) || Number(age) !== 0) {
return { accepted: false, reason: 'cached-age' };
}
}
if (
!Number.isFinite(totalDurationMs)
|| totalDurationMs < 0
|| redisDurationMs > totalDurationMs
) {
return { accepted: false, reason: 'invalid-duration' };
}
return {
accepted: true,
sample: {
bootstrap_tier: tier,
device_class: deviceClass,
total_duration_ms: totalDurationMs,
redis_duration_ms: redisDurationMs,
non_r2_overhead_ms: totalDurationMs - redisDurationMs,
outcome,
},
};
}
|