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

isolated-function

v0.1.26

Published

Runs untrusted code in a Node.js v8 sandbox.

Downloads

168

Readme

Install

npm install isolated-function --save

Quickstart

isolated-function is a modern solution for running untrusted code in Node.js.

const isolatedFunction = require('isolated-function')

/* create an isolated-function, with resources limitation */
const [sum, teardown] = isolatedFunction((y, z) => y + z, {
  memory: 128, // in MB
  timeout: 10000 // in milliseconds
})

/* interact with the isolated-function */
const { value, profiling } = await sum(3, 2)

/* close resources associated with the isolated-function initialization */
await teardown()

Minimal privilege execution

The hosted code runs in a separate process, with minimal privilege, using Node.js permission model API.

const [fn, teardown] = isolatedFunction(() => {
  const fs = require('fs')
  fs.writeFileSync('/etc/passwd', 'foo')
})

await fn()
// => PermissionError: Access to 'FileSystemWrite' has been restricted.

If you exceed your limit, an error will occur. Any of the following interaction will throw an error:

  • Native modules
  • Child process
  • Worker Threads
  • Inspector protocol
  • File system access
  • WASI

Auto install dependencies

The hosted code is parsed for detecting require/import calls and install these dependencies:

const [isEmoji, teardown] = isolatedFunction(input => {
  /* this dependency only exists inside the isolated function */
  const isEmoji = require('[email protected]') // default is latest
  return isEmoji(input)
})

await isEmoji('🙌') // => true
await isEmoji('foo') // => false
await teardown()

The dependencies, along with the hosted code, are bundled by esbuild into a single file that will be evaluated at runtime.

Execution profiling

Any hosted code execution will be run in their own separate process:

/** make a function to consume ~128MB */
const [fn, teardown] = isolatedFunction(() => {
  const storage = []
  const oneMegabyte = 1024 * 1024
  while (storage.length < 78) {
    const array = new Uint8Array(oneMegabyte)
    for (let ii = 0; ii < oneMegabyte; ii += 4096) {
      array[ii] = 1
    }
    storage.push(array)
  }
})
t.teardown(cleanup)

const { value, profiling } = await fn()
console.log(profiling)
// {
//   memory: 128204800,
//   duration: 54.98325
// }

Each execution has a profiling, which helps understand what happened.

Resource limits

You can limit a isolated-function by memory:

const [fn, teardown] = isolatedFunction(() => {
  const storage = []
  const oneMegabyte = 1024 * 1024
  while (storage.length < 78) {
    const array = new Uint8Array(oneMegabyte)
    for (let ii = 0; ii < oneMegabyte; ii += 4096) {
      array[ii] = 1
    }
    storage.push(array)
  }
}, { memory: 64 })

await fn()
// =>  MemoryError: Out of memory

or by execution duration:

const [fn, teardown] = isolatedFunction(() => {
  const delay = ms => new Promise(resolve => setTimeout(resolve, ms))
  await delay(duration)
  return 'done'
}, { timeout: 50 })

await fn(100)
// =>  TimeoutError: Execution timed out

Logging

The logs are collected into a logging object returned after the execution:

const [fn, teardown] = isolatedFunction(() => {
  console.log('console.log')
  console.info('console.info')
  console.debug('console.debug')
  console.warn('console.warn')
  console.error('console.error')
  return 'done'
})

const { logging } await fn()

console.log(logging)
// {
//   log: ['console.log'],
//   info: ['console.info'],
//   debug: ['console.debug'],
//   warn: ['console.warn'],
//   error: ['console.error']
// }

Error handling

Any error during isolated-function execution will be propagated:

const [fn, cleanup] = isolatedFunction(() => {
  throw new TypeError('oh no!')
})

const result = await fn()
// TypeError: oh no!

You can also return the error instead of throwing it with { throwError: false }:

const [fn, cleanup] = isolatedFunction(() => {
  throw new TypeError('oh no!')
})

const { isFullfiled, value } = await fn()

if (!isFufilled) {
  console.error(value)
  // TypeError: oh no!
}

API

isolatedFunction(code, [options])

code

Required Type: function

The hosted function to run.

options

memory

Type: number Default: Infinity

Set the function memory limit, in megabytes.

throwError

Type: boolean Default: false

When is true, it returns the error rather than throw it.

The error will be accessible against { value: error, isFufilled: false } object.

Set the function memory limit, in megabytes.

timeout

Type: number Default: Infinity

Timeout after a specified amount of time, in milliseconds.

tmpdir

Type: function

It setup the temporal folder to be used for installing code dependencies.

The default implementation is:

const tmpdir = async () => {
  const cwd = await fs.mkdtemp(path.join(require('os').tmpdir(), 'compile-'))
  await fs.mkdir(cwd, { recursive: true })
  const cleanup = () => fs.rm(cwd, { recursive: true, force: true })
  return { cwd, cleanup }
}

=> (fn([...args]), teardown())

fn

Type: function

The isolated function to execute. You can pass arguments over it.

teardown

Type: function

A function to be called to release resources associated with the isolated-function.

Environment Variables

ISOLATED_FUNCTIONS_MINIFY

Default: true

When is false, it disabled minify the compiled code.

DEBUG

Pass DEBUG=isolated-function for enabling debug timing output.

License

isolated-function © Kiko Beats, released under the MIT License. Authored and maintained by Kiko Beats with help from contributors.

kikobeats.com · GitHub @Kiko Beats · X @Kikobeats