CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-undici

An HTTP/1.1 client, written from scratch for Node.js

Pending
Overview
Eval results
Files

global-config.mddocs/

Global Configuration

Global settings for default dispatchers, origins, and Web API installation to configure undici behavior across your entire application.

Capabilities

Global Dispatcher Management

Configure a default dispatcher that will be used for all undici requests when no specific dispatcher is provided.

/**
 * Set global dispatcher for all requests
 * @param dispatcher - Dispatcher instance to use globally
 */
function setGlobalDispatcher(dispatcher: Dispatcher): void;

/**
 * Get current global dispatcher
 * @returns Current global dispatcher instance
 */
function getGlobalDispatcher(): Dispatcher;

Usage Examples:

import { setGlobalDispatcher, getGlobalDispatcher, Agent, Pool } from 'undici';

// Set a global agent with custom configuration
const globalAgent = new Agent({
  factory: (origin, opts) => {
    return new Pool(origin, {
      ...opts,
      connections: 10,
      keepAliveTimeout: 60000,
      keepAliveMaxTimeout: 600000
    });
  }
});

setGlobalDispatcher(globalAgent);

// All subsequent requests use the global agent
const response1 = await fetch('https://api.example.com/users');
const response2 = await fetch('https://another-api.example.com/data');

// Check current global dispatcher
const currentDispatcher = getGlobalDispatcher();
console.log(currentDispatcher === globalAgent); // true

// Configure global agent with interceptors
import { interceptors } from 'undici';

const enhancedAgent = new Agent()
  .compose(
    interceptors.retry({ maxRetries: 3 }),
    interceptors.redirect({ maxRedirections: 5 }),
    interceptors.decompress()
  );

setGlobalDispatcher(enhancedAgent);

// All requests now have retry, redirect, and decompression
const response = await fetch('https://api.example.com/data');

Global Origin Management

Set a global origin for the fetch API to resolve relative URLs consistently across your application.

/**
 * Set global origin for fetch API
 * @param origin - Base origin URL for resolving relative URLs
 */
function setGlobalOrigin(origin: string | URL): void;

/**
 * Get current global origin
 * @returns Current global origin or undefined
 */
function getGlobalOrigin(): string | undefined;

Usage Examples:

import { setGlobalOrigin, getGlobalOrigin, fetch } from 'undici';

// Set global origin for API base URL
setGlobalOrigin('https://api.example.com');

// Relative URLs are resolved against the global origin
const response1 = await fetch('/users');        // → https://api.example.com/users
const response2 = await fetch('/posts/123');    // → https://api.example.com/posts/123
const response3 = await fetch('./data.json');   // → https://api.example.com/data.json

// Absolute URLs override the global origin
const response4 = await fetch('https://other-api.com/data'); // → https://other-api.com/data

// Check current global origin
console.log(getGlobalOrigin()); // 'https://api.example.com'

// Update global origin for different environments
const isProduction = process.env.NODE_ENV === 'production';
const apiOrigin = isProduction 
  ? 'https://api.production.com'
  : 'https://api.development.com';

setGlobalOrigin(apiOrigin);

// Environment-specific API calls
const userData = await fetch('/user/profile');
const settings = await fetch('/user/settings');

Global Web API Installation

Install undici's Web API implementations globally to make them available throughout your application without imports.

/**
 * Install Web APIs globally on globalThis
 * Makes fetch, Headers, Request, Response, FormData, WebSocket, etc. available globally
 */
function install(): void;

Usage Examples:

import { install } from 'undici';

// Install all Web APIs globally
install();

// Now you can use Web APIs without importing
// These are now available globally:

// Fetch API
const response = await fetch('https://api.example.com/data');
const data = await response.json();

// Headers API
const headers = new Headers({
  'Content-Type': 'application/json',
  'Authorization': 'Bearer token123'
});

// Request/Response API
const request = new Request('https://api.example.com/users', {
  method: 'POST',
  headers,
  body: JSON.stringify({ name: 'Alice' })
});

const customResponse = new Response(JSON.stringify({ success: true }), {
  status: 201,
  headers: { 'content-type': 'application/json' }
});

// FormData API
const formData = new FormData();
formData.append('file', fileBuffer, 'document.pdf');
formData.append('description', 'Important document');

// WebSocket API
const ws = new WebSocket('wss://api.example.com/socket');
ws.onopen = () => console.log('WebSocket connected');
ws.onmessage = (event) => console.log('Message:', event.data);

// EventSource API
const eventSource = new EventSource('https://api.example.com/events');
eventSource.onmessage = (event) => {
  console.log('Event:', JSON.parse(event.data));
};

// WebSocket Events
ws.addEventListener('close', (event) => {
  if (event instanceof CloseEvent) {
    console.log(`WebSocket closed: ${event.code} ${event.reason}`);
  }
});

Environment-Specific Configuration

Development vs Production Setup

import { 
  setGlobalDispatcher, 
  setGlobalOrigin, 
  install,
  Agent, 
  interceptors,
  cacheStores 
} from 'undici';

function configureUndici() {
  const isDevelopment = process.env.NODE_ENV === 'development';
  const isProduction = process.env.NODE_ENV === 'production';
  
  // Install Web APIs globally
  install();
  
  // Set environment-specific API origin
  const apiOrigin = process.env.API_BASE_URL || (
    isProduction 
      ? 'https://api.production.com'
      : 'http://localhost:3001'
  );
  setGlobalOrigin(apiOrigin);
  
  // Configure global dispatcher based on environment
  const interceptorChain = [];
  
  // Always enable decompression
  interceptorChain.push(interceptors.decompress());
  
  // Enable caching in production
  if (isProduction) {
    interceptorChain.push(interceptors.cache({
      store: new cacheStores.MemoryCacheStore(),
      methods: ['GET', 'HEAD'],
      cacheByDefault: 300 // 5 minutes
    }));
  }
  
  // Enable request logging in development
  if (isDevelopment) {
    interceptorChain.push(interceptors.dump({
      request: true,
      response: true,
      requestHeaders: true,
      responseHeaders: true,
      logger: console.log
    }));
  }
  
  // Always enable retries and redirects
  interceptorChain.push(
    interceptors.retry({
      maxRetries: isProduction ? 3 : 1,
      methods: ['GET', 'HEAD', 'OPTIONS'],
      statusCodes: [408, 413, 429, 500, 502, 503, 504]
    }),
    interceptors.redirect({ maxRedirections: 5 })
  );
  
  // Create and set global agent
  const globalAgent = new Agent({
    factory: (origin, opts) => {
      return new Pool(origin, {
        ...opts,
        connections: isProduction ? 10 : 5,
        keepAliveTimeout: 60000,
        keepAliveMaxTimeout: 600000,
        bodyTimeout: 30000,
        headersTimeout: 10000
      });
    }
  }).compose(...interceptorChain);
  
  setGlobalDispatcher(globalAgent);
  
  console.log(`Undici configured for ${process.env.NODE_ENV} environment`);
  console.log(`API Origin: ${apiOrigin}`);
}

// Call during application startup
configureUndici();

Testing Configuration

import { 
  setGlobalDispatcher, 
  MockAgent, 
  install 
} from 'undici';

function configureUndiciForTesting() {
  // Install Web APIs for test compatibility
  install();
  
  // Create mock agent for testing
  const mockAgent = new MockAgent();
  
  // Disable real network connections in tests
  mockAgent.disableNetConnect();
  
  // Allow connections to test servers if needed
  if (process.env.TEST_SERVER_URL) {
    mockAgent.enableNetConnect(process.env.TEST_SERVER_URL);
  }
  
  // Set as global dispatcher
  setGlobalDispatcher(mockAgent);
  
  return mockAgent;
}

// In test setup
const mockAgent = configureUndiciForTesting();

// In individual tests
const mockPool = mockAgent.get('https://api.example.com');
mockPool.intercept({ path: '/users', method: 'GET' })
  .reply(200, [{ id: 1, name: 'Test User' }]);

Proxy Configuration

import { 
  setGlobalDispatcher, 
  ProxyAgent, 
  EnvHttpProxyAgent 
} from 'undici';

function configureProxy() {
  // Option 1: Explicit proxy configuration
  if (process.env.HTTP_PROXY_URL) {
    const proxyAgent = new ProxyAgent({
      uri: process.env.HTTP_PROXY_URL,
      auth: process.env.HTTP_PROXY_AUTH, // username:password
      token: process.env.HTTP_PROXY_TOKEN
    });
    setGlobalDispatcher(proxyAgent);
    console.log(`Using explicit proxy: ${process.env.HTTP_PROXY_URL}`);
    return;
  }
  
  // Option 2: Environment-based proxy (HTTP_PROXY, HTTPS_PROXY, NO_PROXY)
  if (process.env.HTTP_PROXY || process.env.HTTPS_PROXY) {
    const envProxyAgent = new EnvHttpProxyAgent();
    setGlobalDispatcher(envProxyAgent);
    console.log('Using environment-based proxy configuration');
    return;
  }
  
  console.log('No proxy configuration found');
}

// Configure proxy during application startup
configureProxy();

Advanced Global Configuration

import { 
  setGlobalDispatcher, 
  setGlobalOrigin, 
  install,
  Agent,
  Pool,
  interceptors,
  buildConnector,
  cacheStores
} from 'undici';
import { readFileSync } from 'fs';

function advancedUndiciConfiguration() {
  // Install Web APIs
  install();
  
  // Custom TLS configuration
  const tlsOptions = {
    ca: process.env.CUSTOM_CA_CERT ? readFileSync(process.env.CUSTOM_CA_CERT) : undefined,
    cert: process.env.CLIENT_CERT ? readFileSync(process.env.CLIENT_CERT) : undefined,
    key: process.env.CLIENT_KEY ? readFileSync(process.env.CLIENT_KEY) : undefined,
    rejectUnauthorized: process.env.NODE_ENV === 'production'
  };
  
  // Custom connector with TLS options
  const connector = buildConnector(tlsOptions);
  
  // Advanced agent configuration
  const agent = new Agent({
    factory: (origin, opts) => {
      const poolOptions = {
        ...opts,
        connections: parseInt(process.env.HTTP_POOL_SIZE) || 10,
        keepAliveTimeout: parseInt(process.env.HTTP_KEEP_ALIVE_TIMEOUT) || 60000,
        keepAliveMaxTimeout: parseInt(process.env.HTTP_KEEP_ALIVE_MAX_TIMEOUT) || 600000,
        bodyTimeout: parseInt(process.env.HTTP_BODY_TIMEOUT) || 30000,
        headersTimeout: parseInt(process.env.HTTP_HEADERS_TIMEOUT) || 10000,
        maxHeaderSize: parseInt(process.env.HTTP_MAX_HEADER_SIZE) || 16384,
        connect: connector
      };
      
      return new Pool(origin, poolOptions);
    },
    interceptors: {
      Agent: [
        // Global interceptors applied to all requests
        interceptors.dns({
          maxItems: 100,
          maxTtl: 300000 // 5 minutes DNS cache
        })
      ]
    }
  });
  
  // Compose with additional interceptors
  const configuredAgent = agent.compose(
    // Response caching
    interceptors.cache({
      store: process.env.REDIS_URL 
        ? new CustomRedisCacheStore(process.env.REDIS_URL)
        : new cacheStores.MemoryCacheStore(),
      methods: ['GET', 'HEAD'],
      cacheByDefault: 300
    }),
    
    // Request/response compression
    interceptors.decompress(),
    
    // Automatic redirects
    interceptors.redirect({
      maxRedirections: parseInt(process.env.HTTP_MAX_REDIRECTS) || 5
    }),
    
    // Retry logic
    interceptors.retry({
      maxRetries: parseInt(process.env.HTTP_MAX_RETRIES) || 3,
      maxTimeout: parseInt(process.env.HTTP_RETRY_MAX_TIMEOUT) || 30000,
      methods: ['GET', 'HEAD', 'OPTIONS', 'PUT', 'DELETE'],
      statusCodes: [408, 413, 429, 500, 502, 503, 504],
      errorCodes: ['ECONNRESET', 'ECONNREFUSED', 'ENOTFOUND', 'ENETDOWN']
    }),
    
    // Enhanced error handling
    interceptors.responseError({
      throwOnError: process.env.HTTP_THROW_ON_ERROR === 'true',
      statusCodes: [400, 401, 403, 404, 500, 502, 503, 504],
      includeResponseBody: true,
      maxResponseBodySize: 1024
    })
  );
  
  // Set global configuration
  setGlobalDispatcher(configuredAgent);
  
  if (process.env.API_BASE_URL) {
    setGlobalOrigin(process.env.API_BASE_URL);
  }
  
  console.log('Advanced undici configuration applied');
}

// Initialize during application startup
advancedUndiciConfiguration();

Configuration Best Practices

1. Environment Variables

Use environment variables for configuration:

# .env file
NODE_ENV=production
API_BASE_URL=https://api.production.com
HTTP_PROXY=http://proxy.company.com:8080
HTTP_POOL_SIZE=20
HTTP_KEEP_ALIVE_TIMEOUT=120000
HTTP_MAX_RETRIES=5

2. Graceful Shutdown

Properly close global dispatcher during application shutdown:

import { getGlobalDispatcher } from 'undici';

process.on('SIGTERM', async () => {
  console.log('Shutting down gracefully...');
  
  const dispatcher = getGlobalDispatcher();
  if (dispatcher && typeof dispatcher.close === 'function') {
    await dispatcher.close();
  }
  
  process.exit(0);
});

3. Health Checks

Monitor global dispatcher health:

import { getGlobalDispatcher } from 'undici';

async function healthCheck() {
  try {
    const dispatcher = getGlobalDispatcher();
    
    // Test with a lightweight request
    const response = await fetch('/health', {
      method: 'HEAD',
      dispatcher // Use specific dispatcher for health check
    });
    
    return response.ok;
  } catch (error) {
    console.error('Health check failed:', error.message);
    return false;
  }
}

// Run health checks periodically
setInterval(async () => {
  const isHealthy = await healthCheck();
  console.log(`HTTP client health: ${isHealthy ? 'OK' : 'FAIL'}`);
}, 30000);

Install with Tessl CLI

npx tessl i tessl/npm-undici

docs

caching.md

connection-management.md

cookies.md

core-http.md

errors.md

global-config.md

headers-body.md

index.md

interceptors.md

mock-testing.md

web-standards.md

tile.json