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

@flink-app/debug-plugin

v0.12.1-alpha.45

Published

Flink plugin that make it possbile to debug requests

Readme

Debug Plugin

A Flink plugin for debugging HTTP requests and responses in your application. Capture and inspect request/response data, enable/disable debugging on demand, and integrate with the Management API for admin panel access.

Installation

Install the plugin to your Flink app project:

npm install @flink-app/debug-plugin

Configuration

Basic Setup

Configure the plugin in your app startup:

import { FlinkApp } from "@flink-app/flink";
import { debugPlugin } from "@flink-app/debug-plugin";

function start() {
  new FlinkApp<AppContext>({
    name: "My app",
    plugins: [
      debugPlugin({
        enabledAtStart: false,  // Start with debugging disabled
        logToConsole: false,    // Don't log to console
        keepLogs: 100          // Keep last 100 requests
      })
    ],
  }).start();
}

Plugin Options:

interface StaticOptions {
  logToConsole: boolean;   // Log requests/responses to console
  enabledAtStart: boolean; // Enable debugging when app starts
  keepLogs?: number;       // Number of requests to keep in memory (default: 100)
}

TypeScript Setup

The debug plugin doesn't require adding types to your context, but it does add properties to ctx.plugins.debugPlugin:

ctx.plugins.debugPlugin: {
  requests: request[];  // Array of captured requests
  enabled: boolean;     // Current enabled state
}

How It Works

The debug plugin uses Express middleware to:

  1. Intercept incoming HTTP requests
  2. Capture request details (method, path, body, headers)
  3. Intercept outgoing responses by wrapping res.write and res.end
  4. Store request/response pairs in memory
  5. Keep a rolling window of the most recent N requests

What's Captured:

  • Request method (GET, POST, etc.)
  • Request path and query parameters
  • Request headers
  • Request body
  • Response body
  • Request start and end timestamps

What's NOT Captured:

  • Management API requests (routes starting with /managementapi)
  • Requests when debugging is disabled

Accessing Debug Data

From Handlers

Access captured requests directly from context:

import { Handler } from "@flink-app/flink";
import { Ctx } from "../Ctx";

const GetDebugInfo: Handler<Ctx, any, any> = async ({ ctx, req }) => {
  const debugData = ctx.plugins.debugPlugin;

  return {
    data: {
      enabled: debugData.enabled,
      requestCount: debugData.requests.length,
      recentRequests: debugData.requests.slice(0, 10)
    }
  };
};

export default GetDebugInfo;

Enabling/Disabling Debug Mode

Toggle debug mode programmatically:

// Enable debugging
ctx.plugins.debugPlugin.enabled = true;

// Disable debugging
ctx.plugins.debugPlugin.enabled = false;

// Clear captured requests
ctx.plugins.debugPlugin.requests = [];

Management API Integration

The debug plugin can be exposed as a Management API module for easy access from admin panels:

Setup Management Module

import { FlinkApp } from "@flink-app/flink";
import { Ctx } from "./Ctx";
import {
  debugPlugin,
  GetManagementModule as GetDebugManagementModule
} from "@flink-app/debug-plugin";
import { managementApiPlugin } from "@flink-app/management-api-plugin";

const debugManagementModule = GetDebugManagementModule({
  ui: true,
  uiSettings: {
    title: "Debug Console"
  }
});

function start() {
  new FlinkApp<Ctx>({
    name: "My flink app",
    debug: true,
    db: {
      uri: "mongodb://localhost:27017/my-flink-app"
    },
    plugins: [
      debugPlugin({
        enabledAtStart: false,
        logToConsole: false,
        keepLogs: 100
      }),
      managementApiPlugin({
        token: process.env.MGMT_TOKEN!,
        jwtSecret: process.env.JWT_SECRET!,
        modules: [debugManagementModule]
      })
    ]
  }).start();
}

start();

Management Module Options:

interface GetManagementModuleConfig {
  pluginId?: string;   // Default: "debug"
  ui: boolean;         // Enable UI in admin panel
  uiSettings?: {
    title: string;     // Module title (default: "Debug")
  };
}

Management Endpoints

When using the Management Module, these endpoints are registered under /managementapi/{pluginId}:

GET /managementapi/debug/

Get debug status and captured requests.

Response:

{
  data: {
    enabled: boolean;    // Current debug state
    requests: request[]; // Array of captured requests
  }
}

Example:

curl http://localhost:3000/managementapi/debug/

POST /managementapi/debug/enable

Enable debug mode.

Response:

{
  data: {
    enabled: true
  }
}

Example:

curl -X POST http://localhost:3000/managementapi/debug/enable

POST /managementapi/debug/disable

Disable debug mode.

Response:

{
  data: {
    enabled: false
  }
}

Example:

curl -X POST http://localhost:3000/managementapi/debug/disable

API Reference

Request Type

Each captured request has the following structure:

interface request {
  start: Date;                      // When request started
  end?: Date;                       // When response finished
  method: string;                   // HTTP method (GET, POST, etc.)
  path: string;                     // Request path with query params
  headers?: IncomingHttpHeaders;    // Request headers
  body?: any;                       // Parsed request body
  response?: string;                // Response body as string
}

Context Properties

ctx.plugins.debugPlugin: {
  requests: request[];  // Array of captured requests (newest first)
  enabled: boolean;     // Whether debugging is currently enabled
}

Complete Example

Here's a complete example showing how to use the debug plugin:

import { FlinkApp } from "@flink-app/flink";
import { Ctx } from "./Ctx";
import {
  debugPlugin,
  GetManagementModule as GetDebugManagementModule
} from "@flink-app/debug-plugin";
import { managementApiPlugin } from "@flink-app/management-api-plugin";

// Create debug management module
const debugManagementModule = GetDebugManagementModule({
  ui: true,
  uiSettings: {
    title: "Request Debugger"
  }
});

function start() {
  new FlinkApp<Ctx>({
    name: "My API",
    debug: true,
    db: {
      uri: process.env.MONGODB_URI!
    },
    plugins: [
      // Debug plugin - starts disabled, keeps last 200 requests
      debugPlugin({
        enabledAtStart: false,
        logToConsole: true,  // Also log to console
        keepLogs: 200
      }),

      // Management API with debug module
      managementApiPlugin({
        token: process.env.MGMT_TOKEN!,
        jwtSecret: process.env.JWT_SECRET!,
        modules: [debugManagementModule]
      })
    ]
  }).start();
}

start();

Custom Debug Handler

Create a custom handler to analyze debug data:

import { Handler } from "@flink-app/flink";
import { Ctx } from "../Ctx";

interface DebugStatsResponse {
  totalRequests: number;
  methodCounts: { [method: string]: number };
  slowestRequests: Array<{
    path: string;
    duration: number;
  }>;
  errorResponses: number;
}

const GetDebugStats: Handler<Ctx, any, DebugStatsResponse> = async ({ ctx }) => {
  const requests = ctx.plugins.debugPlugin.requests;

  // Count requests by method
  const methodCounts: { [method: string]: number } = {};
  for (const req of requests) {
    methodCounts[req.method] = (methodCounts[req.method] || 0) + 1;
  }

  // Find slowest requests
  const slowestRequests = requests
    .filter(req => req.end)
    .map(req => ({
      path: req.path,
      duration: req.end!.getTime() - req.start.getTime()
    }))
    .sort((a, b) => b.duration - a.duration)
    .slice(0, 10);

  // Count error responses (5xx, 4xx)
  const errorResponses = requests.filter(req => {
    if (!req.response) return false;
    try {
      const response = JSON.parse(req.response);
      return response.status >= 400;
    } catch {
      return false;
    }
  }).length;

  return {
    data: {
      totalRequests: requests.length,
      methodCounts,
      slowestRequests,
      errorResponses
    }
  };
};

export default GetDebugStats;

Use Cases

1. Development Debugging

Enable debug mode during development to inspect requests:

debugPlugin({
  enabledAtStart: true,
  logToConsole: true,
  keepLogs: 50
})

2. Production Issue Investigation

Keep debug mode off by default, enable on demand when investigating:

debugPlugin({
  enabledAtStart: false,
  logToConsole: false,
  keepLogs: 200  // Keep more logs for analysis
})

Then enable via Management API when needed.

3. API Testing

Use debug data to verify request/response pairs:

// Make test request
await fetch("http://localhost:3000/api/users", {
  method: "POST",
  body: JSON.stringify({ name: "John" })
});

// Check debug data
const debugData = ctx.plugins.debugPlugin.requests[0];
expect(debugData.body).toEqual({ name: "John" });
expect(JSON.parse(debugData.response!)).toHaveProperty("id");

4. Performance Monitoring

Track request durations to identify slow endpoints:

const slowRequests = ctx.plugins.debugPlugin.requests
  .filter(req => req.end)
  .filter(req => {
    const duration = req.end!.getTime() - req.start.getTime();
    return duration > 1000; // Slower than 1 second
  });

console.log(`Found ${slowRequests.length} slow requests`);

Best Practices

Memory Management

The plugin keeps requests in memory. Be careful with settings:

// Good for development
keepLogs: 50

// Good for temporary production debugging
keepLogs: 200

// Be careful - could use significant memory
keepLogs: 10000  // Avoid in production

Each request object includes:

  • Headers (can be large)
  • Request body (can be large)
  • Response body (can be large)

Security Considerations

  1. Disable in Production: Don't enable debug mode in production by default
  2. Sensitive Data: Be aware that debug logs capture request bodies and headers
  3. Access Control: Use Management API with proper authentication
  4. Clear Logs: Regularly clear captured requests to avoid memory leaks
// Clear debug logs periodically
setInterval(() => {
  if (ctx.plugins.debugPlugin.requests.length > 500) {
    ctx.plugins.debugPlugin.requests = [];
  }
}, 60000); // Every minute

Console Logging

Use logToConsole: true carefully:

// Development - useful
debugPlugin({
  logToConsole: true,
  enabledAtStart: true
})

// Production - avoid (too noisy)
debugPlugin({
  logToConsole: false,
  enabledAtStart: false
})

Filtering Sensitive Data

Consider wrapping the plugin to filter sensitive data:

// In your handler
const sanitizedRequests = ctx.plugins.debugPlugin.requests.map(req => ({
  ...req,
  headers: {
    ...req.headers,
    authorization: req.headers?.authorization ? "[REDACTED]" : undefined
  },
  body: req.body?.password ? { ...req.body, password: "[REDACTED]" } : req.body
}));

return { data: { requests: sanitizedRequests } };

Implementation Details

Middleware Order

The debug plugin middleware is registered during plugin initialization and runs for all requests except:

  • Routes starting with /managementapi (to avoid recursion)
  • Requests when enabled is false

Response Interception

The plugin intercepts responses by:

  1. Saving original res.write and res.end functions
  2. Replacing them with custom implementations
  3. Collecting response chunks in a buffer
  4. Restoring original functions after response completes

This ensures the plugin captures the full response without affecting normal operation.

Rolling Window

When the request array exceeds keepLogs:

requests = requests.splice(0, keep);

This keeps only the most recent N requests, with newest first (unshift).

Troubleshooting

Debug Mode Not Working

  1. Check enabled state:

    console.log(ctx.plugins.debugPlugin.enabled);
  2. Verify plugin initialization:

    console.log(app.ctx.plugins.debugPlugin); // Should exist
  3. Check Management API routes:

    # Should work
    curl http://localhost:3000/managementapi/debug/

Requests Not Being Captured

  1. Enable debug mode:

    curl -X POST http://localhost:3000/managementapi/debug/enable
  2. Check if route is excluded:

    • Management API routes are not captured
    • Verify your route doesn't start with /managementapi
  3. Check keepLogs setting:

    • If you have many requests, older ones get removed
    • Increase keepLogs value

Memory Usage High

  1. Reduce keepLogs:

    keepLogs: 50  // Keep fewer logs
  2. Clear logs periodically:

    ctx.plugins.debugPlugin.requests = [];
  3. Disable when not needed:

    curl -X POST http://localhost:3000/managementapi/debug/disable

Console Too Noisy

Set logToConsole: false:

debugPlugin({
  enabledAtStart: true,
  logToConsole: false,  // No console output
  keepLogs: 100
})

Notes

  • The plugin automatically excludes Management API routes to avoid recursion
  • Request bodies are captured after body-parser middleware processes them
  • Response bodies are captured as strings (includes JSON, HTML, etc.)
  • The plugin adds minimal performance overhead when disabled
  • Debug data is stored in memory only (not persisted to database)
  • The enabled flag can be toggled at runtime without restarting the app