CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-agent-base

Turn a function into an `http.Agent` instance

Pending
Overview
Eval results
Files

Agent Base

Agent Base provides an abstract base class for creating custom HTTP agents in Node.js applications. It extends the native http.Agent class with a flexible architecture that allows developers to implement custom connection logic through a connect() method that can return arbitrary Duplex streams or delegate to other agents.

Package Information

  • Package Name: agent-base
  • Package Type: npm
  • Language: TypeScript
  • Installation: npm install agent-base

Core Imports

import { Agent, AgentConnectOpts } from "agent-base";

For helper functions:

import { toBuffer, json, req, ThenableRequest } from "agent-base";

For CommonJS:

const { Agent, toBuffer, json, req } = require("agent-base");

Node.js built-in types used in the API:

import type { Duplex } from 'stream';
import * as http from 'http';
import * as https from 'https';
import * as net from 'net';
import * as tls from 'tls';

Basic Usage

import * as net from 'net';
import * as tls from 'tls';
import * as http from 'http';
import { Agent, AgentConnectOpts } from 'agent-base';

class MyAgent extends Agent {
  connect(req: http.ClientRequest, opts: AgentConnectOpts) {
    // secureEndpoint is true when using the "https" module
    if (opts.secureEndpoint) {
      return tls.connect(opts);
    } else {
      return net.connect(opts);
    }
  }
}

// Keep alive enabled means that connect() will only be
// invoked when a new connection needs to be created
const agent = new MyAgent({ keepAlive: true });

// Pass the agent option when creating the HTTP request
http.get('http://nodejs.org/api/', { agent }, (res) => {
  console.log(res.headers);
  res.pipe(process.stdout);
});

Architecture

Agent Base is built around several key components:

  • Abstract Agent Class: Base class extending http.Agent that must be subclassed
  • Connection Interface: Abstract connect() method for implementing custom connection logic
  • Protocol Detection: Automatic detection of HTTP vs HTTPS endpoints through multiple mechanisms
  • Socket Pooling: Integration with Node.js native connection pooling and keep-alive functionality
  • Helper Utilities: Stream processing and HTTP request utilities for common operations

Capabilities

Agent Base Class

Abstract base class for creating custom HTTP agents with flexible connection handling.

/**
 * Abstract base class for creating custom HTTP agents.
 * Must be extended and implement the connect() method.
 */
abstract class Agent extends http.Agent {
  /**
   * Create a new Agent instance
   * @param opts - Standard http.Agent options including keepAlive, timeout, etc.
   */
  constructor(opts?: http.AgentOptions);

  /**
   * Abstract method that must be implemented by subclasses.
   * Called when a new connection needs to be established.
   * @param req - The HTTP client request being made
   * @param options - Connection options including secureEndpoint flag
   * @returns Promise or direct return of Duplex stream or another Agent
   */
  abstract connect(
    req: http.ClientRequest,
    options: AgentConnectOpts
  ): Promise<Duplex | http.Agent> | Duplex | http.Agent;

  /**
   * Determine whether this is an HTTP or HTTPS request
   * @param options - Connection options to check
   * @returns true if HTTPS, false if HTTP
   */
  isSecureEndpoint(options?: AgentConnectOpts): boolean;

  /**
   * Get connection name for socket pooling (internal Node.js usage)
   * @param options - Connection options
   * @returns Connection name string for pooling
   */
  getName(options?: AgentConnectOpts): string;

  /**
   * Create a socket connection (internal Node.js Agent method)
   * @param req - The HTTP client request
   * @param options - Connection options
   * @param cb - Callback function for connection result
   */
  createSocket(
    req: http.ClientRequest,
    options: AgentConnectOpts,
    cb: (err: Error | null, s?: Duplex) => void
  ): void;

  /**
   * Create connection from current socket (internal Node.js Agent method)
   * @returns Current socket for the connection
   * @throws Error if no socket was returned from connect()
   */
  createConnection(): Duplex;

  /**
   * Default port for connections (getter/setter)
   * Defaults to 443 for HTTPS, 80 for HTTP
   */
  defaultPort: number;

  /**
   * Protocol string (getter/setter)
   * Defaults to 'https:' for secure endpoints, 'http:' otherwise
   */
  protocol: string;

  /**
   * Connection options from http.Agent (inherited properties)
   */
  options: Partial<net.TcpNetConnectOpts & tls.ConnectionOptions>;

  /**
   * Keep-alive setting (inherited from http.Agent)
   */
  keepAlive: boolean;
}

Connection Options

Type definitions for connection options passed to the connect() method.

/**
 * Union type for connection options passed to connect() method.
 * This is a union of HTTP and HTTPS connection options with a secureEndpoint discriminator.
 */
type AgentConnectOpts = {
  /** Always false for HTTP connections */
  secureEndpoint: false;
  /** Protocol string, typically 'http:' */
  protocol?: string;
} & net.TcpNetConnectOpts | {
  /** Always true for HTTPS connections */
  secureEndpoint: true;
  /** Protocol string, typically 'https:' */
  protocol?: string;
  /** Port number for the connection */
  port: number;
} & tls.ConnectionOptions;

Stream Utilities

Helper functions for processing HTTP response streams.

/**
 * Convert a readable stream to a Buffer
 * @param stream - Readable stream to convert
 * @returns Promise resolving to Buffer containing all stream data
 */
async function toBuffer(stream: Readable): Promise<Buffer>;

/**
 * Parse JSON from a readable stream
 * @param stream - Readable stream containing JSON data
 * @returns Promise resolving to parsed JSON object
 * @throws Enhanced error with input context on parse failure
 */
async function json(stream: Readable): Promise<any>;

HTTP Request Utility

Utility function for making HTTP/HTTPS requests with Promise interface.

/**
 * Create an HTTP/HTTPS request with Promise interface
 * @param url - Request URL as string or URL object
 * @param opts - Standard https.RequestOptions
 * @returns Request object with then() method for Promise-like usage
 */
function req(
  url: string | URL,
  opts?: https.RequestOptions
): ThenableRequest;

/**
 * HTTP request with Promise-like interface
 */
type ThenableRequest = http.ClientRequest & {
  /** Promise-like then method for handling responses */
  then: Promise<http.IncomingMessage>['then'];
};

Usage Examples

Custom Proxy Agent

import { Agent, AgentConnectOpts } from 'agent-base';
import * as net from 'net';

class ProxyAgent extends Agent {
  private proxyHost: string;
  private proxyPort: number;

  constructor(proxyHost: string, proxyPort: number, opts?: http.AgentOptions) {
    super(opts);
    this.proxyHost = proxyHost;
    this.proxyPort = proxyPort;
  }

  async connect(req: http.ClientRequest, opts: AgentConnectOpts) {
    // Connect to proxy server
    const socket = net.connect({
      host: this.proxyHost,
      port: this.proxyPort
    });

    // Send CONNECT request through proxy
    const target = `${opts.host}:${opts.port}`;
    socket.write(`CONNECT ${target} HTTP/1.1\r\nHost: ${target}\r\n\r\n`);

    return socket;
  }
}

Async Connection with Delay

import { Agent, AgentConnectOpts } from 'agent-base';
import * as net from 'net';

class DelayedAgent extends Agent {
  private delay: number;

  constructor(delay: number, opts?: http.AgentOptions) {
    super(opts);
    this.delay = delay;
  }

  async connect(req: http.ClientRequest, opts: AgentConnectOpts) {
    // Wait for specified delay before connecting
    await new Promise(resolve => setTimeout(resolve, this.delay));
    
    if (opts.secureEndpoint) {
      return tls.connect(opts);
    } else {
      return net.connect(opts);
    }
  }
}

Using Helper Functions

import { req, json, toBuffer } from 'agent-base';

// Make request and parse JSON response
const response = await req('https://api.example.com/data');
const data = await json(response);
console.log(data);

// Get response as buffer
const response2 = await req('https://api.example.com/file');
const buffer = await toBuffer(response2);
console.log(`Downloaded ${buffer.length} bytes`);

Error Handling

  • Connection Failures: The connect() method can throw errors that are automatically caught and passed to the request callback
  • JSON Parse Errors: The json() function enhances parse errors with input context for better debugging
  • Missing Socket: If connect() doesn't return a socket, a specific error is thrown: "No socket was returned in the connect() function"

Protocol Detection

Agent Base uses multiple mechanisms to detect whether a request is HTTP or HTTPS:

  1. Explicit secureEndpoint property: When set explicitly in options
  2. Protocol property: Checks if options.protocol === 'https:'
  3. Stack trace analysis: Falls back to examining the call stack for HTTPS module usage

This enables the same agent to work with both http and https modules automatically.

Install with Tessl CLI

npx tessl i tessl/npm-agent-base
Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/agent-base@7.1.x
Publish Source
CLI
Badge
tessl/npm-agent-base badge