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

sandybox

v1.1.2

Published

A tiny, experimental library to allow you to execute arbitrary JavaScript functions safely in a sandbox on the web.

Downloads

39

Readme

Sandybox

npm version build status

Sandybox is a tiny (<1.5kb), experimental library to allow you to execute arbitrary JavaScript functions safely in a sandbox on the web.

Goals

Sandybox has three primary goals, to be:

  1. Sandboxed (secure) - Functions should not be able to access any same-origin information or make requests as if it were from the same-origin as the host.
  2. Non-blocking - Sandboxed functions should not be able to block the main thread.
  3. Performant - Sandboxed functions should be created and executed with minimal additional overhead compared to normal functions.

In short, functions should be totally separated from the main application and thus safe to run.

Future Goals

In the future, Sandybox should be:

  1. Compartmentalized - Functions in the sandbox should not be able to influence each other, such as by modifying global objects.

Architecture

Sandybox creates function sandboxes by instantiating a sandboxed iframe and then creating a Web Worker in the iframe. This meets the first two goals of the project, any code executed within the web worker will be secure and non-blocking.

However, in order to communicate with the web worker, you'll need to transfer any data to the iframe and then to the web worker which is definitely not performant.

To solve this problem, we can use a MessageChannel. We keep one port of the channel in the main thread and then send the other one to the web worker, giving us a direct line to the web worker. This will give us the minimal amount of overhead that we could possibly get for code running in a separate thread. In other words, it'll be performant.

Finally, we currently have no good solution to compartmentalization. The only standardized way to achieve it at this point in time would be to create separate web workers for each function, but this would be much harder to make performant. Given this was the lowest priority goal, this has not been implemented and instead moved to a future goal.

In the future, Realms or, more likely, Compartments should make compartmentalization easy, but it is likely a long way until either is standardized.

Limitations

The following are known limitations and/or explicit trade-offs of Sandybox:

  1. No DOM access - Given that sandboxed functions run in a web worker, there is no direct DOM access. Allowing DOM access would make it impossible to be non-blocking at this point in time.
  2. Data limited by the structured clone algorithm - Due to running in a separate execution context, only objects that can be cloned can be sent into or received from the functions.
  3. Functions can block each other - While the functions are guaranteed to not block the main thread, a function in the sandbox can block another function in the sandbox. It would be impossible to guarantee this doesn't happen as browsers can only execute a finite number of threads in parallel.

Usage

const sandbox = await Sandybox.create();
const sandboxedFunction = await sandbox.addFunction((word, repeat) => {
  let result = '';
  for (let i = 0; i < repeat; i++) result += word;
  return result;
});

console.log(await sandboxedFunction('hi!', 100000000));

Cleanup

If you're finished with a function and worried about memory usage, you can use sandbox.removeFunction(fn) to evict the function from the sandbox.

sandbox.removeFunction(sandboxedFunction);

Calling this will cause any unresolved executions of the function to reject. Additionally, once a function has been "removed" any calls to it will result in a rejected promise. Any rejections that are due to sandbox cleanup will be instances of SandboxError.

Similarly, if you are finished with a sandbox you can cleanup the entire thing by calling sandbox.cleanup(). This will remove all functions, the iframe, and the web worker.

sandbox.cleanup();

In the future, sandboxes and their functions will likely cleanup automatically by using a FinalizationRegistry. Until then, you'll need to manually cleanup if memory usage is a concern.

Allow Same Origin

While strongly recommended against, some use cases require the sandbox to run in the same origin as the host. This opens up potential attack vectors, but is still safer than evaluating code directly in your app.

To allow same origin, you can pass an options hash to the create method and set dangerouslyAllowSameOrigin:

const sameOriginSandbox = await Sandybox.create({
  dangerouslyAllowSameOrigin: true,
});