Skip to content

JavaScript Runtime

The devlish-runtime npm package runs compiled Devlish bytecode in any JavaScript environment. It wraps the WASM VM with a zero-dependency API that works in browsers, Node.js, and edge runtimes.

Terminal window
npm install devlish-runtime
import { runTool } from "devlish-runtime";
const bytecode = await fetch("/rules/pricing.dvlc.json").then(r => r.json());
const result = await runTool(bytecode, {
customer_tier: "enterprise",
deal_size: 500000
});
if (result.success) {
console.log("Result:", result.response);
}

For repeated execution, load a tool once and call it multiple times:

import { loadTool } from "devlish-runtime";
const tool = await loadTool({
bytecode: compiledBytecodeJson,
mainThread: false,
instructionLimit: 5000000
});
const result1 = await tool.run({ project_id: "A" });
const result2 = await tool.run({ project_id: "B" });
tool.dispose(); // clean up the Worker
Option Type Default Description
bytecode object or string required Compiled .dvlc.json bytecode
mainThread boolean false Skip Web Worker, run synchronously
instructionLimit number 10000000 Max instructions before termination

One-shot convenience function. Loads, runs, and disposes in one call:

import { runTool } from "devlish-runtime";
const result = await runTool(bytecode, { amount: 1200 });

Always runs on the main thread.

{
"success": true,
"responded": true,
"response": {"status": "approved", "score": 85},
"context": {"amount": 1200, "score": 85},
"results": {}
}
Field Type Description
success boolean Whether execution completed without error
error string Error message if success is false
responded boolean Whether the program used Respond with
response any The value passed to Respond with
context object All variables at end of execution
results object Validation and assertion results

By default, loadTool runs bytecode in a Web Worker, keeping the main thread free for UI. The WASM binary is inlined as base64 in the package for zero-config bundler compatibility.

// Worker execution (default)
const tool = await loadTool({ bytecode });
const result = await tool.run(input);
tool.dispose();
// Main thread execution
const tool = await loadTool({ bytecode, mainThread: true });

The runtime enforces a strict sandbox. Tools that declare certain permissions in their manifest are rejected at load time:

  • HTTP requests: Rejected (WASM sandbox has no network access)
  • Filesystem operations: Rejected (WASM sandbox has no filesystem)
  • Instruction limit: Enforced (prevents infinite loops)
  • Memory isolation: Each tool runs in its own WASM linear memory
<script type="module">
import { runTool } from "https://esm.sh/devlish-runtime";
const bytecode = await fetch("/rules/check.dvlc.json").then(r => r.json());
const result = await runTool(bytecode, { amount: 500 });
document.getElementById("output").textContent = JSON.stringify(result.response);
</script>

The same API works in Node.js and edge runtimes (Cloudflare Workers, Deno, Bun). Import and use identically.