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/agentportal

v0.1.0-alpha.0

Published

NestJS 12 integration for AgentPortal with typed portals, managed CapsuleOS execution, and native streaming HTTP responses.

Readme

@nestm/agentportal

NestJS 12 integration for native AgentPortal Portals. It adds configuration, named dependency-injection registrations, explicit resource ownership, CapsuleOS-managed execution, deterministic testing helpers, and native SSE/NDJSON responses without replacing AgentPortal's lifecycle or event model.

Requirements

  • Node.js 24 or newer
  • NestJS 12.0.0-alpha.5 or a compatible Nest 12 release
  • AgentPortal 0.1.x

Install the root integration and its required native peers:

pnpm add @nestm/agentportal @agentportal/portal @agentportal/provider \
  @nestjs/common @nestjs/core reflect-metadata rxjs

Optional entry points have isolated dependencies:

| Entry point | Additional dependencies | | ------------------------------ | --------------------------------------------------------------------- | | @nestm/agentportal/http | @agentportal/sdk | | @nestm/agentportal/testing | @agentportal/sdk, @agentportal/testing, vitest | | @nestm/agentportal/capsuleos | @capsuleos/agentportal, @capsuleos/core, @agentportal/transport |

The root entry never loads the optional HTTP, testing, transport, or CapsuleOS packages.

Root Portal

Pass either an application-owned Portal or an adapter/config pair owned by Nest. The two modes are mutually exclusive.

import { Module } from "@nestjs/common";
import { AgentPortalModule } from "@nestm/agentportal";
import { codex } from "@agentportal/codex";

@Module({
	imports: [
		AgentPortalModule.forRoot({
			agent: codex({ mode: "app-server" }),
			config: { transports, store, env: {} },
			closeOptions: { timeoutMs: 10_000 },
			isGlobal: true,
		}),
	],
})
export class AppModule {}

Inject the root Portal directly:

import { Injectable } from "@nestjs/common";
import { InjectAgentPortal } from "@nestm/agentportal";
import type { Portal } from "@agentportal/portal";

@Injectable()
export class CodingService {
	constructor(@InjectAgentPortal() readonly portal: Portal) {}
}

forRootAsync() supports Nest's useFactory, useClass, and useExisting patterns. A prebuilt Portal is always external and is never closed by this package. A Portal created from { agent, config } is closed by Nest within the configured deadline.

Named agents and Portals

Named external registrations preserve Nest request, transient, and durable scopes. Only an explicit create definition is module-owned, and created Portals must remain singleton-scoped.

AgentPortalModule.forFeature({
	agents: [{ name: "codex", useValue: codex({ mode: "app-server" }) }],
	portals: [
		{
			name: "coding",
			create: {
				agent: "codex",
				config: { transports, store, env: {} },
			},
		},
	],
});
constructor(
  @InjectAgentPortal("coding") readonly portal: Portal,
  @InjectPortalAgent("codex") readonly adapter: AgentAdapter,
) {}

Duplicate normalized agent or Portal names fail during application bootstrap, including duplicates declared by separate feature modules in the same Nest application context. Native AgentPortal errors retain their identity; the wrapper introduces errors only for invalid Nest configuration, duplicate names, scopes, and missing named providers.

CapsuleOS-managed Portal

The CapsuleOS entry creates one reusable named Portal and one lazy template-resolution lease. The bridge owns session isolation; the resolution lease owns the dedicated control sandbox used for adapter resolution and Portal.models().

import { AgentPortalCapsuleModule } from "@nestm/agentportal/capsuleos";

AgentPortalCapsuleModule.forFeature({
	name: "sandboxed-codex",
	agent: codex({ mode: "app-server" }),
	capsule,
	bridge: {
		sandbox: template,
		retention: { mode: "destroy" },
		bindings: {
			resolver: explicitBindingResolver,
			store: {
				sqlite: {
					path: "./capsule-bindings.db",
					controllerId: "api-1",
					ownershipLeaseMs: 30_000,
				},
			},
		},
	},
	portal: {
		store: metadataOnlySessionStore,
		limits: { idleTimeoutMs: 120_000 },
	},
});

The integration always supplies env: {}, process transports, isolation, resolver, and probe executor. Those fields are reserved and cannot be overridden. Shutdown uses one absolute deadline and always attempts this order:

  1. Portal
  2. resolution lease
  3. module-owned bridge
  4. module-owned binding store

An external bridge or binding store is never closed by Nest.

Native HTTP responses

AgentPortalResponse delegates framing, replay watermarks, pull backpressure, errors, and cancel behavior to @agentportal/sdk/web. Nest only adapts the resulting Fetch Response to Express or Fastify.

import { AgentPortalHttpModule, AgentPortalResponse } from "@nestm/agentportal/http";

@Module({ imports: [AgentPortalHttpModule] })
export class HttpModule {}

return AgentPortalResponse.sse(run, {
	heartbeatMs: 15_000,
	abortOnCancel: false,
});

return AgentPortalResponse.ndjson(run, {
	abortOnCancel: true,
});

SSE uses the complete stamped event as data and its seq as the SSE ID. Omit heartbeatMs—or pass false—to create no heartbeat timer. Before headers, native errors flow to Nest exception handling. After headers, the response/socket is terminated without appending a JSON error body. Disconnect detaches by default and aborts the native run only when abortOnCancel: true.

Testing

The testing entry re-exports @agentportal/sdk/mock and adds Nest-specific module/override helpers:

import {
	createAgentPortalTestingModule,
	createMockPortal,
	overrideAgentPortal,
} from "@nestm/agentportal/testing";

const portal = await createMockPortal({
	scripts: [
		{
			events: [
				{ type: "text", payload: { content: "hello" } },
				{ type: "done", payload: { status: "success" } },
			],
		},
	],
});

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

No ordinary test or CI command makes a live provider call.

The blocking packed release gate also installs all CapsuleOS, AgentPortal, and Nest wrappers into one isolated Nest 12 consumer. It executes the AI SDK Harness path and the native AgentPortal path independently; neither path owns, dispatches, or normalizes the other.

Security and persistence

  • Pass provider credentials and sandbox inputs explicitly; this package does not read them from ambient environment variables.
  • The Capsule integration prevents host environment inheritance with env: {}.
  • Use AgentPortal's metadata-only SQLite mode when prompts, output, stdin, stdout, and stderr must not be persisted.
  • Treat ingress as public unless the selected CapsuleOS provider proves authentication.
  • HTTP disconnect is detach-by-default so one client cannot silently cancel shared or durable work.
  • Cleanup is idempotent and deadline-bound, and native primary errors are not replaced by wrapper errors when cleanup succeeds.

See SECURITY.md for the full boundary and disclosure policy.

License

BSD-3-Clause