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

@nestm/capsuleos

v0.1.0-alpha.0

Published

Typed CapsuleOS integration for NestJS 12 with testing and AI SDK Harness subpaths.

Readme

@nestm/capsuleos

Typed CapsuleOS integration for NestJS 12. It provides a small dependency-injection boundary around a Capsule facade while preserving CapsuleOS provider aliases, native errors, and application ownership.

  • CapsuleOsModule.forRoot() and forRootAsync()
  • Mutually exclusive provider-map and prebuilt-Capsule registration
  • Typed CapsuleOsService, token, and injection decorator
  • Framework-neutral fakes through @nestm/capsuleos/testing
  • Named AI SDK Harness sandbox providers through @nestm/capsuleos/ai-sdk-harness

The root entrypoint does not import provider SDKs, testing utilities, or AI SDK Harness. It never allocates a sandbox at Nest bootstrap.

Requirements

  • Node 24 or newer
  • NestJS ^12.0.0-alpha.5
  • CapsuleOS ^0.2.0
  • ESM

Installation

pnpm add @nestm/capsuleos capsuleos @nestjs/common @nestjs/core reflect-metadata rxjs

Install the CapsuleOS provider package your application uses separately. Construct its client with explicit credentials; this package does not read provider credentials from ambient environment variables.

Provider-map registration

import { Module } from "@nestjs/common";
import { CapsuleOsModule, defineCapsuleOsConfig, secret } from "@nestm/capsuleos";
import { vercel } from "@capsuleos/vercel";

const capsuleConfig = defineCapsuleOsConfig({
	providers: {
		vercel: vercel({
			token: secret(explicitToken),
			teamId: explicitTeamId,
			projectId: explicitProjectId,
		}),
	},
	defaults: { provider: "vercel" },
});

@Module({
	imports: [CapsuleOsModule.forRoot({ ...capsuleConfig, isGlobal: true })],
})
export class AppModule {}

The application owns every provider and native provider client. CapsuleOsModule creates only the Capsule facade and does not close the provider instances. Root registration is global by default; pass isGlobal: false for a module-local registration.

Prebuilt Capsule registration

Use capsule when the application already constructed and owns a Capsule. capsule and providers are mutually exclusive, and defaults or event-buffer settings cannot modify a prebuilt facade.

import { createCapsule } from "capsuleos";

const capsule = createCapsule({ providers: capsuleConfig.providers });

CapsuleOsModule.forRoot({ capsule });

Nest preserves the exact object identity and never closes a prebuilt Capsule.

Injection and typing

import { Inject, Injectable } from "@nestjs/common";
import { CAPSULE_OS, CapsuleOsService, InjectCapsuleOs, type Capsule } from "@nestm/capsuleos";

@Injectable()
export class SandboxService {
	constructor(
		@InjectCapsuleOs()
		readonly capsule: Capsule<typeof capsuleConfig.providers>,
		readonly capsuleOs: CapsuleOsService<typeof capsuleConfig.providers>,
		@Inject(CAPSULE_OS)
		readonly sameCapsule: Capsule<typeof capsuleConfig.providers>,
	) {}
}

To make the provider map the default generic argument across an application, augment the public type registry once:

declare module "@nestm/capsuleos" {
	interface CapsuleOsTypeRegistry {
		providers: typeof capsuleConfig.providers;
	}
}

CapsuleOsService then exposes typed capsule, providers, sandboxes, and events without a local generic argument.

Async registration

forRootAsync() supports Nest's useFactory, useClass, and useExisting patterns:

CapsuleOsModule.forRootAsync({
	imports: [ConfigModule],
	inject: [ConfigService],
	useFactory: (config: ConfigService) => ({
		providers: {
			vercel: vercel({
				token: secret(config.getOrThrow("VERCEL_TOKEN")),
				teamId: config.getOrThrow("VERCEL_TEAM_ID"),
				projectId: config.getOrThrow("VERCEL_PROJECT_ID"),
			}),
		},
		defaults: { provider: "vercel" },
	}),
});

Class and existing factories implement CapsuleOsOptionsFactory.createCapsuleOsOptions(). The createCapsuleOsOptions() identity helper preserves concrete provider-map types in those factories.

Testing

Install @capsuleos/testing and import the optional testing entrypoint:

import { Test } from "@nestjs/testing";
import { createCapsuleOsTestingModule, overrideCapsuleOsProviders } from "@nestm/capsuleos/testing";

const builder = Test.createTestingModule({
	imports: [createCapsuleOsTestingModule()],
});

overrideCapsuleOsProviders(builder, {
	providers: { fake: myFakeProvider },
});

The generated testing module is local by default and performs no sandbox allocation.

AI SDK Harness

The optional entrypoint delegates sandbox behavior to @capsuleos/ai-sdk-harness and requires the exact @ai-sdk/[email protected] compatibility patch:

pnpm add @capsuleos/ai-sdk-harness@^0.2.0 @ai-sdk/[email protected]
import {
	CapsuleOsHarnessModule,
	InjectCapsuleOsHarnessSandbox,
	SqliteCapsuleOsHarnessBindings,
	type HarnessV1SandboxProvider,
} from "@nestm/capsuleos/ai-sdk-harness";

const bindings = new SqliteCapsuleOsHarnessBindings({
	path: "./capsuleos-harness.db",
});

CapsuleOsHarnessModule.register({
	name: "coding",
	provider: "vercel",
	sandbox: { spec: agentSandboxSpec },
	bridgePort: 43_123,
	bindings,
});

@Injectable()
export class CodingSandbox {
	constructor(
		@InjectCapsuleOsHarnessSandbox("coding")
		readonly provider: HarnessV1SandboxProvider,
	) {}
}

registerAsync() supports useFactory, useClass, and useExisting. Registration constructs a Harness sandbox provider but does not create a sandbox; allocation starts only when Harness asks it to create a session. Named registrations are independent and do not register Harness agents.

The upstream adapter's default auto transport is capability-driven. It prefers a loopback-only, base64-line-framed process tunnel when the provider advertises process.stdin, and otherwise uses stable provider ingress:

| Provider | Default Harness transport | Status | | ------------------- | ------------------------- | ---------------------------------------------- | | Vercel Sandbox | Provider ingress | Supported | | Daytona | Process tunnel | Supported | | Docker guest mode | Process tunnel | Supported | | Docker classic mode | Process tunnel | Supported with an exec-stdin-capable transport | | Apple Container | Process tunnel | Supported | | AWS Lambda MicroVMs | Process tunnel | Supported within configured provider limits | | Firecracker | Process tunnel | Preview; requires a compatible supervisor | | libkrun | Process tunnel | Experimental opt-in |

Automatic transport selection happens before a binding is reserved or a sandbox is allocated. A provider that offers neither process stdin nor stable ingress fails that preflight. Explicit Daytona provider-ingress remains experimental because its signed endpoint expires; normal Daytona use selects the process tunnel instead.

The application owns bindings and must close an application-created SQLite backend during its own shutdown. See SECURITY.md before exposing Harness ingress or persisting lifecycle state.

Ownership summary

| Resource | Owner | | ------------------------------------------- | -------------------------------------------------------- | | Provider SDK/client passed in providers | Application; never closed by Nest | | Prebuilt Capsule | Application; identity preserved and never closed by Nest | | Capsule facade constructed from providers | Nest module; providers remain external | | Harness binding store and lease manager | Application | | Harness sandbox sessions | Upstream Harness provider/runner lifecycle |

Package entrypoints

| Import | Purpose | Optional peer | | --------------------------------- | ------------------------------------------- | ---------------------------------------------- | | @nestm/capsuleos | Root Nest module and upstream CapsuleOS API | none beyond root peers | | @nestm/capsuleos/testing | Fake providers and Nest override helpers | @capsuleos/testing | | @nestm/capsuleos/ai-sdk-harness | Named Harness sandbox providers | @capsuleos/ai-sdk-harness, @ai-sdk/harness |