Files
workinf_Blender_Wasm/tools/web/check-deployment-contract.mjs
2026-08-15 01:01:23 -04:00

64 lines
3.7 KiB
JavaScript

import assert from "node:assert/strict";
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
const contractPath = path.join(root, "docs/web/deployment-contract.json");
const contract = JSON.parse(fs.readFileSync(contractPath, "utf8"));
const guide = fs.readFileSync(path.join(root, "docs/web/DEPLOYMENT.md"), "utf8");
const vite = fs.readFileSync(path.join(root, "web/app/vite.config.ts"), "utf8");
const releaseCreator = fs.readFileSync(path.join(root, "tools/web/create-offline-release.mjs"), "utf8");
assert.equal(contract.schemaVersion, 1);
assert.equal(contract.product, "Web Blender Modeler V1");
assert.equal(contract.browserScope, "Chromium");
assert.deepEqual(contract.methods, ["GET", "HEAD"]);
assert.equal(contract.transport.production, "https");
assert.equal(contract.transport.localDevelopment, "http://127.0.0.1");
assert.equal(contract.transport.fileProtocolSupported, false);
assert.equal(contract.transport.sameOriginRuntimeAssets, true);
assert.deepEqual(contract.responseHeaders.allResponses, {
"Cross-Origin-Opener-Policy": "same-origin",
"Cross-Origin-Embedder-Policy": "require-corp",
"Cross-Origin-Resource-Policy": "same-origin",
});
const routes = Object.fromEntries(contract.responseHeaders.routes.map((route) => [route.id, route]));
assert.deepEqual(routes["entry-document"], { id: "entry-document", patterns: ["/", "/index.html"], cacheControl: "no-cache" });
assert.deepEqual(routes["runtime-manifest"], { id: "runtime-manifest", patterns: ["/engine-manifest.json"], cacheControl: "no-cache" });
assert.deepEqual(routes["content-hashed-assets"], { id: "content-hashed-assets", patterns: ["/assets/*"], cacheControl: "public, max-age=31536000, immutable" });
assert.deepEqual(routes["stable-engine-assets"], { id: "stable-engine-assets", patterns: ["/vendor/blender/*"], cacheControl: "no-cache" });
assert.deepEqual(routes.fallback, { id: "fallback", patterns: ["*"], cacheControl: "no-cache" });
for (const [extension, mime] of Object.entries({
".html": "text/html; charset=utf-8",
".js": "text/javascript; charset=utf-8",
".css": "text/css; charset=utf-8",
".wasm": "application/wasm",
".json": "application/json; charset=utf-8",
".png": "image/png",
".wav": "audio/wav",
".blend": "application/octet-stream",
".nvdb": "application/x-nanovdb",
})) assert.equal(contract.mimeTypes[extension], mime, `${extension} MIME drifted`);
assert.deepEqual(contract.rangeRequests.extensions, [".wasm", ".blend", ".nvdb"]);
assert.equal(contract.rangeRequests.unit, "bytes");
assert.equal(contract.rangeRequests.singleRangeOnly, true);
assert.equal(contract.rangeRequests.etag, "strong-sha256");
assert.equal(contract.rangeRequests.satisfiedStatus, 206);
assert.equal(contract.rangeRequests.unsatisfiedStatus, 416);
assert.deepEqual(contract.rangeRequests.requiredSatisfiedHeaders, ["Accept-Ranges", "Content-Range", "Content-Length", "ETag"]);
assert.equal(contract.rangeRequests.ifRangeMismatch, "return-full-200");
for (const value of Object.values(contract.responseHeaders.allResponses)) assert.ok(guide.includes(`\`${value}\``));
for (const status of ["206", "416", "200"]) assert.ok(guide.includes(`\`${status}\``));
assert.match(vite, /deployment-contract\.json/);
assert.match(vite, /responseHeaders\.allResponses/);
assert.match(releaseCreator, /deployment-contract\.json/);
assert.match(releaseCreator, /DEPLOYMENT\.md/);
assert.doesNotMatch(releaseCreator, /Serve app\/ from any local static HTTP server/);
process.stdout.write(`deployment-contract-ok headers=3 routes=${contract.responseHeaders.routes.length} mime=${Object.keys(contract.mimeTypes).length} rangeExtensions=${contract.rangeRequests.extensions.length}\n`);