or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

index.mddocs/

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.