cURL Adapter
The cURL adapter is Rezo’s most protocol-diverse adapter. 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 = rezo.create({
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
Username/password is set via the standard auth option ({ username, password }). The cURL-specific authentication scheme is selected via flags under curl: { ... }:
Basic and Digest
// Basic — auth alone defaults to Basic
const { data } = await rezo.get('https://api.example.com/protected', {
auth: { username: 'admin', password: 'secret' }
});
// Digest — same credentials, just toggle the scheme
const { data } = await rezo.get('https://api.example.com/protected', {
auth: { username: 'admin', password: 'secret' },
curl: { digest: true }
});
// "Try every scheme the server advertises and pick one"
const { data } = await rezo.get('https://api.example.com/protected', {
auth: { username: 'admin', password: 'secret' },
curl: { anyAuth: true }
}); NTLM (and NTLM-WB)
const { data } = await rezo.get('https://intranet.company.com/resource', {
auth: { username: 'DOMAIN\user', password: 'password' },
curl: { ntlmWb: true } // or just rely on `anyAuth: true`
}); Bearer Token
There’s no bearer scheme on the auth field — pass the token as an Authorization header (works with every adapter), or use cURL’s xoauth2Bearer for OAuth2:
// Plain Bearer header (universal)
const { data } = await rezo.get('https://api.example.com/data', {
headers: { Authorization: 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...' }
});
// OAuth2 (cURL --xoauth2-bearer)
const { data } = await rezo.get('https://imap.gmail.com/', {
curl: { xoauth2Bearer: 'access-token-string' }
}); AWS Signature V4
const { data } = await rezo.get('https://s3.amazonaws.com/my-bucket/file.txt', {
auth: {
username: 'AKIAIOSFODNN7EXAMPLE',
password: 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY'
},
curl: {
awsSigv4: { provider: 'aws:amz', region: 'us-east-1', service: 's3' }
}
});
// Or as the shorthand string cURL accepts:
// curl: { awsSigv4: 'aws:amz:us-east-1:s3' } Negotiate (Kerberos / SPNEGO)
const { data } = await rezo.get('https://internal-api.company.com', {
curl: {
negotiate: true,
delegation: 'always' // 'none' | 'policy' | 'always'
}
}); Custom Auth Headers
There’s no auth.custom shape — for custom schemes, set the header(s) directly:
const { data } = await rezo.get('https://api.example.com/data', {
headers: {
'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 (cURL resolves hostnames at the proxy by default for SOCKS5)
const { data } = await rezo.get('https://example.com', {
proxy: { protocol: 'socks5', 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 events come off the RezoDownloadResponse / RezoUploadResponse event emitters returned by rezo.download() and rezo.upload(). The progress event uses percentage and loaded/total (bytes):
const dl = rezo.download('https://example.com/large-file.tar.gz', './file.tar.gz');
dl.on('progress', ({ percentage, loaded, total }) => {
console.log(`Download: ${percentage.toFixed(1)}% (${loaded}/${total})`);
});
dl.on('finish', (info) => {
console.log('Saved:', info.fileName, info.fileSize, 'bytes');
}); For per-request callbacks (rather than events), use onDownloadProgress / onUploadProgress directly on the request config:
await rezo.get('https://example.com/large.json', {
onDownloadProgress: (e) => console.log(`${e.percentage.toFixed(1)}%`)
}); 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 Cookie Jar
The cURL adapter supports Rezo’s cookie jar:
const jar = new RezoCookieJar();
const client = rezo.create({ 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
rezo.stream() returns a RezoStreamResponse synchronously — body chunks arrive as 'data' events on the emitter:
const stream = rezo.stream('https://example.com/live-feed');
stream.on('data', (chunk) => {
process.stdout.write(chunk);
});
stream.on('finish', (info) => {
console.log('Total bytes:', info.contentLength);
});
stream.on('error', (err) => {
console.error('Stream failed:', err.message);
}); Retry and Redirect
const { data } = await rezo.get('https://example.com/data', {
retry: { limit: 3, statusCodes: [502, 503] },
maxRedirects: 10
}); Response Caching
const client = rezo.create({
cache: {
response: { enable: true, ttl: 60_000, 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 thecurlchild process, parses stdout/stderr, extracts response headers and body, tracks progress, and maps cURL exit codes toRezoErrorinstances.
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.