rezo 1.0.122 → 1.0.124
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +110 -2080
- package/dist/adapters/curl.cjs +0 -1
- package/dist/adapters/curl.js +0 -1
- package/dist/adapters/entries/curl.d.ts +179 -2
- package/dist/adapters/entries/fetch.d.ts +179 -2
- package/dist/adapters/entries/http.d.ts +183 -6
- package/dist/adapters/entries/http2.d.ts +179 -2
- package/dist/adapters/entries/react-native.d.ts +179 -2
- package/dist/adapters/entries/xhr.d.ts +179 -2
- package/dist/adapters/fetch.cjs +0 -1
- package/dist/adapters/fetch.js +0 -1
- package/dist/adapters/http.cjs +0 -1
- package/dist/adapters/http.js +0 -1
- package/dist/adapters/http2.cjs +0 -1
- package/dist/adapters/http2.js +0 -1
- package/dist/adapters/index.cjs +6 -6
- package/dist/cache/index.cjs +9 -9
- package/dist/cookies/cookie-jar.cjs +4 -6
- package/dist/cookies/cookie-jar.js +0 -2
- package/dist/cookies/index.cjs +10 -10
- package/dist/core/rezo.cjs +128 -0
- package/dist/core/rezo.js +128 -0
- package/dist/crawler/index.cjs +42 -42
- package/dist/crawler/plugin/index.cjs +1 -1
- package/dist/crawler.d.ts +176 -1
- package/dist/entries/crawler.cjs +6 -6
- package/dist/index.cjs +48 -44
- package/dist/index.d.ts +195 -2
- package/dist/index.js +2 -0
- package/dist/internal/agents/index.cjs +14 -14
- package/dist/platform/browser.d.ts +179 -2
- package/dist/platform/bun.d.ts +179 -2
- package/dist/platform/deno.d.ts +179 -2
- package/dist/platform/node.d.ts +179 -2
- package/dist/platform/react-native.d.ts +179 -2
- package/dist/platform/worker.d.ts +179 -2
- package/dist/proxy/index.cjs +4 -4
- package/dist/queue/index.cjs +8 -8
- package/dist/responses/buildResponse.cjs +0 -1
- package/dist/responses/buildResponse.js +0 -1
- package/dist/responses/universal/index.cjs +11 -11
- package/dist/stealth/index.cjs +17 -17
- package/dist/stealth/profiles/index.cjs +10 -10
- package/dist/utils/http-config.cjs +0 -1
- package/dist/utils/http-config.js +0 -1
- package/dist/utils/link-header.cjs +16 -0
- package/dist/utils/link-header.js +14 -0
- package/dist/utils/uri.cjs +56 -0
- package/dist/utils/uri.js +54 -0
- package/dist/version.cjs +1 -1
- package/dist/version.js +1 -1
- package/dist/wget/downloader.cjs +11 -5
- package/dist/wget/downloader.js +11 -5
- package/dist/wget/index.cjs +51 -51
- package/dist/wget/index.d.ts +179 -3
- package/dist/wget/link-converter.cjs +14 -5
- package/dist/wget/link-converter.js +14 -5
- package/dist/wget/style-extractor.cjs +17 -0
- package/dist/wget/style-extractor.js +17 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,2149 +1,179 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<img src="https://raw.githubusercontent.com/yuniqsolutions/rezo/main/assets/logo.svg" alt="Rezo
|
|
2
|
+
<img src="https://raw.githubusercontent.com/yuniqsolutions/rezo/main/assets/logo.svg" alt="Rezo" width="300">
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
|
-
<h1 align="center">Rezo HTTP Client</h1>
|
|
6
|
-
|
|
7
5
|
<p align="center">
|
|
8
|
-
<strong>
|
|
6
|
+
<strong>The last HTTP client you'll ever need.</strong>
|
|
9
7
|
</p>
|
|
10
8
|
|
|
11
9
|
<p align="center">
|
|
12
|
-
<a href="
|
|
13
|
-
<a href="
|
|
14
|
-
<a href="
|
|
15
|
-
<a href="
|
|
16
|
-
<a href="#adapters">Adapters</a> •
|
|
17
|
-
<a href="#advanced-usage">Advanced Usage</a> •
|
|
18
|
-
<a href="#migration-guide">Migration</a>
|
|
10
|
+
<a href="https://rezo-http.dev/docs">Documentation</a> •
|
|
11
|
+
<a href="https://rezo-http.dev/docs/getting-started/installation">Get Started</a> •
|
|
12
|
+
<a href="https://rezo-http.dev/docs/api/rezo-class">API Reference</a> •
|
|
13
|
+
<a href="https://rezo-http.dev/docs/switch/why-rezo">Why Rezo?</a>
|
|
19
14
|
</p>
|
|
20
15
|
|
|
21
16
|
<p align="center">
|
|
22
|
-
<img src="https://img.shields.io/npm/v/rezo?style=flat-square&color=
|
|
23
|
-
<img src="https://img.shields.io/npm/dm/rezo?style=flat-square&color=
|
|
24
|
-
<img src="https://img.shields.io/bundlephobia/minzip/rezo?style=flat-square&color=
|
|
25
|
-
<img src="https://img.shields.io/npm/l/rezo?style=flat-square&color=
|
|
26
|
-
<img src="https://img.shields.io/node/v/rezo?style=flat-square&color=
|
|
17
|
+
<img src="https://img.shields.io/npm/v/rezo?style=flat-square&color=3080ff" alt="npm version">
|
|
18
|
+
<img src="https://img.shields.io/npm/dm/rezo?style=flat-square&color=3080ff" alt="npm downloads">
|
|
19
|
+
<img src="https://img.shields.io/bundlephobia/minzip/rezo?style=flat-square&color=3080ff" alt="bundle size">
|
|
20
|
+
<img src="https://img.shields.io/npm/l/rezo?style=flat-square&color=3080ff" alt="license">
|
|
21
|
+
<img src="https://img.shields.io/node/v/rezo?style=flat-square&color=3080ff" alt="node version">
|
|
27
22
|
</p>
|
|
28
23
|
|
|
29
24
|
---
|
|
30
25
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
Rezo is a production-ready HTTP client library engineered for Node.js 22+ and universal JavaScript runtimes. Built from the ground up with TypeScript, Rezo delivers exceptional performance, comprehensive feature coverage, and seamless cross-environment compatibility.
|
|
34
|
-
|
|
35
|
-
**Why Rezo?**
|
|
36
|
-
|
|
37
|
-
- **Lightning Fast**: Native HTTP/2 multiplexing, connection pooling, and optimized stream handling
|
|
38
|
-
- **Universal**: Works seamlessly across Node.js, Bun, Deno, browsers, React Native, and edge runtimes
|
|
39
|
-
- **Type-Safe**: First-class TypeScript support with comprehensive type definitions
|
|
40
|
-
- **Enterprise Ready**: Advanced cookie management, proxy support, retry logic, and error handling
|
|
41
|
-
- **Tree-Shakeable**: Modular architecture enables optimal bundle sizes
|
|
42
|
-
- **Production Proven**: Battle-tested in high-throughput enterprise applications
|
|
43
|
-
|
|
44
|
-
---
|
|
45
|
-
|
|
46
|
-
## Table of Contents
|
|
47
|
-
|
|
48
|
-
- [Installation](#installation)
|
|
49
|
-
- [Quick Start](#quick-start)
|
|
50
|
-
- [Features](#features)
|
|
51
|
-
- [Adapters](#adapters)
|
|
52
|
-
- [HTTP Adapter](#http-adapter)
|
|
53
|
-
- [HTTP/2 Adapter](#http2-adapter)
|
|
54
|
-
- [Fetch Adapter](#fetch-adapter)
|
|
55
|
-
- [cURL Adapter](#curl-adapter)
|
|
56
|
-
- [XHR Adapter](#xhr-adapter)
|
|
57
|
-
- [React Native Adapter](#react-native-adapter)
|
|
58
|
-
- [API Reference](#api-reference)
|
|
59
|
-
- [Request Methods](#request-methods)
|
|
60
|
-
- [Request Configuration](#request-configuration)
|
|
61
|
-
- [Response Schema](#response-schema)
|
|
62
|
-
- [Instance Methods](#instance-methods)
|
|
63
|
-
- [Advanced Usage](#advanced-usage)
|
|
64
|
-
- [Cookie Management](#cookie-management)
|
|
65
|
-
- [Proxy Configuration](#proxy-configuration)
|
|
66
|
-
- [Proxy Manager](#proxy-manager)
|
|
67
|
-
- [Request Queue](#request-queue)
|
|
68
|
-
- [Streaming](#streaming)
|
|
69
|
-
- [File Downloads](#file-downloads)
|
|
70
|
-
- [File Uploads](#file-uploads)
|
|
71
|
-
- [Hooks & Interceptors](#hooks--interceptors)
|
|
72
|
-
- [Retry Logic](#retry-logic)
|
|
73
|
-
- [Error Handling](#error-handling)
|
|
74
|
-
- [Performance Metrics](#performance-metrics)
|
|
75
|
-
- [Platform Support](#platform-support)
|
|
76
|
-
- [Migration Guide](#migration-guide)
|
|
77
|
-
- [TypeScript](#typescript)
|
|
78
|
-
- [Crawler Module](#crawler-module)
|
|
79
|
-
- [DOM Module](#dom-module)
|
|
80
|
-
- [Troubleshooting](#troubleshooting)
|
|
81
|
-
- [Contributing](#contributing)
|
|
82
|
-
- [License](#license)
|
|
83
|
-
|
|
84
|
-
---
|
|
85
|
-
|
|
86
|
-
## Installation
|
|
26
|
+
Enterprise-grade HTTP client for Node.js 22+, Bun, Deno, browsers, React Native, and edge runtimes. One API everywhere — HTTP/2, cookies, proxy rotation, stealth mode, web crawling, and 70+ structured error codes out of the box.
|
|
87
27
|
|
|
88
|
-
|
|
28
|
+
## Install
|
|
89
29
|
|
|
90
30
|
```bash
|
|
91
31
|
npm install rezo
|
|
92
32
|
```
|
|
93
33
|
|
|
94
|
-
### Yarn
|
|
95
|
-
|
|
96
|
-
```bash
|
|
97
|
-
yarn add rezo
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
### pnpm
|
|
101
|
-
|
|
102
|
-
```bash
|
|
103
|
-
pnpm add rezo
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
### Bun
|
|
107
|
-
|
|
108
34
|
```bash
|
|
35
|
+
yarn add rezo # or
|
|
36
|
+
pnpm add rezo # or
|
|
109
37
|
bun add rezo
|
|
110
38
|
```
|
|
111
39
|
|
|
112
|
-
### Requirements
|
|
113
|
-
|
|
114
|
-
- **Node.js**: 22.0.0 or higher
|
|
115
|
-
- **Bun**: 1.0.0 or higher
|
|
116
|
-
- **Deno**: 1.40.0 or higher (with Node.js compatibility)
|
|
117
|
-
|
|
118
|
-
---
|
|
119
|
-
|
|
120
40
|
## Quick Start
|
|
121
41
|
|
|
122
|
-
### Basic GET Request
|
|
123
|
-
|
|
124
42
|
```typescript
|
|
125
43
|
import rezo from 'rezo';
|
|
126
44
|
|
|
127
|
-
//
|
|
128
|
-
const { data
|
|
129
|
-
console.log(data); // Response body (auto-parsed JSON)
|
|
130
|
-
console.log(status); // 200
|
|
131
|
-
console.log(headers); // Response headers
|
|
132
|
-
|
|
133
|
-
// With query parameters
|
|
134
|
-
const { data: users } = await rezo.get('https://api.example.com/users', {
|
|
135
|
-
params: { page: 1, limit: 10 }
|
|
136
|
-
});
|
|
137
|
-
console.log(users);
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
### POST Request with JSON
|
|
141
|
-
|
|
142
|
-
```typescript
|
|
143
|
-
import rezo from 'rezo';
|
|
45
|
+
// GET
|
|
46
|
+
const { data } = await rezo('https://api.example.com/users');
|
|
144
47
|
|
|
145
|
-
//
|
|
146
|
-
const { data
|
|
147
|
-
name: '
|
|
148
|
-
email: '
|
|
48
|
+
// POST with JSON
|
|
49
|
+
const { data: user } = await rezo.postJson('https://api.example.com/users', {
|
|
50
|
+
name: 'Ada Lovelace',
|
|
51
|
+
email: 'ada@example.com'
|
|
149
52
|
});
|
|
150
53
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
### Creating an Instance
|
|
156
|
-
|
|
157
|
-
```typescript
|
|
158
|
-
import rezo from 'rezo';
|
|
159
|
-
|
|
160
|
-
const api = rezo.create({
|
|
54
|
+
// Create an instance
|
|
55
|
+
const client = rezo.create({
|
|
161
56
|
baseURL: 'https://api.example.com',
|
|
162
|
-
timeout:
|
|
163
|
-
headers: {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
| **Automatic Transforms** | JSON parsing, content-type detection, compression handling |
|
|
201
|
-
| **Query Parameters** | Automatic URL encoding and serialization |
|
|
202
|
-
| **Request Cancellation** | AbortController support for request cancellation |
|
|
203
|
-
|
|
204
|
-
### Network Features
|
|
205
|
-
|
|
206
|
-
| Feature | Description |
|
|
207
|
-
|---------|-------------|
|
|
208
|
-
| **Cookie Management** | RFC 6265 compliant cookie jar with persistence |
|
|
209
|
-
| **Proxy Support** | HTTP, HTTPS, SOCKS4, and SOCKS5 proxies |
|
|
210
|
-
| **TLS/SSL** | Custom certificates, client certs, certificate pinning |
|
|
211
|
-
| **Compression** | Automatic gzip, deflate, brotli, and zstd handling |
|
|
212
|
-
| **Connection Pooling** | Reusable connections for improved performance |
|
|
213
|
-
| **Keep-Alive** | Persistent connections with configurable timeouts |
|
|
214
|
-
|
|
215
|
-
### Enterprise Features
|
|
216
|
-
|
|
217
|
-
| Feature | Description |
|
|
218
|
-
|---------|-------------|
|
|
219
|
-
| **Retry Logic** | Configurable retry with exponential backoff |
|
|
220
|
-
| **Timeout Control** | Connection, request, and total timeout options |
|
|
221
|
-
| **Rate Limiting** | Built-in request queue with priority, concurrency, and domain-based rate limiting |
|
|
222
|
-
| **Hooks System** | Lifecycle hooks for request/response interception |
|
|
223
|
-
| **Error Handling** | Structured errors with actionable suggestions |
|
|
224
|
-
| **Performance Metrics** | Detailed timing data for monitoring |
|
|
225
|
-
|
|
226
|
-
### Developer Experience
|
|
227
|
-
|
|
228
|
-
| Feature | Description |
|
|
229
|
-
|---------|-------------|
|
|
230
|
-
| **TypeScript First** | Comprehensive type definitions and generics |
|
|
231
|
-
| **Tree-Shakeable** | Modular exports for optimal bundle size |
|
|
232
|
-
| **Zero Config** | Works out of the box with sensible defaults |
|
|
233
|
-
| **Extensive Logging** | Debug mode for troubleshooting |
|
|
234
|
-
| **Cross-Platform** | Node.js, Bun, Deno, browsers, React Native, edge |
|
|
235
|
-
|
|
236
|
-
---
|
|
57
|
+
timeout: 5000,
|
|
58
|
+
headers: { 'Authorization': 'Bearer token' }
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
const { data: posts } = await client.get('/posts');
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## What's Included
|
|
65
|
+
|
|
66
|
+
<table>
|
|
67
|
+
<tr>
|
|
68
|
+
<td width="140"><strong>6 Adapters</strong></td>
|
|
69
|
+
<td>HTTP · HTTP/2 · cURL (200+ options) · Fetch · XHR · React Native</td>
|
|
70
|
+
</tr>
|
|
71
|
+
<tr>
|
|
72
|
+
<td><strong>26 Hooks</strong></td>
|
|
73
|
+
<td>Full request lifecycle — DNS, TLS, redirects, retries, cookies, proxies</td>
|
|
74
|
+
</tr>
|
|
75
|
+
<tr>
|
|
76
|
+
<td><strong>70+ Error Codes</strong></td>
|
|
77
|
+
<td>Structured errors with boolean flags and recovery suggestions</td>
|
|
78
|
+
</tr>
|
|
79
|
+
</table>
|
|
80
|
+
|
|
81
|
+
<br>
|
|
82
|
+
|
|
83
|
+
- **Cookie Jar** — Auto-persistence in JSON and Netscape formats
|
|
84
|
+
- **Proxy Rotation** — HTTP, HTTPS, SOCKS4, SOCKS5 with health monitoring
|
|
85
|
+
- **Stealth Mode** — 18 browser profiles with TLS fingerprinting
|
|
86
|
+
- **Web Crawler** — SQLite persistence, robots.txt, auto-throttle, resumable
|
|
87
|
+
- **Request Queue** — Priority, per-domain concurrency, rate limiting
|
|
88
|
+
- **Streaming** — EventEmitter with progress and lifecycle events
|
|
89
|
+
- **Downloads & Uploads** — Progress, speed, and ETA tracking
|
|
90
|
+
- **Retry** — Exponential/linear backoff with custom conditions
|
|
91
|
+
- **Staged Timeouts** — Separate connect, headers, body, and total phases
|
|
92
|
+
- **Response & DNS Cache** — ETag/Last-Modified revalidation
|
|
93
|
+
- **Site Cloning** — Wget-style mirroring with link conversion
|
|
94
|
+
- **TypeScript** — Strict types, generics, overloads from the ground up
|
|
237
95
|
|
|
238
96
|
## Adapters
|
|
239
97
|
|
|
240
|
-
Rezo
|
|
241
|
-
|
|
242
|
-
### Automatic Adapter Selection
|
|
243
|
-
|
|
244
|
-
By default, Rezo automatically selects the best adapter based on your runtime environment:
|
|
245
|
-
|
|
246
|
-
| Environment | Default Adapter |
|
|
247
|
-
|-------------|-----------------|
|
|
248
|
-
| Node.js | HTTP Adapter |
|
|
249
|
-
| Bun | HTTP Adapter |
|
|
250
|
-
| Deno | HTTP Adapter |
|
|
251
|
-
| Browser | Fetch Adapter |
|
|
252
|
-
| Cloudflare Workers | Fetch Adapter |
|
|
253
|
-
| React Native | React Native Adapter |
|
|
254
|
-
|
|
255
|
-
### HTTP Adapter
|
|
256
|
-
|
|
257
|
-
The full-featured adapter for Node.js environments with complete cookie, proxy, and streaming support.
|
|
258
|
-
|
|
259
|
-
```typescript
|
|
260
|
-
import rezo from 'rezo/adapters/http';
|
|
261
|
-
|
|
262
|
-
const response = await rezo.get('https://api.example.com/data');
|
|
263
|
-
```
|
|
264
|
-
|
|
265
|
-
**Features:**
|
|
266
|
-
- Full cookie jar support with persistence
|
|
267
|
-
- HTTP/HTTPS/SOCKS proxy support
|
|
268
|
-
- Streaming request and response bodies
|
|
269
|
-
- All compression algorithms
|
|
270
|
-
- Custom TLS configuration
|
|
271
|
-
- Connection keep-alive
|
|
272
|
-
|
|
273
|
-
### HTTP/2 Adapter
|
|
274
|
-
|
|
275
|
-
Native HTTP/2 support with session multiplexing for maximum performance.
|
|
276
|
-
|
|
277
|
-
```typescript
|
|
278
|
-
import rezo from 'rezo/adapters/http2';
|
|
279
|
-
|
|
280
|
-
const response = await rezo.get('https://api.example.com/data');
|
|
281
|
-
```
|
|
282
|
-
|
|
283
|
-
**Features:**
|
|
284
|
-
- HTTP/2 multiplexing (multiple requests over single connection)
|
|
285
|
-
- Automatic session pooling and reuse
|
|
286
|
-
- ALPN protocol negotiation
|
|
287
|
-
- Falls back to HTTP/1.1 when needed
|
|
288
|
-
- Server push support
|
|
289
|
-
- Header compression (HPACK)
|
|
290
|
-
|
|
291
|
-
### Fetch Adapter
|
|
292
|
-
|
|
293
|
-
Lightweight adapter using the native Fetch API, ideal for browsers and edge runtimes.
|
|
294
|
-
|
|
295
|
-
```typescript
|
|
296
|
-
import rezo from 'rezo/adapters/fetch';
|
|
297
|
-
|
|
298
|
-
const response = await rezo.get('https://api.example.com/data');
|
|
299
|
-
```
|
|
300
|
-
|
|
301
|
-
**Features:**
|
|
302
|
-
- Minimal bundle size
|
|
303
|
-
- Native browser support
|
|
304
|
-
- Edge runtime compatible (Cloudflare Workers, Vercel Edge)
|
|
305
|
-
- Streaming response bodies
|
|
306
|
-
- AbortController integration
|
|
307
|
-
|
|
308
|
-
### cURL Adapter
|
|
309
|
-
|
|
310
|
-
Advanced adapter wrapping the cURL command-line tool with **120+ configuration options** for maximum compatibility, debugging, and fine-grained control.
|
|
311
|
-
|
|
312
|
-
```typescript
|
|
313
|
-
import rezo from 'rezo/adapters/curl';
|
|
314
|
-
|
|
315
|
-
const response = await rezo.get('https://api.example.com/data', {
|
|
316
|
-
curl: {
|
|
317
|
-
connectTimeout: 10,
|
|
318
|
-
limitRate: '500K',
|
|
319
|
-
retry: { attempts: 3, allErrors: true },
|
|
320
|
-
verbose: true
|
|
321
|
-
}
|
|
322
|
-
});
|
|
323
|
-
```
|
|
324
|
-
|
|
325
|
-
**Features:**
|
|
326
|
-
- 120+ cURL command-line options via `curl` property
|
|
327
|
-
- HTTP/1.0, 1.1, 2.0, 3.0 protocol support
|
|
328
|
-
- Advanced authentication (Basic, Digest, NTLM, Negotiate, AWS SigV4, OAuth2)
|
|
329
|
-
- Comprehensive TLS/SSL configuration
|
|
330
|
-
- FTP, SSH, SMTP, and TFTP protocol support
|
|
331
|
-
- Connection pooling and reuse
|
|
332
|
-
- Detailed timing and debugging information
|
|
333
|
-
- Proxy authentication and chaining
|
|
334
|
-
|
|
335
|
-
**Important**: The `curl` property is **only available** when importing from `rezo/adapters/curl`. It does not appear in the base `RezoRequestConfig` type.
|
|
336
|
-
|
|
337
|
-
#### cURL Options Categories
|
|
338
|
-
|
|
339
|
-
The cURL adapter provides options across the following categories:
|
|
340
|
-
|
|
341
|
-
| Category | Example Options | Description |
|
|
342
|
-
|----------|----------------|-------------|
|
|
343
|
-
| **Connection** | `connectTimeout`, `maxTime`, `tcpFastOpen`, `tcpNodelay` | Connection timing and TCP settings |
|
|
344
|
-
| **Rate Limiting** | `limitRate`, `speedLimit`, `maxFilesize` | Bandwidth and transfer limits |
|
|
345
|
-
| **Retry** | `retry.attempts`, `retry.delay`, `retry.allErrors` | Automatic retry configuration |
|
|
346
|
-
| **Network** | `interface`, `localPort`, `ipVersion`, `resolve` | Network interface and routing |
|
|
347
|
-
| **HTTP** | `httpVersion`, `pathAsIs`, `maxRedirs`, `referer` | HTTP protocol settings |
|
|
348
|
-
| **TLS/SSL** | `tls.min`, `tls.ciphers`, `tls.cert`, `insecure` | Comprehensive TLS configuration |
|
|
349
|
-
| **Proxy** | `proxyHeaders`, `proxyTls`, `proxyTunnel` | Proxy-specific settings |
|
|
350
|
-
| **DNS** | `dns.servers`, `dns.dohUrl`, `dns.dohInsecure` | DNS resolution and DoH |
|
|
351
|
-
| **Authentication** | `negotiate`, `awsSigv4`, `oauth2Bearer`, `kerberos` | Advanced auth methods |
|
|
352
|
-
| **FTP** | `ftp.pasv`, `ftp.createDirs`, `ftp.method` | FTP protocol options |
|
|
353
|
-
| **SSH** | `ssh.privateKey`, `ssh.knownHosts`, `ssh.compression` | SSH/SCP/SFTP settings |
|
|
354
|
-
| **SMTP** | `smtp.mailFrom`, `smtp.mailRcpt` | Email sending configuration |
|
|
355
|
-
| **Debug** | `verbose`, `trace`, `traceTime`, `dumpHeader` | Debugging and tracing |
|
|
356
|
-
|
|
357
|
-
#### cURL Options Examples
|
|
358
|
-
|
|
359
|
-
##### Connection & Timeout
|
|
360
|
-
|
|
361
|
-
```typescript
|
|
362
|
-
import rezo from 'rezo/adapters/curl';
|
|
363
|
-
|
|
364
|
-
await rezo.get('https://api.example.com/data', {
|
|
365
|
-
curl: {
|
|
366
|
-
connectTimeout: 10, // 10 seconds for TCP connection
|
|
367
|
-
maxTime: 300, // 5 minutes max for entire request
|
|
368
|
-
keepaliveTime: 60, // Send keepalive after 60s idle
|
|
369
|
-
tcpFastOpen: true, // Enable TCP Fast Open
|
|
370
|
-
tcpNodelay: true, // Disable Nagle algorithm
|
|
371
|
-
happyEyeballsTimeout: 200 // IPv6/IPv4 fallback timeout
|
|
372
|
-
}
|
|
373
|
-
});
|
|
374
|
-
```
|
|
375
|
-
|
|
376
|
-
##### Rate Limiting & Bandwidth
|
|
377
|
-
|
|
378
|
-
```typescript
|
|
379
|
-
import rezo from 'rezo/adapters/curl';
|
|
380
|
-
|
|
381
|
-
await rezo.get('https://example.com/large-file.zip', {
|
|
382
|
-
curl: {
|
|
383
|
-
limitRate: '1M', // Limit to 1 MB/s
|
|
384
|
-
speedLimit: { limit: 1000, time: 30 }, // Abort if <1KB/s for 30s
|
|
385
|
-
maxFilesize: 100 * 1024 * 1024 // Max 100MB response
|
|
386
|
-
}
|
|
387
|
-
});
|
|
388
|
-
```
|
|
389
|
-
|
|
390
|
-
##### Retry Configuration
|
|
391
|
-
|
|
392
|
-
```typescript
|
|
393
|
-
import rezo from 'rezo/adapters/curl';
|
|
394
|
-
|
|
395
|
-
await rezo.get('https://unreliable-api.com/data', {
|
|
396
|
-
curl: {
|
|
397
|
-
retry: {
|
|
398
|
-
attempts: 5, // Retry up to 5 times
|
|
399
|
-
delay: 2, // 2 seconds between retries
|
|
400
|
-
maxTime: 60, // Max 60 seconds total for retries
|
|
401
|
-
allErrors: true, // Retry on all errors (not just transient)
|
|
402
|
-
connRefused: true // Retry on connection refused
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
});
|
|
406
|
-
```
|
|
407
|
-
|
|
408
|
-
##### Custom DNS Resolution
|
|
409
|
-
|
|
410
|
-
```typescript
|
|
411
|
-
import rezo from 'rezo/adapters/curl';
|
|
412
|
-
|
|
413
|
-
await rezo.get('https://api.example.com/data', {
|
|
414
|
-
curl: {
|
|
415
|
-
resolve: [
|
|
416
|
-
{ host: 'api.example.com', port: 443, address: '10.0.0.1' }
|
|
417
|
-
],
|
|
418
|
-
dns: {
|
|
419
|
-
servers: '8.8.8.8,8.8.4.4',
|
|
420
|
-
dohUrl: 'https://dns.google/dns-query'
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
});
|
|
424
|
-
```
|
|
425
|
-
|
|
426
|
-
##### Comprehensive TLS Configuration
|
|
98
|
+
Rezo selects the optimal adapter for your runtime automatically.
|
|
427
99
|
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
ciphers: 'ECDHE-RSA-AES256-GCM-SHA384', // TLS 1.2 ciphers
|
|
437
|
-
certStatus: true, // OCSP stapling
|
|
438
|
-
pinnedPubKey: 'sha256//base64hash=', // Certificate pinning
|
|
439
|
-
cert: '/path/to/client.crt', // Client certificate
|
|
440
|
-
key: '/path/to/client.key', // Client key
|
|
441
|
-
cacert: '/path/to/ca-bundle.crt' // CA certificate
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
});
|
|
445
|
-
```
|
|
446
|
-
|
|
447
|
-
##### Advanced Authentication
|
|
448
|
-
|
|
449
|
-
```typescript
|
|
450
|
-
import rezo from 'rezo/adapters/curl';
|
|
451
|
-
|
|
452
|
-
// AWS Signature Version 4
|
|
453
|
-
await rezo.get('https://s3.amazonaws.com/bucket/object', {
|
|
454
|
-
curl: {
|
|
455
|
-
awsSigv4: {
|
|
456
|
-
provider: 'aws:amz',
|
|
457
|
-
region: 'us-east-1',
|
|
458
|
-
service: 's3'
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
});
|
|
462
|
-
|
|
463
|
-
// Kerberos/SPNEGO
|
|
464
|
-
await rezo.get('https://internal.company.com/api', {
|
|
465
|
-
curl: {
|
|
466
|
-
negotiate: true,
|
|
467
|
-
delegation: 'policy'
|
|
468
|
-
}
|
|
469
|
-
});
|
|
470
|
-
|
|
471
|
-
// OAuth 2.0 Bearer Token
|
|
472
|
-
await rezo.get('https://api.example.com/protected', {
|
|
473
|
-
curl: {
|
|
474
|
-
oauth2Bearer: 'your-access-token'
|
|
475
|
-
}
|
|
476
|
-
});
|
|
477
|
-
```
|
|
478
|
-
|
|
479
|
-
##### FTP Operations
|
|
480
|
-
|
|
481
|
-
```typescript
|
|
482
|
-
import rezo from 'rezo/adapters/curl';
|
|
483
|
-
|
|
484
|
-
await rezo.get('ftp://ftp.example.com/file.txt', {
|
|
485
|
-
curl: {
|
|
486
|
-
ftp: {
|
|
487
|
-
pasv: true,
|
|
488
|
-
createDirs: true,
|
|
489
|
-
method: 'singlecwd',
|
|
490
|
-
sslControl: true
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
|
-
});
|
|
494
|
-
```
|
|
495
|
-
|
|
496
|
-
##### SSH/SFTP Configuration
|
|
497
|
-
|
|
498
|
-
```typescript
|
|
499
|
-
import rezo from 'rezo/adapters/curl';
|
|
100
|
+
| Adapter | Runtime | Cookies | Proxy | HTTP/2 | Streaming |
|
|
101
|
+
|---|---|---|---|---|---|
|
|
102
|
+
| **HTTP** | Node.js, Bun | ● | ● | | ● |
|
|
103
|
+
| **HTTP/2** | Node.js, Bun | ● | ● | ● | ● |
|
|
104
|
+
| **cURL** | Node.js | ● | ● | ● | ● |
|
|
105
|
+
| **Fetch** | Browsers, Deno, Edge | | | | ● |
|
|
106
|
+
| **XHR** | Browsers | | | | |
|
|
107
|
+
| **React Native** | iOS, Android | | | | ● |
|
|
500
108
|
|
|
501
|
-
|
|
502
|
-
curl: {
|
|
503
|
-
ssh: {
|
|
504
|
-
privateKey: '/home/user/.ssh/id_rsa',
|
|
505
|
-
publicKey: '/home/user/.ssh/id_rsa.pub',
|
|
506
|
-
knownHosts: '/home/user/.ssh/known_hosts',
|
|
507
|
-
compression: true
|
|
508
|
-
}
|
|
509
|
-
}
|
|
510
|
-
});
|
|
511
|
-
```
|
|
109
|
+
## Examples
|
|
512
110
|
|
|
513
|
-
|
|
111
|
+
**Proxy rotation with stealth:**
|
|
514
112
|
|
|
515
113
|
```typescript
|
|
516
|
-
import rezo from 'rezo
|
|
114
|
+
import rezo, { RezoStealth } from 'rezo';
|
|
517
115
|
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
116
|
+
const client = rezo.create({
|
|
117
|
+
stealth: RezoStealth.chrome(),
|
|
118
|
+
proxyManager: {
|
|
119
|
+
proxies: ['socks5://proxy1:1080', 'http://proxy2:8080'],
|
|
120
|
+
rotation: { strategy: 'random' },
|
|
121
|
+
autoDisableDeadProxies: true
|
|
524
122
|
}
|
|
525
123
|
});
|
|
526
|
-
```
|
|
527
|
-
|
|
528
|
-
#### CurlRequestConfig Type
|
|
529
|
-
|
|
530
|
-
When using the cURL adapter, the request configuration type extends the base with cURL-specific options:
|
|
531
|
-
|
|
532
|
-
```typescript
|
|
533
|
-
import rezo, { CurlRequestConfig } from 'rezo/adapters/curl';
|
|
534
|
-
|
|
535
|
-
const config: CurlRequestConfig = {
|
|
536
|
-
url: 'https://api.example.com/data',
|
|
537
|
-
method: 'GET',
|
|
538
|
-
headers: { 'Accept': 'application/json' },
|
|
539
|
-
curl: {
|
|
540
|
-
connectTimeout: 10,
|
|
541
|
-
retry: { attempts: 3 }
|
|
542
|
-
}
|
|
543
|
-
};
|
|
544
|
-
|
|
545
|
-
const response = await rezo.request(config);
|
|
546
|
-
```
|
|
547
|
-
|
|
548
|
-
#### Available cURL Option Types
|
|
549
|
-
|
|
550
|
-
The cURL adapter exports all option types for TypeScript users:
|
|
551
|
-
|
|
552
|
-
```typescript
|
|
553
|
-
import type {
|
|
554
|
-
CurlOptions,
|
|
555
|
-
CurlRequestConfig,
|
|
556
|
-
CurlTlsOptions,
|
|
557
|
-
CurlFtpOptions,
|
|
558
|
-
CurlSshOptions,
|
|
559
|
-
CurlSmtpOptions,
|
|
560
|
-
CurlDnsOptions,
|
|
561
|
-
CurlRetryOptions,
|
|
562
|
-
CurlProxyTlsOptions,
|
|
563
|
-
CurlResolveEntry,
|
|
564
|
-
CurlConnectToEntry,
|
|
565
|
-
CurlSpeedLimit,
|
|
566
|
-
CurlParallelOptions,
|
|
567
|
-
CurlHttpVersion,
|
|
568
|
-
CurlSslVersion,
|
|
569
|
-
CurlIpVersion,
|
|
570
|
-
CurlAuthMethod,
|
|
571
|
-
CurlDelegation
|
|
572
|
-
} from 'rezo/adapters/curl';
|
|
573
|
-
```
|
|
574
|
-
|
|
575
|
-
### XHR Adapter
|
|
576
|
-
|
|
577
|
-
Legacy browser support using XMLHttpRequest for maximum compatibility.
|
|
578
|
-
|
|
579
|
-
```typescript
|
|
580
|
-
import rezo from 'rezo/adapters/xhr';
|
|
581
|
-
|
|
582
|
-
const response = await rezo.get('https://api.example.com/data');
|
|
583
|
-
```
|
|
584
|
-
|
|
585
|
-
**Features:**
|
|
586
|
-
- Legacy browser support (IE11+)
|
|
587
|
-
- Upload progress events
|
|
588
|
-
- Download progress events
|
|
589
|
-
- Synchronous request option
|
|
590
|
-
- Cross-origin request handling
|
|
591
|
-
|
|
592
|
-
### React Native Adapter
|
|
593
|
-
|
|
594
|
-
Optimized adapter for React Native mobile applications.
|
|
595
|
-
|
|
596
|
-
```typescript
|
|
597
|
-
import rezo from 'rezo/adapters/react-native';
|
|
598
|
-
|
|
599
|
-
const response = await rezo.get('https://api.example.com/data');
|
|
600
|
-
```
|
|
601
|
-
|
|
602
|
-
**Features:**
|
|
603
|
-
- Optimized for mobile networks
|
|
604
|
-
- File download support (react-native-fs)
|
|
605
|
-
- Manual cookie header management
|
|
606
|
-
- Background fetch support
|
|
607
|
-
- Network state awareness
|
|
608
|
-
|
|
609
|
-
---
|
|
610
|
-
|
|
611
|
-
## API Reference
|
|
612
|
-
|
|
613
|
-
### Request Methods
|
|
614
124
|
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
```typescript
|
|
618
|
-
// GET request
|
|
619
|
-
rezo.get(url[, config])
|
|
620
|
-
|
|
621
|
-
// POST request
|
|
622
|
-
rezo.post(url[, data[, config]])
|
|
623
|
-
|
|
624
|
-
// PUT request
|
|
625
|
-
rezo.put(url[, data[, config]])
|
|
626
|
-
|
|
627
|
-
// PATCH request
|
|
628
|
-
rezo.patch(url[, data[, config]])
|
|
629
|
-
|
|
630
|
-
// DELETE request
|
|
631
|
-
rezo.delete(url[, config])
|
|
632
|
-
|
|
633
|
-
// HEAD request
|
|
634
|
-
rezo.head(url[, config])
|
|
635
|
-
|
|
636
|
-
// OPTIONS request
|
|
637
|
-
rezo.options(url[, config])
|
|
638
|
-
|
|
639
|
-
// Generic request
|
|
640
|
-
rezo.request(config)
|
|
641
|
-
```
|
|
642
|
-
|
|
643
|
-
### Convenience Methods
|
|
644
|
-
|
|
645
|
-
Rezo provides specialized methods for common content types:
|
|
646
|
-
|
|
647
|
-
```typescript
|
|
648
|
-
// JSON POST with automatic Content-Type header
|
|
649
|
-
rezo.postJson(url, data[, config])
|
|
650
|
-
|
|
651
|
-
// Form-encoded POST
|
|
652
|
-
rezo.postForm(url, data[, config])
|
|
653
|
-
|
|
654
|
-
// Multipart form data POST
|
|
655
|
-
rezo.postMultipart(url, data[, config])
|
|
656
|
-
|
|
657
|
-
// Same patterns available for PUT and PATCH
|
|
658
|
-
rezo.putJson(url, data[, config])
|
|
659
|
-
rezo.patchJson(url, data[, config])
|
|
660
|
-
```
|
|
661
|
-
|
|
662
|
-
### Request Configuration
|
|
663
|
-
|
|
664
|
-
```typescript
|
|
665
|
-
interface RezoConfig {
|
|
666
|
-
// URL and Method
|
|
667
|
-
url?: string;
|
|
668
|
-
method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS';
|
|
669
|
-
baseURL?: string;
|
|
670
|
-
|
|
671
|
-
// Request Data
|
|
672
|
-
params?: Record<string, any>;
|
|
673
|
-
data?: any;
|
|
674
|
-
headers?: RezoHeaders | Record<string, string>;
|
|
675
|
-
|
|
676
|
-
// Timeouts (in milliseconds)
|
|
677
|
-
timeout?: number;
|
|
678
|
-
connectTimeout?: number;
|
|
679
|
-
requestTimeout?: number;
|
|
680
|
-
|
|
681
|
-
// Response Handling
|
|
682
|
-
responseType?: 'json' | 'text' | 'arraybuffer' | 'blob' | 'stream';
|
|
683
|
-
responseEncoding?: string;
|
|
684
|
-
validateStatus?: (status: number) => boolean;
|
|
685
|
-
maxContentLength?: number;
|
|
686
|
-
maxBodyLength?: number;
|
|
687
|
-
|
|
688
|
-
// Redirects
|
|
689
|
-
maxRedirects?: number;
|
|
690
|
-
followRedirect?: boolean;
|
|
691
|
-
|
|
692
|
-
// Authentication
|
|
693
|
-
auth?: {
|
|
694
|
-
username: string;
|
|
695
|
-
password: string;
|
|
696
|
-
};
|
|
697
|
-
|
|
698
|
-
// Proxy Configuration
|
|
699
|
-
proxy?: {
|
|
700
|
-
protocol?: 'http' | 'https' | 'socks4' | 'socks5';
|
|
701
|
-
host: string;
|
|
702
|
-
port: number;
|
|
703
|
-
auth?: {
|
|
704
|
-
username: string;
|
|
705
|
-
password: string;
|
|
706
|
-
};
|
|
707
|
-
};
|
|
708
|
-
|
|
709
|
-
// TLS/SSL
|
|
710
|
-
httpsAgent?: any;
|
|
711
|
-
rejectUnauthorized?: boolean;
|
|
712
|
-
ca?: string | Buffer;
|
|
713
|
-
cert?: string | Buffer;
|
|
714
|
-
key?: string | Buffer;
|
|
715
|
-
|
|
716
|
-
// Advanced
|
|
717
|
-
decompress?: boolean;
|
|
718
|
-
signal?: AbortSignal;
|
|
719
|
-
onUploadProgress?: (progressEvent: ProgressEvent) => void;
|
|
720
|
-
onDownloadProgress?: (progressEvent: ProgressEvent) => void;
|
|
721
|
-
|
|
722
|
-
// Retry Configuration
|
|
723
|
-
retry?: {
|
|
724
|
-
limit?: number;
|
|
725
|
-
delay?: number;
|
|
726
|
-
maxDelay?: number;
|
|
727
|
-
backoff?: number;
|
|
728
|
-
retryOn?: number[] | ((error: Error, attempt: number) => boolean);
|
|
729
|
-
};
|
|
730
|
-
|
|
731
|
-
// Cookies
|
|
732
|
-
jar?: CookieJar;
|
|
733
|
-
withCredentials?: boolean;
|
|
734
|
-
}
|
|
735
|
-
```
|
|
736
|
-
|
|
737
|
-
### Response Schema
|
|
738
|
-
|
|
739
|
-
```typescript
|
|
740
|
-
interface RezoResponse<T = any> {
|
|
741
|
-
// Response data (automatically parsed based on content-type)
|
|
742
|
-
data: T;
|
|
743
|
-
|
|
744
|
-
// HTTP status
|
|
745
|
-
status: number;
|
|
746
|
-
statusText: string;
|
|
747
|
-
|
|
748
|
-
// Response headers (case-insensitive access)
|
|
749
|
-
headers: RezoHeaders;
|
|
750
|
-
|
|
751
|
-
// Request configuration used
|
|
752
|
-
config: RezoConfig;
|
|
753
|
-
|
|
754
|
-
// The request that generated this response
|
|
755
|
-
request: any;
|
|
756
|
-
|
|
757
|
-
// Timing metrics (when available)
|
|
758
|
-
timing?: {
|
|
759
|
-
start: number;
|
|
760
|
-
dns: number;
|
|
761
|
-
connect: number;
|
|
762
|
-
tls: number;
|
|
763
|
-
firstByte: number;
|
|
764
|
-
download: number;
|
|
765
|
-
total: number;
|
|
766
|
-
};
|
|
767
|
-
}
|
|
125
|
+
const { data } = await client.get('https://protected-site.com');
|
|
768
126
|
```
|
|
769
127
|
|
|
770
|
-
|
|
128
|
+
**Download with progress:**
|
|
771
129
|
|
|
772
130
|
```typescript
|
|
773
|
-
const
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
instance.put(url, data?, config?)
|
|
779
|
-
instance.patch(url, data?, config?)
|
|
780
|
-
instance.delete(url, config?)
|
|
781
|
-
instance.head(url, config?)
|
|
782
|
-
instance.options(url, config?)
|
|
783
|
-
instance.request(config)
|
|
784
|
-
|
|
785
|
-
// Instance configuration
|
|
786
|
-
instance.defaults // Access default configuration
|
|
787
|
-
instance.getUri(config) // Get the full URL
|
|
788
|
-
|
|
789
|
-
// Cookie management
|
|
790
|
-
instance.jar // Access the cookie jar
|
|
791
|
-
instance.getCookies(url)
|
|
792
|
-
instance.setCookie(cookie, url)
|
|
793
|
-
instance.clearCookies()
|
|
794
|
-
|
|
795
|
-
// Hooks
|
|
796
|
-
instance.hooks.beforeRequest.push(handler)
|
|
797
|
-
instance.hooks.afterResponse.push(handler)
|
|
798
|
-
instance.hooks.beforeRetry.push(handler)
|
|
799
|
-
instance.hooks.beforeError.push(handler)
|
|
131
|
+
const download = await rezo.download(
|
|
132
|
+
'https://example.com/file.zip',
|
|
133
|
+
'./file.zip'
|
|
134
|
+
);
|
|
135
|
+
download.on('progress', (p) => console.log(`${p.percentage}%`));
|
|
800
136
|
```
|
|
801
137
|
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
## Advanced Usage
|
|
805
|
-
|
|
806
|
-
### Cookie Management
|
|
807
|
-
|
|
808
|
-
Rezo provides RFC 6265 compliant cookie management with automatic persistence. The default instance already has a built-in cookie jar - no configuration required.
|
|
138
|
+
**Streaming:**
|
|
809
139
|
|
|
810
140
|
```typescript
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
// Cookies work automatically with the default instance
|
|
814
|
-
await rezo.post('https://api.example.com/login', { username: 'user', password: 'pass' });
|
|
815
|
-
|
|
816
|
-
// Subsequent requests automatically include session cookies
|
|
817
|
-
const profile = await rezo.get('https://api.example.com/profile');
|
|
818
|
-
|
|
819
|
-
// Access cookies directly from the default instance
|
|
820
|
-
const cookies = rezo.getCookies('https://api.example.com');
|
|
821
|
-
console.log(cookies);
|
|
822
|
-
|
|
823
|
-
// Set cookies manually
|
|
824
|
-
rezo.setCookie('custom=value; Path=/; HttpOnly', 'https://api.example.com');
|
|
825
|
-
|
|
826
|
-
// Clear all cookies
|
|
827
|
-
rezo.clearCookies();
|
|
141
|
+
const stream = await rezo.stream('https://api.example.com/events');
|
|
142
|
+
stream.on('data', (chunk) => process.stdout.write(chunk));
|
|
828
143
|
```
|
|
829
144
|
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
Only create your own CookieJar if you need to manage cookies externally or use multiple isolated jars:
|
|
145
|
+
**26 lifecycle hooks:**
|
|
833
146
|
|
|
834
147
|
```typescript
|
|
835
|
-
import rezo, { CookieJar } from 'rezo';
|
|
836
|
-
|
|
837
|
-
// Custom jar for isolated cookie management
|
|
838
|
-
const myJar = new CookieJar();
|
|
839
|
-
|
|
840
148
|
const client = rezo.create({
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
const setCookieHeaders = myJar.toSetCookieStrings();
|
|
848
|
-
const jsonFormat = myJar.toJSON();
|
|
849
|
-
```
|
|
850
|
-
|
|
851
|
-
### Proxy Configuration
|
|
852
|
-
|
|
853
|
-
Rezo provides comprehensive proxy support for HTTP, HTTPS, SOCKS4, and SOCKS5 protocols, enabling secure and anonymous web requests through proxy servers.
|
|
854
|
-
|
|
855
|
-
#### Quick Usage (Per-Request)
|
|
856
|
-
|
|
857
|
-
You can use a proxy directly in any request without creating an instance:
|
|
858
|
-
|
|
859
|
-
```typescript
|
|
860
|
-
import rezo from 'rezo';
|
|
861
|
-
|
|
862
|
-
// Use proxy for a single request
|
|
863
|
-
const response = await rezo.get('https://api.example.com/data', {
|
|
864
|
-
proxy: {
|
|
865
|
-
protocol: 'http',
|
|
866
|
-
host: 'proxy.example.com',
|
|
867
|
-
port: 8080
|
|
149
|
+
hooks: {
|
|
150
|
+
beforeRequest: [(config) => { /* modify config */ }],
|
|
151
|
+
afterResponse: [(response) => response],
|
|
152
|
+
onDns: [(event) => { /* DNS resolved */ }],
|
|
153
|
+
onTls: [(event) => { /* TLS handshake done */ }],
|
|
154
|
+
beforeRetry: [(config, error) => { /* about to retry */ }],
|
|
868
155
|
}
|
|
869
156
|
});
|
|
870
157
|
```
|
|
871
158
|
|
|
872
|
-
|
|
159
|
+
## Documentation
|
|
873
160
|
|
|
874
|
-
|
|
875
|
-
|----------|-------------|----------|
|
|
876
|
-
| `http` | HTTP proxy (CONNECT method for HTTPS targets) | General-purpose web proxy |
|
|
877
|
-
| `https` | HTTPS proxy (encrypted proxy connection) | Secure corporate proxies |
|
|
878
|
-
| `socks4` | SOCKS4 proxy (TCP connections only) | Legacy proxy servers |
|
|
879
|
-
| `socks5` | SOCKS5 proxy (TCP + UDP, authentication) | Anonymous browsing, Tor |
|
|
161
|
+
Full documentation at **[rezo-http.dev](https://rezo-http.dev/docs)**
|
|
880
162
|
|
|
881
|
-
|
|
163
|
+
- [Installation](https://rezo-http.dev/docs/getting-started/installation)
|
|
164
|
+
- [Quick Start](https://rezo-http.dev/docs/getting-started/quick-start)
|
|
165
|
+
- [API Reference](https://rezo-http.dev/docs/api/rezo-class)
|
|
166
|
+
- [Adapters](https://rezo-http.dev/docs/adapters/overview)
|
|
167
|
+
- [Stealth Mode](https://rezo-http.dev/docs/stealth/overview)
|
|
168
|
+
- [Web Crawler](https://rezo-http.dev/docs/crawler/overview)
|
|
169
|
+
- [Error Handling](https://rezo-http.dev/docs/core/error-handling)
|
|
170
|
+
- [Hooks](https://rezo-http.dev/docs/features/hooks)
|
|
171
|
+
- [Switching from another library?](https://rezo-http.dev/docs/switch/why-rezo)
|
|
882
172
|
|
|
883
|
-
|
|
884
|
-
import rezo from 'rezo';
|
|
885
|
-
|
|
886
|
-
// HTTP Proxy - routes all traffic through the proxy
|
|
887
|
-
const client = rezo.create({
|
|
888
|
-
proxy: {
|
|
889
|
-
protocol: 'http',
|
|
890
|
-
host: 'proxy.example.com',
|
|
891
|
-
port: 8080
|
|
892
|
-
}
|
|
893
|
-
});
|
|
173
|
+
## License
|
|
894
174
|
|
|
895
|
-
|
|
896
|
-
```
|
|
897
|
-
|
|
898
|
-
#### HTTPS Proxy
|
|
899
|
-
|
|
900
|
-
```typescript
|
|
901
|
-
import rezo from 'rezo';
|
|
902
|
-
|
|
903
|
-
// HTTPS Proxy - encrypted connection to proxy server
|
|
904
|
-
const client = rezo.create({
|
|
905
|
-
proxy: {
|
|
906
|
-
protocol: 'https',
|
|
907
|
-
host: 'secure-proxy.example.com',
|
|
908
|
-
port: 443
|
|
909
|
-
}
|
|
910
|
-
});
|
|
911
|
-
```
|
|
912
|
-
|
|
913
|
-
#### Authenticated Proxy
|
|
914
|
-
|
|
915
|
-
```typescript
|
|
916
|
-
import rezo from 'rezo';
|
|
917
|
-
|
|
918
|
-
// Proxy with username/password authentication
|
|
919
|
-
const client = rezo.create({
|
|
920
|
-
proxy: {
|
|
921
|
-
protocol: 'http',
|
|
922
|
-
host: 'proxy.example.com',
|
|
923
|
-
port: 8080,
|
|
924
|
-
auth: {
|
|
925
|
-
username: 'proxyuser',
|
|
926
|
-
password: 'proxypass'
|
|
927
|
-
}
|
|
928
|
-
}
|
|
929
|
-
});
|
|
930
|
-
```
|
|
931
|
-
|
|
932
|
-
#### SOCKS4 Proxy
|
|
933
|
-
|
|
934
|
-
```typescript
|
|
935
|
-
import rezo from 'rezo';
|
|
936
|
-
|
|
937
|
-
// SOCKS4 Proxy - TCP connections only, no authentication
|
|
938
|
-
const client = rezo.create({
|
|
939
|
-
proxy: {
|
|
940
|
-
protocol: 'socks4',
|
|
941
|
-
host: 'socks4.example.com',
|
|
942
|
-
port: 1080
|
|
943
|
-
}
|
|
944
|
-
});
|
|
945
|
-
```
|
|
946
|
-
|
|
947
|
-
#### SOCKS5 Proxy
|
|
948
|
-
|
|
949
|
-
```typescript
|
|
950
|
-
import rezo from 'rezo';
|
|
951
|
-
|
|
952
|
-
// SOCKS5 Proxy - supports TCP, UDP, and authentication
|
|
953
|
-
const client = rezo.create({
|
|
954
|
-
proxy: {
|
|
955
|
-
protocol: 'socks5',
|
|
956
|
-
host: 'socks5.example.com',
|
|
957
|
-
port: 1080
|
|
958
|
-
}
|
|
959
|
-
});
|
|
960
|
-
|
|
961
|
-
// SOCKS5 with authentication
|
|
962
|
-
const authenticatedSocks = rezo.create({
|
|
963
|
-
proxy: {
|
|
964
|
-
protocol: 'socks5',
|
|
965
|
-
host: 'socks5.example.com',
|
|
966
|
-
port: 1080,
|
|
967
|
-
auth: {
|
|
968
|
-
username: 'socksuser',
|
|
969
|
-
password: 'sockspass'
|
|
970
|
-
}
|
|
971
|
-
}
|
|
972
|
-
});
|
|
973
|
-
|
|
974
|
-
// Using Tor network (typically SOCKS5 on port 9050)
|
|
975
|
-
const torClient = rezo.create({
|
|
976
|
-
proxy: {
|
|
977
|
-
protocol: 'socks5',
|
|
978
|
-
host: '127.0.0.1',
|
|
979
|
-
port: 9050
|
|
980
|
-
}
|
|
981
|
-
});
|
|
982
|
-
```
|
|
983
|
-
|
|
984
|
-
#### Per-Request Proxy Override
|
|
985
|
-
|
|
986
|
-
```typescript
|
|
987
|
-
import rezo from 'rezo';
|
|
988
|
-
|
|
989
|
-
const client = rezo.create({
|
|
990
|
-
proxy: {
|
|
991
|
-
protocol: 'http',
|
|
992
|
-
host: 'default-proxy.example.com',
|
|
993
|
-
port: 8080
|
|
994
|
-
}
|
|
995
|
-
});
|
|
996
|
-
|
|
997
|
-
// Use a different proxy for this specific request
|
|
998
|
-
await client.get('https://api.example.com/data', {
|
|
999
|
-
proxy: {
|
|
1000
|
-
protocol: 'https',
|
|
1001
|
-
host: 'different-proxy.example.com',
|
|
1002
|
-
port: 443
|
|
1003
|
-
}
|
|
1004
|
-
});
|
|
1005
|
-
|
|
1006
|
-
// Disable proxy for specific request (direct connection)
|
|
1007
|
-
await client.get('https://internal.example.com/data', {
|
|
1008
|
-
proxy: false
|
|
1009
|
-
});
|
|
1010
|
-
```
|
|
1011
|
-
|
|
1012
|
-
#### Proxy Configuration Interface
|
|
1013
|
-
|
|
1014
|
-
```typescript
|
|
1015
|
-
interface ProxyConfig {
|
|
1016
|
-
protocol: 'http' | 'https' | 'socks4' | 'socks5';
|
|
1017
|
-
host: string;
|
|
1018
|
-
port: number;
|
|
1019
|
-
auth?: {
|
|
1020
|
-
username: string;
|
|
1021
|
-
password: string;
|
|
1022
|
-
};
|
|
1023
|
-
}
|
|
1024
|
-
```
|
|
1025
|
-
|
|
1026
|
-
### Proxy Manager
|
|
1027
|
-
|
|
1028
|
-
Rezo includes a powerful Proxy Manager for enterprise scenarios requiring proxy rotation, health monitoring, and intelligent failover. The Proxy Manager automatically rotates through a pool of proxies, tracks their health, and removes failing proxies from circulation.
|
|
1029
|
-
|
|
1030
|
-
#### Basic Usage
|
|
1031
|
-
|
|
1032
|
-
```typescript
|
|
1033
|
-
import rezo, { ProxyManager } from 'rezo';
|
|
1034
|
-
|
|
1035
|
-
// Create a proxy manager with a pool of proxies
|
|
1036
|
-
const proxyManager = new ProxyManager({
|
|
1037
|
-
proxies: [
|
|
1038
|
-
{ protocol: 'http', host: 'proxy1.example.com', port: 8080 },
|
|
1039
|
-
{ protocol: 'http', host: 'proxy2.example.com', port: 8080 },
|
|
1040
|
-
{ protocol: 'socks5', host: 'proxy3.example.com', port: 1080 }
|
|
1041
|
-
]
|
|
1042
|
-
});
|
|
1043
|
-
|
|
1044
|
-
// Create client with proxy manager
|
|
1045
|
-
const client = rezo.create({
|
|
1046
|
-
proxyManager
|
|
1047
|
-
});
|
|
1048
|
-
|
|
1049
|
-
// Requests automatically rotate through available proxies
|
|
1050
|
-
await client.get('https://api.example.com/data');
|
|
1051
|
-
```
|
|
1052
|
-
|
|
1053
|
-
#### Rotation Strategies
|
|
1054
|
-
|
|
1055
|
-
```typescript
|
|
1056
|
-
import { ProxyManager } from 'rezo';
|
|
1057
|
-
|
|
1058
|
-
// Random rotation (default) - randomly selects from available proxies
|
|
1059
|
-
const randomManager = new ProxyManager({
|
|
1060
|
-
proxies: [...],
|
|
1061
|
-
rotationStrategy: 'random'
|
|
1062
|
-
});
|
|
1063
|
-
|
|
1064
|
-
// Sequential rotation - cycles through proxies in order
|
|
1065
|
-
const sequentialManager = new ProxyManager({
|
|
1066
|
-
proxies: [...],
|
|
1067
|
-
rotationStrategy: 'sequential'
|
|
1068
|
-
});
|
|
1069
|
-
|
|
1070
|
-
// Per-proxy limit - switches after N requests per proxy
|
|
1071
|
-
const limitManager = new ProxyManager({
|
|
1072
|
-
proxies: [...],
|
|
1073
|
-
rotationStrategy: 'per-proxy-limit',
|
|
1074
|
-
perProxyLimit: 100 // Switch after 100 requests
|
|
1075
|
-
});
|
|
1076
|
-
```
|
|
1077
|
-
|
|
1078
|
-
#### URL Filtering (Whitelist/Blacklist)
|
|
1079
|
-
|
|
1080
|
-
Control which URLs use the proxy manager with glob patterns or regular expressions:
|
|
1081
|
-
|
|
1082
|
-
```typescript
|
|
1083
|
-
import { ProxyManager } from 'rezo';
|
|
1084
|
-
|
|
1085
|
-
const proxyManager = new ProxyManager({
|
|
1086
|
-
proxies: [...],
|
|
1087
|
-
|
|
1088
|
-
// Only use proxies for these URL patterns (glob or regex)
|
|
1089
|
-
whitelist: [
|
|
1090
|
-
'*.example.com', // Glob pattern
|
|
1091
|
-
'https://api.service.io/*',
|
|
1092
|
-
/^https:\/\/secure\./ // Regex pattern
|
|
1093
|
-
],
|
|
1094
|
-
|
|
1095
|
-
// Never use proxies for these URLs
|
|
1096
|
-
blacklist: [
|
|
1097
|
-
'*.internal.company.com',
|
|
1098
|
-
'https://localhost/*'
|
|
1099
|
-
]
|
|
1100
|
-
});
|
|
1101
|
-
|
|
1102
|
-
const client = rezo.create({ proxyManager });
|
|
1103
|
-
|
|
1104
|
-
// Uses proxy (matches whitelist)
|
|
1105
|
-
await client.get('https://api.example.com/data');
|
|
1106
|
-
|
|
1107
|
-
// Direct connection (matches blacklist)
|
|
1108
|
-
await client.get('https://app.internal.company.com/status');
|
|
1109
|
-
```
|
|
1110
|
-
|
|
1111
|
-
#### Health Monitoring & Failover
|
|
1112
|
-
|
|
1113
|
-
The Proxy Manager automatically tracks proxy health and removes failing proxies:
|
|
1114
|
-
|
|
1115
|
-
```typescript
|
|
1116
|
-
import { ProxyManager } from 'rezo';
|
|
1117
|
-
|
|
1118
|
-
const proxyManager = new ProxyManager({
|
|
1119
|
-
proxies: [...],
|
|
1120
|
-
|
|
1121
|
-
// Mark proxy as dead after 5 consecutive failures
|
|
1122
|
-
maxFailures: 5,
|
|
1123
|
-
|
|
1124
|
-
// Re-enable dead proxies after 5 minutes cooldown
|
|
1125
|
-
cooldownPeriod: 5 * 60 * 1000,
|
|
1126
|
-
|
|
1127
|
-
// Fail request if no proxies available (vs direct connection)
|
|
1128
|
-
failWithoutProxy: true
|
|
1129
|
-
});
|
|
1130
|
-
|
|
1131
|
-
// Check proxy pool status
|
|
1132
|
-
const status = proxyManager.getStatus();
|
|
1133
|
-
console.log('Active proxies:', status.active);
|
|
1134
|
-
console.log('Disabled proxies:', status.disabled);
|
|
1135
|
-
console.log('Total proxies:', status.total);
|
|
1136
|
-
|
|
1137
|
-
// Check if proxies are available
|
|
1138
|
-
if (proxyManager.hasAvailableProxies()) {
|
|
1139
|
-
await client.get('https://api.example.com/data');
|
|
1140
|
-
}
|
|
1141
|
-
|
|
1142
|
-
// Reset all proxy states (re-enable all)
|
|
1143
|
-
proxyManager.reset();
|
|
1144
|
-
```
|
|
1145
|
-
|
|
1146
|
-
#### Lifecycle Hooks
|
|
1147
|
-
|
|
1148
|
-
Monitor and react to proxy events with lifecycle hooks:
|
|
1149
|
-
|
|
1150
|
-
```typescript
|
|
1151
|
-
import { ProxyManager } from 'rezo';
|
|
1152
|
-
|
|
1153
|
-
const proxyManager = new ProxyManager({
|
|
1154
|
-
proxies: [...],
|
|
1155
|
-
|
|
1156
|
-
hooks: {
|
|
1157
|
-
// Called before selecting a proxy
|
|
1158
|
-
beforeProxySelect: (url) => {
|
|
1159
|
-
console.log('Selecting proxy for:', url);
|
|
1160
|
-
},
|
|
1161
|
-
|
|
1162
|
-
// Called after proxy selection
|
|
1163
|
-
afterProxySelect: (proxy, url) => {
|
|
1164
|
-
console.log('Selected:', proxy.host);
|
|
1165
|
-
},
|
|
1166
|
-
|
|
1167
|
-
// Called before reporting a proxy error
|
|
1168
|
-
beforeProxyError: (proxy, error) => {
|
|
1169
|
-
console.log('Proxy failed:', proxy.host, error.message);
|
|
1170
|
-
},
|
|
1171
|
-
|
|
1172
|
-
// Called after error is recorded
|
|
1173
|
-
afterProxyError: (proxy, error, failureCount) => {
|
|
1174
|
-
console.log('Failure count:', failureCount);
|
|
1175
|
-
},
|
|
1176
|
-
|
|
1177
|
-
// Called when proxy is disabled
|
|
1178
|
-
afterProxyDisable: (proxy, reason) => {
|
|
1179
|
-
console.log('Proxy disabled:', proxy.host, reason);
|
|
1180
|
-
},
|
|
1181
|
-
|
|
1182
|
-
// Called when proxy is re-enabled
|
|
1183
|
-
afterProxyEnable: (proxy) => {
|
|
1184
|
-
console.log('Proxy re-enabled:', proxy.host);
|
|
1185
|
-
},
|
|
1186
|
-
|
|
1187
|
-
// Called after rotation occurs
|
|
1188
|
-
afterProxyRotate: (oldProxy, newProxy) => {
|
|
1189
|
-
console.log('Rotated from', oldProxy?.host, 'to', newProxy.host);
|
|
1190
|
-
}
|
|
1191
|
-
}
|
|
1192
|
-
});
|
|
1193
|
-
```
|
|
1194
|
-
|
|
1195
|
-
#### Instance-Level Hooks
|
|
1196
|
-
|
|
1197
|
-
You can also add proxy hooks at the instance level:
|
|
1198
|
-
|
|
1199
|
-
```typescript
|
|
1200
|
-
import rezo, { ProxyManager } from 'rezo';
|
|
1201
|
-
|
|
1202
|
-
const proxyManager = new ProxyManager({ proxies: [...] });
|
|
1203
|
-
|
|
1204
|
-
const client = rezo.create({
|
|
1205
|
-
proxyManager,
|
|
1206
|
-
hooks: {
|
|
1207
|
-
afterProxySelect: (proxy, url) => {
|
|
1208
|
-
console.log('Request will use proxy:', proxy.host);
|
|
1209
|
-
},
|
|
1210
|
-
afterProxyDisable: (proxy) => {
|
|
1211
|
-
// Alert monitoring system
|
|
1212
|
-
alertMonitoring('Proxy disabled', proxy.host);
|
|
1213
|
-
}
|
|
1214
|
-
}
|
|
1215
|
-
});
|
|
1216
|
-
```
|
|
1217
|
-
|
|
1218
|
-
#### Manual Proxy Control
|
|
1219
|
-
|
|
1220
|
-
Override Proxy Manager for specific requests:
|
|
1221
|
-
|
|
1222
|
-
```typescript
|
|
1223
|
-
import rezo, { ProxyManager } from 'rezo';
|
|
1224
|
-
|
|
1225
|
-
const proxyManager = new ProxyManager({ proxies: [...] });
|
|
1226
|
-
const client = rezo.create({ proxyManager });
|
|
1227
|
-
|
|
1228
|
-
// Use a specific proxy (bypasses Proxy Manager)
|
|
1229
|
-
await client.get('https://api.example.com/data', {
|
|
1230
|
-
proxy: {
|
|
1231
|
-
protocol: 'http',
|
|
1232
|
-
host: 'specific-proxy.example.com',
|
|
1233
|
-
port: 8080
|
|
1234
|
-
}
|
|
1235
|
-
});
|
|
1236
|
-
|
|
1237
|
-
// Direct connection (bypasses Proxy Manager)
|
|
1238
|
-
await client.get('https://api.example.com/data', {
|
|
1239
|
-
useProxyManager: false
|
|
1240
|
-
});
|
|
1241
|
-
```
|
|
1242
|
-
|
|
1243
|
-
#### Proxy Manager Configuration
|
|
1244
|
-
|
|
1245
|
-
```typescript
|
|
1246
|
-
interface ProxyManagerConfig {
|
|
1247
|
-
// Array of proxy configurations
|
|
1248
|
-
proxies: ProxyConfig[];
|
|
1249
|
-
|
|
1250
|
-
// Rotation strategy: 'random' | 'sequential' | 'per-proxy-limit'
|
|
1251
|
-
rotationStrategy?: string;
|
|
1252
|
-
|
|
1253
|
-
// Requests per proxy before rotation (for 'per-proxy-limit')
|
|
1254
|
-
perProxyLimit?: number;
|
|
1255
|
-
|
|
1256
|
-
// URL patterns to use with proxies (glob or regex)
|
|
1257
|
-
whitelist?: (string | RegExp)[];
|
|
1258
|
-
|
|
1259
|
-
// URL patterns to bypass proxies (glob or regex)
|
|
1260
|
-
blacklist?: (string | RegExp)[];
|
|
1261
|
-
|
|
1262
|
-
// Consecutive failures before disabling proxy
|
|
1263
|
-
maxFailures?: number;
|
|
1264
|
-
|
|
1265
|
-
// Milliseconds before re-enabling disabled proxy
|
|
1266
|
-
cooldownPeriod?: number;
|
|
1267
|
-
|
|
1268
|
-
// Throw error if no proxy available (vs direct connection)
|
|
1269
|
-
failWithoutProxy?: boolean;
|
|
1270
|
-
|
|
1271
|
-
// Lifecycle hooks
|
|
1272
|
-
hooks?: ProxyManagerHooks;
|
|
1273
|
-
}
|
|
1274
|
-
```
|
|
1275
|
-
|
|
1276
|
-
#### Adapter Support
|
|
1277
|
-
|
|
1278
|
-
| Adapter | Proxy Manager Support |
|
|
1279
|
-
|---------|----------------------|
|
|
1280
|
-
| HTTP | Full support |
|
|
1281
|
-
| HTTP/2 | Full support |
|
|
1282
|
-
| cURL | Full support |
|
|
1283
|
-
| Fetch | Not supported (browser security) |
|
|
1284
|
-
| React Native | Not supported (platform limitations) |
|
|
1285
|
-
|
|
1286
|
-
### Request Queue
|
|
1287
|
-
|
|
1288
|
-
Rezo includes a built-in zero-dependency request queue system for rate limiting, priority management, and concurrency control.
|
|
1289
|
-
|
|
1290
|
-
#### RezoQueue - General Purpose Queue
|
|
1291
|
-
|
|
1292
|
-
```typescript
|
|
1293
|
-
import { RezoQueue, Priority } from 'rezo';
|
|
1294
|
-
|
|
1295
|
-
const queue = new RezoQueue({
|
|
1296
|
-
concurrency: 5, // Max concurrent tasks
|
|
1297
|
-
interval: 1000, // Rate limit interval (ms)
|
|
1298
|
-
intervalCap: 10, // Max tasks per interval
|
|
1299
|
-
timeout: 30000, // Task timeout (ms)
|
|
1300
|
-
autoStart: true // Start processing immediately
|
|
1301
|
-
});
|
|
1302
|
-
|
|
1303
|
-
// Add tasks with priority
|
|
1304
|
-
queue.add(async () => {
|
|
1305
|
-
return await fetch('https://api.example.com/data');
|
|
1306
|
-
}, { priority: Priority.HIGH });
|
|
1307
|
-
|
|
1308
|
-
// Priority constants: LOWEST (0), LOW (25), NORMAL (50), HIGH (75), HIGHEST (100), CRITICAL (1000)
|
|
1309
|
-
|
|
1310
|
-
// Event handling
|
|
1311
|
-
queue.on('completed', ({ id, result, duration }) => {
|
|
1312
|
-
console.log(`Task ${id} completed in ${duration}ms`);
|
|
1313
|
-
});
|
|
1314
|
-
|
|
1315
|
-
queue.on('error', ({ id, error }) => {
|
|
1316
|
-
console.error(`Task ${id} failed:`, error);
|
|
1317
|
-
});
|
|
1318
|
-
|
|
1319
|
-
// Queue control
|
|
1320
|
-
queue.pause();
|
|
1321
|
-
queue.resume();
|
|
1322
|
-
queue.cancel(taskId);
|
|
1323
|
-
queue.clear();
|
|
1324
|
-
|
|
1325
|
-
// Statistics
|
|
1326
|
-
const stats = queue.stats();
|
|
1327
|
-
console.log(`Completed: ${stats.completed}, Failed: ${stats.failed}`);
|
|
1328
|
-
```
|
|
1329
|
-
|
|
1330
|
-
#### HttpQueue - HTTP-Aware Queue
|
|
1331
|
-
|
|
1332
|
-
```typescript
|
|
1333
|
-
import { HttpQueue, HttpMethodPriority } from 'rezo';
|
|
1334
|
-
|
|
1335
|
-
const httpQueue = new HttpQueue({
|
|
1336
|
-
concurrency: 10,
|
|
1337
|
-
perDomainConcurrency: 2, // Limit concurrent requests per domain
|
|
1338
|
-
retryOnRateLimit: true, // Auto-retry on 429 responses
|
|
1339
|
-
maxRetries: 3,
|
|
1340
|
-
retryDelay: 1000
|
|
1341
|
-
});
|
|
1342
|
-
|
|
1343
|
-
// Add HTTP requests
|
|
1344
|
-
const result = await httpQueue.addHttp(
|
|
1345
|
-
'https://api.example.com/users',
|
|
1346
|
-
async () => fetch('https://api.example.com/users'),
|
|
1347
|
-
{
|
|
1348
|
-
priority: HttpMethodPriority.GET, // GET=75, POST=50, DELETE=25
|
|
1349
|
-
timeout: 10000
|
|
1350
|
-
}
|
|
1351
|
-
);
|
|
1352
|
-
|
|
1353
|
-
// Domain-specific control
|
|
1354
|
-
httpQueue.pauseDomain('api.example.com');
|
|
1355
|
-
httpQueue.resumeDomain('api.example.com');
|
|
1356
|
-
|
|
1357
|
-
// Rate limit handling
|
|
1358
|
-
httpQueue.onHttp('rateLimited', ({ domain, retryAfter }) => {
|
|
1359
|
-
console.log(`Rate limited on ${domain}, retry in ${retryAfter}s`);
|
|
1360
|
-
});
|
|
1361
|
-
|
|
1362
|
-
// Per-domain statistics
|
|
1363
|
-
const domainStats = httpQueue.httpStats();
|
|
1364
|
-
console.log(domainStats.byDomain['api.example.com']);
|
|
1365
|
-
```
|
|
1366
|
-
|
|
1367
|
-
#### Queue Events
|
|
1368
|
-
|
|
1369
|
-
| Event | Description |
|
|
1370
|
-
|-------|-------------|
|
|
1371
|
-
| `add` | Task added to queue |
|
|
1372
|
-
| `start` | Task started processing |
|
|
1373
|
-
| `completed` | Task completed successfully |
|
|
1374
|
-
| `error` | Task failed with error |
|
|
1375
|
-
| `timeout` | Task timed out |
|
|
1376
|
-
| `cancelled` | Task was cancelled |
|
|
1377
|
-
| `active` | Queue became active |
|
|
1378
|
-
| `idle` | Queue became idle |
|
|
1379
|
-
| `empty` | Queue is empty |
|
|
1380
|
-
| `rateLimited` | Rate limit detected (HttpQueue) |
|
|
1381
|
-
| `retry` | Task being retried (HttpQueue) |
|
|
1382
|
-
|
|
1383
|
-
### Streaming
|
|
1384
|
-
|
|
1385
|
-
Rezo provides powerful streaming capabilities for handling large data efficiently.
|
|
1386
|
-
|
|
1387
|
-
```typescript
|
|
1388
|
-
import rezo from 'rezo';
|
|
1389
|
-
import { createWriteStream } from 'fs';
|
|
1390
|
-
|
|
1391
|
-
const client = rezo.create();
|
|
1392
|
-
|
|
1393
|
-
// Stream response to file
|
|
1394
|
-
const response = await client.get('https://example.com/large-file.zip', {
|
|
1395
|
-
responseType: 'stream'
|
|
1396
|
-
});
|
|
1397
|
-
|
|
1398
|
-
const writer = createWriteStream('./download.zip');
|
|
1399
|
-
response.data.pipe(writer);
|
|
1400
|
-
|
|
1401
|
-
await new Promise((resolve, reject) => {
|
|
1402
|
-
writer.on('finish', resolve);
|
|
1403
|
-
writer.on('error', reject);
|
|
1404
|
-
});
|
|
1405
|
-
|
|
1406
|
-
// Stream request body
|
|
1407
|
-
import { createReadStream } from 'fs';
|
|
1408
|
-
|
|
1409
|
-
await client.post('https://api.example.com/upload', createReadStream('./file.txt'), {
|
|
1410
|
-
headers: {
|
|
1411
|
-
'Content-Type': 'application/octet-stream'
|
|
1412
|
-
}
|
|
1413
|
-
});
|
|
1414
|
-
```
|
|
1415
|
-
|
|
1416
|
-
### File Downloads
|
|
1417
|
-
|
|
1418
|
-
Rezo provides a dedicated download API with progress tracking.
|
|
1419
|
-
|
|
1420
|
-
```typescript
|
|
1421
|
-
import rezo, { DownloadResponse } from 'rezo';
|
|
1422
|
-
|
|
1423
|
-
const client = rezo.create();
|
|
1424
|
-
|
|
1425
|
-
// Download with progress
|
|
1426
|
-
const download = await client.download('https://example.com/file.zip', {
|
|
1427
|
-
outputPath: './downloads/file.zip'
|
|
1428
|
-
});
|
|
1429
|
-
|
|
1430
|
-
download.on('progress', (progress) => {
|
|
1431
|
-
console.log(`Downloaded: ${progress.percent}%`);
|
|
1432
|
-
console.log(`Speed: ${progress.speed} bytes/sec`);
|
|
1433
|
-
console.log(`ETA: ${progress.eta} seconds`);
|
|
1434
|
-
});
|
|
1435
|
-
|
|
1436
|
-
download.on('complete', (result) => {
|
|
1437
|
-
console.log('Download complete:', result.path);
|
|
1438
|
-
console.log('Total size:', result.size);
|
|
1439
|
-
console.log('Duration:', result.duration);
|
|
1440
|
-
});
|
|
1441
|
-
|
|
1442
|
-
download.on('error', (error) => {
|
|
1443
|
-
console.error('Download failed:', error.message);
|
|
1444
|
-
});
|
|
1445
|
-
|
|
1446
|
-
// Wait for completion
|
|
1447
|
-
await download.finished();
|
|
1448
|
-
```
|
|
1449
|
-
|
|
1450
|
-
### File Uploads
|
|
1451
|
-
|
|
1452
|
-
Upload files with progress tracking and multipart support.
|
|
1453
|
-
|
|
1454
|
-
```typescript
|
|
1455
|
-
import rezo, { FormData } from 'rezo';
|
|
1456
|
-
import { createReadStream } from 'fs';
|
|
1457
|
-
|
|
1458
|
-
const client = rezo.create();
|
|
1459
|
-
|
|
1460
|
-
// Simple file upload
|
|
1461
|
-
const formData = new FormData();
|
|
1462
|
-
formData.append('file', createReadStream('./document.pdf'));
|
|
1463
|
-
formData.append('name', 'My Document');
|
|
1464
|
-
|
|
1465
|
-
const response = await client.post('https://api.example.com/upload', formData, {
|
|
1466
|
-
onUploadProgress: (progress) => {
|
|
1467
|
-
console.log(`Uploaded: ${Math.round(progress.loaded / progress.total * 100)}%`);
|
|
1468
|
-
}
|
|
1469
|
-
});
|
|
1470
|
-
|
|
1471
|
-
// Upload with detailed progress
|
|
1472
|
-
const upload = await client.upload('https://api.example.com/upload', {
|
|
1473
|
-
file: createReadStream('./large-file.zip'),
|
|
1474
|
-
filename: 'archive.zip'
|
|
1475
|
-
});
|
|
1476
|
-
|
|
1477
|
-
upload.on('progress', (progress) => {
|
|
1478
|
-
console.log(`Uploaded: ${progress.percent}%`);
|
|
1479
|
-
});
|
|
1480
|
-
|
|
1481
|
-
await upload.finished();
|
|
1482
|
-
console.log('Upload complete:', upload.response.data);
|
|
1483
|
-
```
|
|
1484
|
-
|
|
1485
|
-
### Hooks & Interceptors
|
|
1486
|
-
|
|
1487
|
-
Rezo provides a powerful hooks system for request/response interception.
|
|
1488
|
-
|
|
1489
|
-
```typescript
|
|
1490
|
-
import rezo from 'rezo';
|
|
1491
|
-
|
|
1492
|
-
const client = rezo.create({
|
|
1493
|
-
baseURL: 'https://api.example.com'
|
|
1494
|
-
});
|
|
1495
|
-
|
|
1496
|
-
// Before request hook
|
|
1497
|
-
client.hooks.beforeRequest.push((options) => {
|
|
1498
|
-
// Add timestamp to all requests
|
|
1499
|
-
options.headers['X-Request-Time'] = Date.now().toString();
|
|
1500
|
-
|
|
1501
|
-
// Log outgoing requests
|
|
1502
|
-
console.log(`-> ${options.method} ${options.url}`);
|
|
1503
|
-
|
|
1504
|
-
return options;
|
|
1505
|
-
});
|
|
1506
|
-
|
|
1507
|
-
// After response hook
|
|
1508
|
-
client.hooks.afterResponse.push((response, options) => {
|
|
1509
|
-
// Log responses
|
|
1510
|
-
console.log(`<- ${response.status} ${options.url}`);
|
|
1511
|
-
|
|
1512
|
-
// Transform response data
|
|
1513
|
-
if (response.data && typeof response.data === 'object') {
|
|
1514
|
-
response.data._receivedAt = new Date().toISOString();
|
|
1515
|
-
}
|
|
1516
|
-
|
|
1517
|
-
return response;
|
|
1518
|
-
});
|
|
1519
|
-
|
|
1520
|
-
// Before retry hook
|
|
1521
|
-
client.hooks.beforeRetry.push((error, retryCount) => {
|
|
1522
|
-
console.log(`Retry attempt ${retryCount} for ${error.config.url}`);
|
|
1523
|
-
|
|
1524
|
-
// Optionally modify the request before retry
|
|
1525
|
-
error.config.headers['X-Retry-Count'] = retryCount.toString();
|
|
1526
|
-
});
|
|
1527
|
-
|
|
1528
|
-
// Before error hook (transform errors)
|
|
1529
|
-
client.hooks.beforeError.push((error) => {
|
|
1530
|
-
// Add additional context to errors
|
|
1531
|
-
error.timestamp = new Date().toISOString();
|
|
1532
|
-
error.requestId = error.config?.headers?.['X-Request-ID'];
|
|
1533
|
-
|
|
1534
|
-
return error;
|
|
1535
|
-
});
|
|
1536
|
-
|
|
1537
|
-
// Authentication refresh example
|
|
1538
|
-
client.hooks.afterResponse.push(async (response, options, client) => {
|
|
1539
|
-
if (response.status === 401 && !options._retry) {
|
|
1540
|
-
// Refresh token
|
|
1541
|
-
const refreshResponse = await client.post('/auth/refresh', {
|
|
1542
|
-
refreshToken: getRefreshToken()
|
|
1543
|
-
});
|
|
1544
|
-
|
|
1545
|
-
// Update authorization header
|
|
1546
|
-
const newToken = refreshResponse.data.accessToken;
|
|
1547
|
-
client.defaults.headers['Authorization'] = `Bearer ${newToken}`;
|
|
1548
|
-
|
|
1549
|
-
// Retry original request
|
|
1550
|
-
options._retry = true;
|
|
1551
|
-
return client.request(options);
|
|
1552
|
-
}
|
|
1553
|
-
|
|
1554
|
-
return response;
|
|
1555
|
-
});
|
|
1556
|
-
```
|
|
1557
|
-
|
|
1558
|
-
### Retry Logic
|
|
1559
|
-
|
|
1560
|
-
Configure automatic retry with exponential backoff.
|
|
1561
|
-
|
|
1562
|
-
```typescript
|
|
1563
|
-
import rezo from 'rezo';
|
|
1564
|
-
|
|
1565
|
-
const client = rezo.create({
|
|
1566
|
-
retry: {
|
|
1567
|
-
limit: 3, // Maximum retry attempts
|
|
1568
|
-
delay: 1000, // Initial delay (ms)
|
|
1569
|
-
maxDelay: 30000, // Maximum delay (ms)
|
|
1570
|
-
backoff: 2, // Exponential backoff multiplier
|
|
1571
|
-
retryOn: [408, 429, 500, 502, 503, 504] // Status codes to retry
|
|
1572
|
-
}
|
|
1573
|
-
});
|
|
1574
|
-
|
|
1575
|
-
// Custom retry logic
|
|
1576
|
-
const customClient = rezo.create({
|
|
1577
|
-
retry: {
|
|
1578
|
-
limit: 5,
|
|
1579
|
-
retryOn: (error, attemptNumber) => {
|
|
1580
|
-
// Retry on network errors
|
|
1581
|
-
if (error.code === 'ECONNRESET' || error.code === 'ETIMEDOUT') {
|
|
1582
|
-
return true;
|
|
1583
|
-
}
|
|
1584
|
-
|
|
1585
|
-
// Retry on specific status codes
|
|
1586
|
-
if (error.response?.status >= 500) {
|
|
1587
|
-
return true;
|
|
1588
|
-
}
|
|
1589
|
-
|
|
1590
|
-
// Don't retry on 4xx errors (except 429)
|
|
1591
|
-
if (error.response?.status === 429) {
|
|
1592
|
-
return true;
|
|
1593
|
-
}
|
|
1594
|
-
|
|
1595
|
-
return false;
|
|
1596
|
-
}
|
|
1597
|
-
}
|
|
1598
|
-
});
|
|
1599
|
-
|
|
1600
|
-
// Per-request retry configuration
|
|
1601
|
-
await client.get('https://api.example.com/data', {
|
|
1602
|
-
retry: {
|
|
1603
|
-
limit: 10,
|
|
1604
|
-
delay: 500
|
|
1605
|
-
}
|
|
1606
|
-
});
|
|
1607
|
-
|
|
1608
|
-
// Disable retry for specific request
|
|
1609
|
-
await client.get('https://api.example.com/critical', {
|
|
1610
|
-
retry: false
|
|
1611
|
-
});
|
|
1612
|
-
```
|
|
1613
|
-
|
|
1614
|
-
### Error Handling
|
|
1615
|
-
|
|
1616
|
-
Rezo provides structured errors with actionable information.
|
|
1617
|
-
|
|
1618
|
-
```typescript
|
|
1619
|
-
import rezo, { RezoError, isRezoError, RezoErrorCode } from 'rezo';
|
|
1620
|
-
|
|
1621
|
-
const client = rezo.create();
|
|
1622
|
-
|
|
1623
|
-
try {
|
|
1624
|
-
await client.get('https://api.example.com/data');
|
|
1625
|
-
} catch (error) {
|
|
1626
|
-
if (isRezoError(error)) {
|
|
1627
|
-
// Access structured error information
|
|
1628
|
-
console.log('Error Code:', error.code);
|
|
1629
|
-
console.log('Message:', error.message);
|
|
1630
|
-
console.log('Details:', error.details);
|
|
1631
|
-
console.log('Suggestion:', error.suggestion);
|
|
1632
|
-
|
|
1633
|
-
// Check error type
|
|
1634
|
-
if (error.isTimeout) {
|
|
1635
|
-
console.log('Request timed out');
|
|
1636
|
-
}
|
|
1637
|
-
|
|
1638
|
-
if (error.isNetworkError) {
|
|
1639
|
-
console.log('Network error occurred');
|
|
1640
|
-
}
|
|
1641
|
-
|
|
1642
|
-
if (error.isHttpError) {
|
|
1643
|
-
console.log('HTTP error:', error.status, error.statusText);
|
|
1644
|
-
console.log('Response data:', error.response?.data);
|
|
1645
|
-
}
|
|
1646
|
-
|
|
1647
|
-
if (error.isProxyError) {
|
|
1648
|
-
console.log('Proxy connection failed');
|
|
1649
|
-
}
|
|
1650
|
-
|
|
1651
|
-
if (error.isTlsError) {
|
|
1652
|
-
console.log('TLS/SSL error');
|
|
1653
|
-
}
|
|
1654
|
-
|
|
1655
|
-
// Check if error is retryable
|
|
1656
|
-
if (error.isRetryable) {
|
|
1657
|
-
console.log('This error can be retried');
|
|
1658
|
-
}
|
|
1659
|
-
|
|
1660
|
-
// Access original request configuration
|
|
1661
|
-
console.log('Request URL:', error.config?.url);
|
|
1662
|
-
console.log('Request Method:', error.config?.method);
|
|
1663
|
-
|
|
1664
|
-
// Serialize error (hides sensitive data)
|
|
1665
|
-
console.log('Error JSON:', JSON.stringify(error));
|
|
1666
|
-
}
|
|
1667
|
-
}
|
|
1668
|
-
|
|
1669
|
-
// Error code enumeration
|
|
1670
|
-
switch (error.code) {
|
|
1671
|
-
case RezoErrorCode.TIMEOUT:
|
|
1672
|
-
// Handle timeout
|
|
1673
|
-
break;
|
|
1674
|
-
case RezoErrorCode.NETWORK_ERROR:
|
|
1675
|
-
// Handle network error
|
|
1676
|
-
break;
|
|
1677
|
-
case RezoErrorCode.PROXY_ERROR:
|
|
1678
|
-
// Handle proxy error
|
|
1679
|
-
break;
|
|
1680
|
-
case RezoErrorCode.TLS_ERROR:
|
|
1681
|
-
// Handle TLS error
|
|
1682
|
-
break;
|
|
1683
|
-
case RezoErrorCode.HTTP_ERROR:
|
|
1684
|
-
// Handle HTTP error
|
|
1685
|
-
break;
|
|
1686
|
-
}
|
|
1687
|
-
```
|
|
1688
|
-
|
|
1689
|
-
### Performance Metrics
|
|
1690
|
-
|
|
1691
|
-
Track detailed timing information for performance monitoring.
|
|
1692
|
-
|
|
1693
|
-
```typescript
|
|
1694
|
-
import rezo, { RezoPerformance } from 'rezo';
|
|
1695
|
-
|
|
1696
|
-
const client = rezo.create({
|
|
1697
|
-
timing: true // Enable timing collection
|
|
1698
|
-
});
|
|
1699
|
-
|
|
1700
|
-
const response = await client.get('https://api.example.com/data');
|
|
1701
|
-
|
|
1702
|
-
// Access timing metrics
|
|
1703
|
-
const timing = response.timing;
|
|
1704
|
-
console.log('DNS Lookup:', timing.dns, 'ms');
|
|
1705
|
-
console.log('TCP Connect:', timing.connect, 'ms');
|
|
1706
|
-
console.log('TLS Handshake:', timing.tls, 'ms');
|
|
1707
|
-
console.log('Time to First Byte:', timing.firstByte, 'ms');
|
|
1708
|
-
console.log('Download Time:', timing.download, 'ms');
|
|
1709
|
-
console.log('Total Time:', timing.total, 'ms');
|
|
1710
|
-
|
|
1711
|
-
// Using RezoPerformance utility
|
|
1712
|
-
const perf = new RezoPerformance();
|
|
1713
|
-
|
|
1714
|
-
perf.mark('start');
|
|
1715
|
-
await client.get('https://api.example.com/data');
|
|
1716
|
-
perf.mark('end');
|
|
1717
|
-
|
|
1718
|
-
const metrics = perf.measure('request', 'start', 'end');
|
|
1719
|
-
console.log('Request Duration:', metrics.duration, 'ms');
|
|
1720
|
-
```
|
|
1721
|
-
|
|
1722
|
-
---
|
|
1723
|
-
|
|
1724
|
-
## Platform Support
|
|
1725
|
-
|
|
1726
|
-
Rezo is designed for universal JavaScript environments with platform-specific optimizations.
|
|
1727
|
-
|
|
1728
|
-
### Node.js
|
|
1729
|
-
|
|
1730
|
-
Full feature support including all adapters, cookie management, proxy, and streaming.
|
|
1731
|
-
|
|
1732
|
-
```typescript
|
|
1733
|
-
import rezo from 'rezo';
|
|
1734
|
-
// or
|
|
1735
|
-
import rezo from 'rezo/platform/node';
|
|
1736
|
-
```
|
|
1737
|
-
|
|
1738
|
-
### Bun
|
|
1739
|
-
|
|
1740
|
-
Optimized for Bun runtime with native performance.
|
|
1741
|
-
|
|
1742
|
-
```typescript
|
|
1743
|
-
import rezo from 'rezo';
|
|
1744
|
-
// or
|
|
1745
|
-
import rezo from 'rezo/platform/bun';
|
|
1746
|
-
```
|
|
1747
|
-
|
|
1748
|
-
### Deno
|
|
1749
|
-
|
|
1750
|
-
Compatible with Deno's Node.js compatibility layer.
|
|
1751
|
-
|
|
1752
|
-
```typescript
|
|
1753
|
-
import rezo from 'npm:rezo';
|
|
1754
|
-
// or
|
|
1755
|
-
import rezo from 'npm:rezo/platform/deno';
|
|
1756
|
-
```
|
|
1757
|
-
|
|
1758
|
-
### Browser
|
|
1759
|
-
|
|
1760
|
-
Lightweight Fetch-based implementation for browsers.
|
|
1761
|
-
|
|
1762
|
-
```typescript
|
|
1763
|
-
import rezo from 'rezo';
|
|
1764
|
-
// or
|
|
1765
|
-
import rezo from 'rezo/platform/browser';
|
|
1766
|
-
```
|
|
1767
|
-
|
|
1768
|
-
### Cloudflare Workers & Edge Runtimes
|
|
1769
|
-
|
|
1770
|
-
Edge-compatible Fetch adapter with minimal footprint.
|
|
1771
|
-
|
|
1772
|
-
```typescript
|
|
1773
|
-
import rezo from 'rezo';
|
|
1774
|
-
// or
|
|
1775
|
-
import rezo from 'rezo/platform/worker';
|
|
1776
|
-
```
|
|
1777
|
-
|
|
1778
|
-
### React Native
|
|
1779
|
-
|
|
1780
|
-
Mobile-optimized adapter with file system integration.
|
|
1781
|
-
|
|
1782
|
-
```typescript
|
|
1783
|
-
import rezo from 'rezo';
|
|
1784
|
-
// or
|
|
1785
|
-
import rezo from 'rezo/platform/react-native';
|
|
1786
|
-
```
|
|
1787
|
-
|
|
1788
|
-
---
|
|
1789
|
-
|
|
1790
|
-
## Migration Guide
|
|
1791
|
-
|
|
1792
|
-
### Migrating from Fetch API
|
|
1793
|
-
|
|
1794
|
-
```typescript
|
|
1795
|
-
// Before (Fetch)
|
|
1796
|
-
const response = await fetch('https://api.example.com/data', {
|
|
1797
|
-
method: 'POST',
|
|
1798
|
-
headers: { 'Content-Type': 'application/json' },
|
|
1799
|
-
body: JSON.stringify({ name: 'John' })
|
|
1800
|
-
});
|
|
1801
|
-
const data = await response.json();
|
|
1802
|
-
|
|
1803
|
-
// After (Rezo)
|
|
1804
|
-
const response = await rezo.post('https://api.example.com/data', {
|
|
1805
|
-
name: 'John'
|
|
1806
|
-
});
|
|
1807
|
-
const data = response.data; // Automatically parsed
|
|
1808
|
-
```
|
|
1809
|
-
|
|
1810
|
-
### Migrating from Got
|
|
1811
|
-
|
|
1812
|
-
```typescript
|
|
1813
|
-
// Before (Got)
|
|
1814
|
-
import got from 'got';
|
|
1815
|
-
const response = await got.post('https://api.example.com/data', {
|
|
1816
|
-
json: { name: 'John' },
|
|
1817
|
-
responseType: 'json',
|
|
1818
|
-
retry: { limit: 3 }
|
|
1819
|
-
});
|
|
1820
|
-
|
|
1821
|
-
// After (Rezo)
|
|
1822
|
-
import rezo from 'rezo';
|
|
1823
|
-
const response = await rezo.post('https://api.example.com/data',
|
|
1824
|
-
{ name: 'John' },
|
|
1825
|
-
{ retry: { limit: 3 } }
|
|
1826
|
-
);
|
|
1827
|
-
```
|
|
1828
|
-
|
|
1829
|
-
### Migrating from Node-Fetch
|
|
1830
|
-
|
|
1831
|
-
```typescript
|
|
1832
|
-
// Before (node-fetch)
|
|
1833
|
-
import fetch from 'node-fetch';
|
|
1834
|
-
const response = await fetch('https://api.example.com/data');
|
|
1835
|
-
const data = await response.json();
|
|
1836
|
-
|
|
1837
|
-
// After (Rezo)
|
|
1838
|
-
import rezo from 'rezo';
|
|
1839
|
-
const { data } = await rezo.get('https://api.example.com/data');
|
|
1840
|
-
```
|
|
1841
|
-
|
|
1842
|
-
---
|
|
1843
|
-
|
|
1844
|
-
## TypeScript
|
|
1845
|
-
|
|
1846
|
-
Rezo is written in TypeScript and provides comprehensive type definitions.
|
|
1847
|
-
|
|
1848
|
-
### Generic Response Types
|
|
1849
|
-
|
|
1850
|
-
```typescript
|
|
1851
|
-
import rezo from 'rezo';
|
|
1852
|
-
|
|
1853
|
-
interface User {
|
|
1854
|
-
id: number;
|
|
1855
|
-
name: string;
|
|
1856
|
-
email: string;
|
|
1857
|
-
}
|
|
1858
|
-
|
|
1859
|
-
interface ApiResponse<T> {
|
|
1860
|
-
data: T;
|
|
1861
|
-
meta: { total: number; page: number };
|
|
1862
|
-
}
|
|
1863
|
-
|
|
1864
|
-
const client = rezo.create({ baseURL: 'https://api.example.com' });
|
|
1865
|
-
|
|
1866
|
-
// Typed response
|
|
1867
|
-
const response = await client.get<User>('/users/1');
|
|
1868
|
-
const user: User = response.data;
|
|
1869
|
-
|
|
1870
|
-
// Nested generic types
|
|
1871
|
-
const listResponse = await client.get<ApiResponse<User[]>>('/users');
|
|
1872
|
-
const users: User[] = listResponse.data.data;
|
|
1873
|
-
const total: number = listResponse.data.meta.total;
|
|
1874
|
-
```
|
|
1875
|
-
|
|
1876
|
-
### Request Configuration Types
|
|
1877
|
-
|
|
1878
|
-
```typescript
|
|
1879
|
-
import { RezoConfig, RezoResponse, RezoError } from 'rezo';
|
|
1880
|
-
|
|
1881
|
-
// Type-safe configuration
|
|
1882
|
-
const config: RezoConfig = {
|
|
1883
|
-
baseURL: 'https://api.example.com',
|
|
1884
|
-
timeout: 30000,
|
|
1885
|
-
headers: {
|
|
1886
|
-
'Authorization': 'Bearer token'
|
|
1887
|
-
}
|
|
1888
|
-
};
|
|
1889
|
-
|
|
1890
|
-
// Type-safe error handling
|
|
1891
|
-
function handleError(error: RezoError): void {
|
|
1892
|
-
if (error.isHttpError) {
|
|
1893
|
-
console.log('Status:', error.status);
|
|
1894
|
-
}
|
|
1895
|
-
}
|
|
1896
|
-
```
|
|
1897
|
-
|
|
1898
|
-
### Custom Type Guards
|
|
1899
|
-
|
|
1900
|
-
```typescript
|
|
1901
|
-
import { isRezoError, RezoError } from 'rezo';
|
|
1902
|
-
|
|
1903
|
-
try {
|
|
1904
|
-
await rezo.get('/data');
|
|
1905
|
-
} catch (error) {
|
|
1906
|
-
if (isRezoError(error)) {
|
|
1907
|
-
// TypeScript knows error is RezoError here
|
|
1908
|
-
console.log(error.code);
|
|
1909
|
-
console.log(error.details);
|
|
1910
|
-
}
|
|
1911
|
-
}
|
|
1912
|
-
```
|
|
1913
|
-
|
|
1914
|
-
---
|
|
1915
|
-
|
|
1916
|
-
## Crawler Module
|
|
1917
|
-
|
|
1918
|
-
Rezo includes a powerful web crawler module for web scraping scenarios.
|
|
1919
|
-
|
|
1920
|
-
```typescript
|
|
1921
|
-
import { Crawler, CrawlerOptions } from 'rezo/crawler';
|
|
1922
|
-
|
|
1923
|
-
const options = new CrawlerOptions()
|
|
1924
|
-
.setGlobalProxy({ host: 'proxy.example.com', port: 8080 })
|
|
1925
|
-
.setGlobalHeaders({ 'User-Agent': 'Mozilla/5.0...' })
|
|
1926
|
-
.addLimiter({ domain: 'example.com', concurrency: 2, interval: 1000 });
|
|
1927
|
-
|
|
1928
|
-
const crawler = new Crawler(options);
|
|
1929
|
-
|
|
1930
|
-
crawler.onDocument(async (doc, url) => {
|
|
1931
|
-
const title = doc.querySelector('title')?.textContent;
|
|
1932
|
-
console.log(`Title: ${title}`);
|
|
1933
|
-
});
|
|
1934
|
-
|
|
1935
|
-
crawler.onAnchor((href, anchor) => {
|
|
1936
|
-
console.log(`Found link: ${href}`);
|
|
1937
|
-
});
|
|
1938
|
-
|
|
1939
|
-
await crawler.crawl('https://example.com');
|
|
1940
|
-
```
|
|
1941
|
-
|
|
1942
|
-
---
|
|
1943
|
-
|
|
1944
|
-
## DOM Module
|
|
1945
|
-
|
|
1946
|
-
Rezo provides a lightweight DOM parsing module for server-side HTML manipulation. Built on [linkedom](https://github.com/WebReflection/linkedom), it enables fast, standards-compliant DOM operations in Node, Bun, Deno or Edge environments - perfect for web scraping, HTML transformation, and testing.
|
|
1947
|
-
|
|
1948
|
-
### Parsing HTML
|
|
1949
|
-
|
|
1950
|
-
```typescript
|
|
1951
|
-
import { parseHTML } from 'rezo/dom';
|
|
1952
|
-
|
|
1953
|
-
// Parse HTML and work with the document
|
|
1954
|
-
const { document, window } = parseHTML(`
|
|
1955
|
-
<html>
|
|
1956
|
-
<body>
|
|
1957
|
-
<h1>Hello World</h1>
|
|
1958
|
-
<ul id="items">
|
|
1959
|
-
<li>Item 1</li>
|
|
1960
|
-
<li>Item 2</li>
|
|
1961
|
-
</ul>
|
|
1962
|
-
</body>
|
|
1963
|
-
</html>
|
|
1964
|
-
`);
|
|
1965
|
-
|
|
1966
|
-
// Use familiar DOM APIs
|
|
1967
|
-
console.log(document.querySelector('h1')?.textContent); // 'Hello World'
|
|
1968
|
-
console.log(document.querySelectorAll('li').length); // 2
|
|
1969
|
-
```
|
|
1970
|
-
|
|
1971
|
-
### Using with Rezo HTTP Client
|
|
1972
|
-
|
|
1973
|
-
```typescript
|
|
1974
|
-
import rezo from 'rezo';
|
|
1975
|
-
import { parseHTML } from 'rezo/dom';
|
|
1976
|
-
|
|
1977
|
-
// Fetch and parse a webpage
|
|
1978
|
-
const { data: html } = await rezo.get('https://example.com');
|
|
1979
|
-
const { document } = parseHTML(html);
|
|
1980
|
-
|
|
1981
|
-
// Extract data from the page
|
|
1982
|
-
const title = document.querySelector('title')?.textContent;
|
|
1983
|
-
const links = [...document.querySelectorAll('a')].map(a => a.getAttribute('href'));
|
|
1984
|
-
```
|
|
1985
|
-
|
|
1986
|
-
### DOMParser Interface
|
|
1987
|
-
|
|
1988
|
-
```typescript
|
|
1989
|
-
import { DOMParser } from 'rezo/dom';
|
|
1990
|
-
|
|
1991
|
-
const parser = new DOMParser();
|
|
1992
|
-
const doc = parser.parseFromString('<div class="content">Text</div>', 'text/html');
|
|
1993
|
-
console.log(doc.querySelector('.content')?.textContent); // 'Text'
|
|
1994
|
-
```
|
|
1995
|
-
|
|
1996
|
-
### Available APIs
|
|
1997
|
-
|
|
1998
|
-
| Export | Description |
|
|
1999
|
-
|--------|-------------|
|
|
2000
|
-
| `parseHTML` | Parse HTML string into window/document objects |
|
|
2001
|
-
| `DOMParser` | Standard W3C DOMParser interface |
|
|
2002
|
-
| `Document` | Document constructor for creating new documents |
|
|
2003
|
-
| `Event` / `CustomEvent` | DOM Event interfaces |
|
|
2004
|
-
| `EventTarget` | Event handling interface |
|
|
2005
|
-
| `NodeList` | Standard NodeList interface |
|
|
2006
|
-
|
|
2007
|
-
---
|
|
2008
|
-
|
|
2009
|
-
## Troubleshooting
|
|
2010
|
-
|
|
2011
|
-
### Common Issues
|
|
2012
|
-
|
|
2013
|
-
#### Request Timeout
|
|
2014
|
-
|
|
2015
|
-
```typescript
|
|
2016
|
-
// Increase timeout
|
|
2017
|
-
const client = rezo.create({
|
|
2018
|
-
timeout: 60000, // 60 seconds
|
|
2019
|
-
connectTimeout: 10000 // 10 seconds for connection
|
|
2020
|
-
});
|
|
2021
|
-
```
|
|
2022
|
-
|
|
2023
|
-
#### SSL Certificate Errors
|
|
2024
|
-
|
|
2025
|
-
```typescript
|
|
2026
|
-
// For development only - not recommended for production
|
|
2027
|
-
const client = rezo.create({
|
|
2028
|
-
rejectUnauthorized: false
|
|
2029
|
-
});
|
|
2030
|
-
|
|
2031
|
-
// Better: provide custom CA
|
|
2032
|
-
const client = rezo.create({
|
|
2033
|
-
ca: fs.readFileSync('./custom-ca.pem')
|
|
2034
|
-
});
|
|
2035
|
-
```
|
|
2036
|
-
|
|
2037
|
-
#### Proxy Connection Issues
|
|
2038
|
-
|
|
2039
|
-
```typescript
|
|
2040
|
-
// Verify proxy settings
|
|
2041
|
-
const client = rezo.create({
|
|
2042
|
-
proxy: {
|
|
2043
|
-
protocol: 'http', // Ensure correct protocol
|
|
2044
|
-
host: 'proxy.example.com',
|
|
2045
|
-
port: 8080
|
|
2046
|
-
}
|
|
2047
|
-
});
|
|
2048
|
-
|
|
2049
|
-
// Test proxy connection
|
|
2050
|
-
try {
|
|
2051
|
-
await client.get('https://httpbin.org/ip');
|
|
2052
|
-
} catch (error) {
|
|
2053
|
-
if (error.isProxyError) {
|
|
2054
|
-
console.log('Proxy connection failed:', error.details);
|
|
2055
|
-
}
|
|
2056
|
-
}
|
|
2057
|
-
```
|
|
2058
|
-
|
|
2059
|
-
#### Memory Issues with Large Files
|
|
2060
|
-
|
|
2061
|
-
```typescript
|
|
2062
|
-
// Use streaming for large files
|
|
2063
|
-
const response = await client.get('https://example.com/large-file', {
|
|
2064
|
-
responseType: 'stream'
|
|
2065
|
-
});
|
|
2066
|
-
|
|
2067
|
-
// Or use download API
|
|
2068
|
-
const download = await client.download('https://example.com/large-file', {
|
|
2069
|
-
outputPath: './large-file.zip'
|
|
2070
|
-
});
|
|
2071
|
-
```
|
|
2072
|
-
|
|
2073
|
-
### Debug Mode
|
|
2074
|
-
|
|
2075
|
-
```typescript
|
|
2076
|
-
// Enable debug logging
|
|
2077
|
-
const client = rezo.create({
|
|
2078
|
-
debug: true
|
|
2079
|
-
});
|
|
2080
|
-
|
|
2081
|
-
// Or set environment variable
|
|
2082
|
-
process.env.REZO_DEBUG = 'true';
|
|
2083
|
-
```
|
|
2084
|
-
|
|
2085
|
-
---
|
|
2086
|
-
|
|
2087
|
-
## Contributing
|
|
2088
|
-
|
|
2089
|
-
We welcome contributions to Rezo! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
|
|
2090
|
-
|
|
2091
|
-
### Development Setup
|
|
2092
|
-
|
|
2093
|
-
```bash
|
|
2094
|
-
# Clone repository
|
|
2095
|
-
git clone https://github.com/yuniqsolutions/rezo.git
|
|
2096
|
-
cd rezo
|
|
2097
|
-
|
|
2098
|
-
# Install dependencies
|
|
2099
|
-
bun install
|
|
2100
|
-
|
|
2101
|
-
# Run tests
|
|
2102
|
-
bun test
|
|
2103
|
-
|
|
2104
|
-
# Build
|
|
2105
|
-
bun run bundle
|
|
2106
|
-
|
|
2107
|
-
# Lint
|
|
2108
|
-
bun run lint
|
|
2109
|
-
```
|
|
2110
|
-
|
|
2111
|
-
### Running Tests
|
|
2112
|
-
|
|
2113
|
-
```bash
|
|
2114
|
-
# Run all tests
|
|
2115
|
-
bun test
|
|
2116
|
-
|
|
2117
|
-
# Run with coverage
|
|
2118
|
-
bun run test:coverage
|
|
2119
|
-
|
|
2120
|
-
# Run specific test file
|
|
2121
|
-
bun test src/adapters/http.test.ts
|
|
2122
|
-
```
|
|
2123
|
-
|
|
2124
|
-
---
|
|
2125
|
-
|
|
2126
|
-
## Acknowledgments
|
|
2127
|
-
|
|
2128
|
-
Rezo was built with inspiration from the JavaScript HTTP client ecosystem, including the excellent work done by the teams behind Got, Ky, Undici, and other HTTP client libraries. We thank the open-source community for their contributions to the JavaScript ecosystem.
|
|
2129
|
-
|
|
2130
|
-
---
|
|
2131
|
-
|
|
2132
|
-
## License
|
|
2133
|
-
|
|
2134
|
-
Rezo is open source software licensed under the [MIT License](LICENSE).
|
|
2135
|
-
|
|
2136
|
-
Copyright (c) 2024-2025 Yuniq Solutions Tech
|
|
2137
|
-
|
|
2138
|
-
See the [LICENSE](LICENSE) file for the complete license text.
|
|
2139
|
-
|
|
2140
|
-
---
|
|
2141
|
-
|
|
2142
|
-
<p align="center">
|
|
2143
|
-
<img src="https://raw.githubusercontent.com/yuniqsolutions/rezo/main/assets/icon.svg" alt="Rezo Icon" width="60">
|
|
2144
|
-
</p>
|
|
175
|
+
MIT — Made with care by [Yuniq Solutions Tech](https://yuniq.solutions). Built by developers, for developers.
|
|
2145
176
|
|
|
2146
177
|
<p align="center">
|
|
2147
|
-
<
|
|
2148
|
-
<sub>Made by <a href="https://yuniq.solutions">Yuniq Solutions Tech</a></sub>
|
|
178
|
+
<img src="https://raw.githubusercontent.com/yuniqsolutions/rezo/main/assets/icon.svg" alt="Rezo" width="40">
|
|
2149
179
|
</p>
|