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

@frontman-ai/nextjs

v0.6.2

Published

Next.js integration for Frontman - AI-powered development tools and observability

Readme

@frontman-ai/nextjs

Next.js integration for Frontman - provides development tools and observability for Next.js applications.

Installation

Quick Install (Recommended)

The fastest way to install Frontman is using our CLI installer:

npx @frontman-ai/nextjs install

# Or with a custom server host
npx @frontman-ai/nextjs install --server frontman.company.com

The installer will:

  • Detect your Next.js version (15 or 16+)
  • Create the appropriate middleware/proxy file
  • Set up OpenTelemetry instrumentation
  • Configure everything to connect to your Frontman server

CLI Options

npx @frontman-ai/nextjs install [options]

Options:
  --server <host>   Frontman server host (default: api.frontman.sh)
  --prefix <path>   Target directory (default: current directory)
  --dry-run         Preview changes without writing files
  --skip-deps       Skip dependency installation
  --help            Show help message

Manual Installation

If you prefer to set things up manually or need to integrate with an existing configuration:

npm install @frontman-ai/nextjs

Then follow the Manual Setup instructions below.

Quick Start

After running the installer, you're ready to go! Start your Next.js dev server:

npm run dev

Then open your browser to http://localhost:3000/frontman to access the Frontman UI.

Manual Setup

Next.js 15 (middleware.ts)

Create middleware.ts in your project root:

import { createMiddleware } from '@frontman-ai/nextjs';
import { NextRequest, NextResponse } from 'next/server';

const frontman = createMiddleware({
  host: 'api.frontman.sh', // or 'frontman.local:4000' for local development
});

export async function middleware(req: NextRequest) {
  const response = await frontman(req);
  if (response) return response;
  return NextResponse.next();
}

export const config = {
  matcher: ['/frontman', '/frontman/:path*'],
};

Next.js 16+ (proxy.ts)

Create proxy.ts in your project root:

import { createMiddleware } from '@frontman-ai/nextjs';
import { NextRequest, NextResponse } from 'next/server';

const frontman = createMiddleware({
  host: 'api.frontman.sh', // or 'frontman.local:4000' for local development
});

export function proxy(req: NextRequest): NextResponse | Promise<NextResponse> {
  if (req.nextUrl.pathname === '/frontman' || req.nextUrl.pathname.startsWith('/frontman/')) {
    return frontman(req) || NextResponse.next();
  }
  return NextResponse.next();
}

export const config = {
  matcher: ['/frontman', '/frontman/:path*'],
};

OpenTelemetry Setup (Recommended)

Create instrumentation.ts in your project root (or src/ if you use that directory):

export async function register() {
  if (process.env.NEXT_RUNTIME === 'nodejs') {
    const { NodeSDK } = await import('@opentelemetry/sdk-node');
    const { setup } = await import('@frontman-ai/nextjs/Instrumentation');
    const [logProcessor, spanProcessor] = setup();
    new NodeSDK({
      logRecordProcessors: [logProcessor],
      spanProcessors: [spanProcessor],
    }).start();
  }
}

That's it! Frontman will now:

  • Capture console logs, build output, and errors
  • Track Next.js HTTP requests, API routes, and rendering
  • Make all logs available via the Frontman UI at /frontman

Adding to Existing Files

If you already have middleware.ts, proxy.ts, or instrumentation.ts files, the installer will show you manual integration steps. Here's how to add Frontman to existing files:

Existing middleware.ts (Next.js 15)

import { createMiddleware } from '@frontman-ai/nextjs';
import { NextRequest, NextResponse } from 'next/server';
// ... your other imports

const frontman = createMiddleware({
  host: 'api.frontman.sh', // or 'frontman.local:4000' for local development
});

export async function middleware(req: NextRequest) {
  // Add Frontman handler first - it will handle /frontman/* routes
  const response = await frontman(req);
  if (response) return response;

  // ... your existing middleware logic below
  return NextResponse.next();
}

export const config = {
  // Add Frontman matcher alongside your existing matchers
  matcher: ['/frontman', '/frontman/:path*', '/your-other-routes/:path*'],
};

Existing proxy.ts (Next.js 16+)

import { createMiddleware } from '@frontman-ai/nextjs';
import { NextRequest, NextResponse } from 'next/server';
// ... your other imports

const frontman = createMiddleware({
  host: 'api.frontman.sh', // or 'frontman.local:4000' for local development
});

export function proxy(req: NextRequest): NextResponse | Promise<NextResponse> {
  // Add Frontman handler first - it will handle /frontman/* routes
  if (req.nextUrl.pathname === '/frontman' || req.nextUrl.pathname.startsWith('/frontman/')) {
    return frontman(req) || NextResponse.next();
  }

  // ... your existing proxy logic below
  return NextResponse.next();
}

export const config = {
  // Add Frontman matcher alongside your existing matchers
  matcher: ['/frontman', '/frontman/:path*', '/your-other-routes/:path*'],
};

Existing instrumentation.ts

If you don't have OpenTelemetry set up yet:

export async function register() {
  if (process.env.NEXT_RUNTIME === 'nodejs') {
    const { NodeSDK } = await import('@opentelemetry/sdk-node');
    const { setup } = await import('@frontman-ai/nextjs/Instrumentation');
    const [logProcessor, spanProcessor] = setup();

    new NodeSDK({
      logRecordProcessors: [logProcessor],
      spanProcessors: [spanProcessor],
    }).start();
  }

  // ... your existing instrumentation logic
}

If you already have OpenTelemetry set up, add the Frontman processors to your existing configuration:

export async function register() {
  if (process.env.NEXT_RUNTIME === 'nodejs') {
    const { setup } = await import('@frontman-ai/nextjs/Instrumentation');
    const [logProcessor, spanProcessor] = setup();

    new NodeSDK({
      // ... your existing OTEL config
      logRecordProcessors: [logProcessor, ...yourExistingLogProcessors],
      spanProcessors: [spanProcessor, ...yourExistingSpanProcessors],
    }).start();
  }
}

What Gets Captured

Automatic Console Patching (Node.js only)

LogCapture automatically initializes when the module is imported and patches:

  • All console methods: console.log(), console.error(), console.warn(), console.info(), console.debug()
  • process.stdout.write() for build output (webpack/turbopack compilation messages)
  • process.on('uncaughtException') for unhandled errors
  • process.on('unhandledRejection') for unhandled promise rejections

Browser environments are automatically skipped - no console patching occurs in the browser.

Via OpenTelemetry Spans (Optional)

When you set up instrumentation.ts:

  • HTTP requests (BaseServer.handleRequest)
  • Route rendering (AppRender.getBodyResult)
  • API route execution (AppRouteRouteHandlers.runHandler)
  • Request method, path, status code, duration

Storage & Cross-Context Sharing

All captured data is stored in a circular buffer (1024 entries by default) using a globalThis singleton pattern. This ensures logs are shared across Next.js/Turbopack execution contexts:

  • Instrumentation context (startup)
  • Page render context
  • API route context
  • Middleware context (Edge runtime - read-only)

The buffer persists for the lifetime of the Node.js process and is accessible through the Frontman UI and get_logs tool.

Configuration Options

Middleware Options

createMiddleware({
  host: string,                // Frontman server host (required) - the client UI connects here via WebSocket
  basePath: string,            // Base path for Frontman routes (default: "frontman")
  serverName: string,          // Server name (default: "frontman-nextjs")
  serverVersion: string,       // Server version (default: package version)
  clientUrl: string,           // Custom client bundle URL
  clientCssUrl: string,        // Custom client CSS URL
  entrypointUrl: string,       // Custom entrypoint URL
  isLightTheme: boolean,       // Use light theme (default: false)
  projectRoot: string,         // Project root directory (default: process.cwd())
})

Understanding the host Option

The host option specifies the Frontman server that the client UI will connect to for AI capabilities. When you visit /frontman in your Next.js app:

  1. The middleware serves the Frontman UI HTML
  2. The UI loads the client JavaScript with ?host=<your-host>
  3. The client establishes a WebSocket connection to wss://<host>/socket
  4. AI interactions and tool calls flow through this connection

The middleware itself doesn't connect to the Frontman server - it only passes the host to the client.

Examples:

  • Production: host: 'api.frontman.sh' → client connects to wss://api.frontman.sh/socket
  • Local dev: host: 'frontman.local:4000' → client connects to wss://frontman.local:4000/socket

Supported Next.js Versions

| Version | Middleware File | Status | |---------|----------------|--------| | Next.js 15.x | middleware.ts | Fully supported | | Next.js 16.x | proxy.ts | Fully supported |

Both versions have built-in OpenTelemetry support with no additional configuration required.

Architecture

Next.js App (Turbopack/Webpack)
│
├─> Module Import (first context - instrumentation)
│   └─> LogCapture auto-initializes at module level
│       ├─> Creates globalThis.__FRONTMAN_INSTANCE__
│       ├─> Patches console.log/warn/error/info/debug
│       ├─> Intercepts process.stdout.write
│       └─> Listens to uncaughtException/unhandledRejection
│
├─> Module Import (second context - page render)
│   └─> LogCapture reuses existing globalThis.__FRONTMAN_INSTANCE__
│       └─> Same buffer, no re-patching (guarded by __FRONTMAN_CONSOLE_PATCHED__ flag)
│
├─> instrumentation.ts (startup) - OPTIONAL
│   └─> setup() returns OTEL processors that write to same buffer
│
├─> middleware.ts / proxy.ts (per-request)
│   └─> Serves Frontman UI at /frontman
│       └─> Connects to Frontman server for AI tools
│
└─> OpenTelemetry SDK (optional)
    ├─> LogRecordProcessor → globalThis.__FRONTMAN_INSTANCE__.buffer
    └─> SpanProcessor → globalThis.__FRONTMAN_INSTANCE__.buffer

Key Technical Details

Cross-Context Buffer Sharing

  • Next.js 15+ with Turbopack runs code in multiple isolated contexts
  • globalThis.__FRONTMAN_INSTANCE__ stores the singleton buffer instance
  • All contexts read/write to the same circular buffer
  • Console patching happens only once (protected by __FRONTMAN_CONSOLE_PATCHED__ flag)

Circular Buffer

  • Fixed capacity: 1024 entries (configurable)
  • Oldest entries automatically evicted when full
  • Entries include: timestamp, level, message, attributes, consoleMethod
  • Thread-safe for concurrent writes from different contexts

Advanced Usage

Custom OTEL Configuration

If you need more control over OpenTelemetry setup:

import { setup } from '@frontman-ai/nextjs/Instrumentation';
import { NodeSDK } from '@opentelemetry/sdk-node';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';

export async function register() {
  if (process.env.NEXT_RUNTIME === 'nodejs') {
    const [logProcessor, spanProcessor] = setup();

    new NodeSDK({
      serviceName: 'my-app',
      resource: resourceFromAttributes({
        'service.version': '1.0.0',
      }),
      traceExporter: new OTLPTraceExporter({
        url: process.env.OTEL_EXPORTER_OTLP_ENDPOINT,
      }),
      logRecordProcessors: [logProcessor],
      spanProcessors: [spanProcessor],
    }).start();
  }
}

Without OpenTelemetry

Frontman works without OpenTelemetry! If you only set up middleware (skip instrumentation.ts):

  • Console logs are still captured (auto-initialized at module import)
  • Build output is tracked
  • Errors are logged
  • Frontman UI available at /frontman
  • HTTP spans are not captured (requires OTEL)

LogCapture auto-initializes when the module is imported, so console patching happens automatically in Node.js environments - no explicit initialization needed.

Custom LogCapture Configuration

You can customize the buffer size and stdout patterns:

import { initialize } from '@frontman-ai/nextjs/LogCapture';

// Call this BEFORE any console.log() calls (e.g., in instrumentation.ts)
initialize({
  bufferCapacity: 2048,  // Default: 1024
  stdoutPatterns: ['webpack', 'turbopack', 'Compiled', 'Failed', 'custom-pattern'],
});

Note: Configuration only takes effect on the first call. Subsequent calls are ignored because the singleton instance is already created.

Troubleshooting

Logs not being captured

Check 1: Verify module is imported LogCapture only initializes when the module is imported in a Node.js context. Make sure either:

  • You have instrumentation.ts that imports from @frontman-ai/nextjs/Instrumentation
  • OR you have middleware.ts that imports from @frontman-ai/nextjs

Check 2: Verify Node.js runtime LogCapture doesn't run in browser or Edge runtime. Check your environment:

console.log('Runtime:', process.env.NEXT_RUNTIME); // Should be 'nodejs'

Check 3: Verify buffer contents Query the buffer directly to see if logs are present:

import { getLogs } from '@frontman-ai/nextjs/LogCapture';

const allLogs = getLogs();
console.log('Buffer contains', allLogs.length, 'logs');

Check 4: Multiple contexts In Next.js 15+, code may run in different contexts. Verify all contexts share the same buffer:

console.log('Instance:', globalThis.__FRONTMAN_INSTANCE__);
console.log('Buffer size:', globalThis.__FRONTMAN_INSTANCE__?.buffer.contents.items.length);

Console logs appear twice

This is normal behavior - LogCapture captures logs AND calls the original console method so logs still appear in your terminal/browser console.

Build output not captured

By default, only these patterns are captured from process.stdout:

  • "webpack"
  • "turbopack"
  • "Compiled"
  • "Failed"

To capture additional patterns, use custom configuration (see above).

Installer shows "manual modification required"

This happens when you have existing middleware, proxy, or instrumentation files that don't already include Frontman. The installer won't overwrite your existing code. Follow the Adding to Existing Files instructions to manually integrate Frontman.

API

createMiddleware(options)

Creates a Next.js middleware handler that serves the Frontman UI and connects to your Frontman server.

import { createMiddleware } from '@frontman-ai/nextjs';

const middleware = createMiddleware({
  host: string,                // Frontman server host (required)
  basePath: string,            // Base path (default: "frontman")
  serverName: string,          // Server name (default: "frontman-nextjs")
  serverVersion: string,       // Version (default: package version)
  projectRoot: string,         // Project root (default: process.cwd())
});

Returns: (request: NextRequest) => Promise<NextResponse | undefined>

setup()

Initializes LogCapture (console patching, error handlers) and returns OTEL processors for use with OpenTelemetry SDK.

import { setup } from '@frontman-ai/nextjs/Instrumentation';

const [logProcessor, spanProcessor] = setup();

Returns: [LogRecordProcessor, SpanProcessor]

initialize(config?)

Manually initialize LogCapture with custom configuration. Usually not needed since auto-initialization happens at module import.

import { initialize } from '@frontman-ai/nextjs/LogCapture';

initialize({
  bufferCapacity: number,           // Buffer size (default: 1024)
  stdoutPatterns: string[],         // Patterns to capture from stdout
});

Returns: void

getLogs(options?)

Query the log buffer with optional filters.

import { getLogs } from '@frontman-ai/nextjs/LogCapture';

const logs = getLogs({
  pattern: string,        // Regex pattern to match messages (case-insensitive)
  level: 'console' | 'build' | 'error',  // Filter by log level
  since: number,          // Unix timestamp - only logs after this time
  tail: number,           // Limit to last N logs
});

Returns: LogEntry[]

LogEntry type:

type LogEntry = {
  timestamp: string;                           // ISO 8601 timestamp
  level: 'console' | 'build' | 'error';       // Log level
  message: string;                             // Log message (ANSI codes stripped)
  attributes?: Record<string, any>;            // Additional attributes
  resource?: Record<string, any>;              // Resource info
  consoleMethod?: 'log' | 'info' | 'warn' | 'error' | 'debug';  // Original console method
};

License

MIT