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

@bestest/node-module-sandbox

v1.1.1

Published

Sandbox Node.js modules along with require function

Downloads

14

Readme

@bestest/node-module-sandbox

This module is trying to separate node modules creation in selected context, without touching i.e. regular require cache.

Warning: Remember, you should not treat this as a safe sandbox solution! It is also changing some default behaviors, so you may treat is as a buggy as well.

How to use it

Execute code (with sandboxed modules cache)

// fn.js
exports.fn = () => 3

// main.js
const { NodeModuleSandbox } = require('@bestest/node-module-sandbox')

const sandbox1 = new NodeModuleSandbox()
const sandbox2 = new NodeModuleSandbox()

// Modify fn.js module in "sandbox1"
sandbox1.executeScript('require("./fn").fn = () => 5')

// Verify that './fn' has been modified in "sandbox1"
console.log(sandbox1.executeScript('require("./fn").fn()')) // 5

// Verify that './fn' has been modified in "sandbox2"
console.log(sandbox2.executeScript('require("./fn").fn()')) // 3

// Verify that './fn' has not been modified locally
console.log(require('./fn').fn()) // 3

Passing arguments (or callback)

const { NodeModuleSandbox } = require('@bestest/node-module-sandbox')

const sandbox = new NodeModuleSandbox()

// Remember that this function will be serialized,
// so you should not use anything from outside of its context.
const fn = (callback) => {
  setTimeout(() => {
    callback(10)    
  }, 1000)
}

// Remember that this function will be serialized,
// so you should not use anything from outside of its context.
const fn2 = (x, y, z) => {
    console.log('Sum:', x + y + z)
}

sandbox.executeScriptWithArguments(fn, value => {
  console.log('The value is', value)
})

sandbox.executeScriptWithArguments(fn2, 1, 2, 3)

Passing custom file system

const { FileSystem } = require('@bestest/fs')
const { NodeModuleSandbox } = require('@bestest/node-module-sandbox')

const fileSystem = new FileSystem()

fileSystem.setLocalFile('./fixture.json', '"text"')

fileSystem.setLocalFile('./example.js', `
  module.exports = {
    root: "/root/"
  }
`)

fileSystem.setLocalFile('./a.js', `
  // File system can be mocked as well
  const fs = require('fs')
  const fixture = JSON.parse(fs.readFileSync('./fixture.json'))

  console.log(require('./example').root + fixture) // "/root/text"
`)

const sandbox = new NodeModuleSandbox({
  modules: { fs: fileSystem.fs }
})

sandbox.requireModule('./a.js', module) // logs "/root/text"
sandbox.requireModule('./a.js', module) // does nothing - this module is already resolved
sandbox.executeScript('require("./a.js")') // does nothing - this module is already resolved

Other options

  • If you would like to run code in better sandbox:
    • You may use native vm module, which will create new V8 context (but i.e. without access to Node.js modules).
  • If you would like to run code in separate thread:
    • You may think about worker threads, available since Node.js 10
    • You can run it as a separate process through child_process module
    • You may also want to take a look at cluster module

Problems

Extensions

Due to the way it is resolved, there are some differences in behavior:

  • .js and .json files will be loaded without any registered extension handlers (i.e. ts-node or @babel/register)
  • Native modules may be replaced by selected implementation
  • All other files will be loaded regularly, outside of sandbox

Global context is still available

Module context (module, require, __dirname, __filename) will be replaced, but other global objects will still be the same.

ESM imports are not modified

Unfortunately, there is no API yet available to access and modify ESMLoader.

Changelog

  • 1.1.1 (on 13.08.2019): improve list of script extensions for file resolution
  • 1.1.0 (on 13.08.2019): add option to pass arguments for executed scripts
  • 1.0.0 (on 13.08.2019): initial version