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

ri-sandbox

v1.0.1

Published

Deterministic WASM execution with resource limits, isolation, and snapshot/restore

Readme

ri-sandbox

Deterministic WASM execution with resource limits, isolation, and snapshot/restore.

Status

v1.0.0 — Production Ready

| Milestone | Status | |-----------|--------| | M1: Project Scaffolding | Complete | | M2: Core Types & Configuration | Complete | | M3: WASM Module Loading & Instantiation | Complete | | M4: Execution Engine & Host Function Bridge | Complete | | M5: Gas Metering & Resource Limits | Complete | | M6: Determinism Enforcement | Complete | | M7: Snapshot & Restore | Complete | | M8: Memory Pressure System | Complete | | M9: Integration Tests & Performance Validation | Complete |

See ROADMAP.md for the full development plan.

Overview

ri-sandbox is a standalone TypeScript library that provides:

  • Deterministic execution — identical inputs produce identical outputs, always
  • Resource limits — memory caps, gas metering, wall-clock timeouts
  • Complete isolation — no host memory access, no ambient authority
  • Host function injection — controlled WASM-to-host bridge
  • Gas metering enforcement — computation budget per execution
  • Determinism enforcement — seeded PRNG, injected time, import isolation
  • Snapshot/restore — serialize and resume execution state
  • Memory pressure monitoring — tiered alerts with actionable recommendations

Install

npm install ri-sandbox

Quick Start

import { createWasmSandbox } from 'ri-sandbox';

// 1. Create a sandbox factory
const sandbox = createWasmSandbox();

// 2. Create an instance with resource limits
const instance = sandbox.create({
  maxMemoryBytes: 1_048_576,     // 1 MB
  maxGas: 500_000,
  maxExecutionMs: 30,
  hostFunctions: {},
  deterministicSeed: 42,
  eventTimestamp: 1700000000000,
});
// instance.id → "sandbox-0", instance.status → "created"

// 3. Load a WASM module
const wasmBytes = new Uint8Array(/* ... your .wasm file ... */);
await sandbox.load(instance, wasmBytes);
// instance status is now "loaded"

// 4. Execute a WASM function
const result = sandbox.execute(instance, 'add', [3, 7]);
if (result.ok) {
  console.log(result.value); // 10
  console.log(result.metrics);
  console.log(result.gasUsed); // gas consumed during execution
  console.log(result.durationMs); // wall-clock time in ms
}

// 5. Check resource metrics
const metrics = sandbox.getMetrics(instance);
// metrics.memoryUsedBytes, metrics.memoryLimitBytes, ...

// 6. Clean up
sandbox.destroy(instance);
// instance status is now "destroyed"

API

Resource Enforcement

The sandbox enforces three resource limits during execution:

| Resource | Config | Error Code | Enforcement | |----------|--------|------------|-------------| | Gas (computation) | maxGas | GAS_EXHAUSTED | Consumed at host function call boundaries | | Memory | maxMemoryBytes | MEMORY_EXCEEDED | Checked after execution; WebAssembly.Memory maximum enforces hard limit | | Timeout | maxExecutionMs | TIMEOUT | Checked at host function call boundaries via injectable timer |

const result = sandbox.execute(instance, 'expensive', payload);
if (!result.ok) {
  switch (result.error.code) {
    case 'GAS_EXHAUSTED':
      console.log(`Gas: ${result.error.gasUsed}/${result.error.gasLimit}`);
      break;
    case 'TIMEOUT':
      console.log(`Timeout: ${result.error.elapsedMs}ms > ${result.error.limitMs}ms`);
      break;
    case 'MEMORY_EXCEEDED':
      console.log(`Memory: ${result.error.memoryUsed}/${result.error.memoryLimit} bytes`);
      break;
  }
}

Determinism Enforcement

The sandbox eliminates all sources of non-determinism at load time and execution time:

| Mechanism | Module | Description | |-----------|--------|-------------| | Time injection | time-injection.ts | __get_time() host function returns config.eventTimestamp — never reads the system clock | | Seeded PRNG | random-injection.ts | __get_random() host function returns values from a Mulberry32 PRNG seeded with config.deterministicSeed | | Import isolation | isolation.ts | Rejects WASM modules that import WASI, undeclared functions, or non-env namespaces | | Double-execution check | determinism-validator.ts | Runs a function twice with state capture/restore and compares results byte-for-byte |

The __get_time and __get_random host functions are automatically injected into every sandbox instance. WASM modules can import them from the env namespace:

(import "env" "__get_time" (func $get_time (result i32)))
(import "env" "__get_random" (func $get_random (result i32)))

Import validation runs during sandbox.load() — modules with disallowed imports are rejected before instantiation with an INVALID_MODULE error.

Snapshot & Restore

Sandbox state (WASM linear memory, PRNG position, gas counter) can be serialized to a binary snapshot and restored later:

// Capture state
const snap = sandbox.snapshot(instance);

// Execute more actions...
sandbox.execute(instance, 'processEvent', payload);

// Rollback to captured state
sandbox.restore(instance, snap);

// Execution after restore is identical to execution after snapshot
const result = sandbox.execute(instance, 'processEvent', payload);

Snapshot binary format: 5-byte header (WSNP magic + version), memory section (uint32 length + raw bytes), state section (uint32 length + JSON). Invalid or corrupted snapshots are rejected with SNAPSHOT_ERROR.

Memory Pressure

Monitor system-wide memory usage across sandbox instances and get actionable recommendations:

import { getMemoryPressure, advise } from 'ri-sandbox';

// Compute pressure level — caller provides the memory budget
const level = getMemoryPressure(instances, availableBytes);
// level: 'NORMAL' | 'WARNING' | 'PRESSURE' | 'CRITICAL' | 'OOM'

// Get actionable recommendation
const rec = advise(level, instances, foregroundInstanceId);
switch (rec.action) {
  case 'none': break;
  case 'log': console.warn(rec.message); break;
  case 'suspend': rec.instanceIds.forEach(id => /* suspend */); break;
  case 'emergency_save': rec.instanceIds.forEach(id => /* snapshot + suspend */); break;
}

| Level | Threshold | Recommendation | |-------|-----------|----------------| | NORMAL | < 70% | No action | | WARNING | 70–85% | Log a warning | | PRESSURE | 85–95% | Suspend non-foreground instances | | CRITICAL | ≥ 95% | Emergency save all non-foreground | | OOM | ≥ 100% | Emergency save (should never happen) |

createWasmSandbox(): WasmSandbox

Factory function — creates a new WasmSandbox with its own instance registry.

import { createWasmSandbox } from 'ri-sandbox';

const sandbox = createWasmSandbox();

WasmSandbox

The main sandbox interface — all 7 methods for WASM execution lifecycle.

interface WasmSandbox {
  create(config: SandboxConfig): SandboxInstance;
  load(instance: SandboxInstance, module: Uint8Array): Promise<void>;
  execute(instance: SandboxInstance, action: string, payload: unknown): ExecutionResult;
  destroy(instance: SandboxInstance): void;
  snapshot(instance: SandboxInstance): Uint8Array;
  restore(instance: SandboxInstance, snapshot: Uint8Array): void;
  getMetrics(instance: SandboxInstance): ResourceMetrics;
}

SandboxConfig

Configuration for creating a sandbox instance.

interface SandboxConfig {
  readonly maxMemoryBytes: number;          // Hard memory limit (default: 16,777,216 — 16 MB)
  readonly maxGas: number;                  // Computation budget per execution (default: 1,000,000)
  readonly maxExecutionMs: number;          // Wall-clock timeout (default: 50ms)
  readonly hostFunctions: HostFunctionMap;  // Injected bridge functions (default: {})
  readonly deterministicSeed: number;       // PRNG seed (default: 0)
  readonly eventTimestamp: number;          // Injected "current time" (ms since epoch)
}

Default constants:

| Constant | Value | |----------|-------| | DEFAULT_MAX_MEMORY_BYTES | 16,777,216 (16 MB) | | DEFAULT_MAX_GAS | 1,000,000 | | DEFAULT_MAX_EXECUTION_MS | 50 | | DEFAULT_DETERMINISTIC_SEED | 0 |

SandboxInstance

An isolated WASM execution environment.

interface SandboxInstance {
  readonly id: string;
  readonly config: Readonly<SandboxConfig>;
  readonly status: SandboxStatus;
  readonly metrics: ResourceMetrics;
}

type SandboxStatus = 'created' | 'loaded' | 'running' | 'suspended' | 'destroyed';

ExecutionResult

Discriminated union returned by execute().

// Success
{ ok: true; value: unknown; metrics: ResourceMetrics; gasUsed: number; durationMs: number }

// Failure
{ ok: false; error: SandboxError }

ResourceMetrics

Current resource usage for a sandbox instance.

interface ResourceMetrics {
  readonly memoryUsedBytes: number;
  readonly memoryLimitBytes: number;
  readonly gasUsed: number;
  readonly gasLimit: number;
  readonly executionMs: number;
  readonly executionLimitMs: number;
}

HostFunction & HostFunctionMap

Host functions injected from the caller into WASM.

interface HostFunction {
  readonly name: string;
  readonly params: readonly WasmValueType[];
  readonly results: readonly WasmValueType[];
  readonly handler: (...args: readonly number[]) => number | undefined;
}

type HostFunctionMap = Readonly<Record<string, HostFunction>>;
type WasmValueType = 'i32' | 'i64' | 'f32' | 'f64';

SandboxError

Discriminated union with 8 error codes:

| Code | Fields | |------|--------| | GAS_EXHAUSTED | gasUsed, gasLimit | | MEMORY_EXCEEDED | memoryUsed, memoryLimit | | TIMEOUT | elapsedMs, limitMs | | WASM_TRAP | trapKind, message | | INVALID_MODULE | reason | | HOST_FUNCTION_ERROR | functionName, message | | INSTANCE_DESTROYED | instanceId | | SNAPSHOT_ERROR | reason |

Error factory functions: gasExhausted(), memoryExceeded(), timeout(), wasmTrap(), invalidModule(), hostFunctionError(), instanceDestroyed(), snapshotError().

MemoryPressureLevel

System-wide memory pressure level (percentage of available memory).

type MemoryPressureLevel = 'NORMAL' | 'WARNING' | 'PRESSURE' | 'CRITICAL' | 'OOM';

| Level | Threshold | |-------|-----------| | NORMAL | < 70% | | WARNING | 70–85% | | PRESSURE | 85–95% | | CRITICAL | ≥ 95% | | OOM | ≥ 100% |

Result<T, E>

Generic discriminated union for fallible operations.

type Result<T, E> = { ok: true; value: T } | { ok: false; error: E };

Development

npm install          # Install dependencies
npm run typecheck    # Type check
npm run test         # Run tests
npm run test:watch   # Run tests in watch mode
npm run test:coverage # Run tests with coverage
npm run lint         # Lint
npm run format       # Format
npm run build        # Build

Determinism Guarantees

| Non-Determinism Source | Prevention | |------------------------|------------| | System clock | Injected eventTimestamp | | Random numbers | Deterministic PRNG with injected seed | | Memory layout | WASM linear memory is deterministic | | Floating point | WASM IEEE 754 compliance | | Thread scheduling | Single-threaded (no concurrency) | | GC | WASM has manual memory (no GC) | | Browser differences | WASM spec guarantees identical behavior |

License

MIT

Architecture

The sandbox is structured as a pipeline:

Caller
  │
  ├─ create(config) ─────→ Instance Factory → WebAssembly.Memory + PRNG
  ├─ load(instance, wasm) ─→ Module Loader → Import Validator → Instantiator
  ├─ execute(instance, ..) → Executor → Gas Meter + Timeout + Memory Check
  ├─ snapshot(instance) ──→ Serializer → Binary (WSNP header + memory + state)
  ├─ restore(instance, ..) → Deserializer → Memory + PRNG + gas restoration
  └─ destroy(instance) ───→ Resource cleanup

Key internal modules:

| Module | Path | Responsibility | |--------|------|----------------| | Instance Factory | src/loader/instance-factory.ts | Creates sandbox instances with WASM memory and PRNG | | Module Loader | src/loader/module-loader.ts | Validates and compiles WASM bytes | | Import Validator | src/determinism/isolation.ts | Rejects WASI, undeclared imports, non-env namespaces | | Instantiator | src/loader/instantiator.ts | Wires host functions, memory, time, and random injection | | Executor | src/execution/executor.ts | Executes WASM functions with resource enforcement | | Gas Meter | src/resources/gas-meter.ts | Tracks computation budget at host function boundaries | | Timeout Checker | src/resources/timeout.ts | Wall-clock timeout with injectable timer | | Memory Limiter | src/resources/memory-limiter.ts | Post-execution memory usage check | | Serializer | src/snapshot/serializer.ts | Binary snapshot creation (WSNP format) | | Deserializer | src/snapshot/deserializer.ts | Binary snapshot restoration with full validation | | Pressure | src/pressure/memory-pressure.ts | System-wide memory pressure computation | | Advisor | src/pressure/pressure-advisor.ts | Actionable pressure recommendations |

Performance Characteristics

| Operation | Target | Measured | |-----------|--------|----------| | Create sandbox instance | < 5ms | < 1ms | | Load WASM module | < 50ms | < 5ms | | Execute simple function (add) | < 1ms | < 0.1ms | | Execute fibonacci(20) with gas metering | < 50ms | < 5ms | | Snapshot | < 10ms | < 1ms | | Restore | < 10ms | < 1ms | | Create + load + execute end-to-end | < 100ms | < 10ms | | 10 concurrent instances | all functional | < 10ms total |

Test WASM Modules

The library includes hand-crafted WASM binaries in src/loader/__tests__/wasm-fixtures.ts for testing:

| Module | Exports | Purpose | |--------|---------|----------| | addWasmModule() | add(i32, i32): i32 | Pure computation | | counterWasmModule() | increment(): void, get(): i32 | Stateful execution | | fibonacciWasmModule() | fib(i32): i32 | Gas metering (calls __get_time each iteration) | | memoryHogWasmModule() | allocate(i32): void, getMemSize(): i32 | Memory growth testing | | infiniteLoopWasmModule() | loop(): void | Gas/timeout testing (never returns) | | hostCallWasmModule() | callDouble(i32): i32 | Single host function call | | multiHostCallWasmModule() | callBoth(i32): i32 | Multiple host function calls | | randomImportWasmModule() | getRandom(): i32 | Deterministic PRNG testing | | timeImportWasmModule() | getTime(): i32 | Deterministic time testing | | memoryImportWasmModule() | getMemSize(): i32 | Memory import testing |

All modules are hand-crafted byte arrays — no WAT toolchain required.

Contributing

  1. Clone the repo and install dependencies:
git clone https://github.com/Robust-infrastructure/ri-sandbox.git
cd ri-sandbox
npm install
  1. Run the development workflow:
npm run typecheck     # Must pass with zero errors
npm run lint          # Must pass with zero warnings
npm run test          # All tests must pass
npm run test:coverage # Coverage ≥ 90% lines, 85% branches, 90% functions
npm run build         # Must produce clean ESM + CJS + types
  1. Follow the commit conventions in .github/instructions/git-workflow.instructions.md.
  2. Development follows the ROADMAP — complete milestones in order.