import assert from "node:assert/strict"; import fs from "node:fs"; import vm from "node:vm"; import test from "node:test"; import ts from "typescript"; const registrySource = fs.readFileSync(new URL("../src/module-registry.generated.ts", import.meta.url), "utf8"); const registryAst = ts.createSourceFile("registry.ts", registrySource, ts.ScriptTarget.Latest, true); const routes = new Map(); const mapping = registryAst.statements.find(node => ts.isFunctionDeclaration(node) && node.name?.text === "getWebModuleWorkerForCommand"); const inspect = node => { if (ts.isCaseClause(node) && ts.isStringLiteral(node.expression)) { const result = node.statements.find(ts.isReturnStatement)?.expression; if (result && ts.isStringLiteral(result)) routes.set(node.expression.text, result.text); } ts.forEachChild(node, inspect); }; inspect(mapping); function fixture() { const workers = []; const route = { module: "TechDraw", primaryWorker: "techdraw-native.worker.ts", commands: [ "techdraw.createRecompute", "techdraw.desktopCommand", "techdraw.nativeSaveReopen", ] }; const registry = { getWebModuleRoute: module => module === "TechDraw" ? route : undefined, getWebModuleWorkerForCommand: (module, command) => routes.get(`${module}:${command}`) ?? route.primaryWorker, createWebModuleWorker: (_module, workerFile) => { const worker = { workerFile, sent: [], terminated: 0, postMessage(message) { this.sent.push(message); }, terminate() { this.terminated += 1; }, emit(data) { this.onmessage({ data }); }, }; workers.push(worker); return worker; }, }; const cache = new Map([ ["./module-registry.generated.js", registry], ["./module-loader.js", {}], ["./native-source-policy.js", { nativeSourceDecision: () => undefined }], ]); function load(name) { if (cache.has(name)) return cache.get(name); const source = fs.readFileSync(new URL(`../src/${name.replace(/^\.\//, "").replace(/\.js$/, ".ts")}`, import.meta.url), "utf8"); const compiled = ts.transpileModule(source, { compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2022 } }).outputText; const module = { exports: {} }; vm.runInNewContext("(function(exports,require,module){" + compiled + "})", { AbortController })(module.exports, load, module); cache.set(name, module.exports); return module.exports; } return { router: new (load("./module-router.js").WebModuleRouter)(), workers }; } test("drawing, desktop commands and save use one existing native document worker", async () => { const { router, workers } = fixture(); try { for (const command of ["techdraw.createRecompute", "techdraw.desktopCommand", "techdraw.nativeSaveReopen"]) { assert.equal(routes.get(`TechDraw:${command}`), "techdraw-python.worker.ts"); const result = router.request("TechDraw", command, { documentId: "CurrentDrawing" }); if (workers.length === 1 && workers[0].sent.length === 0) workers[0].emit({ kind: "ready" }); await Promise.resolve(); const request = workers[0].sent.at(-1); workers[0].emit({ kind: "result", requestId: request.requestId, result: { documentId: "CurrentDrawing" } }); assert.equal((await result).result.documentId, "CurrentDrawing"); } assert.equal(workers.length, 1); assert.equal(workers[0].workerFile, "techdraw-python.worker.ts"); } finally { router.dispose(); } }); test("uncorrelated worker errors reject pending commands instead of waiting forever", async () => { const { router, workers } = fixture(); const result = router.request("TechDraw", "techdraw.createRecompute", {}); workers[0].emit({ kind: "ready" }); await Promise.resolve(); const rejected = assert.rejects(result, /invalid_request: wrong envelope/); workers[0].emit({ kind: "error", requestId: "invalid", error: { code: "invalid_request", message: "wrong envelope" } }); await rejected; assert.equal(router.listLoaded().length, 0); assert.equal(workers[0].terminated, 1); }); test("initialization failure rejects readiness and permits a fresh worker", async () => { const { router, workers } = fixture(); const first = router.preload("TechDraw", "techdraw-python.worker.ts"); const rejected = assert.rejects(first, /kernel_load_failed: missing wasm/); workers[0].emit({ kind: "error", requestId: "initialization", error: { code: "kernel_load_failed", message: "missing wasm" } }); await rejected; const retry = router.preload("TechDraw", "techdraw-python.worker.ts"); assert.equal(workers.length, 2); workers[1].emit({ kind: "ready" }); await retry; router.dispose(); }); test("correlated business failure keeps the healthy worker available", async () => { const { router, workers } = fixture(); const result = router.request("TechDraw", "techdraw.createRecompute", {}); workers[0].emit({ kind: "ready" }); await Promise.resolve(); workers[0].emit({ kind: "error", requestId: workers[0].sent[0].requestId, error: { code: "invalid_argument", message: "bad size" } }); assert.equal((await result).error.code, "invalid_argument"); assert.equal(router.listLoaded().length, 1); router.dispose(); });