import { blockedGate, capabilityIssue, readyGate, type CapabilityGateResult } from "./capability-gates"; import type { WebEngineManifestV2, WebEngineVariantV2 } from "./manifest"; export interface WasmThreadingCapabilities { crossOriginIsolated: boolean; sharedArrayBuffer: boolean; worker: boolean; } export type WebEngineVariantPolicy = "AUTO" | "SINGLE_REQUIRED" | "PTHREAD_REQUIRED"; export interface WebEngineVariantSelection { policy: WebEngineVariantPolicy; selectedVariant: WebEngineVariantV2 | null; pthreadGate: CapabilityGateResult; } export type WebEngineReleaseBinding = | { status: "READY"; releaseId: string; manifest: WebEngineManifestV2 } | { status: "REFRESH_REQUIRED"; expectedReleaseId: string; actualReleaseId: string; manifest: null; }; export function bindWebEngineRelease( expectedReleaseId: string, manifest: WebEngineManifestV2, ): WebEngineReleaseBinding { if (manifest.releaseId === expectedReleaseId) { return { status: "READY", releaseId: manifest.releaseId, manifest }; } return { status: "REFRESH_REQUIRED", expectedReleaseId, actualReleaseId: manifest.releaseId, manifest: null, }; } export function gateWasmThreadingCapability(capabilities: WasmThreadingCapabilities): CapabilityGateResult { const issues = []; if (!capabilities.crossOriginIsolated) { issues.push(capabilityIssue( "PLATFORM_CAPABILITY_UNAVAILABLE", "Cross-origin isolation is required for the pthread WASM engine", "crossOriginIsolated", )); } if (!capabilities.sharedArrayBuffer) { issues.push(capabilityIssue( "PLATFORM_CAPABILITY_UNAVAILABLE", "SharedArrayBuffer is required for the pthread WASM engine", "sharedArrayBuffer", )); } if (!capabilities.worker) { issues.push(capabilityIssue( "PLATFORM_CAPABILITY_UNAVAILABLE", "Worker is required for the pthread WASM engine", "worker", )); } return issues.length > 0 ? blockedGate("M6-02", "WASM_PTHREAD_ENGINE", issues) : readyGate("M6-02", "WASM_PTHREAD_ENGINE"); } export function selectWebEngineVariant( manifest: WebEngineManifestV2, policy: WebEngineVariantPolicy, capabilities: WasmThreadingCapabilities, ): WebEngineVariantSelection { const single = manifest.variants.find((variant) => variant.id === "single"); const pthread = manifest.variants.find((variant) => variant.id === "pthread"); if (!single || !pthread) throw new Error("ENGINE_MANIFEST_VARIANTS_MISSING"); const pthreadGate = gateWasmThreadingCapability(capabilities); if (policy === "SINGLE_REQUIRED") return { policy, selectedVariant: single, pthreadGate }; if (policy === "AUTO") { return { policy, selectedVariant: pthreadGate.status === "READY" ? pthread : single, pthreadGate, }; } if (policy === "PTHREAD_REQUIRED") { return { policy, selectedVariant: pthreadGate.status === "READY" ? pthread : null, pthreadGate, }; } throw new Error("ENGINE_VARIANT_POLICY_INVALID"); }