Adapters

cURL Adapter

The cURL adapter is Rezo’s most protocol-diverse adapter. At 3,355 lines, it wraps the curl command-line tool with full programmatic control over 200+ options. It supports HTTP versions from 1.0 through 3.0, 20+ authentication methods, multi-protocol transfers (FTP, SSH, SMTP, TFTP), DNS-over-HTTPS, and comprehensive TLS/SSL configuration.

import rezo from 'rezo/adapters/curl';

Import and Setup

import rezo, {
  Rezo,
  RezoError,
  RezoHeaders,
  RezoFormData,
  RezoCookieJar
} from 'rezo/adapters/curl';

// Default instance
const { data } = await rezo.get('https://api.example.com/users');

// Custom instance with cURL-specific options
const client = new Rezo({
  baseURL: 'https://api.example.com',
  timeout: 30000
});

Capabilities Detection

Before executing requests, the adapter uses the CurlCapabilities singleton to detect the installed cURL version, supported features, and available protocols:

import { CurlCapabilities } from 'rezo/adapters/curl';

const caps = CurlCapabilities.getInstance();
await caps.initialize();

// Check if cURL is available and what it supports
console.log(caps.getVersion());     // "8.7.1"
console.log(caps.hasFeature('HTTP2'));    // true
console.log(caps.hasFeature('HTTP3'));    // true
console.log(caps.hasProtocol('ftps'));    // true
console.log(caps.hasProtocol('sftp'));    // true

The capabilities check runs curl --version once and parses the output to determine available features and protocols. If cURL is not installed, the adapter throws a helpful error with platform-specific installation instructions (Homebrew on macOS, apt on Debian, dnf on Red Hat, pacman on Arch, etc.).

HTTP Protocol Versions

The cURL adapter supports all HTTP versions:

// HTTP/1.0
const { data } = await rezo.get('https://example.com', {
  curl: { httpVersion: '1.0' }
});

// HTTP/1.1 (default)
const { data } = await rezo.get('https://example.com', {
  curl: { httpVersion: '1.1' }
});

// HTTP/2
const { data } = await rezo.get('https://example.com', {
  curl: { httpVersion: '2' }
});

// HTTP/2 with prior knowledge (skip upgrade)
const { data } = await rezo.get('https://example.com', {
  curl: { httpVersion: '2-prior-knowledge' }
});

// HTTP/3 (QUIC)
const { data } = await rezo.get('https://example.com', {
  curl: { httpVersion: '3' }
});

Authentication Methods

The adapter supports a wide range of authentication methods through cURL’s built-in auth handling:

Basic and Digest

// Basic authentication
const { data } = await rezo.get('https://api.example.com/protected', {
  auth: {
    type: 'basic',
    username: 'admin',
    password: 'secret'
  }
});

// Digest authentication
const { data } = await rezo.get('https://api.example.com/protected', {
  auth: {
    type: 'digest',
    username: 'admin',
    password: 'secret'
  }
});

NTLM

const { data } = await rezo.get('https://intranet.company.com/resource', {
  auth: {
    type: 'ntlm',
    username: 'DOMAIN\user',
    password: 'password'
  }
});

Bearer Token

const { data } = await rezo.get('https://api.example.com/data', {
  auth: {
    type: 'bearer',
    token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
  }
});

AWS Signature V4

const { data } = await rezo.get('https://s3.amazonaws.com/my-bucket/file.txt', {
  curl: {
    awsSigv4: {
      provider: 'aws',
      region: 'us-east-1',
      service: 's3'
    }
  },
  auth: {
    username: 'AKIAIOSFODNN7EXAMPLE',
    password: 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY'
  }
});

Negotiate (Kerberos/SPNEGO)

const { data } = await rezo.get('https://internal-api.company.com', {
  curl: {
    negotiate: true,
    delegation: 'always',
    serviceName: 'HTTP'
  }
});

Custom Auth Headers

const { data } = await rezo.get('https://api.example.com/data', {
  auth: {
    type: 'custom',
    custom: {
      'X-API-Key': 'my-api-key',
      'X-Signature': 'hmac-sha256-signature'
    }
  }
});

TLS/SSL Configuration

Comprehensive TLS control for enterprise environments:

// Client certificate authentication
const { data } = await rezo.get('https://mtls-api.example.com/data', {
  curl: {
    tls: {
      cert: '/path/to/client.pem',
      key: '/path/to/client-key.pem',
      cacert: '/path/to/ca-bundle.crt',
      certType: 'PEM',
      keyType: 'PEM'
    }
  }
});

// Specific TLS version
const { data } = await rezo.get('https://example.com', {
  curl: {
    tls: {
      tlsVersion: 'tlsv1.3',
      ciphers: 'TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256'
    }
  }
});

// Skip certificate verification (development only)
const { data } = await rezo.get('https://self-signed.example.com', {
  rejectUnauthorized: false
});

Proxy TLS

Separate TLS configuration for the proxy connection:

const { data } = await rezo.get('https://example.com', {
  proxy: 'https://proxy.company.com:8443',
  curl: {
    proxyTls: {
      proxyCacert: '/path/to/proxy-ca.crt',
      proxyCert: '/path/to/proxy-client.pem',
      proxyKey: '/path/to/proxy-client-key.pem'
    }
  }
});

Proxy Support

All proxy types supported by cURL:

// HTTP proxy
const { data } = await rezo.get('https://example.com', {
  proxy: { protocol: 'http', host: 'proxy.example.com', port: 8080 }
});

// HTTPS proxy
const { data } = await rezo.get('https://example.com', {
  proxy: { protocol: 'https', host: 'proxy.example.com', port: 8443 }
});

// SOCKS5 proxy
const { data } = await rezo.get('https://example.com', {
  proxy: { protocol: 'socks5', host: '127.0.0.1', port: 1080 }
});

// SOCKS5 with hostname resolution at proxy
const { data } = await rezo.get('https://example.com', {
  proxy: { protocol: 'socks5h', host: '127.0.0.1', port: 1080 }
});

DNS Options

Custom DNS resolution, including DNS-over-HTTPS (DoH):

// DNS-over-HTTPS
const { data } = await rezo.get('https://example.com', {
  curl: {
    dns: {
      dohUrl: 'https://cloudflare-dns.com/dns-query'
    }
  }
});

// Custom DNS servers
const { data } = await rezo.get('https://example.com', {
  curl: {
    dns: {
      servers: '8.8.8.8,8.8.4.4'
    }
  }
});

// DNS interface binding
const { data } = await rezo.get('https://example.com', {
  curl: {
    dns: {
      interface: 'eth0'
    }
  }
});

FTP Support

Full FTP/FTPS support with directory operations:

// Download a file via FTP
const { data } = await rezo.get('ftp://ftp.example.com/pub/file.txt', {
  auth: { username: 'user', password: 'pass' },
  curl: {
    ftp: {
      pasv: true,        // passive mode
      createDirs: true,  // create remote directories
      method: 'multicwd' // directory traversal method
    }
  }
});

// Upload a file via FTP
await rezo.put('ftp://ftp.example.com/uploads/report.csv', fileData, {
  auth: { username: 'user', password: 'pass' },
  curl: {
    ftp: {
      createDirs: true
    }
  }
});

SSH/SFTP Support

// SFTP download with key authentication
const { data } = await rezo.get('sftp://server.example.com/path/to/file.txt', {
  curl: {
    ssh: {
      privateKey: '/home/user/.ssh/id_rsa',
      publicKey: '/home/user/.ssh/id_rsa.pub',
      knownHosts: '/home/user/.ssh/known_hosts'
    }
  }
});

// SCP transfer
const { data } = await rezo.get('scp://server.example.com/var/log/app.log', {
  curl: {
    ssh: {
      privateKey: '/home/user/.ssh/id_ed25519',
      compressedSsh: true
    }
  }
});

SMTP Support

Send emails directly through cURL:

await rezo.post('smtp://mail.example.com:587', emailBody, {
  curl: {
    smtp: {
      mailFrom: 'sender@example.com',
      mailRcpt: ['recipient@example.com', 'cc@example.com'],
      auth: true
    }
  },
  auth: {
    username: 'sender@example.com',
    password: 'app-password'
  }
});

Progress Tracking

Upload and download progress via hooks:

const client = new Rezo({
  hooks: {
    onDownloadProgress: [({ loaded, total, percent }) => {
      console.log(`Download: ${percent.toFixed(1)}%`);
    }],
    onUploadProgress: [({ loaded, total, percent }) => {
      console.log(`Upload: ${percent.toFixed(1)}%`);
    }]
  }
});

await client.download('https://example.com/large-file.tar.gz', './file.tar.gz');

Timing Metrics

cURL provides detailed timing information for each request phase:

const response = await rezo.get('https://example.com', {
  debug: true
});

// Available timing data from cURL's write-out:
// - DNS lookup time
// - TCP connect time
// - TLS handshake time
// - Time to first byte (TTFB)
// - Total transfer time
// - Redirect time

The cURL adapter supports Rezo’s cookie jar:

const jar = new RezoCookieJar();
const client = new Rezo({ jar });

await client.post('https://example.com/login', {
  username: 'admin',
  password: 'secret'
});

// Subsequent requests include session cookies
const { data } = await client.get('https://example.com/dashboard');

Streaming

const response = await rezo.stream('https://example.com/live-feed');

for await (const chunk of response.data) {
  process.stdout.write(chunk);
}

Retry and Redirect

const { data } = await rezo.get('https://example.com/data', {
  retry: { limit: 3, statusCodes: [502, 503] },
  maxRedirects: 10
});

Response Caching

const client = new Rezo({
  cache: { maxAge: 60000, maxEntries: 500 }
});

Builder and Executor Classes

Internally, the adapter is structured around two exported classes:

  • CurlCommandBuilder — Translates Rezo configuration into cURL command-line arguments. Handles the 200+ options, temp file management for request bodies and certificates, and argument escaping.
  • CurlExecutor — Spawns the curl child process, parses stdout/stderr, extracts response headers and body, tracks progress, and maps cURL exit codes to RezoError instances.
import { CurlCommandBuilder, CurlExecutor, CurlCapabilities } from 'rezo/adapters/curl';

// These are available for advanced use cases like:
// - Building cURL commands without executing them
// - Custom execution environments
// - Testing and mocking

Debug Mode

const { data } = await rezo.get('https://api.example.com/users', {
  debug: true
});
// [Rezo Debug] GET https://api.example.com/users
// [Rezo Debug] Request ID: req_abc123
// [Rezo Debug] cURL command: curl -X GET "https://api.example.com/users" ...
// [Rezo Debug] Response: 200 OK (234.12ms)

When to Use This Adapter

The cURL adapter is the right choice when:

  • You need protocols beyond HTTP (FTP, SFTP, SCP, SMTP, TFTP)
  • You need HTTP/3 (QUIC) support
  • You need advanced TLS options (specific ciphers, client certificates, proxy TLS)
  • You want DNS-over-HTTPS
  • You need NTLM or Kerberos/Negotiate authentication
  • You need AWS Signature V4 signing without an SDK
  • You are building a debugging or testing tool and want cURL-level control
  • You want to leverage cURL features not available in Node.js’s http module

The tradeoff is that the cURL adapter spawns a child process for each request, which has higher overhead than the HTTP adapter or HTTP/2 adapter. For high-throughput scenarios, prefer the native Node.js adapters.