{"id":17142731,"url":"https://github.com/only-cliches/quickjs-worker","last_synced_at":"2026-02-14T05:05:43.032Z","repository":{"id":237307278,"uuid":"794256243","full_name":"only-cliches/quickjs-worker","owner":"only-cliches","description":"Run QuickJS as a worker from NodeJS","archived":false,"fork":false,"pushed_at":"2025-12-25T06:16:33.000Z","size":11241,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-12-26T19:52:14.620Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/only-cliches.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-04-30T18:56:58.000Z","updated_at":"2025-12-25T06:16:37.000Z","dependencies_parsed_at":"2024-04-30T20:00:44.757Z","dependency_job_id":"c150cdb8-abff-407a-abb1-e6e44e2d3216","html_url":"https://github.com/only-cliches/quickjs-worker","commit_stats":null,"previous_names":["only-cliches/quickjs-worker"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/only-cliches/quickjs-worker","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/only-cliches%2Fquickjs-worker","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/only-cliches%2Fquickjs-worker/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/only-cliches%2Fquickjs-worker/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/only-cliches%2Fquickjs-worker/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/only-cliches","download_url":"https://codeload.github.com/only-cliches/quickjs-worker/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/only-cliches%2Fquickjs-worker/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29437368,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-14T03:34:37.767Z","status":"ssl_error","status_checked_at":"2026-02-14T03:34:09.092Z","response_time":53,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-14T20:32:26.577Z","updated_at":"2026-02-14T05:05:43.026Z","avatar_url":"https://github.com/only-cliches.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# quickjs-vm\n\n**High-performance native Node.js bindings for the [QuickJS](https://bellard.org/quickjs/) JavaScript engine.**\n\n`quickjs-vm` allows you to safely execute **untrusted JavaScript** inside a sandboxed QuickJS runtime embedded directly in Node.js.\n\nUnlike libraries that compile QuickJS to WebAssembly, `quickjs-vm` uses **native N-API bindings written in Rust**, providing:\n\n- ⚡ Significantly higher performance\n- 🧠 Lower memory overhead\n- ⏱ True synchronous execution (no async WASM trampolines)\n\nIf you need **fast, deterministic, sandboxed JavaScript execution** inside Node — this library is built for that purpose.\n\n---\n\n## 🚀 Features\n\n### ⚡ Performance\n- Native QuickJS runtime (no WASM)\n- Direct execution on the host CPU\n- Lower startup and execution overhead\n\n### 🔄 Execution Modes\n- `evalSync()` — blocking, deterministic execution\n- `eval()` — Promise-based async execution\n- `evalModule()` — ES module support\n\n### 🛡 Sandboxing \u0026 Limits\nProtect your host application from runaway or malicious scripts:\n\n- **Execution timeouts** (`maxEvalMs`)\n- **Memory limits** (`maxMemoryBytes`)\n- **Prevent Infinite Loops** (`maxInterrupt`)\n- **Stack depth limits** (prevents recursion abuse)\n\n### 💾 Data Serialization\nSafe, seamless data exchange between Node and QuickJS:\n\n- Primitives (`string`, `number`, `boolean`, `null`, `undefined`)\n- Structured data (Objects, Arrays, JSON)\n- `Date`\n- `Error`\n- `Buffer` / `Uint8Array`\n- Functions (call Node functions from QuickJS)\n\n### 📞 Messaging \u0026 IPC\n- Bidirectional `postMessage` API\n- Event-based lifecycle:\n  - `on('message')`\n  - `on('close')`\n\n### ⚙️ Bytecode Support\n- Compile source → bytecode (`getByteCode`)\n- Execute bytecode later (`loadByteCode`)\n- Faster startup for repeated workloads\n\n---\n\n## 📊 Performance Benchmarks\n\nBecause `quickjs-vm` binds directly to the native QuickJS C library, it **significantly outperforms** WASM-based implementations.\n\nBenchmarks were run using the **V8 Benchmark Suite (v7)** comparing:\n\n- `quickjs-vm` (native)\n- `quickjs-emscripten` (WASM)\n\n### 🏆 Overall Score (Higher is Better)\n\n| Library | Score | Improvement |\n|------|------|------|\n| **quickjs-vm (Native)** | **1052** | **~42% Faster** 🚀 |\n| quickjs-emscripten (WASM) | 742 | |\n\n### 📉 Detailed Results\n\n| Benchmark | quickjs-vm | emscripten | Δ |\n|--------|-----------|------------|----|\n| Richards | **1014** | 579 | +75% |\n| DeltaBlue | **1043** | 653 | +60% |\n| Crypto | **878** | 556 | +58% |\n| RayTrace | **1008** | 773 | +30% |\n| EarleyBoyer | **1948** | 1409 | +38% |\n| RegExp | **270** | 227 | +19% |\n| Splay | **2208** | 1862 | +19% |\n| NavierStokes | **1385** | 948 | +46% |\n\n\u003e Benchmarks run on macOS (Apple Silicon). Absolute numbers vary by machine, but the relative performance gap is consistent.\n\n---\n\n## 📦 Installation\n\n```sh\nnpm install quickjs-vm\n````\n\n---\n\n## 💻 Usage\n\n### Basic Evaluation\n\n```ts\nimport { QuickJS } from 'quickjs-vm';\n\nconst vm = new QuickJS();\n\nconst result = await vm.eval('1 + 2');\nconsole.log(result); // 3\n\n// optionally resolves promises as well\nconst result = await vm.eval('new Promise(res =\u003e res(1 + 2))');\nconsole.log(result); // 3\n\n// blocking call\nconst syncResult = vm.evalSync('\"Hello \" + \"World\"');\nconsole.log(syncResult); // Hello World\n\n// get number of bytes currently in use by the vm\nconst memory = await vm.memory();\nconsole.log(memory.memory_used_size);\n\nawait vm.close();\n```\n\n---\n\n### Passing Arguments Safely\n\nAvoid string interpolation — pass arguments explicitly:\n\n```js\nconst vm = new QuickJS();\n\nconst fn = `\n  (greeting, name, count) =\u003e {\n    return Array.from({ length: count }, () =\u003e\n      \\`\\${greeting}, \\${name}!\\`\n    );\n  }\n`;\n\nconst result = await vm.eval(fn, {\n  args: ['Hello', 'Developer', 3]\n});\n\nconsole.log(result);\n// [\"Hello, Developer!\", \"Hello, Developer!\", \"Hello, Developer!\"]\n```\n\n---\n\n### Global State\n\n#### Static Globals (at startup)\n\n```js\nconst vm = new QuickJS({\n  globals: {\n    version: '1.0.0',\n    utils: {\n      add: (a, b) =\u003e a + b,\n      log: msg =\u003e console.log('[VM]', msg)\n      getData: async (opts) =\u003e {\n        // runs in Node context, callable from QuickJS\n        return new Promise((res, rej) =\u003e {\n          setTimeout(() =\u003e {\n            res(\"Hello, Data\")\n          }, 100);\n        })\n      }\n    }\n  }\n});\n\nawait vm.eval('utils.log(version); utils.add(10, 20)');\n```\n\n#### Dynamic Globals (runtime)\n\n```js\nawait vm.setGlobal('user', {name: \"John\"}};\nconst name = await vm.eval('user.name');\n```\n\n---\n\n### Advanced Configuration\n\n```js\nconst vm = new QuickJS({\n  maxMemoryBytes: 5 * 1024 * 1024,\n  maxEvalMs: 500,\n  // pass through vm console.XXX to NodeJS\n  console: console\n  // optional: provide your own handlers:\n  // console: { log: ..., error: ... }\n});\n\nawait vm.setGlobal('fetchUser', async id =\u003e {\n  return db.users.find(id);\n});\n\nconst user = await vm.eval('fetchUser(123)');\n```\n\n---\n\n### ES Modules \u0026 Custom Imports\n\n```js\nconst vm = new QuickJS({\n  imports: path =\u003e {\n    if (path === './math.js') {\n      return 'export const add = (a, b) =\u003e a + b;';\n    }\n    throw new Error('Module not found');\n  }\n});\n\nconst result = await vm.evalModule(`\n  import { add } from './math.js';\n  export default add(10, 20);\n`);\n```\n\n---\n\n### Messaging (`postMessage`)\n\n```js\nvm.on('message', msg =\u003e {\n  console.log('From VM:', msg);\n});\n\nvm.postMessage({ type: 'INIT' });\n```\n\n```js\n// Inside QuickJS\non('message', msg =\u003e {\n  if (msg.type === 'INIT') {\n    postMessage({ status: 'READY' });\n  }\n});\n```\n\n---\n\n## 🧠 When Should I Use This?\n\n### `quickjs-vm` vs Node `vm`\n\n| Node `vm`         | quickjs-vm                  |\n| ----------------- | --------------------------- |\n| Shares V8 runtime | Separate JS engine          |\n| Limited isolation | Stronger isolation boundary |\n| No memory limits  | Enforced memory caps        |\n| Same event loop   | Independent execution       |\n\n**Use `quickjs-vm`** when running untrusted or user-supplied code.\n\n---\n\n### `quickjs-vm` vs `isolated-vm`\n\n| isolated-vm       | quickjs-vm             |\n| ----------------- | ---------------------- |\n| V8 isolates       | QuickJS runtime        |\n| Higher overhead   | Lower memory footprint |\n| Async-only APIs   | True sync execution    |\n| Larger dependency | Smaller native core    |\n\n**Use `quickjs-vm`** when you want deterministic sync execution, lower memory use, or simpler deployment.\n\n---\n\n### `quickjs-vm` vs WASM (emscripten)\n\n| quickjs-emscripten    | quickjs-vm        |\n| --------------------- | ----------------- |\n| Interpreted execution | Native execution  |\n| Async trampolines     | True sync         |\n| Higher memory         | Lower overhead    |\n| Slower startup        | Faster cold start |\n\n**Use `quickjs-vm`** when performance, latency, and predictability matter.\n\n---\n\n## 🏗 Architecture \u0026 Lifecycle\n\n### High-Level Architecture\n\n```\n┌─────────────┐\n│   Node.js   │\n│ Application │\n└─────┬───────┘\n      │ N-API (Rust)\n┌─────▼───────────────────────────┐\n│         quickjs-vm              │\n│  ┌───────────────────────────┐  │\n│  │  Control Thread (Node)    │◄─┼── eval / postMessage\n│  └───────────┬───────────────┘  │\n│              │ Channels         │\n│  ┌───────────▼───────────────┐  │\n│  │  QuickJS Runtime Thread   │  │\n│  │  • QuickJS VM             │  │\n│  │  • Memory limits          │  │\n│  │  • Execution timeouts     │  │\n│  └───────────┬───────────────┘  │\n│              │ Messages         │\n│  ┌───────────▼───────────────┐  │\n│  │  Dispatcher / Callbacks   │──┼── JS callbacks\n│  └───────────────────────────┘  │\n└─────────────────────────────────┘\n```\n\n### Execution Lifecycle\n\n1. **VM creation**\n\n   * Native QuickJS runtime initialized\n   * Memory and execution limits applied\n   * Static globals injected\n\n2. **Script execution**\n\n   * Code is sent to the runtime thread\n   * Execution is interrupted if limits are exceeded\n   * Results are serialized back to Node\n\n3. **Messaging**\n\n   * `postMessage` enables async communication\n   * Messages are queued and dispatched safely\n\n4. **Shutdown**\n\n   * `close()` signals all worker threads\n   * Native resources are freed deterministically\n   * No lingering handles\n\n---\n\n## 🧪 Testing\n\nThe project includes a comprehensive **Jest** test suite covering:\n\n* Serialization correctness\n* Sync vs async behavior\n* Promise handling\n* Module resolution\n* Resource cleanup \u0026 leak detection\n* Performance benchmarks\n\n```bash\nnpm test\n```\n\n---\n\n## 📄 License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fonly-cliches%2Fquickjs-worker","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fonly-cliches%2Fquickjs-worker","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fonly-cliches%2Fquickjs-worker/lists"}