rezo 1.0.0
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/LICENSE +202 -0
- package/README.md +1507 -0
- package/assets/icon.svg +37 -0
- package/assets/logo-dark.svg +47 -0
- package/assets/logo.svg +58 -0
- package/dist/adapters/curl.cjs +1034 -0
- package/dist/adapters/curl.js +1031 -0
- package/dist/adapters/entries/curl.cjs +4 -0
- package/dist/adapters/entries/curl.d.ts +2136 -0
- package/dist/adapters/entries/curl.js +2 -0
- package/dist/adapters/entries/fetch.cjs +2 -0
- package/dist/adapters/entries/fetch.d.ts +2127 -0
- package/dist/adapters/entries/fetch.js +1 -0
- package/dist/adapters/entries/http.cjs +2 -0
- package/dist/adapters/entries/http.d.ts +2126 -0
- package/dist/adapters/entries/http.js +1 -0
- package/dist/adapters/entries/http2.cjs +4 -0
- package/dist/adapters/entries/http2.d.ts +2136 -0
- package/dist/adapters/entries/http2.js +2 -0
- package/dist/adapters/entries/react-native.cjs +2 -0
- package/dist/adapters/entries/react-native.d.ts +2126 -0
- package/dist/adapters/entries/react-native.js +1 -0
- package/dist/adapters/entries/xhr.cjs +2 -0
- package/dist/adapters/entries/xhr.d.ts +2127 -0
- package/dist/adapters/entries/xhr.js +1 -0
- package/dist/adapters/fetch.cjs +740 -0
- package/dist/adapters/fetch.js +739 -0
- package/dist/adapters/http.cjs +1153 -0
- package/dist/adapters/http.js +1151 -0
- package/dist/adapters/http2.cjs +957 -0
- package/dist/adapters/http2.js +956 -0
- package/dist/adapters/index.cjs +6 -0
- package/dist/adapters/index.js +7 -0
- package/dist/adapters/picker.cjs +342 -0
- package/dist/adapters/picker.js +331 -0
- package/dist/adapters/react-native.cjs +545 -0
- package/dist/adapters/react-native.js +544 -0
- package/dist/adapters/xhr.cjs +622 -0
- package/dist/adapters/xhr.js +621 -0
- package/dist/cache/dns-cache.cjs +118 -0
- package/dist/cache/dns-cache.js +113 -0
- package/dist/cache/file-cacher.cjs +264 -0
- package/dist/cache/file-cacher.js +261 -0
- package/dist/cache/index.cjs +13 -0
- package/dist/cache/index.js +5 -0
- package/dist/cache/lru-cache.cjs +96 -0
- package/dist/cache/lru-cache.js +93 -0
- package/dist/cache/response-cache.cjs +314 -0
- package/dist/cache/response-cache.js +310 -0
- package/dist/cache/url-store.cjs +288 -0
- package/dist/cache/url-store.js +285 -0
- package/dist/core/hooks.cjs +133 -0
- package/dist/core/hooks.js +120 -0
- package/dist/core/rezo.cjs +464 -0
- package/dist/core/rezo.js +458 -0
- package/dist/crawler.d.ts +6255 -0
- package/dist/dom/index.cjs +1 -0
- package/dist/dom/index.d.ts +23 -0
- package/dist/dom/index.js +1 -0
- package/dist/entries/crawler.cjs +5 -0
- package/dist/entries/crawler.js +2 -0
- package/dist/errors/rezo-error.cjs +722 -0
- package/dist/errors/rezo-error.js +716 -0
- package/dist/index.cjs +34 -0
- package/dist/index.d.ts +3335 -0
- package/dist/index.js +26 -0
- package/dist/platform/browser.cjs +9 -0
- package/dist/platform/browser.d.ts +3203 -0
- package/dist/platform/browser.js +7 -0
- package/dist/platform/bun.cjs +9 -0
- package/dist/platform/bun.d.ts +3203 -0
- package/dist/platform/bun.js +7 -0
- package/dist/platform/deno.cjs +9 -0
- package/dist/platform/deno.d.ts +3203 -0
- package/dist/platform/deno.js +7 -0
- package/dist/platform/node.cjs +9 -0
- package/dist/platform/node.d.ts +3203 -0
- package/dist/platform/node.js +7 -0
- package/dist/platform/react-native.cjs +9 -0
- package/dist/platform/react-native.d.ts +3203 -0
- package/dist/platform/react-native.js +7 -0
- package/dist/platform/worker.cjs +9 -0
- package/dist/platform/worker.d.ts +3203 -0
- package/dist/platform/worker.js +7 -0
- package/dist/plugin/addon/decodo/index.cjs +1 -0
- package/dist/plugin/addon/decodo/index.js +1 -0
- package/dist/plugin/addon/decodo/options.cjs +1 -0
- package/dist/plugin/addon/decodo/options.js +1 -0
- package/dist/plugin/addon/oxylabs/index.cjs +1 -0
- package/dist/plugin/addon/oxylabs/index.js +1 -0
- package/dist/plugin/addon/oxylabs/options.cjs +1 -0
- package/dist/plugin/addon/oxylabs/options.js +1 -0
- package/dist/plugin/crawler-options.cjs +1 -0
- package/dist/plugin/crawler-options.js +1 -0
- package/dist/plugin/crawler.cjs +519 -0
- package/dist/plugin/crawler.js +517 -0
- package/dist/plugin/index.cjs +36 -0
- package/dist/plugin/index.js +32 -0
- package/dist/proxy/index.cjs +142 -0
- package/dist/proxy/index.js +139 -0
- package/dist/responses/buildError.cjs +452 -0
- package/dist/responses/buildError.js +441 -0
- package/dist/responses/buildResponse.cjs +365 -0
- package/dist/responses/buildResponse.js +361 -0
- package/dist/responses/download.cjs +54 -0
- package/dist/responses/download.js +52 -0
- package/dist/responses/stream.cjs +60 -0
- package/dist/responses/stream.js +58 -0
- package/dist/responses/upload.cjs +54 -0
- package/dist/responses/upload.js +52 -0
- package/dist/types/cookies.cjs +394 -0
- package/dist/types/cookies.js +391 -0
- package/dist/types/download.cjs +10 -0
- package/dist/types/download.js +10 -0
- package/dist/types/rezo-request.cjs +131 -0
- package/dist/types/rezo-request.js +131 -0
- package/dist/utils/agent-merger.cjs +111 -0
- package/dist/utils/agent-merger.js +108 -0
- package/dist/utils/compression.cjs +84 -0
- package/dist/utils/compression.js +82 -0
- package/dist/utils/cookies.cjs +514 -0
- package/dist/utils/cookies.js +511 -0
- package/dist/utils/data-operations.cjs +75 -0
- package/dist/utils/data-operations.js +73 -0
- package/dist/utils/form-data.cjs +164 -0
- package/dist/utils/form-data.js +161 -0
- package/dist/utils/headers.cjs +162 -0
- package/dist/utils/headers.js +161 -0
- package/dist/utils/http-config.cjs +723 -0
- package/dist/utils/http-config.js +718 -0
- package/dist/utils/index.cjs +8 -0
- package/dist/utils/index.js +8 -0
- package/dist/utils/tools.cjs +18 -0
- package/dist/utils/tools.js +15 -0
- package/package.json +172 -0
package/README.md
ADDED
|
@@ -0,0 +1,1507 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="assets/logo.svg" alt="Rezo HTTP Client" width="400">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h1 align="center">Rezo HTTP Client</h1>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<strong>Lightning-fast, enterprise-grade HTTP client for modern JavaScript</strong>
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
<p align="center">
|
|
12
|
+
<a href="#installation">Installation</a> •
|
|
13
|
+
<a href="#quick-start">Quick Start</a> •
|
|
14
|
+
<a href="#features">Features</a> •
|
|
15
|
+
<a href="#api-reference">API Reference</a> •
|
|
16
|
+
<a href="#adapters">Adapters</a> •
|
|
17
|
+
<a href="#advanced-usage">Advanced Usage</a> •
|
|
18
|
+
<a href="#migration-guide">Migration</a>
|
|
19
|
+
</p>
|
|
20
|
+
|
|
21
|
+
<p align="center">
|
|
22
|
+
<img src="https://img.shields.io/npm/v/rezo?style=flat-square&color=00D4FF" alt="npm version">
|
|
23
|
+
<img src="https://img.shields.io/npm/dm/rezo?style=flat-square&color=0099FF" alt="npm downloads">
|
|
24
|
+
<img src="https://img.shields.io/bundlephobia/minzip/rezo?style=flat-square&color=0066CC" alt="bundle size">
|
|
25
|
+
<img src="https://img.shields.io/npm/l/rezo?style=flat-square&color=00D4FF" alt="license">
|
|
26
|
+
<img src="https://img.shields.io/node/v/rezo?style=flat-square&color=0099FF" alt="node version">
|
|
27
|
+
</p>
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Overview
|
|
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
|
+
- [Streaming](#streaming)
|
|
67
|
+
- [File Downloads](#file-downloads)
|
|
68
|
+
- [File Uploads](#file-uploads)
|
|
69
|
+
- [Hooks & Interceptors](#hooks--interceptors)
|
|
70
|
+
- [Retry Logic](#retry-logic)
|
|
71
|
+
- [Error Handling](#error-handling)
|
|
72
|
+
- [Performance Metrics](#performance-metrics)
|
|
73
|
+
- [Platform Support](#platform-support)
|
|
74
|
+
- [Migration Guide](#migration-guide)
|
|
75
|
+
- [TypeScript](#typescript)
|
|
76
|
+
- [Crawler Module](#crawler-module)
|
|
77
|
+
- [DOM Module](#dom-module)
|
|
78
|
+
- [Troubleshooting](#troubleshooting)
|
|
79
|
+
- [Contributing](#contributing)
|
|
80
|
+
- [License](#license)
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Installation
|
|
85
|
+
|
|
86
|
+
### npm
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
npm install rezo
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Yarn
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
yarn add rezo
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### pnpm
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
pnpm add rezo
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Bun
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
bun add rezo
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Requirements
|
|
111
|
+
|
|
112
|
+
- **Node.js**: 22.0.0 or higher
|
|
113
|
+
- **Bun**: 1.0.0 or higher
|
|
114
|
+
- **Deno**: 1.40.0 or higher (with Node.js compatibility)
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## Quick Start
|
|
119
|
+
|
|
120
|
+
### Basic GET Request
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
import rezo from 'rezo';
|
|
124
|
+
|
|
125
|
+
// Simple GET request
|
|
126
|
+
const response = await rezo.get('https://api.example.com/users');
|
|
127
|
+
console.log(response.data);
|
|
128
|
+
|
|
129
|
+
// With query parameters
|
|
130
|
+
const users = await rezo.get('https://api.example.com/users', {
|
|
131
|
+
params: { page: 1, limit: 10 }
|
|
132
|
+
});
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### POST Request with JSON
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
import rezo from 'rezo';
|
|
139
|
+
|
|
140
|
+
const response = await rezo.post('https://api.example.com/users', {
|
|
141
|
+
name: 'John Doe',
|
|
142
|
+
email: 'john@example.com'
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
console.log(response.data);
|
|
146
|
+
console.log(response.status); // 201
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Creating an Instance
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
import rezo from 'rezo';
|
|
153
|
+
|
|
154
|
+
const api = rezo.create({
|
|
155
|
+
baseURL: 'https://api.example.com',
|
|
156
|
+
timeout: 30000,
|
|
157
|
+
headers: {
|
|
158
|
+
'Authorization': 'Bearer your-token',
|
|
159
|
+
'Content-Type': 'application/json'
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// All requests will use the base configuration
|
|
164
|
+
const users = await api.get('/users');
|
|
165
|
+
const user = await api.post('/users', { name: 'Jane Doe' });
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### CommonJS Usage
|
|
169
|
+
|
|
170
|
+
```javascript
|
|
171
|
+
const rezo = require('rezo').default;
|
|
172
|
+
|
|
173
|
+
// Using default instance
|
|
174
|
+
rezo.get('https://api.example.com/data')
|
|
175
|
+
.then(response => console.log(response.data))
|
|
176
|
+
.catch(error => console.error(error));
|
|
177
|
+
|
|
178
|
+
// Creating custom instance
|
|
179
|
+
const client = rezo.create({ baseURL: 'https://api.example.com' });
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## Features
|
|
185
|
+
|
|
186
|
+
### Core Capabilities
|
|
187
|
+
|
|
188
|
+
| Feature | Description |
|
|
189
|
+
|---------|-------------|
|
|
190
|
+
| **HTTP/1.1 & HTTP/2** | Full support for both protocols with automatic negotiation |
|
|
191
|
+
| **All HTTP Methods** | GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS, TRACE |
|
|
192
|
+
| **Request Body Types** | JSON, FormData, URLSearchParams, Streams, Buffers |
|
|
193
|
+
| **Response Types** | JSON, Text, ArrayBuffer, Blob, Streams |
|
|
194
|
+
| **Automatic Transforms** | JSON parsing, content-type detection, compression handling |
|
|
195
|
+
| **Query Parameters** | Automatic URL encoding and serialization |
|
|
196
|
+
| **Request Cancellation** | AbortController support for request cancellation |
|
|
197
|
+
|
|
198
|
+
### Network Features
|
|
199
|
+
|
|
200
|
+
| Feature | Description |
|
|
201
|
+
|---------|-------------|
|
|
202
|
+
| **Cookie Management** | RFC 6265 compliant cookie jar with persistence |
|
|
203
|
+
| **Proxy Support** | HTTP, HTTPS, SOCKS4, and SOCKS5 proxies |
|
|
204
|
+
| **TLS/SSL** | Custom certificates, client certs, certificate pinning |
|
|
205
|
+
| **Compression** | Automatic gzip, deflate, brotli, and zstd handling |
|
|
206
|
+
| **Connection Pooling** | Reusable connections for improved performance |
|
|
207
|
+
| **Keep-Alive** | Persistent connections with configurable timeouts |
|
|
208
|
+
|
|
209
|
+
### Enterprise Features
|
|
210
|
+
|
|
211
|
+
| Feature | Description |
|
|
212
|
+
|---------|-------------|
|
|
213
|
+
| **Retry Logic** | Configurable retry with exponential backoff |
|
|
214
|
+
| **Timeout Control** | Connection, request, and total timeout options |
|
|
215
|
+
| **Rate Limiting** | Request queue with priority and concurrency control |
|
|
216
|
+
| **Hooks System** | Lifecycle hooks for request/response interception |
|
|
217
|
+
| **Error Handling** | Structured errors with actionable suggestions |
|
|
218
|
+
| **Performance Metrics** | Detailed timing data for monitoring |
|
|
219
|
+
|
|
220
|
+
### Developer Experience
|
|
221
|
+
|
|
222
|
+
| Feature | Description |
|
|
223
|
+
|---------|-------------|
|
|
224
|
+
| **TypeScript First** | Comprehensive type definitions and generics |
|
|
225
|
+
| **Tree-Shakeable** | Modular exports for optimal bundle size |
|
|
226
|
+
| **Zero Config** | Works out of the box with sensible defaults |
|
|
227
|
+
| **Extensive Logging** | Debug mode for troubleshooting |
|
|
228
|
+
| **Cross-Platform** | Node.js, Bun, Deno, browsers, React Native, edge |
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## Adapters
|
|
233
|
+
|
|
234
|
+
Rezo uses a pluggable adapter architecture, allowing you to choose the optimal HTTP implementation for your environment and requirements.
|
|
235
|
+
|
|
236
|
+
### Automatic Adapter Selection
|
|
237
|
+
|
|
238
|
+
By default, Rezo automatically selects the best adapter based on your runtime environment:
|
|
239
|
+
|
|
240
|
+
| Environment | Default Adapter |
|
|
241
|
+
|-------------|-----------------|
|
|
242
|
+
| Node.js | HTTP Adapter |
|
|
243
|
+
| Bun | HTTP Adapter |
|
|
244
|
+
| Deno | HTTP Adapter |
|
|
245
|
+
| Browser | Fetch Adapter |
|
|
246
|
+
| Cloudflare Workers | Fetch Adapter |
|
|
247
|
+
| React Native | React Native Adapter |
|
|
248
|
+
|
|
249
|
+
### HTTP Adapter
|
|
250
|
+
|
|
251
|
+
The full-featured adapter for Node.js environments with complete cookie, proxy, and streaming support.
|
|
252
|
+
|
|
253
|
+
```typescript
|
|
254
|
+
import rezo from 'rezo/adapters/http';
|
|
255
|
+
|
|
256
|
+
const response = await rezo.get('https://api.example.com/data');
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
**Features:**
|
|
260
|
+
- Full cookie jar support with persistence
|
|
261
|
+
- HTTP/HTTPS/SOCKS proxy support
|
|
262
|
+
- Streaming request and response bodies
|
|
263
|
+
- All compression algorithms
|
|
264
|
+
- Custom TLS configuration
|
|
265
|
+
- Connection keep-alive
|
|
266
|
+
|
|
267
|
+
### HTTP/2 Adapter
|
|
268
|
+
|
|
269
|
+
Native HTTP/2 support with session multiplexing for maximum performance.
|
|
270
|
+
|
|
271
|
+
```typescript
|
|
272
|
+
import rezo from 'rezo/adapters/http2';
|
|
273
|
+
|
|
274
|
+
const response = await rezo.get('https://api.example.com/data');
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
**Features:**
|
|
278
|
+
- HTTP/2 multiplexing (multiple requests over single connection)
|
|
279
|
+
- Automatic session pooling and reuse
|
|
280
|
+
- ALPN protocol negotiation
|
|
281
|
+
- Falls back to HTTP/1.1 when needed
|
|
282
|
+
- Server push support
|
|
283
|
+
- Header compression (HPACK)
|
|
284
|
+
|
|
285
|
+
### Fetch Adapter
|
|
286
|
+
|
|
287
|
+
Lightweight adapter using the native Fetch API, ideal for browsers and edge runtimes.
|
|
288
|
+
|
|
289
|
+
```typescript
|
|
290
|
+
import rezo from 'rezo/adapters/fetch';
|
|
291
|
+
|
|
292
|
+
const response = await rezo.get('https://api.example.com/data');
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
**Features:**
|
|
296
|
+
- Minimal bundle size
|
|
297
|
+
- Native browser support
|
|
298
|
+
- Edge runtime compatible (Cloudflare Workers, Vercel Edge)
|
|
299
|
+
- Streaming response bodies
|
|
300
|
+
- AbortController integration
|
|
301
|
+
|
|
302
|
+
### cURL Adapter
|
|
303
|
+
|
|
304
|
+
Advanced adapter wrapping the cURL command-line tool for maximum compatibility and debugging.
|
|
305
|
+
|
|
306
|
+
```typescript
|
|
307
|
+
import rezo from 'rezo/adapters/curl';
|
|
308
|
+
|
|
309
|
+
const response = await rezo.get('https://api.example.com/data', {
|
|
310
|
+
curl: {
|
|
311
|
+
verbose: true,
|
|
312
|
+
insecure: false
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
**Features:**
|
|
318
|
+
- 200+ cURL options available
|
|
319
|
+
- Advanced authentication (Basic, Digest, NTLM, Negotiate)
|
|
320
|
+
- Connection pooling
|
|
321
|
+
- Detailed timing information
|
|
322
|
+
- Perfect for debugging and testing
|
|
323
|
+
|
|
324
|
+
### XHR Adapter
|
|
325
|
+
|
|
326
|
+
Legacy browser support using XMLHttpRequest for maximum compatibility.
|
|
327
|
+
|
|
328
|
+
```typescript
|
|
329
|
+
import rezo from 'rezo/adapters/xhr';
|
|
330
|
+
|
|
331
|
+
const response = await rezo.get('https://api.example.com/data');
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
**Features:**
|
|
335
|
+
- Legacy browser support (IE11+)
|
|
336
|
+
- Upload progress events
|
|
337
|
+
- Download progress events
|
|
338
|
+
- Synchronous request option
|
|
339
|
+
- Cross-origin request handling
|
|
340
|
+
|
|
341
|
+
### React Native Adapter
|
|
342
|
+
|
|
343
|
+
Optimized adapter for React Native mobile applications.
|
|
344
|
+
|
|
345
|
+
```typescript
|
|
346
|
+
import rezo from 'rezo/adapters/react-native';
|
|
347
|
+
|
|
348
|
+
const response = await rezo.get('https://api.example.com/data');
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
**Features:**
|
|
352
|
+
- Optimized for mobile networks
|
|
353
|
+
- File download support (react-native-fs)
|
|
354
|
+
- Manual cookie header management
|
|
355
|
+
- Background fetch support
|
|
356
|
+
- Network state awareness
|
|
357
|
+
|
|
358
|
+
---
|
|
359
|
+
|
|
360
|
+
## API Reference
|
|
361
|
+
|
|
362
|
+
### Request Methods
|
|
363
|
+
|
|
364
|
+
Rezo provides convenient methods for all standard HTTP verbs:
|
|
365
|
+
|
|
366
|
+
```typescript
|
|
367
|
+
// GET request
|
|
368
|
+
rezo.get(url[, config])
|
|
369
|
+
|
|
370
|
+
// POST request
|
|
371
|
+
rezo.post(url[, data[, config]])
|
|
372
|
+
|
|
373
|
+
// PUT request
|
|
374
|
+
rezo.put(url[, data[, config]])
|
|
375
|
+
|
|
376
|
+
// PATCH request
|
|
377
|
+
rezo.patch(url[, data[, config]])
|
|
378
|
+
|
|
379
|
+
// DELETE request
|
|
380
|
+
rezo.delete(url[, config])
|
|
381
|
+
|
|
382
|
+
// HEAD request
|
|
383
|
+
rezo.head(url[, config])
|
|
384
|
+
|
|
385
|
+
// OPTIONS request
|
|
386
|
+
rezo.options(url[, config])
|
|
387
|
+
|
|
388
|
+
// Generic request
|
|
389
|
+
rezo.request(config)
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
### Convenience Methods
|
|
393
|
+
|
|
394
|
+
Rezo provides specialized methods for common content types:
|
|
395
|
+
|
|
396
|
+
```typescript
|
|
397
|
+
// JSON POST with automatic Content-Type header
|
|
398
|
+
rezo.postJson(url, data[, config])
|
|
399
|
+
|
|
400
|
+
// Form-encoded POST
|
|
401
|
+
rezo.postForm(url, data[, config])
|
|
402
|
+
|
|
403
|
+
// Multipart form data POST
|
|
404
|
+
rezo.postMultipart(url, data[, config])
|
|
405
|
+
|
|
406
|
+
// Same patterns available for PUT and PATCH
|
|
407
|
+
rezo.putJson(url, data[, config])
|
|
408
|
+
rezo.patchJson(url, data[, config])
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
### Request Configuration
|
|
412
|
+
|
|
413
|
+
```typescript
|
|
414
|
+
interface RezoConfig {
|
|
415
|
+
// URL and Method
|
|
416
|
+
url?: string;
|
|
417
|
+
method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS';
|
|
418
|
+
baseURL?: string;
|
|
419
|
+
|
|
420
|
+
// Request Data
|
|
421
|
+
params?: Record<string, any>;
|
|
422
|
+
data?: any;
|
|
423
|
+
headers?: RezoHeaders | Record<string, string>;
|
|
424
|
+
|
|
425
|
+
// Timeouts (in milliseconds)
|
|
426
|
+
timeout?: number;
|
|
427
|
+
connectTimeout?: number;
|
|
428
|
+
requestTimeout?: number;
|
|
429
|
+
|
|
430
|
+
// Response Handling
|
|
431
|
+
responseType?: 'json' | 'text' | 'arraybuffer' | 'blob' | 'stream';
|
|
432
|
+
responseEncoding?: string;
|
|
433
|
+
validateStatus?: (status: number) => boolean;
|
|
434
|
+
maxContentLength?: number;
|
|
435
|
+
maxBodyLength?: number;
|
|
436
|
+
|
|
437
|
+
// Redirects
|
|
438
|
+
maxRedirects?: number;
|
|
439
|
+
followRedirect?: boolean;
|
|
440
|
+
|
|
441
|
+
// Authentication
|
|
442
|
+
auth?: {
|
|
443
|
+
username: string;
|
|
444
|
+
password: string;
|
|
445
|
+
};
|
|
446
|
+
|
|
447
|
+
// Proxy Configuration
|
|
448
|
+
proxy?: {
|
|
449
|
+
protocol?: 'http' | 'https' | 'socks4' | 'socks5';
|
|
450
|
+
host: string;
|
|
451
|
+
port: number;
|
|
452
|
+
auth?: {
|
|
453
|
+
username: string;
|
|
454
|
+
password: string;
|
|
455
|
+
};
|
|
456
|
+
};
|
|
457
|
+
|
|
458
|
+
// TLS/SSL
|
|
459
|
+
httpsAgent?: any;
|
|
460
|
+
rejectUnauthorized?: boolean;
|
|
461
|
+
ca?: string | Buffer;
|
|
462
|
+
cert?: string | Buffer;
|
|
463
|
+
key?: string | Buffer;
|
|
464
|
+
|
|
465
|
+
// Advanced
|
|
466
|
+
decompress?: boolean;
|
|
467
|
+
signal?: AbortSignal;
|
|
468
|
+
onUploadProgress?: (progressEvent: ProgressEvent) => void;
|
|
469
|
+
onDownloadProgress?: (progressEvent: ProgressEvent) => void;
|
|
470
|
+
|
|
471
|
+
// Retry Configuration
|
|
472
|
+
retry?: {
|
|
473
|
+
limit?: number;
|
|
474
|
+
delay?: number;
|
|
475
|
+
maxDelay?: number;
|
|
476
|
+
backoff?: number;
|
|
477
|
+
retryOn?: number[] | ((error: Error, attempt: number) => boolean);
|
|
478
|
+
};
|
|
479
|
+
|
|
480
|
+
// Cookies
|
|
481
|
+
jar?: CookieJar;
|
|
482
|
+
withCredentials?: boolean;
|
|
483
|
+
}
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
### Response Schema
|
|
487
|
+
|
|
488
|
+
```typescript
|
|
489
|
+
interface RezoResponse<T = any> {
|
|
490
|
+
// Response data (automatically parsed based on content-type)
|
|
491
|
+
data: T;
|
|
492
|
+
|
|
493
|
+
// HTTP status
|
|
494
|
+
status: number;
|
|
495
|
+
statusText: string;
|
|
496
|
+
|
|
497
|
+
// Response headers (case-insensitive access)
|
|
498
|
+
headers: RezoHeaders;
|
|
499
|
+
|
|
500
|
+
// Request configuration used
|
|
501
|
+
config: RezoConfig;
|
|
502
|
+
|
|
503
|
+
// The request that generated this response
|
|
504
|
+
request: any;
|
|
505
|
+
|
|
506
|
+
// Timing metrics (when available)
|
|
507
|
+
timing?: {
|
|
508
|
+
start: number;
|
|
509
|
+
dns: number;
|
|
510
|
+
connect: number;
|
|
511
|
+
tls: number;
|
|
512
|
+
firstByte: number;
|
|
513
|
+
download: number;
|
|
514
|
+
total: number;
|
|
515
|
+
};
|
|
516
|
+
}
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
### Instance Methods
|
|
520
|
+
|
|
521
|
+
```typescript
|
|
522
|
+
const instance = rezo.create(config);
|
|
523
|
+
|
|
524
|
+
// Request methods
|
|
525
|
+
instance.get(url, config?)
|
|
526
|
+
instance.post(url, data?, config?)
|
|
527
|
+
instance.put(url, data?, config?)
|
|
528
|
+
instance.patch(url, data?, config?)
|
|
529
|
+
instance.delete(url, config?)
|
|
530
|
+
instance.head(url, config?)
|
|
531
|
+
instance.options(url, config?)
|
|
532
|
+
instance.request(config)
|
|
533
|
+
|
|
534
|
+
// Instance configuration
|
|
535
|
+
instance.defaults // Access default configuration
|
|
536
|
+
instance.getUri(config) // Get the full URL
|
|
537
|
+
|
|
538
|
+
// Cookie management
|
|
539
|
+
instance.jar // Access the cookie jar
|
|
540
|
+
instance.getCookies(url)
|
|
541
|
+
instance.setCookie(cookie, url)
|
|
542
|
+
instance.clearCookies()
|
|
543
|
+
|
|
544
|
+
// Hooks
|
|
545
|
+
instance.hooks.beforeRequest.push(handler)
|
|
546
|
+
instance.hooks.afterResponse.push(handler)
|
|
547
|
+
instance.hooks.beforeRetry.push(handler)
|
|
548
|
+
instance.hooks.beforeError.push(handler)
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
---
|
|
552
|
+
|
|
553
|
+
## Advanced Usage
|
|
554
|
+
|
|
555
|
+
### Cookie Management
|
|
556
|
+
|
|
557
|
+
Rezo provides RFC 6265 compliant cookie management with automatic persistence. The default instance already has a built-in cookie jar - no configuration required.
|
|
558
|
+
|
|
559
|
+
```typescript
|
|
560
|
+
import rezo from 'rezo';
|
|
561
|
+
|
|
562
|
+
// Cookies work automatically with the default instance
|
|
563
|
+
await rezo.post('https://api.example.com/login', { username: 'user', password: 'pass' });
|
|
564
|
+
|
|
565
|
+
// Subsequent requests automatically include session cookies
|
|
566
|
+
const profile = await rezo.get('https://api.example.com/profile');
|
|
567
|
+
|
|
568
|
+
// Access cookies directly from the default instance
|
|
569
|
+
const cookies = rezo.getCookies('https://api.example.com');
|
|
570
|
+
console.log(cookies);
|
|
571
|
+
|
|
572
|
+
// Set cookies manually
|
|
573
|
+
rezo.setCookie('custom=value; Path=/; HttpOnly', 'https://api.example.com');
|
|
574
|
+
|
|
575
|
+
// Clear all cookies
|
|
576
|
+
rezo.clearCookies();
|
|
577
|
+
```
|
|
578
|
+
|
|
579
|
+
#### Custom Cookie Jar (Optional)
|
|
580
|
+
|
|
581
|
+
Only create your own CookieJar if you need to manage cookies externally or use multiple isolated jars:
|
|
582
|
+
|
|
583
|
+
```typescript
|
|
584
|
+
import rezo, { CookieJar } from 'rezo';
|
|
585
|
+
|
|
586
|
+
// Custom jar for isolated cookie management
|
|
587
|
+
const myJar = new CookieJar();
|
|
588
|
+
|
|
589
|
+
const client = rezo.create({
|
|
590
|
+
baseURL: 'https://api.example.com',
|
|
591
|
+
jar: myJar
|
|
592
|
+
});
|
|
593
|
+
|
|
594
|
+
// Export cookies to different formats
|
|
595
|
+
const netscapeFormat = myJar.toNetscapeString();
|
|
596
|
+
const setCookieHeaders = myJar.toSetCookieStrings();
|
|
597
|
+
const jsonFormat = myJar.toJSON();
|
|
598
|
+
```
|
|
599
|
+
|
|
600
|
+
### Proxy Configuration
|
|
601
|
+
|
|
602
|
+
Rezo provides comprehensive proxy support for HTTP, HTTPS, SOCKS4, and SOCKS5 protocols, enabling secure and anonymous web requests through proxy servers.
|
|
603
|
+
|
|
604
|
+
#### Quick Usage (Per-Request)
|
|
605
|
+
|
|
606
|
+
You can use a proxy directly in any request without creating an instance:
|
|
607
|
+
|
|
608
|
+
```typescript
|
|
609
|
+
import rezo from 'rezo';
|
|
610
|
+
|
|
611
|
+
// Use proxy for a single request
|
|
612
|
+
const response = await rezo.get('https://api.example.com/data', {
|
|
613
|
+
proxy: {
|
|
614
|
+
protocol: 'http',
|
|
615
|
+
host: 'proxy.example.com',
|
|
616
|
+
port: 8080
|
|
617
|
+
}
|
|
618
|
+
});
|
|
619
|
+
```
|
|
620
|
+
|
|
621
|
+
#### Proxy Protocols
|
|
622
|
+
|
|
623
|
+
| Protocol | Description | Use Case |
|
|
624
|
+
|----------|-------------|----------|
|
|
625
|
+
| `http` | HTTP proxy (CONNECT method for HTTPS targets) | General-purpose web proxy |
|
|
626
|
+
| `https` | HTTPS proxy (encrypted proxy connection) | Secure corporate proxies |
|
|
627
|
+
| `socks4` | SOCKS4 proxy (TCP connections only) | Legacy proxy servers |
|
|
628
|
+
| `socks5` | SOCKS5 proxy (TCP + UDP, authentication) | Anonymous browsing, Tor |
|
|
629
|
+
|
|
630
|
+
#### Basic HTTP Proxy
|
|
631
|
+
|
|
632
|
+
```typescript
|
|
633
|
+
import rezo from 'rezo';
|
|
634
|
+
|
|
635
|
+
// HTTP Proxy - routes all traffic through the proxy
|
|
636
|
+
const client = rezo.create({
|
|
637
|
+
proxy: {
|
|
638
|
+
protocol: 'http',
|
|
639
|
+
host: 'proxy.example.com',
|
|
640
|
+
port: 8080
|
|
641
|
+
}
|
|
642
|
+
});
|
|
643
|
+
|
|
644
|
+
const response = await client.get('https://api.example.com/data');
|
|
645
|
+
```
|
|
646
|
+
|
|
647
|
+
#### HTTPS Proxy
|
|
648
|
+
|
|
649
|
+
```typescript
|
|
650
|
+
import rezo from 'rezo';
|
|
651
|
+
|
|
652
|
+
// HTTPS Proxy - encrypted connection to proxy server
|
|
653
|
+
const client = rezo.create({
|
|
654
|
+
proxy: {
|
|
655
|
+
protocol: 'https',
|
|
656
|
+
host: 'secure-proxy.example.com',
|
|
657
|
+
port: 443
|
|
658
|
+
}
|
|
659
|
+
});
|
|
660
|
+
```
|
|
661
|
+
|
|
662
|
+
#### Authenticated Proxy
|
|
663
|
+
|
|
664
|
+
```typescript
|
|
665
|
+
import rezo from 'rezo';
|
|
666
|
+
|
|
667
|
+
// Proxy with username/password authentication
|
|
668
|
+
const client = rezo.create({
|
|
669
|
+
proxy: {
|
|
670
|
+
protocol: 'http',
|
|
671
|
+
host: 'proxy.example.com',
|
|
672
|
+
port: 8080,
|
|
673
|
+
auth: {
|
|
674
|
+
username: 'proxyuser',
|
|
675
|
+
password: 'proxypass'
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
});
|
|
679
|
+
```
|
|
680
|
+
|
|
681
|
+
#### SOCKS4 Proxy
|
|
682
|
+
|
|
683
|
+
```typescript
|
|
684
|
+
import rezo from 'rezo';
|
|
685
|
+
|
|
686
|
+
// SOCKS4 Proxy - TCP connections only, no authentication
|
|
687
|
+
const client = rezo.create({
|
|
688
|
+
proxy: {
|
|
689
|
+
protocol: 'socks4',
|
|
690
|
+
host: 'socks4.example.com',
|
|
691
|
+
port: 1080
|
|
692
|
+
}
|
|
693
|
+
});
|
|
694
|
+
```
|
|
695
|
+
|
|
696
|
+
#### SOCKS5 Proxy
|
|
697
|
+
|
|
698
|
+
```typescript
|
|
699
|
+
import rezo from 'rezo';
|
|
700
|
+
|
|
701
|
+
// SOCKS5 Proxy - supports TCP, UDP, and authentication
|
|
702
|
+
const client = rezo.create({
|
|
703
|
+
proxy: {
|
|
704
|
+
protocol: 'socks5',
|
|
705
|
+
host: 'socks5.example.com',
|
|
706
|
+
port: 1080
|
|
707
|
+
}
|
|
708
|
+
});
|
|
709
|
+
|
|
710
|
+
// SOCKS5 with authentication
|
|
711
|
+
const authenticatedSocks = rezo.create({
|
|
712
|
+
proxy: {
|
|
713
|
+
protocol: 'socks5',
|
|
714
|
+
host: 'socks5.example.com',
|
|
715
|
+
port: 1080,
|
|
716
|
+
auth: {
|
|
717
|
+
username: 'socksuser',
|
|
718
|
+
password: 'sockspass'
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
});
|
|
722
|
+
|
|
723
|
+
// Using Tor network (typically SOCKS5 on port 9050)
|
|
724
|
+
const torClient = rezo.create({
|
|
725
|
+
proxy: {
|
|
726
|
+
protocol: 'socks5',
|
|
727
|
+
host: '127.0.0.1',
|
|
728
|
+
port: 9050
|
|
729
|
+
}
|
|
730
|
+
});
|
|
731
|
+
```
|
|
732
|
+
|
|
733
|
+
#### Per-Request Proxy Override
|
|
734
|
+
|
|
735
|
+
```typescript
|
|
736
|
+
import rezo from 'rezo';
|
|
737
|
+
|
|
738
|
+
const client = rezo.create({
|
|
739
|
+
proxy: {
|
|
740
|
+
protocol: 'http',
|
|
741
|
+
host: 'default-proxy.example.com',
|
|
742
|
+
port: 8080
|
|
743
|
+
}
|
|
744
|
+
});
|
|
745
|
+
|
|
746
|
+
// Use a different proxy for this specific request
|
|
747
|
+
await client.get('https://api.example.com/data', {
|
|
748
|
+
proxy: {
|
|
749
|
+
protocol: 'https',
|
|
750
|
+
host: 'different-proxy.example.com',
|
|
751
|
+
port: 443
|
|
752
|
+
}
|
|
753
|
+
});
|
|
754
|
+
|
|
755
|
+
// Disable proxy for specific request (direct connection)
|
|
756
|
+
await client.get('https://internal.example.com/data', {
|
|
757
|
+
proxy: false
|
|
758
|
+
});
|
|
759
|
+
```
|
|
760
|
+
|
|
761
|
+
#### Proxy Configuration Interface
|
|
762
|
+
|
|
763
|
+
```typescript
|
|
764
|
+
interface ProxyConfig {
|
|
765
|
+
protocol: 'http' | 'https' | 'socks4' | 'socks5';
|
|
766
|
+
host: string;
|
|
767
|
+
port: number;
|
|
768
|
+
auth?: {
|
|
769
|
+
username: string;
|
|
770
|
+
password: string;
|
|
771
|
+
};
|
|
772
|
+
}
|
|
773
|
+
```
|
|
774
|
+
|
|
775
|
+
### Streaming
|
|
776
|
+
|
|
777
|
+
Rezo provides powerful streaming capabilities for handling large data efficiently.
|
|
778
|
+
|
|
779
|
+
```typescript
|
|
780
|
+
import rezo from 'rezo';
|
|
781
|
+
import { createWriteStream } from 'fs';
|
|
782
|
+
|
|
783
|
+
const client = rezo.create();
|
|
784
|
+
|
|
785
|
+
// Stream response to file
|
|
786
|
+
const response = await client.get('https://example.com/large-file.zip', {
|
|
787
|
+
responseType: 'stream'
|
|
788
|
+
});
|
|
789
|
+
|
|
790
|
+
const writer = createWriteStream('./download.zip');
|
|
791
|
+
response.data.pipe(writer);
|
|
792
|
+
|
|
793
|
+
await new Promise((resolve, reject) => {
|
|
794
|
+
writer.on('finish', resolve);
|
|
795
|
+
writer.on('error', reject);
|
|
796
|
+
});
|
|
797
|
+
|
|
798
|
+
// Stream request body
|
|
799
|
+
import { createReadStream } from 'fs';
|
|
800
|
+
|
|
801
|
+
await client.post('https://api.example.com/upload', createReadStream('./file.txt'), {
|
|
802
|
+
headers: {
|
|
803
|
+
'Content-Type': 'application/octet-stream'
|
|
804
|
+
}
|
|
805
|
+
});
|
|
806
|
+
```
|
|
807
|
+
|
|
808
|
+
### File Downloads
|
|
809
|
+
|
|
810
|
+
Rezo provides a dedicated download API with progress tracking.
|
|
811
|
+
|
|
812
|
+
```typescript
|
|
813
|
+
import rezo, { DownloadResponse } from 'rezo';
|
|
814
|
+
|
|
815
|
+
const client = rezo.create();
|
|
816
|
+
|
|
817
|
+
// Download with progress
|
|
818
|
+
const download = await client.download('https://example.com/file.zip', {
|
|
819
|
+
outputPath: './downloads/file.zip'
|
|
820
|
+
});
|
|
821
|
+
|
|
822
|
+
download.on('progress', (progress) => {
|
|
823
|
+
console.log(`Downloaded: ${progress.percent}%`);
|
|
824
|
+
console.log(`Speed: ${progress.speed} bytes/sec`);
|
|
825
|
+
console.log(`ETA: ${progress.eta} seconds`);
|
|
826
|
+
});
|
|
827
|
+
|
|
828
|
+
download.on('complete', (result) => {
|
|
829
|
+
console.log('Download complete:', result.path);
|
|
830
|
+
console.log('Total size:', result.size);
|
|
831
|
+
console.log('Duration:', result.duration);
|
|
832
|
+
});
|
|
833
|
+
|
|
834
|
+
download.on('error', (error) => {
|
|
835
|
+
console.error('Download failed:', error.message);
|
|
836
|
+
});
|
|
837
|
+
|
|
838
|
+
// Wait for completion
|
|
839
|
+
await download.finished();
|
|
840
|
+
```
|
|
841
|
+
|
|
842
|
+
### File Uploads
|
|
843
|
+
|
|
844
|
+
Upload files with progress tracking and multipart support.
|
|
845
|
+
|
|
846
|
+
```typescript
|
|
847
|
+
import rezo, { FormData } from 'rezo';
|
|
848
|
+
import { createReadStream } from 'fs';
|
|
849
|
+
|
|
850
|
+
const client = rezo.create();
|
|
851
|
+
|
|
852
|
+
// Simple file upload
|
|
853
|
+
const formData = new FormData();
|
|
854
|
+
formData.append('file', createReadStream('./document.pdf'));
|
|
855
|
+
formData.append('name', 'My Document');
|
|
856
|
+
|
|
857
|
+
const response = await client.post('https://api.example.com/upload', formData, {
|
|
858
|
+
onUploadProgress: (progress) => {
|
|
859
|
+
console.log(`Uploaded: ${Math.round(progress.loaded / progress.total * 100)}%`);
|
|
860
|
+
}
|
|
861
|
+
});
|
|
862
|
+
|
|
863
|
+
// Upload with detailed progress
|
|
864
|
+
const upload = await client.upload('https://api.example.com/upload', {
|
|
865
|
+
file: createReadStream('./large-file.zip'),
|
|
866
|
+
filename: 'archive.zip'
|
|
867
|
+
});
|
|
868
|
+
|
|
869
|
+
upload.on('progress', (progress) => {
|
|
870
|
+
console.log(`Uploaded: ${progress.percent}%`);
|
|
871
|
+
});
|
|
872
|
+
|
|
873
|
+
await upload.finished();
|
|
874
|
+
console.log('Upload complete:', upload.response.data);
|
|
875
|
+
```
|
|
876
|
+
|
|
877
|
+
### Hooks & Interceptors
|
|
878
|
+
|
|
879
|
+
Rezo provides a powerful hooks system for request/response interception.
|
|
880
|
+
|
|
881
|
+
```typescript
|
|
882
|
+
import rezo from 'rezo';
|
|
883
|
+
|
|
884
|
+
const client = rezo.create({
|
|
885
|
+
baseURL: 'https://api.example.com'
|
|
886
|
+
});
|
|
887
|
+
|
|
888
|
+
// Before request hook
|
|
889
|
+
client.hooks.beforeRequest.push((options) => {
|
|
890
|
+
// Add timestamp to all requests
|
|
891
|
+
options.headers['X-Request-Time'] = Date.now().toString();
|
|
892
|
+
|
|
893
|
+
// Log outgoing requests
|
|
894
|
+
console.log(`-> ${options.method} ${options.url}`);
|
|
895
|
+
|
|
896
|
+
return options;
|
|
897
|
+
});
|
|
898
|
+
|
|
899
|
+
// After response hook
|
|
900
|
+
client.hooks.afterResponse.push((response, options) => {
|
|
901
|
+
// Log responses
|
|
902
|
+
console.log(`<- ${response.status} ${options.url}`);
|
|
903
|
+
|
|
904
|
+
// Transform response data
|
|
905
|
+
if (response.data && typeof response.data === 'object') {
|
|
906
|
+
response.data._receivedAt = new Date().toISOString();
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
return response;
|
|
910
|
+
});
|
|
911
|
+
|
|
912
|
+
// Before retry hook
|
|
913
|
+
client.hooks.beforeRetry.push((error, retryCount) => {
|
|
914
|
+
console.log(`Retry attempt ${retryCount} for ${error.config.url}`);
|
|
915
|
+
|
|
916
|
+
// Optionally modify the request before retry
|
|
917
|
+
error.config.headers['X-Retry-Count'] = retryCount.toString();
|
|
918
|
+
});
|
|
919
|
+
|
|
920
|
+
// Before error hook (transform errors)
|
|
921
|
+
client.hooks.beforeError.push((error) => {
|
|
922
|
+
// Add additional context to errors
|
|
923
|
+
error.timestamp = new Date().toISOString();
|
|
924
|
+
error.requestId = error.config?.headers?.['X-Request-ID'];
|
|
925
|
+
|
|
926
|
+
return error;
|
|
927
|
+
});
|
|
928
|
+
|
|
929
|
+
// Authentication refresh example
|
|
930
|
+
client.hooks.afterResponse.push(async (response, options, client) => {
|
|
931
|
+
if (response.status === 401 && !options._retry) {
|
|
932
|
+
// Refresh token
|
|
933
|
+
const refreshResponse = await client.post('/auth/refresh', {
|
|
934
|
+
refreshToken: getRefreshToken()
|
|
935
|
+
});
|
|
936
|
+
|
|
937
|
+
// Update authorization header
|
|
938
|
+
const newToken = refreshResponse.data.accessToken;
|
|
939
|
+
client.defaults.headers['Authorization'] = `Bearer ${newToken}`;
|
|
940
|
+
|
|
941
|
+
// Retry original request
|
|
942
|
+
options._retry = true;
|
|
943
|
+
return client.request(options);
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
return response;
|
|
947
|
+
});
|
|
948
|
+
```
|
|
949
|
+
|
|
950
|
+
### Retry Logic
|
|
951
|
+
|
|
952
|
+
Configure automatic retry with exponential backoff.
|
|
953
|
+
|
|
954
|
+
```typescript
|
|
955
|
+
import rezo from 'rezo';
|
|
956
|
+
|
|
957
|
+
const client = rezo.create({
|
|
958
|
+
retry: {
|
|
959
|
+
limit: 3, // Maximum retry attempts
|
|
960
|
+
delay: 1000, // Initial delay (ms)
|
|
961
|
+
maxDelay: 30000, // Maximum delay (ms)
|
|
962
|
+
backoff: 2, // Exponential backoff multiplier
|
|
963
|
+
retryOn: [408, 429, 500, 502, 503, 504] // Status codes to retry
|
|
964
|
+
}
|
|
965
|
+
});
|
|
966
|
+
|
|
967
|
+
// Custom retry logic
|
|
968
|
+
const customClient = rezo.create({
|
|
969
|
+
retry: {
|
|
970
|
+
limit: 5,
|
|
971
|
+
retryOn: (error, attemptNumber) => {
|
|
972
|
+
// Retry on network errors
|
|
973
|
+
if (error.code === 'ECONNRESET' || error.code === 'ETIMEDOUT') {
|
|
974
|
+
return true;
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
// Retry on specific status codes
|
|
978
|
+
if (error.response?.status >= 500) {
|
|
979
|
+
return true;
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
// Don't retry on 4xx errors (except 429)
|
|
983
|
+
if (error.response?.status === 429) {
|
|
984
|
+
return true;
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
return false;
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
});
|
|
991
|
+
|
|
992
|
+
// Per-request retry configuration
|
|
993
|
+
await client.get('https://api.example.com/data', {
|
|
994
|
+
retry: {
|
|
995
|
+
limit: 10,
|
|
996
|
+
delay: 500
|
|
997
|
+
}
|
|
998
|
+
});
|
|
999
|
+
|
|
1000
|
+
// Disable retry for specific request
|
|
1001
|
+
await client.get('https://api.example.com/critical', {
|
|
1002
|
+
retry: false
|
|
1003
|
+
});
|
|
1004
|
+
```
|
|
1005
|
+
|
|
1006
|
+
### Error Handling
|
|
1007
|
+
|
|
1008
|
+
Rezo provides structured errors with actionable information.
|
|
1009
|
+
|
|
1010
|
+
```typescript
|
|
1011
|
+
import rezo, { RezoError, isRezoError, RezoErrorCode } from 'rezo';
|
|
1012
|
+
|
|
1013
|
+
const client = rezo.create();
|
|
1014
|
+
|
|
1015
|
+
try {
|
|
1016
|
+
await client.get('https://api.example.com/data');
|
|
1017
|
+
} catch (error) {
|
|
1018
|
+
if (isRezoError(error)) {
|
|
1019
|
+
// Access structured error information
|
|
1020
|
+
console.log('Error Code:', error.code);
|
|
1021
|
+
console.log('Message:', error.message);
|
|
1022
|
+
console.log('Details:', error.details);
|
|
1023
|
+
console.log('Suggestion:', error.suggestion);
|
|
1024
|
+
|
|
1025
|
+
// Check error type
|
|
1026
|
+
if (error.isTimeout) {
|
|
1027
|
+
console.log('Request timed out');
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
if (error.isNetworkError) {
|
|
1031
|
+
console.log('Network error occurred');
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
if (error.isHttpError) {
|
|
1035
|
+
console.log('HTTP error:', error.status, error.statusText);
|
|
1036
|
+
console.log('Response data:', error.response?.data);
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
if (error.isProxyError) {
|
|
1040
|
+
console.log('Proxy connection failed');
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
if (error.isTlsError) {
|
|
1044
|
+
console.log('TLS/SSL error');
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
// Check if error is retryable
|
|
1048
|
+
if (error.isRetryable) {
|
|
1049
|
+
console.log('This error can be retried');
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
// Access original request configuration
|
|
1053
|
+
console.log('Request URL:', error.config?.url);
|
|
1054
|
+
console.log('Request Method:', error.config?.method);
|
|
1055
|
+
|
|
1056
|
+
// Serialize error (hides sensitive data)
|
|
1057
|
+
console.log('Error JSON:', JSON.stringify(error));
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
// Error code enumeration
|
|
1062
|
+
switch (error.code) {
|
|
1063
|
+
case RezoErrorCode.TIMEOUT:
|
|
1064
|
+
// Handle timeout
|
|
1065
|
+
break;
|
|
1066
|
+
case RezoErrorCode.NETWORK_ERROR:
|
|
1067
|
+
// Handle network error
|
|
1068
|
+
break;
|
|
1069
|
+
case RezoErrorCode.PROXY_ERROR:
|
|
1070
|
+
// Handle proxy error
|
|
1071
|
+
break;
|
|
1072
|
+
case RezoErrorCode.TLS_ERROR:
|
|
1073
|
+
// Handle TLS error
|
|
1074
|
+
break;
|
|
1075
|
+
case RezoErrorCode.HTTP_ERROR:
|
|
1076
|
+
// Handle HTTP error
|
|
1077
|
+
break;
|
|
1078
|
+
}
|
|
1079
|
+
```
|
|
1080
|
+
|
|
1081
|
+
### Performance Metrics
|
|
1082
|
+
|
|
1083
|
+
Track detailed timing information for performance monitoring.
|
|
1084
|
+
|
|
1085
|
+
```typescript
|
|
1086
|
+
import rezo, { RezoPerformance } from 'rezo';
|
|
1087
|
+
|
|
1088
|
+
const client = rezo.create({
|
|
1089
|
+
timing: true // Enable timing collection
|
|
1090
|
+
});
|
|
1091
|
+
|
|
1092
|
+
const response = await client.get('https://api.example.com/data');
|
|
1093
|
+
|
|
1094
|
+
// Access timing metrics
|
|
1095
|
+
const timing = response.timing;
|
|
1096
|
+
console.log('DNS Lookup:', timing.dns, 'ms');
|
|
1097
|
+
console.log('TCP Connect:', timing.connect, 'ms');
|
|
1098
|
+
console.log('TLS Handshake:', timing.tls, 'ms');
|
|
1099
|
+
console.log('Time to First Byte:', timing.firstByte, 'ms');
|
|
1100
|
+
console.log('Download Time:', timing.download, 'ms');
|
|
1101
|
+
console.log('Total Time:', timing.total, 'ms');
|
|
1102
|
+
|
|
1103
|
+
// Using RezoPerformance utility
|
|
1104
|
+
const perf = new RezoPerformance();
|
|
1105
|
+
|
|
1106
|
+
perf.mark('start');
|
|
1107
|
+
await client.get('https://api.example.com/data');
|
|
1108
|
+
perf.mark('end');
|
|
1109
|
+
|
|
1110
|
+
const metrics = perf.measure('request', 'start', 'end');
|
|
1111
|
+
console.log('Request Duration:', metrics.duration, 'ms');
|
|
1112
|
+
```
|
|
1113
|
+
|
|
1114
|
+
---
|
|
1115
|
+
|
|
1116
|
+
## Platform Support
|
|
1117
|
+
|
|
1118
|
+
Rezo is designed for universal JavaScript environments with platform-specific optimizations.
|
|
1119
|
+
|
|
1120
|
+
### Node.js
|
|
1121
|
+
|
|
1122
|
+
Full feature support including all adapters, cookie management, proxy, and streaming.
|
|
1123
|
+
|
|
1124
|
+
```typescript
|
|
1125
|
+
import rezo from 'rezo';
|
|
1126
|
+
// or
|
|
1127
|
+
import rezo from 'rezo/platform/node';
|
|
1128
|
+
```
|
|
1129
|
+
|
|
1130
|
+
### Bun
|
|
1131
|
+
|
|
1132
|
+
Optimized for Bun runtime with native performance.
|
|
1133
|
+
|
|
1134
|
+
```typescript
|
|
1135
|
+
import rezo from 'rezo';
|
|
1136
|
+
// or
|
|
1137
|
+
import rezo from 'rezo/platform/bun';
|
|
1138
|
+
```
|
|
1139
|
+
|
|
1140
|
+
### Deno
|
|
1141
|
+
|
|
1142
|
+
Compatible with Deno's Node.js compatibility layer.
|
|
1143
|
+
|
|
1144
|
+
```typescript
|
|
1145
|
+
import rezo from 'npm:rezo';
|
|
1146
|
+
// or
|
|
1147
|
+
import rezo from 'npm:rezo/platform/deno';
|
|
1148
|
+
```
|
|
1149
|
+
|
|
1150
|
+
### Browser
|
|
1151
|
+
|
|
1152
|
+
Lightweight Fetch-based implementation for browsers.
|
|
1153
|
+
|
|
1154
|
+
```typescript
|
|
1155
|
+
import rezo from 'rezo';
|
|
1156
|
+
// or
|
|
1157
|
+
import rezo from 'rezo/platform/browser';
|
|
1158
|
+
```
|
|
1159
|
+
|
|
1160
|
+
### Cloudflare Workers & Edge Runtimes
|
|
1161
|
+
|
|
1162
|
+
Edge-compatible Fetch adapter with minimal footprint.
|
|
1163
|
+
|
|
1164
|
+
```typescript
|
|
1165
|
+
import rezo from 'rezo';
|
|
1166
|
+
// or
|
|
1167
|
+
import rezo from 'rezo/platform/worker';
|
|
1168
|
+
```
|
|
1169
|
+
|
|
1170
|
+
### React Native
|
|
1171
|
+
|
|
1172
|
+
Mobile-optimized adapter with file system integration.
|
|
1173
|
+
|
|
1174
|
+
```typescript
|
|
1175
|
+
import rezo from 'rezo';
|
|
1176
|
+
// or
|
|
1177
|
+
import rezo from 'rezo/platform/react-native';
|
|
1178
|
+
```
|
|
1179
|
+
|
|
1180
|
+
---
|
|
1181
|
+
|
|
1182
|
+
## Migration Guide
|
|
1183
|
+
|
|
1184
|
+
### Migrating from Fetch API
|
|
1185
|
+
|
|
1186
|
+
```typescript
|
|
1187
|
+
// Before (Fetch)
|
|
1188
|
+
const response = await fetch('https://api.example.com/data', {
|
|
1189
|
+
method: 'POST',
|
|
1190
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1191
|
+
body: JSON.stringify({ name: 'John' })
|
|
1192
|
+
});
|
|
1193
|
+
const data = await response.json();
|
|
1194
|
+
|
|
1195
|
+
// After (Rezo)
|
|
1196
|
+
const response = await rezo.post('https://api.example.com/data', {
|
|
1197
|
+
name: 'John'
|
|
1198
|
+
});
|
|
1199
|
+
const data = response.data; // Automatically parsed
|
|
1200
|
+
```
|
|
1201
|
+
|
|
1202
|
+
### Migrating from Got
|
|
1203
|
+
|
|
1204
|
+
```typescript
|
|
1205
|
+
// Before (Got)
|
|
1206
|
+
import got from 'got';
|
|
1207
|
+
const response = await got.post('https://api.example.com/data', {
|
|
1208
|
+
json: { name: 'John' },
|
|
1209
|
+
responseType: 'json',
|
|
1210
|
+
retry: { limit: 3 }
|
|
1211
|
+
});
|
|
1212
|
+
|
|
1213
|
+
// After (Rezo)
|
|
1214
|
+
import rezo from 'rezo';
|
|
1215
|
+
const response = await rezo.post('https://api.example.com/data',
|
|
1216
|
+
{ name: 'John' },
|
|
1217
|
+
{ retry: { limit: 3 } }
|
|
1218
|
+
);
|
|
1219
|
+
```
|
|
1220
|
+
|
|
1221
|
+
### Migrating from Node-Fetch
|
|
1222
|
+
|
|
1223
|
+
```typescript
|
|
1224
|
+
// Before (node-fetch)
|
|
1225
|
+
import fetch from 'node-fetch';
|
|
1226
|
+
const response = await fetch('https://api.example.com/data');
|
|
1227
|
+
const data = await response.json();
|
|
1228
|
+
|
|
1229
|
+
// After (Rezo)
|
|
1230
|
+
import rezo from 'rezo';
|
|
1231
|
+
const { data } = await rezo.get('https://api.example.com/data');
|
|
1232
|
+
```
|
|
1233
|
+
|
|
1234
|
+
---
|
|
1235
|
+
|
|
1236
|
+
## TypeScript
|
|
1237
|
+
|
|
1238
|
+
Rezo is written in TypeScript and provides comprehensive type definitions.
|
|
1239
|
+
|
|
1240
|
+
### Generic Response Types
|
|
1241
|
+
|
|
1242
|
+
```typescript
|
|
1243
|
+
import rezo from 'rezo';
|
|
1244
|
+
|
|
1245
|
+
interface User {
|
|
1246
|
+
id: number;
|
|
1247
|
+
name: string;
|
|
1248
|
+
email: string;
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1251
|
+
interface ApiResponse<T> {
|
|
1252
|
+
data: T;
|
|
1253
|
+
meta: { total: number; page: number };
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
const client = rezo.create({ baseURL: 'https://api.example.com' });
|
|
1257
|
+
|
|
1258
|
+
// Typed response
|
|
1259
|
+
const response = await client.get<User>('/users/1');
|
|
1260
|
+
const user: User = response.data;
|
|
1261
|
+
|
|
1262
|
+
// Nested generic types
|
|
1263
|
+
const listResponse = await client.get<ApiResponse<User[]>>('/users');
|
|
1264
|
+
const users: User[] = listResponse.data.data;
|
|
1265
|
+
const total: number = listResponse.data.meta.total;
|
|
1266
|
+
```
|
|
1267
|
+
|
|
1268
|
+
### Request Configuration Types
|
|
1269
|
+
|
|
1270
|
+
```typescript
|
|
1271
|
+
import { RezoConfig, RezoResponse, RezoError } from 'rezo';
|
|
1272
|
+
|
|
1273
|
+
// Type-safe configuration
|
|
1274
|
+
const config: RezoConfig = {
|
|
1275
|
+
baseURL: 'https://api.example.com',
|
|
1276
|
+
timeout: 30000,
|
|
1277
|
+
headers: {
|
|
1278
|
+
'Authorization': 'Bearer token'
|
|
1279
|
+
}
|
|
1280
|
+
};
|
|
1281
|
+
|
|
1282
|
+
// Type-safe error handling
|
|
1283
|
+
function handleError(error: RezoError): void {
|
|
1284
|
+
if (error.isHttpError) {
|
|
1285
|
+
console.log('Status:', error.status);
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
```
|
|
1289
|
+
|
|
1290
|
+
### Custom Type Guards
|
|
1291
|
+
|
|
1292
|
+
```typescript
|
|
1293
|
+
import { isRezoError, RezoError } from 'rezo';
|
|
1294
|
+
|
|
1295
|
+
try {
|
|
1296
|
+
await rezo.get('/data');
|
|
1297
|
+
} catch (error) {
|
|
1298
|
+
if (isRezoError(error)) {
|
|
1299
|
+
// TypeScript knows error is RezoError here
|
|
1300
|
+
console.log(error.code);
|
|
1301
|
+
console.log(error.details);
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
```
|
|
1305
|
+
|
|
1306
|
+
---
|
|
1307
|
+
|
|
1308
|
+
## Crawler Module
|
|
1309
|
+
|
|
1310
|
+
Rezo includes a powerful web crawler module for web scraping scenarios.
|
|
1311
|
+
|
|
1312
|
+
```typescript
|
|
1313
|
+
import { Crawler, CrawlerOptions } from 'rezo/crawler';
|
|
1314
|
+
|
|
1315
|
+
const options = new CrawlerOptions()
|
|
1316
|
+
.setGlobalProxy({ host: 'proxy.example.com', port: 8080 })
|
|
1317
|
+
.setGlobalHeaders({ 'User-Agent': 'Mozilla/5.0...' })
|
|
1318
|
+
.addLimiter({ domain: 'example.com', concurrency: 2, interval: 1000 });
|
|
1319
|
+
|
|
1320
|
+
const crawler = new Crawler(options);
|
|
1321
|
+
|
|
1322
|
+
crawler.onDocument(async (doc, url) => {
|
|
1323
|
+
const title = doc.querySelector('title')?.textContent;
|
|
1324
|
+
console.log(`Title: ${title}`);
|
|
1325
|
+
});
|
|
1326
|
+
|
|
1327
|
+
crawler.onAnchor((href, anchor) => {
|
|
1328
|
+
console.log(`Found link: ${href}`);
|
|
1329
|
+
});
|
|
1330
|
+
|
|
1331
|
+
await crawler.crawl('https://example.com');
|
|
1332
|
+
```
|
|
1333
|
+
|
|
1334
|
+
---
|
|
1335
|
+
|
|
1336
|
+
## DOM Module
|
|
1337
|
+
|
|
1338
|
+
Rezo includes a DOM parsing module that re-exports all [linkedom](https://github.com/WebReflection/linkedom) utilities for HTML parsing and DOM manipulation.
|
|
1339
|
+
|
|
1340
|
+
```typescript
|
|
1341
|
+
import { parseHTML, DOMParser } from 'rezo/dom';
|
|
1342
|
+
|
|
1343
|
+
// Parse HTML string into a document
|
|
1344
|
+
const { document } = parseHTML('<html><body><h1>Hello World</h1></body></html>');
|
|
1345
|
+
console.log(document.querySelector('h1')?.textContent); // 'Hello World'
|
|
1346
|
+
|
|
1347
|
+
// Using DOMParser
|
|
1348
|
+
const parser = new DOMParser();
|
|
1349
|
+
const doc = parser.parseFromString('<div class="content">Text</div>', 'text/html');
|
|
1350
|
+
console.log(doc.querySelector('.content')?.textContent); // 'Text'
|
|
1351
|
+
```
|
|
1352
|
+
|
|
1353
|
+
### Available Exports
|
|
1354
|
+
|
|
1355
|
+
All linkedom exports are available from `rezo/dom`:
|
|
1356
|
+
|
|
1357
|
+
- `parseHTML` - Parse HTML string into a window-like object
|
|
1358
|
+
- `parseJSON` / `toJSON` - JSON serialization utilities
|
|
1359
|
+
- `DOMParser` - Standard DOMParser interface
|
|
1360
|
+
- `Document` - Document constructor
|
|
1361
|
+
- `Event` / `CustomEvent` / `InputEvent` - Event classes
|
|
1362
|
+
- `EventTarget` - EventTarget interface
|
|
1363
|
+
- `NodeList` - NodeList interface
|
|
1364
|
+
|
|
1365
|
+
---
|
|
1366
|
+
|
|
1367
|
+
## Troubleshooting
|
|
1368
|
+
|
|
1369
|
+
### Common Issues
|
|
1370
|
+
|
|
1371
|
+
#### Request Timeout
|
|
1372
|
+
|
|
1373
|
+
```typescript
|
|
1374
|
+
// Increase timeout
|
|
1375
|
+
const client = rezo.create({
|
|
1376
|
+
timeout: 60000, // 60 seconds
|
|
1377
|
+
connectTimeout: 10000 // 10 seconds for connection
|
|
1378
|
+
});
|
|
1379
|
+
```
|
|
1380
|
+
|
|
1381
|
+
#### SSL Certificate Errors
|
|
1382
|
+
|
|
1383
|
+
```typescript
|
|
1384
|
+
// For development only - not recommended for production
|
|
1385
|
+
const client = rezo.create({
|
|
1386
|
+
rejectUnauthorized: false
|
|
1387
|
+
});
|
|
1388
|
+
|
|
1389
|
+
// Better: provide custom CA
|
|
1390
|
+
const client = rezo.create({
|
|
1391
|
+
ca: fs.readFileSync('./custom-ca.pem')
|
|
1392
|
+
});
|
|
1393
|
+
```
|
|
1394
|
+
|
|
1395
|
+
#### Proxy Connection Issues
|
|
1396
|
+
|
|
1397
|
+
```typescript
|
|
1398
|
+
// Verify proxy settings
|
|
1399
|
+
const client = rezo.create({
|
|
1400
|
+
proxy: {
|
|
1401
|
+
protocol: 'http', // Ensure correct protocol
|
|
1402
|
+
host: 'proxy.example.com',
|
|
1403
|
+
port: 8080
|
|
1404
|
+
}
|
|
1405
|
+
});
|
|
1406
|
+
|
|
1407
|
+
// Test proxy connection
|
|
1408
|
+
try {
|
|
1409
|
+
await client.get('https://httpbin.org/ip');
|
|
1410
|
+
} catch (error) {
|
|
1411
|
+
if (error.isProxyError) {
|
|
1412
|
+
console.log('Proxy connection failed:', error.details);
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
```
|
|
1416
|
+
|
|
1417
|
+
#### Memory Issues with Large Files
|
|
1418
|
+
|
|
1419
|
+
```typescript
|
|
1420
|
+
// Use streaming for large files
|
|
1421
|
+
const response = await client.get('https://example.com/large-file', {
|
|
1422
|
+
responseType: 'stream'
|
|
1423
|
+
});
|
|
1424
|
+
|
|
1425
|
+
// Or use download API
|
|
1426
|
+
const download = await client.download('https://example.com/large-file', {
|
|
1427
|
+
outputPath: './large-file.zip'
|
|
1428
|
+
});
|
|
1429
|
+
```
|
|
1430
|
+
|
|
1431
|
+
### Debug Mode
|
|
1432
|
+
|
|
1433
|
+
```typescript
|
|
1434
|
+
// Enable debug logging
|
|
1435
|
+
const client = rezo.create({
|
|
1436
|
+
debug: true
|
|
1437
|
+
});
|
|
1438
|
+
|
|
1439
|
+
// Or set environment variable
|
|
1440
|
+
process.env.REZO_DEBUG = 'true';
|
|
1441
|
+
```
|
|
1442
|
+
|
|
1443
|
+
---
|
|
1444
|
+
|
|
1445
|
+
## Contributing
|
|
1446
|
+
|
|
1447
|
+
We welcome contributions to Rezo! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
|
|
1448
|
+
|
|
1449
|
+
### Development Setup
|
|
1450
|
+
|
|
1451
|
+
```bash
|
|
1452
|
+
# Clone repository
|
|
1453
|
+
git clone https://github.com/yuniqsolutions/rezo.git
|
|
1454
|
+
cd rezo
|
|
1455
|
+
|
|
1456
|
+
# Install dependencies
|
|
1457
|
+
bun install
|
|
1458
|
+
|
|
1459
|
+
# Run tests
|
|
1460
|
+
bun test
|
|
1461
|
+
|
|
1462
|
+
# Build
|
|
1463
|
+
bun run bundle
|
|
1464
|
+
|
|
1465
|
+
# Lint
|
|
1466
|
+
bun run lint
|
|
1467
|
+
```
|
|
1468
|
+
|
|
1469
|
+
### Running Tests
|
|
1470
|
+
|
|
1471
|
+
```bash
|
|
1472
|
+
# Run all tests
|
|
1473
|
+
bun test
|
|
1474
|
+
|
|
1475
|
+
# Run with coverage
|
|
1476
|
+
bun run test:coverage
|
|
1477
|
+
|
|
1478
|
+
# Run specific test file
|
|
1479
|
+
bun test src/adapters/http.test.ts
|
|
1480
|
+
```
|
|
1481
|
+
|
|
1482
|
+
---
|
|
1483
|
+
|
|
1484
|
+
## Acknowledgments
|
|
1485
|
+
|
|
1486
|
+
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.
|
|
1487
|
+
|
|
1488
|
+
---
|
|
1489
|
+
|
|
1490
|
+
## License
|
|
1491
|
+
|
|
1492
|
+
Rezo is open source software licensed under the [MIT License](LICENSE).
|
|
1493
|
+
|
|
1494
|
+
Copyright (c) 2024-2025 Yuniq Solutions Tech
|
|
1495
|
+
|
|
1496
|
+
See the [LICENSE](LICENSE) file for the complete license text.
|
|
1497
|
+
|
|
1498
|
+
---
|
|
1499
|
+
|
|
1500
|
+
<p align="center">
|
|
1501
|
+
<img src="assets/icon.svg" alt="Rezo Icon" width="60">
|
|
1502
|
+
</p>
|
|
1503
|
+
|
|
1504
|
+
<p align="center">
|
|
1505
|
+
<strong>Built with lightning speed in mind</strong><br>
|
|
1506
|
+
<sub>Made by <a href="https://yuniq.solutions">Yuniq Solutions Tech</a></sub>
|
|
1507
|
+
</p>
|