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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@iso4/sandbox

v0.0.4

Published

Fast, sandboxed V8 isolate runtime for agent-generated JavaScript. Two-process architecture for crash isolation.

Readme

@iso4/sandbox

Fast, sandboxed V8 isolate runtime for agent-generated JavaScript. Runs user code in a separate Rust process for full crash isolation — an OOM or panic in the sandbox kills only the subprocess, not your host application.

Built for the AI-agent prefix/postfix pattern: precompile host setup (globals, libraries, tool bindings) once into a V8 startup snapshot, then run many agent-generated code strings against the snapshot in parallel.

Status: core execution works end-to-end. Not yet at 1.0.

Install

npm i @iso4/sandbox
# hardened fetch defaults (recommended):
npm i @iso4/fetch

Quick start

import { createSandbox } from '@iso4/sandbox'
import { createSafeFetch } from '@iso4/fetch'

const sandbox = await createSandbox()

// Compile host setup once into a V8 snapshot
const prefix = await sandbox.precompile({
  code: `
    const config = { apiBase: 'https://api.example.com' }
    globalThis.config = config
  `,
  globals: {
    fetch: createSafeFetch({ policy: ({ host }) => host === 'api.example.com' }),
  },
})

// Run agent-generated code against the snapshot — as many times as needed
const result = await prefix.run({
  code: `
    const res = await fetch(config.apiBase + '/users')
    export default { count: res.length }
  `,
  limits: { cpuTimeMs: 200, wallTimeMs: 5_000, memoryMb: 64 },
})

if (result.ok) {
  console.log(result.exports.default) // { count: 42 }
} else {
  console.error(result.error.code, result.error.message)
}

await sandbox.dispose()

How globals work

globals wires any non-reserved name directly into the sandbox's global object as a bridge stub. The bridge is fully generic — fetch is not special-cased:

const options = {
  globals: {
    searchWeb: async (query: string) => {
      const res = await fetch(`https://api.example.com/search?q=${encodeURIComponent(query)}`)
      return res.json()
    },
  }
}

Functions in bridge return values are currently dropped — return plain data, not class instances with methods.

TypeScript-checked rebinding

precompile() infers the globals shape G from what you pass, and the returned Prefix<G> only allows rebinding those names at run time:

const prefix = await sandbox.precompile({
  globals: { fetch: defaultFetch, myTool: defaultTool },
})

prefix.run({ globals: { fetch: perUserFetch } }) // ✅ rebind one
prefix.run({ globals: { unknown: handler } }) // ❌ TS error

Resource limits

prefix.run({
  code: agentCode,
  limits: {
    cpuTimeMs: 200, // active JS execution only (await time excluded)
    wallTimeMs: 5_000, // hard cap including async waits
    memoryMb: 64, // V8 heap + ArrayBuffer budget
    maxBridgeCalls: 10, // max host-bridge calls per run (0 = unlimited)
    maxBridgePayloadBytes: 0, // max bytes per bridge call (0 = 64 MiB framing cap)
  },
})

Result shape

type RunResult
  = | { ok: true, exports: SandboxExports, stdout: string[], stderr: string[], durationMs: number }
    | { ok: false, error: RunError, stdout: string[], stderr: string[], durationMs: number }

interface RunError { code: RunErrorCode, name: string, message: string, stack?: string }

run() never throws for sandboxed failures — only for infrastructure errors (subprocess crashed, binary not found). ok: false with an error code is the normal failure path.

Architecture

V8 runs in a separate Rust subprocess communicating over a Unix domain socket. A pool of connections (one per maxIsolates slot) provides concurrency — five concurrent prefix.run() calls each get their own slot and execute in parallel.

License

MIT