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

@ricsam/isolate

v0.1.2

Published

Unified runtime host for app servers, script runtimes, browser runtimes, module resolution, file bindings, and typechecking

Readme

@ricsam/isolate

@ricsam/isolate is a runtime-centric JavaScript sandbox built on isolated-vm. It gives you a single host API for running isolated code with web-style capabilities such as fetch, files, streams, server handlers, module loading, and Playwright-backed browser tests.

Installation

npm add @ricsam/isolate isolated-vm

Install Playwright when you want browser runtimes:

npm add playwright

What You Get

@ricsam/isolate exports a small top-level API:

  • createIsolateHost() to start, connect to, and manage isolate-backed runtimes
  • createModuleResolver() to provide virtual modules, source trees, mounted node_modules, and fallback resolution
  • createFileBindings() to expose a rooted file API to sandboxed code
  • getTypeProfile(), typecheck(), and formatTypecheckErrors() for sandbox-aware TypeScript tooling

The host can create three runtime styles:

  • host.createRuntime() for scripts, agents, and ad hoc execution
  • host.createAppServer() for serve()-based request handlers
  • host.createBrowserRuntime() for Playwright-backed execution

Host Bindings

Each runtime is configured through bindings, which describe how sandboxed code talks to the host:

  • console forwards runtime and browser console output
  • fetch handles outbound HTTP requests from the sandbox
  • files exposes a safe, root-scoped filesystem
  • modules resolves virtual modules, source trees, and mounted packages
  • tools exposes async host functions and async iterators

Every host callback receives a HostCallContext with an AbortSignal, runtime identity, resource identity, and request metadata.

Quick Start

import {
  createFileBindings,
  createIsolateHost,
  createModuleResolver,
} from "@ricsam/isolate";

const host = await createIsolateHost({
  daemon: {
    socketPath: "/tmp/isolate.sock",
  },
});

const runtime = await host.createRuntime({
  bindings: {
    console: {
      onEntry(entry) {
        if (entry.type === "output") {
          console.log(entry.stdout);
        }
      },
    },
    fetch: async (request) => await fetch(request),
    files: createFileBindings({
      root: process.cwd(),
      allowWrite: true,
    }),
    modules: createModuleResolver()
      .virtual(
        "@/env",
        `export const mode = "sandbox";`,
        { filename: "env.ts", resolveDir: "/app" },
      )
      .virtual(
        "/app/main.ts",
        `
          import { mode } from "@/env";

          const response = await fetch("https://example.com");
          console.log("mode:", mode);
          console.log("status:", response.status);
          console.log(await greet("isolate"));
        `,
        { filename: "main.ts", resolveDir: "/app" },
      ),
    tools: {
      greet: async (name: string) => `hello ${name}`,
    },
  },
});

try {
  await runtime.eval(`import "/app/main.ts";`, { filename: "/app/entry.ts" });
} finally {
  await runtime.dispose();
  await host.close();
}

App Servers

createAppServer() is the long-lived server-oriented API. It boots a runtime around an entry module that calls serve() and then lets the host dispatch requests into it.

import { createIsolateHost, createModuleResolver } from "@ricsam/isolate";

const host = await createIsolateHost();
const server = await host.createAppServer({
  key: "example/server",
  entry: "/server.ts",
  bindings: {
    modules: createModuleResolver().virtual(
      "/server.ts",
      `
        serve({
          fetch(request) {
            return Response.json({
              pathname: new URL(request.url).pathname,
            });
          },
        });
      `,
    ),
  },
});

const result = await server.handle(new Request("http://localhost/hello"));
if (result.type === "response") {
  console.log(await result.response.json());
}

await server.dispose();
await host.close();

server.handle() returns either a normal HTTP response or WebSocket upgrade metadata. The server.ws helpers let the host continue an upgraded connection by sending open, message, close, and error events back into the runtime.

Browser Runtimes

createBrowserRuntime() runs sandboxed code against a Playwright page while keeping the host in control of file access, diagnostics, and browser event collection.

import { chromium } from "playwright";
import { createIsolateHost } from "@ricsam/isolate";

const browser = await chromium.launch();
const context = await browser.newContext();
const page = await context.newPage();

const host = await createIsolateHost();
const runtime = await host.createBrowserRuntime({
  key: "example/browser",
  bindings: {},
  features: { tests: true },
  browser: {
    page,
    captureConsole: true,
  },
});

const result = await runtime.run(
  `
    test("loads a page", async () => {
      await page.goto("https://example.com");
      await expect(page).toHaveTitle(/Example Domain/);
    });
  `,
  {
    filename: "/browser-test.ts",
    asTestSuite: true,
    timeoutMs: 10_000,
  },
);

console.log(result.tests);

await runtime.dispose();
await context.close();
await browser.close();
await host.close();

Module Resolution

createModuleResolver() is a fluent builder. You can mix and match:

  • virtual(specifier, source, options) for inline modules
  • virtualFile(specifier, filePath, options) for a host file mapped to a virtual specifier
  • sourceTree(prefix, loader) for lazy source loading under a virtual path
  • mountNodeModules(virtualMount, hostPath) for package resolution from a real node_modules
  • fallback(loader) for custom last-resort resolution

File Bindings

createFileBindings({ root, allowWrite }) creates a filesystem bridge that stays inside the configured root directory. Attempts to escape that root are rejected, and write operations are disabled unless allowWrite is set to true.

Typechecking

The typecheck helpers let you validate sandbox code against supported capability profiles before executing it.

import {
  formatTypecheckErrors,
  getTypeProfile,
  typecheck,
} from "@ricsam/isolate";

const profile = getTypeProfile({
  profile: "browser-test",
  capabilities: ["files"],
});

console.log(profile.include);

const result = typecheck({
  code: "page.goto('/')",
  profile: "browser-test",
});

if (!result.success) {
  console.error(formatTypecheckErrors(result.errors));
}

Built-in profiles:

  • backend
  • agent
  • browser-test

Capabilities can extend a profile with fetch, files, tests, browser, tools, console, encoding, and timers.

Daemon CLI

The package also exposes an isolate-daemon binary:

isolate-daemon --socket /tmp/isolate.sock

By default, createIsolateHost() will auto-start a daemon when needed. You can also point the host at an already-running daemon with daemon.socketPath, or disable auto-start with daemon.autoStart: false.

Development

npm run build
npm run typecheck
npm test