Files
workinf_Blender_Wasm/web/protocol/manifest.ts
2026-08-12 04:47:48 -04:00

45 lines
1.6 KiB
TypeScript

export interface WasmResource {
id: string;
fileName: string;
url: string;
sha256: string;
required: boolean;
}
export interface WebEngineManifest {
schemaVersion: number;
protocolVersion: number;
engineVersion: string;
engine: "mock" | "blender-wasm";
memory: {
initialPages: number;
maximumPages: number;
shared: boolean;
};
wasm: WasmResource[];
}
export async function loadWebEngineManifest(url = "/engine-manifest.json"): Promise<WebEngineManifest> {
const response = await fetch(url, { cache: "no-store" });
if (!response.ok) throw new Error(`Engine manifest request failed: ${response.status}`);
const manifest = await response.json() as Partial<WebEngineManifest>;
if (manifest.schemaVersion !== 1 || manifest.protocolVersion !== 1) {
throw new Error("Unsupported engine manifest version");
}
if (!manifest.engine || !manifest.memory || !Array.isArray(manifest.wasm)) {
throw new Error("Invalid engine manifest shape");
}
return manifest as WebEngineManifest;
}
export async function verifyWasmResource(resource: WasmResource): Promise<void> {
const response = await fetch(resource.url, { cache: "no-store" });
if (!response.ok) throw new Error(`WASM resource request failed: ${resource.id}`);
const bytes = await response.arrayBuffer();
const digest = await crypto.subtle.digest("SHA-256", bytes);
const actual = [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
if (actual !== resource.sha256.toLowerCase()) {
throw new Error(`WASM resource hash mismatch: ${resource.id}`);
}
}