npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

worker-sandbox

v1.0.1

Published

The Javascript sandbox based on Web Workers.

Downloads

27

Readme

worker-sandbox npm GitHub license Build Status Coverage Status

The Javascript sandbox based on Web Workers.

Usage

Install

npm install --save worker-sandbox

OR

yarn add worker-sandbox

Quickstart

To build a runInContext function as an example:

import Sandbox from 'worker-sandbox' // Import module

async function runInContext(code, context) {
  try {
    const sandbox = new Sandbox() // Create a sandbox instance
    await sandbox.assign(context) // Assign the context of the sandbox
    return await sandbox.eval(code) // Run the code
  } finally {
    sandbox.destroy() // Destroy the Web Worker instance in the sandbox
  }
}

runInContext('sayHelloWorld()', {
  helloWorld: 'hello world'
, sayHelloWorld() {
    return helloWorld
  }
})
.then(console.log) // hello world

API

class Sandbox([worker: Worker])

Use the new operator to create a sandbox instance, and the Sandbox class constructor has no arguments.

const sandbox = new Sandbox()
sandbox instanceof Sandbox // true

You can also use your own Worker instance, see below.

Sandbox#eval(code: string): Promise<any>

Eval code in the sandbox.

const sandbox = new Sandbox()
const result = await sandbox.eval('"hello world"')
result === 'hello world' // true

Sandbox#execute(code: string): Promise<void>

No return value version of Sandbox#eval.

const sandbox = new Sandbox()
const result = await sandbox.execute('"hello world"')
result === undefined // true

Sandbox#context: { [string]: any }

This is an asynchronous Proxy object that can be used as syntactic sugar for Sandbox#set, Sandbox#get, Sandbox#remove, Sandbox#call.

const sandbox = new Sandbox()

// Get the full context
await sandbox.context // {}

// Set the value of a specific path
sandbox.context.helloWorld = 'hello world'

// Get the value of a specific path
await sandbox.context.helloWorld === 'hello world' // true

// Set a specific path as a function
sandbox.context.sayHelloWorld = speaker =>
  `${ speaker }: ${ helloWorld }`

// Call a function of a specific path (the actual function runs in the sandbox)
await sandbox.context.sayHelloWorld('Sandbox') === 'Sandbox: hello world'

// Remove the value of a specific path
delete sandbox.context.helloWorld
delete sandbox.context.sayHelloWorld
await sandbox.context.helloWorld === undefined // true
await sandbox.context.sayHelloWorld === undefined // true

Sandbox#set(path: string | string[], value: any): Promise<void>

Set the value of a specific path in the sandbox context.

const sandbox = new Sandbox()
await sandbox.set('arr', [])
await sandbox.set('arr[0]', 'hello')
await sandbox.set('arr[1]', 'world')
await sandbox.set(['arr[2]'], 'arr[2]')
(await sandbox.context.arr).join(' ') === 'hello world' // true
await sandbox.context['arr[2]'] === 'arr[2]' // true

Equivalent to

const sandbox = new Sandbox()
await sandbox.set('arr', [])
await sandbox.set(['arr', '0'], 'hello')
await sandbox.set(['arr', '1'], 'world')
await sandbox.set(['arr[2]'], 'arr[2]')
(await sandbox.context.arr).join(' ') === 'hello world' // true
await sandbox.context['arr[2]'] === 'arr[2]' // true

Equivalent to

const sandbox = new Sandbox()
sandbox.context.arr = []
sandbox.context.arr[0] = 'hello'
sandbox.context.arr[1] = 'world'
sandbox.context['arr[2]'] = 'arr[2]'
(await sandbox.context.arr).join(' ') === 'hello world' // true
await sandbox.context['arr[2]'] === 'arr[2]' // true

Sandbox#assign(obj: any) : Promise<void>

It is the Object.assign() for Sandbox#context.

const sandbox = new Sandbox()
await sandbox.assign({
  hello: 'hello'
, world: 'world'
, sayHelloWorld() {
    return `${ hello } ${ world}`
  }
, 'functions.sayHelloWorld': function() {
    return `${ hello } ${ world}`
  }
})
await sandbox.context.sayHelloWorld() === 'hello world' // true
await sandbox.context['functions.sayHelloWorld']() === 'hello world' // true

Equivalent to

const sandbox = new Sandbox()
Object.assign(sandbox.context, {
  hello: 'hello'
, world: 'world'
, sayHelloWorld() {
    return `${ hello } ${ world}`
  }
, ['functions.sayHelloWorld']() {
    return `${ hello } ${ world}`
  }
})
await sandbox.context.sayHelloWorld() === 'hello world' // true
await sandbox.context['functions.sayHelloWorld']() === 'hello world' // true

Sandbox#get(path: string | string[]): Promsie<any>

Get the value of a specific path in the sandbox context.

const sandbox = new Sandbox()
await sandbox.set('obj', {
  hello: 'hello'
, world: 'world'
})
await sandbox.get('obj.hello') === 'hello' // true
await sandbox.get('obj["world"]') === 'world' // true

Equivalent to

const sandbox = new Sandbox()
sandbox.set('obj', {
  hello: 'hello'
, world: 'world'
})
await sandbox.get(['obj', 'hello']) === 'hello' // true
await sandbox.get(['obj', 'world']) === 'world' // true

Equivalent to

const sandbox = new Sandbox()
await sandbox.set('obj', {
  hello: 'hello'
, world: 'world'
})
await sandbox.context.obj.hello === 'hello' // true
await sandbox.context.obj['world'] === 'world' // true

Sandbox#remove(path: string | string[]): Promise<void>

Remove the value of a specific path in the sandbox context.

const sandbox = new Sandbox()
await sandbox.set('obj', {
  hello: 'hello'
, world: 'world'
})
await sandbox.remove('obj.hello')
await sandbox.remove('obj["world"]')
await sandbox.context.obj // {}

Equivalent to

const sandbox = new Sandbox()
await sandbox.set('obj', {
  hello: 'hello'
, world: 'world'
})
await sandbox.remove(['obj', 'hello'])
await sandbox.remove(['obj', 'world'])
await sandbox.context.obj // {}

Equivalent to

const sandbox = new Sandbox()
await sandbox.set('obj', {
  hello: 'hello'
, world: 'world'
})
delete sandbox.context.obj.hello
delete sandbox.context.obj.world
await sandbox.context.obj // {}

Sandbox#call(path: string | string[], ...args: any[]): Promise<any>

Calling a function within a sandbox context within a specific path, the actual function runs in the sandbox.

const sandbox = new Sandbox()
sandbox.context.helloWorld = 'hello world'
sandbox.context.functions = {}
sandbox.context.functions.sayHelloWorld = speaker =>
  `${ speaker }: ${ helloWorld }`
await sandbox.call('functions.sayHelloWorld', 'Sandbox') === 'Sandbox: hello world' // true

Equivalent to

const sandbox = new Sandbox()
sandbox.context.helloWorld = 'hello world'
sandbox.context.functions = {}
sandbox.context.functions.sayHelloWorld = speaker =>
  `${ speaker }: ${ helloWorld }`
await sandbox.call(['functions', 'sayHelloWorld'], 'Sandbox') === 'Sandbox: hello world' // true

Equivalent to

const sandbox = new Sandbox()
sandbox.context.helloWorld = 'hello world'
sandbox.context.functions = {}
sandbox.context.functions.sayHelloWorld = speaker => {
  `${ speaker }: ${ helloWorld }`
await sandbox.context.functions.sayHelloWorld('Sandbox') === 'Sandbox: hello world' // true

Sandbox#callable : { [string]: Function }

This is an asynchronous Proxy object that can be used as syntactic sugar for Sandbox#registerCall and Sandbox#cancelCall.

const sandbox = new Sandbox()
const helloWorld = 'hello world'

// Register the Callable function
sandbox.callable.sayHelloWorld = function(speaker) {
  return `${ speaker }: ${ helloWorld }`
}

// Call the Callable function
await sandbox.eval('sayHelloWorld("Sandbox")') === 'Sandbox: hello world' // true

// Cancel registered Callable function
delete sandbox.callable.sayHelloWorld
await sandbox.eval('sayHelloWorld') // ReferenceError!

Sandbox#registerCall(path: string | string[], func: Function): Promise<void>

Register a Callable function in the sandbox, which can be called in the sandbox, but the actual function is done outside the sandbox.

const sandbox = new Sandbox()
const helloWorld = 'hello world'
await sandbox.registerCall('sayHelloWorld', speaker =>
  `${ speaker }: ${ helloWorld }`
)
await sandbox.eval('sayHelloWorld("Sandbox")') === 'Sandbox: hello world' // true

Sandbox#cancelCall(path: string | string[]): Promise<void>

Cancel registered Callable function.

const sandbox = new Sandbox()
const helloWorld = 'hello world'
await sandbox.registerCall('sayHelloWorld', speaker =>
  `${ speaker }: ${ helloWorld }`
)
await sandbox.cancelCall('sayHelloWorld')
await sandbox.eval('sayHelloWorld')  // ReferenceError

Sandbox#destroy(): void

Destroy the Web Worker in the instance of the sandbox, which will call the Worker#terminate () to terminate the Web Worker.

const sandbox = new Sandbox()
sandbox.destroy()

Advanced

Custom worker

The minimal worker code is:

import { MessageSystem, PERMISSION } from 'message-system'
import { WorkerMessenger } from 'message-system-worker-messenger'

(self as any)['window'] = self

new MessageSystem(new WorkerMessenger(), [
  PERMISSION.RECEIVE.EVAL
, PERMISSION.RECEIVE.CALL
, PERMISSION.RECEIVE.ASSIGN
, PERMISSION.RECEIVE.ACCESS
, PERMISSION.RECEIVE.REMOVE
, PERMISSION.RECEIVE.REGISTER
, PERMISSION.SEND.CALL
], {/* add your context here */})

Tips

The await operator can be omitted when you call Sandbox#set, Sandbox#assign, Sandox#remove, Sandbox#registerCall, Sandbox#cancelCall in the async function. Because the Web Worker inside the sandbox is single-threaded, the asynchronous methods are executed in the order they are called, the await operator is just need added when calling a function that requires a return value.

const sandbox = new Sandbox()
for (let i = 1000; i--;) {
  sandbox.set('hello', 'hello')
  sandbox.assign({
    world: 'world'
  , removable: 'removable'
  })
  sandbox.remove('removable')
}
await sandbox.context.removable === undefined // true
await sandbox.context.hello === 'hello' // true
await sandbox.context.world === 'world' // true

Projects using worker-sandbox

gloria-sandbox: Sandbox for Gloria based on worker-sandbox