import assert from "node:assert/strict"; import fs from "node:fs"; import os from "node:os"; import path from "node:path"; const root = path.resolve(new URL("../..", import.meta.url).pathname); const cachePath = path.join(root, "build_web_blender6", "CMakeCache.txt"); const cache = fs.readFileSync(cachePath, "utf8"); assert.match(cache, /^WITH_OPENVDB:BOOL=OFF$/m, "Browser OpenVDB must remain disabled; conversion belongs to desktop/server targets"); const protocol = fs.readFileSync(path.join(root, "web", "protocol", "volume-vdb.ts"), "utf8"); assert.match(protocol, /prepareVDBConversionInput/, "VDB conversion input validation is missing"); assert.match(protocol, /validateNanoVDBBundleManifest/, "NanoVDB bundle validation is missing"); assert.match(protocol, /gateNanoVDBPipeline/, "NanoVDB stage capability gates are missing"); assert.doesNotMatch(protocol, /export async function decodeVDBResource/, "Browser raw OpenVDB decode entry must not be restored"); const roots = [ path.join(root, "resource-library"), path.join(root, "tests"), path.resolve(process.env.VDB_RESOURCE_ROOT ?? path.join(os.homedir(), "resource-library/blender-web-vdb")), ]; const vdbFiles = []; function scan(directory) { if (!fs.existsSync(directory)) return; for (const entry of fs.readdirSync(directory, { withFileTypes: true })) { const fullPath = path.join(directory, entry.name); if (entry.isDirectory()) scan(fullPath); else if (/\.(?:vdb(?:\.gz)?|nvdb)$/i.test(entry.name)) vdbFiles.push(fullPath); } } for (const directory of roots) scan(directory); const converterCandidates = [ path.join(root, "build_vdb_tools", "vdb_to_nanovdb"), path.join(root, "tools", "vdb", "convert-openvdb-to-nanovdb"), path.join(root, "tools", "vdb", "convert-openvdb-to-nanovdb.py"), ]; const converterConfigured = converterCandidates.some((candidate) => fs.existsSync(candidate)); const rendererConfigured = fs.existsSync(path.join(root, "web", "app", "src", "render", "nanovdb-volume-renderer.ts")); const serverConfigured = fs.existsSync(path.join(root, "tools", "vdb", "server", "vdb-job-service.mjs")); const opfsConfigured = fs.existsSync(path.join(root, "web", "app", "src", "volume", "nanovdb-opfs.ts")); const mainWriterConfigured = fs.readFileSync(path.join(root, "blender-5.2.0", "source", "blender", "web_engine", "web_engine_api.cpp"), "utf8").includes("setVolumeProperties"); const coreStatus = converterConfigured && serverConfigured && opfsConfigured && rendererConfigured && mainWriterConfigured && vdbFiles.some((file) => /\.vdb(?:\.gz)?$/i.test(file)) ? "READY" : "BLOCKED"; const releaseStatus = "BLOCKED"; assert.equal(coreStatus, "READY", "VDB core pipeline files or real resources are missing"); assert.equal(releaseStatus, "BLOCKED", "VDB release must remain blocked until viewport integration, advanced grids, and full goldens are present"); process.stdout.write(`vdb-availability-ok core=${coreStatus} release=${releaseStatus} browser-openvdb=disabled desktop=ready server=ready opfs=ready webgpu-core=ready main-roundtrip=ready viewport=blocked advanced-material=blocked resources=${vdbFiles.length}\n`);