Socket
Socket
Sign inDemoInstall

quickjs-emscripten

Package Overview
Dependencies
0
Maintainers
1
Versions
56
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

    quickjs-emscripten

Javascript/Typescript bindings for [QuickJS, a modern Javascript interpreter written in C by Fabrice Bellard](https://bellard.org/quickjs/).


Version published
Weekly downloads
20K
decreased by-11.28%
Maintainers
1
Install size
1.09 MB
Created
Weekly downloads
 

Readme

Source

quickjs-emscripten

Javascript/Typescript bindings for QuickJS, a modern Javascript interpreter written in C by Fabrice Bellard.

  • Safely evaluate untrusted Javascript (up to ES2020).
  • Create and manipulate values inside the QuickJS runtime.
  • Expose host functions to the QuickJS runtime.
import { getQuickJS } from 'quickjs-emscripten'

async function main() {
  const QuickJS = await getQuickJS()
  const vm = QuickJS.createVm()

  const world = vm.createString('world')
  vm.setProp(vm.global, 'NAME', world)
  world.dispose()

  const result = vm.evalCode(`"Hello " + NAME + "!"`)
  if (result.error) {
    console.log('Execution failed:', vm.dump(result.error))
    result.error.dispose()
  } else {
    console.log('Success:', vm.dump(result.value))
    result.value.dispose()
  }

  vm.dispose()
}

main()

Usage

Install from npm: npm install --save quickjs-emscripten or yarn add quickjs-emscripten.

The root entrypoint of this library is the getQuickJS function, which returns a promise that resolves to a QuickJS singleton when the Emscripten WASM module is ready.

Safely evaluate Javascript code

See QuickJS.evalCode

import { getQuickJS, shouldInterruptAfterDeadline } from 'quickjs-emscripten'

getQuickJS.then(QuickJS => {
  const result = QuickJS.evalCode('1 + 1', {
    shouldInterrupt: shouldInterruptAfterDeadline(Date.now() + 1000)
  })
  console.log(result)
})

Interfacing with the interpreter

You can use QuickJSVm to build a scripting environment by modifying globals and exposing functions into the QuickJS interpreter.

const vm = QuickJS.createVm()
let state = 0

const fnHandle = vm.newFunction('nextId', () => {
  return vm.newNumber(++state)
})

vm.setProp(vm.global, 'nextId', fnHandle)
fnHandle.dispose()

const nextId = vm.unwrapResult(vm.evalCode(`nextId(); nextId(); nextId()`))
console.log('vm result:', vm.getNumber(nextId), 'native state:', state)

More Documentation

Background

This was inspired by seeing https://github.com/maple3142/duktape-eval on Hacker News and Figma's blogposts about using building a Javascript plugin runtime:

Status & TODOs

Both the original project quickjs and this project are still in the early stage of development. There are tests, but I haven't built anything on top of this. Please use this project carefully in a production environment.

Ideas for future work:

  • Simplify memory management. Currently the user must call handle.dispose() on all handles they create to avoid leaking memory in C.
    • We chould use a Pool abstraction and do a Pool.freeAll() to free all handles and pointers in the pool.
    • Pools, etc, should not pollute QuickJSVm interface. Composition!
  • quickjs-emscripten only exposes a small subset of the QuickJS APIs. Add more QuickJS bindings!
    • Expose tools for object and array iteration and creation.
    • Stretch goals: class support, an event emitter bridge implementation
  • Higher-level abstractions for translating values into (and out of) QuickJS. These should be implemented in a way that works for any LowLevelJavascriptVm implementation.
  • Removing the singleton limitations. Each QuickJS class instance could create its own copy of the emscripten module, although we'd need to make all public methods async - so they wait for the module instance to be ready.
  • Run quickjs-emscripten inside quickjs-emscripten.

Developing

This library is implemented in two languages: C (compiled to WASM with Emscripten), and Typescript. Emscripten outputs are checked in, so you will only need the C compiler if you need to modify C code.

The C parts

The ./c directory contains C code that wraps the QuickJS C library (in ./quickjs). Public functions (those starting with QTS_) in ./c/interface.c are automatically exported to native code (via a generated header) and to Typescript (via a generated FFI class). See ./generate.ts for how this works.

The C code builds as both with emscripten (using emcc), to produce WASM (or ASM.js) and with clang. Build outputs are checked in, so Intermediate object files from QuickJS end up in ./build/quickjs/{wasm,native}.

You'll need to install emscripten. Following the offical instructions here, using emsdk: https://emscripten.org/docs/getting_started/downloads.html#installation-instructions

Related NPM scripts:

  • yarn update-quickjs will sync the ./quickjs folder with a github repo tracking the upstream QuickJS.
  • yarn make-debug will rebuild C outputs into ./build/wrapper
  • yarn run-n builds and runs ./c/test.c

The Typescript parts

The ./ts directory contains Typescript types and wraps the generated Emscripten FFI in a more usable interface.

You'll need node and npm or yarn. Install dependencies with npm install or yarn install.

  • yarn build produces ./dist.
  • yarn test runs the tests.
  • yarn test --watch watches for changes and re-runs the tests.

FAQs

Last updated on 25 Jun 2020

Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc