rezo 1.0.44 → 1.0.46

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.
Files changed (37) hide show
  1. package/dist/adapters/entries/curl.d.ts +115 -0
  2. package/dist/adapters/entries/fetch.d.ts +115 -0
  3. package/dist/adapters/entries/http.d.ts +115 -0
  4. package/dist/adapters/entries/http2.d.ts +115 -0
  5. package/dist/adapters/entries/react-native.d.ts +115 -0
  6. package/dist/adapters/entries/xhr.d.ts +115 -0
  7. package/dist/adapters/fetch.cjs +18 -0
  8. package/dist/adapters/fetch.js +18 -0
  9. package/dist/adapters/http.cjs +22 -4
  10. package/dist/adapters/http.js +22 -4
  11. package/dist/adapters/http2.cjs +21 -0
  12. package/dist/adapters/http2.js +21 -0
  13. package/dist/adapters/index.cjs +6 -6
  14. package/dist/adapters/xhr.cjs +19 -0
  15. package/dist/adapters/xhr.js +19 -0
  16. package/dist/cache/index.cjs +9 -9
  17. package/dist/core/hooks.cjs +4 -2
  18. package/dist/core/hooks.js +4 -2
  19. package/dist/crawler/index.cjs +40 -40
  20. package/dist/crawler.d.ts +115 -0
  21. package/dist/entries/crawler.cjs +5 -5
  22. package/dist/index.cjs +27 -27
  23. package/dist/index.d.ts +115 -0
  24. package/dist/internal/agents/index.cjs +10 -10
  25. package/dist/platform/browser.d.ts +115 -0
  26. package/dist/platform/bun.d.ts +115 -0
  27. package/dist/platform/deno.d.ts +115 -0
  28. package/dist/platform/node.d.ts +115 -0
  29. package/dist/platform/react-native.d.ts +115 -0
  30. package/dist/platform/worker.d.ts +115 -0
  31. package/dist/proxy/index.cjs +5 -5
  32. package/dist/proxy/index.js +1 -1
  33. package/dist/queue/index.cjs +8 -8
  34. package/dist/responses/universal/index.cjs +11 -11
  35. package/dist/utils/rate-limit-wait.cjs +217 -0
  36. package/dist/utils/rate-limit-wait.js +208 -0
  37. package/package.json +1 -1
@@ -3,7 +3,7 @@ import {
3
3
  HttpProxyAgent,
4
4
  HttpsProxyAgent,
5
5
  SocksProxyAgent
6
- } from '../internal/agents.js';
6
+ } from '../internal/agents/index.js';
7
7
  import { parseProxyString } from './parse.js';
8
8
  export { ProxyManager } from './manager.js';
9
9
  export { parseProxyString } from './parse.js';
@@ -1,8 +1,8 @@
1
- const _mod_hijcy5 = require('./queue.cjs');
2
- exports.RezoQueue = _mod_hijcy5.RezoQueue;;
3
- const _mod_ccb3p2 = require('./http-queue.cjs');
4
- exports.HttpQueue = _mod_ccb3p2.HttpQueue;
5
- exports.extractDomain = _mod_ccb3p2.extractDomain;;
6
- const _mod_h69bcv = require('./types.cjs');
7
- exports.Priority = _mod_h69bcv.Priority;
8
- exports.HttpMethodPriority = _mod_h69bcv.HttpMethodPriority;;
1
+ const _mod_o7kuxe = require('./queue.cjs');
2
+ exports.RezoQueue = _mod_o7kuxe.RezoQueue;;
3
+ const _mod_6uv6qn = require('./http-queue.cjs');
4
+ exports.HttpQueue = _mod_6uv6qn.HttpQueue;
5
+ exports.extractDomain = _mod_6uv6qn.extractDomain;;
6
+ const _mod_3lc2he = require('./types.cjs');
7
+ exports.Priority = _mod_3lc2he.Priority;
8
+ exports.HttpMethodPriority = _mod_3lc2he.HttpMethodPriority;;
@@ -1,11 +1,11 @@
1
- const _mod_gfdadc = require('./event-emitter.cjs');
2
- exports.UniversalEventEmitter = _mod_gfdadc.UniversalEventEmitter;;
3
- const _mod_9z6wit = require('./stream.cjs');
4
- exports.UniversalStreamResponse = _mod_9z6wit.UniversalStreamResponse;
5
- exports.StreamResponse = _mod_9z6wit.StreamResponse;;
6
- const _mod_ybfqy6 = require('./download.cjs');
7
- exports.UniversalDownloadResponse = _mod_ybfqy6.UniversalDownloadResponse;
8
- exports.DownloadResponse = _mod_ybfqy6.DownloadResponse;;
9
- const _mod_48lipr = require('./upload.cjs');
10
- exports.UniversalUploadResponse = _mod_48lipr.UniversalUploadResponse;
11
- exports.UploadResponse = _mod_48lipr.UploadResponse;;
1
+ const _mod_074c53 = require('./event-emitter.cjs');
2
+ exports.UniversalEventEmitter = _mod_074c53.UniversalEventEmitter;;
3
+ const _mod_z5czf2 = require('./stream.cjs');
4
+ exports.UniversalStreamResponse = _mod_z5czf2.UniversalStreamResponse;
5
+ exports.StreamResponse = _mod_z5czf2.StreamResponse;;
6
+ const _mod_n8mvxg = require('./download.cjs');
7
+ exports.UniversalDownloadResponse = _mod_n8mvxg.UniversalDownloadResponse;
8
+ exports.DownloadResponse = _mod_n8mvxg.DownloadResponse;;
9
+ const _mod_n99wlf = require('./upload.cjs');
10
+ exports.UniversalUploadResponse = _mod_n99wlf.UniversalUploadResponse;
11
+ exports.UploadResponse = _mod_n99wlf.UploadResponse;;
@@ -0,0 +1,217 @@
1
+ const { RezoHeaders } = require('./headers.cjs');
2
+ const DEFAULT_WAIT_STATUS_CODES = exports.DEFAULT_WAIT_STATUS_CODES = [429];
3
+ const DEFAULT_MAX_WAIT_TIME = exports.DEFAULT_MAX_WAIT_TIME = 60000;
4
+ const DEFAULT_WAIT_TIME = exports.DEFAULT_WAIT_TIME = 1000;
5
+ const DEFAULT_MAX_WAIT_ATTEMPTS = exports.DEFAULT_MAX_WAIT_ATTEMPTS = 3;
6
+ function shouldWaitOnStatus(status, waitOnStatus) {
7
+ if (!waitOnStatus)
8
+ return false;
9
+ if (waitOnStatus === true) {
10
+ return DEFAULT_WAIT_STATUS_CODES.includes(status);
11
+ }
12
+ if (Array.isArray(waitOnStatus)) {
13
+ return waitOnStatus.includes(status);
14
+ }
15
+ return false;
16
+ }
17
+ function parseRetryAfterHeader(value) {
18
+ if (!value)
19
+ return null;
20
+ const trimmed = value.trim();
21
+ const seconds = parseInt(trimmed, 10);
22
+ if (!isNaN(seconds) && seconds >= 0) {
23
+ return seconds * 1000;
24
+ }
25
+ const date = new Date(trimmed);
26
+ if (!isNaN(date.getTime())) {
27
+ const delayMs = date.getTime() - Date.now();
28
+ return delayMs > 0 ? delayMs : 0;
29
+ }
30
+ return null;
31
+ }
32
+ function getNestedValue(obj, path) {
33
+ if (!obj || typeof path !== "string")
34
+ return;
35
+ const parts = path.split(".");
36
+ let current = obj;
37
+ for (const part of parts) {
38
+ if (current === null || current === undefined)
39
+ return;
40
+ if (typeof current !== "object")
41
+ return;
42
+ current = current[part];
43
+ }
44
+ return current;
45
+ }
46
+ function extractWaitTime(response, options) {
47
+ const source = options.waitTimeSource ?? "retry-after";
48
+ const defaultWaitTime = options.defaultWaitTime ?? DEFAULT_WAIT_TIME;
49
+ if (typeof source === "function") {
50
+ try {
51
+ const seconds = source(response);
52
+ if (seconds !== null && seconds !== undefined && seconds > 0) {
53
+ return {
54
+ waitTimeMs: seconds * 1000,
55
+ source: "function"
56
+ };
57
+ }
58
+ } catch {}
59
+ return {
60
+ waitTimeMs: defaultWaitTime,
61
+ source: "default"
62
+ };
63
+ }
64
+ if (source === "retry-after") {
65
+ const headerValue = response.headers?.get?.("retry-after") ?? response.headers?.get?.("Retry-After") ?? response.headers?.["retry-after"] ?? response.headers?.["Retry-After"];
66
+ const waitTimeMs = parseRetryAfterHeader(headerValue);
67
+ if (waitTimeMs !== null) {
68
+ return {
69
+ waitTimeMs,
70
+ source: "header",
71
+ sourcePath: "retry-after"
72
+ };
73
+ }
74
+ return {
75
+ waitTimeMs: defaultWaitTime,
76
+ source: "default"
77
+ };
78
+ }
79
+ if (typeof source === "object" && "header" in source) {
80
+ const headerName = source.header;
81
+ const headerValue = response.headers?.get?.(headerName) ?? response.headers?.get?.(headerName.toLowerCase()) ?? response.headers?.[headerName] ?? response.headers?.[headerName.toLowerCase()];
82
+ if (headerValue) {
83
+ const numValue = parseInt(headerValue, 10);
84
+ if (!isNaN(numValue)) {
85
+ const now = Math.floor(Date.now() / 1000);
86
+ if (numValue > now && numValue < now + 86400 * 365) {
87
+ const waitTimeMs = (numValue - now) * 1000;
88
+ return {
89
+ waitTimeMs: waitTimeMs > 0 ? waitTimeMs : defaultWaitTime,
90
+ source: "header",
91
+ sourcePath: headerName
92
+ };
93
+ }
94
+ return {
95
+ waitTimeMs: numValue * 1000,
96
+ source: "header",
97
+ sourcePath: headerName
98
+ };
99
+ }
100
+ const waitTimeMs = parseRetryAfterHeader(headerValue);
101
+ if (waitTimeMs !== null) {
102
+ return {
103
+ waitTimeMs,
104
+ source: "header",
105
+ sourcePath: headerName
106
+ };
107
+ }
108
+ }
109
+ return {
110
+ waitTimeMs: defaultWaitTime,
111
+ source: "default"
112
+ };
113
+ }
114
+ if (typeof source === "object" && "body" in source) {
115
+ const bodyPath = source.body;
116
+ const value = getNestedValue(response.data, bodyPath);
117
+ if (value !== null && value !== undefined) {
118
+ const numValue = typeof value === "number" ? value : parseInt(String(value), 10);
119
+ if (!isNaN(numValue) && numValue > 0) {
120
+ return {
121
+ waitTimeMs: numValue * 1000,
122
+ source: "body",
123
+ sourcePath: bodyPath
124
+ };
125
+ }
126
+ }
127
+ return {
128
+ waitTimeMs: defaultWaitTime,
129
+ source: "default"
130
+ };
131
+ }
132
+ return {
133
+ waitTimeMs: defaultWaitTime,
134
+ source: "default"
135
+ };
136
+ }
137
+ function createRateLimitWaitEvent(status, waitTimeMs, attempt, maxAttempts, source, sourcePath, url, method) {
138
+ return {
139
+ status,
140
+ waitTime: waitTimeMs,
141
+ attempt,
142
+ maxAttempts,
143
+ source,
144
+ sourcePath,
145
+ url,
146
+ method,
147
+ timestamp: Date.now()
148
+ };
149
+ }
150
+ async function executeRateLimitWaitHooks(event, config) {
151
+ const hooks = config.hooks?.onRateLimitWait;
152
+ if (!hooks || hooks.length === 0)
153
+ return;
154
+ for (const hook of hooks) {
155
+ try {
156
+ await hook(event, config);
157
+ } catch (err) {
158
+ if (config.debug) {
159
+ console.log("[Rezo Debug] onRateLimitWait hook error:", err);
160
+ }
161
+ }
162
+ }
163
+ }
164
+ function sleep(ms) {
165
+ return new Promise((resolve) => setTimeout(resolve, ms));
166
+ }
167
+ function normalizeHeaders(headers) {
168
+ if (!headers)
169
+ return new RezoHeaders;
170
+ if (headers instanceof RezoHeaders)
171
+ return headers;
172
+ if (typeof headers.get === "function")
173
+ return headers;
174
+ try {
175
+ return new RezoHeaders(headers);
176
+ } catch {
177
+ return new RezoHeaders;
178
+ }
179
+ }
180
+ async function handleRateLimitWait(ctx) {
181
+ const { status, headers, data, url, method, config, options, currentWaitAttempt } = ctx;
182
+ if (!shouldWaitOnStatus(status, options.waitOnStatus)) {
183
+ return { shouldRetry: false, waitAttempt: currentWaitAttempt, waitedMs: 0 };
184
+ }
185
+ const maxAttempts = options.maxWaitAttempts ?? DEFAULT_MAX_WAIT_ATTEMPTS;
186
+ const maxWaitTime = options.maxWaitTime ?? DEFAULT_MAX_WAIT_TIME;
187
+ const nextAttempt = currentWaitAttempt + 1;
188
+ if (nextAttempt > maxAttempts) {
189
+ return { shouldRetry: false, waitAttempt: currentWaitAttempt, waitedMs: 0 };
190
+ }
191
+ const normalizedHeaders = normalizeHeaders(headers);
192
+ const extracted = extractWaitTime({ status, headers: normalizedHeaders, data }, options);
193
+ let waitTimeMs = extracted.waitTimeMs;
194
+ if (maxWaitTime > 0 && waitTimeMs > maxWaitTime) {
195
+ return { shouldRetry: false, waitAttempt: currentWaitAttempt, waitedMs: 0 };
196
+ }
197
+ const event = createRateLimitWaitEvent(status, waitTimeMs, nextAttempt, maxAttempts, extracted.source, extracted.sourcePath, url, method);
198
+ await executeRateLimitWaitHooks(event, config);
199
+ if (config.debug) {
200
+ console.log(`[Rezo Debug] Rate limit (${status}) - waiting ${waitTimeMs}ms (attempt ${nextAttempt}/${maxAttempts}, source: ${extracted.source}${extracted.sourcePath ? `:${extracted.sourcePath}` : ""})`);
201
+ }
202
+ await sleep(waitTimeMs);
203
+ return {
204
+ shouldRetry: true,
205
+ waitAttempt: nextAttempt,
206
+ waitedMs: waitTimeMs
207
+ };
208
+ }
209
+
210
+ exports.shouldWaitOnStatus = shouldWaitOnStatus;
211
+ exports.parseRetryAfterHeader = parseRetryAfterHeader;
212
+ exports.getNestedValue = getNestedValue;
213
+ exports.extractWaitTime = extractWaitTime;
214
+ exports.createRateLimitWaitEvent = createRateLimitWaitEvent;
215
+ exports.executeRateLimitWaitHooks = executeRateLimitWaitHooks;
216
+ exports.sleep = sleep;
217
+ exports.handleRateLimitWait = handleRateLimitWait;
@@ -0,0 +1,208 @@
1
+ import { RezoHeaders } from './headers.js';
2
+ export const DEFAULT_WAIT_STATUS_CODES = [429];
3
+ export const DEFAULT_MAX_WAIT_TIME = 60000;
4
+ export const DEFAULT_WAIT_TIME = 1000;
5
+ export const DEFAULT_MAX_WAIT_ATTEMPTS = 3;
6
+ export function shouldWaitOnStatus(status, waitOnStatus) {
7
+ if (!waitOnStatus)
8
+ return false;
9
+ if (waitOnStatus === true) {
10
+ return DEFAULT_WAIT_STATUS_CODES.includes(status);
11
+ }
12
+ if (Array.isArray(waitOnStatus)) {
13
+ return waitOnStatus.includes(status);
14
+ }
15
+ return false;
16
+ }
17
+ export function parseRetryAfterHeader(value) {
18
+ if (!value)
19
+ return null;
20
+ const trimmed = value.trim();
21
+ const seconds = parseInt(trimmed, 10);
22
+ if (!isNaN(seconds) && seconds >= 0) {
23
+ return seconds * 1000;
24
+ }
25
+ const date = new Date(trimmed);
26
+ if (!isNaN(date.getTime())) {
27
+ const delayMs = date.getTime() - Date.now();
28
+ return delayMs > 0 ? delayMs : 0;
29
+ }
30
+ return null;
31
+ }
32
+ export function getNestedValue(obj, path) {
33
+ if (!obj || typeof path !== "string")
34
+ return;
35
+ const parts = path.split(".");
36
+ let current = obj;
37
+ for (const part of parts) {
38
+ if (current === null || current === undefined)
39
+ return;
40
+ if (typeof current !== "object")
41
+ return;
42
+ current = current[part];
43
+ }
44
+ return current;
45
+ }
46
+ export function extractWaitTime(response, options) {
47
+ const source = options.waitTimeSource ?? "retry-after";
48
+ const defaultWaitTime = options.defaultWaitTime ?? DEFAULT_WAIT_TIME;
49
+ if (typeof source === "function") {
50
+ try {
51
+ const seconds = source(response);
52
+ if (seconds !== null && seconds !== undefined && seconds > 0) {
53
+ return {
54
+ waitTimeMs: seconds * 1000,
55
+ source: "function"
56
+ };
57
+ }
58
+ } catch {}
59
+ return {
60
+ waitTimeMs: defaultWaitTime,
61
+ source: "default"
62
+ };
63
+ }
64
+ if (source === "retry-after") {
65
+ const headerValue = response.headers?.get?.("retry-after") ?? response.headers?.get?.("Retry-After") ?? response.headers?.["retry-after"] ?? response.headers?.["Retry-After"];
66
+ const waitTimeMs = parseRetryAfterHeader(headerValue);
67
+ if (waitTimeMs !== null) {
68
+ return {
69
+ waitTimeMs,
70
+ source: "header",
71
+ sourcePath: "retry-after"
72
+ };
73
+ }
74
+ return {
75
+ waitTimeMs: defaultWaitTime,
76
+ source: "default"
77
+ };
78
+ }
79
+ if (typeof source === "object" && "header" in source) {
80
+ const headerName = source.header;
81
+ const headerValue = response.headers?.get?.(headerName) ?? response.headers?.get?.(headerName.toLowerCase()) ?? response.headers?.[headerName] ?? response.headers?.[headerName.toLowerCase()];
82
+ if (headerValue) {
83
+ const numValue = parseInt(headerValue, 10);
84
+ if (!isNaN(numValue)) {
85
+ const now = Math.floor(Date.now() / 1000);
86
+ if (numValue > now && numValue < now + 86400 * 365) {
87
+ const waitTimeMs = (numValue - now) * 1000;
88
+ return {
89
+ waitTimeMs: waitTimeMs > 0 ? waitTimeMs : defaultWaitTime,
90
+ source: "header",
91
+ sourcePath: headerName
92
+ };
93
+ }
94
+ return {
95
+ waitTimeMs: numValue * 1000,
96
+ source: "header",
97
+ sourcePath: headerName
98
+ };
99
+ }
100
+ const waitTimeMs = parseRetryAfterHeader(headerValue);
101
+ if (waitTimeMs !== null) {
102
+ return {
103
+ waitTimeMs,
104
+ source: "header",
105
+ sourcePath: headerName
106
+ };
107
+ }
108
+ }
109
+ return {
110
+ waitTimeMs: defaultWaitTime,
111
+ source: "default"
112
+ };
113
+ }
114
+ if (typeof source === "object" && "body" in source) {
115
+ const bodyPath = source.body;
116
+ const value = getNestedValue(response.data, bodyPath);
117
+ if (value !== null && value !== undefined) {
118
+ const numValue = typeof value === "number" ? value : parseInt(String(value), 10);
119
+ if (!isNaN(numValue) && numValue > 0) {
120
+ return {
121
+ waitTimeMs: numValue * 1000,
122
+ source: "body",
123
+ sourcePath: bodyPath
124
+ };
125
+ }
126
+ }
127
+ return {
128
+ waitTimeMs: defaultWaitTime,
129
+ source: "default"
130
+ };
131
+ }
132
+ return {
133
+ waitTimeMs: defaultWaitTime,
134
+ source: "default"
135
+ };
136
+ }
137
+ export function createRateLimitWaitEvent(status, waitTimeMs, attempt, maxAttempts, source, sourcePath, url, method) {
138
+ return {
139
+ status,
140
+ waitTime: waitTimeMs,
141
+ attempt,
142
+ maxAttempts,
143
+ source,
144
+ sourcePath,
145
+ url,
146
+ method,
147
+ timestamp: Date.now()
148
+ };
149
+ }
150
+ export async function executeRateLimitWaitHooks(event, config) {
151
+ const hooks = config.hooks?.onRateLimitWait;
152
+ if (!hooks || hooks.length === 0)
153
+ return;
154
+ for (const hook of hooks) {
155
+ try {
156
+ await hook(event, config);
157
+ } catch (err) {
158
+ if (config.debug) {
159
+ console.log("[Rezo Debug] onRateLimitWait hook error:", err);
160
+ }
161
+ }
162
+ }
163
+ }
164
+ export function sleep(ms) {
165
+ return new Promise((resolve) => setTimeout(resolve, ms));
166
+ }
167
+ function normalizeHeaders(headers) {
168
+ if (!headers)
169
+ return new RezoHeaders;
170
+ if (headers instanceof RezoHeaders)
171
+ return headers;
172
+ if (typeof headers.get === "function")
173
+ return headers;
174
+ try {
175
+ return new RezoHeaders(headers);
176
+ } catch {
177
+ return new RezoHeaders;
178
+ }
179
+ }
180
+ export async function handleRateLimitWait(ctx) {
181
+ const { status, headers, data, url, method, config, options, currentWaitAttempt } = ctx;
182
+ if (!shouldWaitOnStatus(status, options.waitOnStatus)) {
183
+ return { shouldRetry: false, waitAttempt: currentWaitAttempt, waitedMs: 0 };
184
+ }
185
+ const maxAttempts = options.maxWaitAttempts ?? DEFAULT_MAX_WAIT_ATTEMPTS;
186
+ const maxWaitTime = options.maxWaitTime ?? DEFAULT_MAX_WAIT_TIME;
187
+ const nextAttempt = currentWaitAttempt + 1;
188
+ if (nextAttempt > maxAttempts) {
189
+ return { shouldRetry: false, waitAttempt: currentWaitAttempt, waitedMs: 0 };
190
+ }
191
+ const normalizedHeaders = normalizeHeaders(headers);
192
+ const extracted = extractWaitTime({ status, headers: normalizedHeaders, data }, options);
193
+ let waitTimeMs = extracted.waitTimeMs;
194
+ if (maxWaitTime > 0 && waitTimeMs > maxWaitTime) {
195
+ return { shouldRetry: false, waitAttempt: currentWaitAttempt, waitedMs: 0 };
196
+ }
197
+ const event = createRateLimitWaitEvent(status, waitTimeMs, nextAttempt, maxAttempts, extracted.source, extracted.sourcePath, url, method);
198
+ await executeRateLimitWaitHooks(event, config);
199
+ if (config.debug) {
200
+ console.log(`[Rezo Debug] Rate limit (${status}) - waiting ${waitTimeMs}ms (attempt ${nextAttempt}/${maxAttempts}, source: ${extracted.source}${extracted.sourcePath ? `:${extracted.sourcePath}` : ""})`);
201
+ }
202
+ await sleep(waitTimeMs);
203
+ return {
204
+ shouldRetry: true,
205
+ waitAttempt: nextAttempt,
206
+ waitedMs: waitTimeMs
207
+ };
208
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rezo",
3
- "version": "1.0.44",
3
+ "version": "1.0.46",
4
4
  "description": "Lightning-fast, enterprise-grade HTTP client for modern JavaScript. Full HTTP/2 support, intelligent cookie management, multiple adapters (HTTP, Fetch, cURL, XHR), streaming, proxy support (HTTP/HTTPS/SOCKS), and cross-environment compatibility.",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.js",