45 lines
1.6 KiB
TypeScript
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}`);
|
|
}
|
|
}
|