// Ephemeral media leases — the discriminated union from design §12. // // A lease is the resolver's answer to "how do I play this item RIGHT NOW": // either a transport-private URL (webview) or an opaque native handle, plus // a conservative `safeForMs` after which the transport must re-resolve. // Leases are never persisted, never used as cache identity, and never logged // in full (see redact.js). /** * Safety margin subtracted from every derived lifetime. ADR (Phase 0): leases * hard-403 after their signed exp with NO grace observed (206 at +14 min * against a +14.97 exp, 403 by +17.5). 20 s covers request latency, decoder * spin-up and one settle-window retry without meaningfully shortening a * 13-minute lease. */ export const LEASE_SAFETY_MARGIN_MS = 20_000; /** * Fallback lifetime when provider time data is missing, malformed or * contradictory. Deliberately short: Phase 0 never observed a lease younger * than ~13 min, so 60 s is far inside any real lifetime while still letting * a clip play out (clips are 30 s) before a forced refresh. */ export const LEASE_FALLBACK_SAFE_MS = 60_000; /** Longest lifetime we will ever trust, however healthy the inputs look — * a parse artifact claiming hours must not disable refresh. */ export const LEASE_MAX_SAFE_MS = 30 * 60_000; /** * Derive `safeForMs` from provider time data, per design §12: * conservative, provider-clock based, never trusting any single input. * * @param {object} t * @param {number|null} t.expEpochMs parsed signed expiry (provider clock) * @param {number|null} t.dateHeaderMs provider `Date` header (provider clock) * @param {number} t.localNowMs local wall clock at receipt * @returns {number} milliseconds the lease may be used, >= 0 */ export function computeSafeForMs({ expEpochMs, dateHeaderMs, localNowMs }) { const bad = !Number.isFinite(expEpochMs) || !Number.isFinite(localNowMs) || expEpochMs <= 0; if (bad) return LEASE_FALLBACK_SAFE_MS; // Remaining lifetime on the provider's own clock when both ends of it // are known — immune to local clock skew entirely. let remaining = null; if (Number.isFinite(dateHeaderMs) && dateHeaderMs > 0) { remaining = expEpochMs - dateHeaderMs; // Contradictory provider data (exp at/before Date, or a lifetime far // beyond anything the provider actually issues) → fallback. if (remaining <= 0 || remaining > 2 * LEASE_MAX_SAFE_MS) { return LEASE_FALLBACK_SAFE_MS; } } // Local-clock view. If the local clock is skewed AHEAD of the provider, // this is smaller than `remaining` and correctly wins (we refresh early). // If skewed BEHIND, `remaining` wins and the local view can't extend it. const localView = expEpochMs - localNowMs; if (localView <= 0 && remaining === null) return LEASE_FALLBACK_SAFE_MS; const usable = remaining === null ? localView : Math.min(remaining, localView > 0 ? localView : remaining); const safe = Math.min(usable, LEASE_MAX_SAFE_MS) - LEASE_SAFETY_MARGIN_MS; return Math.max(0, safe); } /** Build a native-transport lease (the ratified transport). */ export function makeNativeLease({ source, opaqueLeaseId, safeForMs, mimeType, clipDurationMs, byteLength, supportsRanges }) { if (typeof opaqueLeaseId !== "string" || !opaqueLeaseId) { throw new Error("native lease requires opaqueLeaseId"); } return Object.freeze({ transport: "native", source, opaqueLeaseId, safeForMs, mimeType, clipDurationMs, byteLength, supportsRanges, }); } /** Build a webview-transport lease (documented fallback transport). */ export function makeWebviewLease({ source, url, safeForMs, mimeType, clipDurationMs, byteLength, supportsRanges }) { if (typeof url !== "string" || !url) { throw new Error("webview lease requires url"); } return Object.freeze({ transport: "webview", source, url, safeForMs, mimeType, clipDurationMs, byteLength, supportsRanges, }); } /** Union validity: exactly one locator, matching the transport tag. */ export function isValidLease(lease) { if (!lease || typeof lease !== "object") return false; if (!Number.isFinite(lease.safeForMs) || lease.safeForMs < 0) return false; if (lease.transport === "native") { return typeof lease.opaqueLeaseId === "string" && lease.opaqueLeaseId !== "" && lease.url === undefined; } if (lease.transport === "webview") { return typeof lease.url === "string" && lease.url !== "" && lease.opaqueLeaseId === undefined; } return false; }