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.
Installation
Section titled “Installation”npm install devlish-runtimeQuick Start
Section titled “Quick Start”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);}loadTool API
Section titled “loadTool API”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 WorkerOptions
Section titled “Options”| 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 |
runTool API
Section titled “runTool API”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.
RunResult
Section titled “RunResult”{ "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 |
Web Worker Execution
Section titled “Web Worker Execution”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 executionconst tool = await loadTool({ bytecode, mainThread: true });Permission Checking
Section titled “Permission Checking”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
Browser Embed
Section titled “Browser Embed”<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>Node.js and Edge
Section titled “Node.js and Edge”The same API works in Node.js and edge runtimes (Cloudflare Workers, Deno, Bun). Import and use identically.