recker 1.0.26 → 1.0.27

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 (171) hide show
  1. package/dist/browser/browser/cache.d.ts +40 -0
  2. package/dist/browser/browser/cache.js +199 -0
  3. package/dist/browser/browser/crypto.d.ts +24 -0
  4. package/dist/browser/browser/crypto.js +80 -0
  5. package/dist/browser/browser/index.d.ts +31 -0
  6. package/dist/browser/browser/index.js +31 -0
  7. package/dist/browser/browser/recker.d.ts +26 -0
  8. package/dist/browser/browser/recker.js +61 -0
  9. package/dist/browser/cache/basic-file-storage.d.ts +12 -0
  10. package/dist/browser/cache/basic-file-storage.js +50 -0
  11. package/dist/browser/cache/memory-limits.d.ts +20 -0
  12. package/dist/browser/cache/memory-limits.js +96 -0
  13. package/dist/browser/cache/memory-storage.d.ts +132 -0
  14. package/dist/browser/cache/memory-storage.js +454 -0
  15. package/dist/browser/cache.d.ts +40 -0
  16. package/dist/browser/cache.js +199 -0
  17. package/dist/browser/constants/http-status.d.ts +73 -0
  18. package/dist/browser/constants/http-status.js +156 -0
  19. package/dist/browser/cookies/memory-cookie-jar.d.ts +30 -0
  20. package/dist/browser/cookies/memory-cookie-jar.js +210 -0
  21. package/dist/browser/core/client.d.ts +118 -0
  22. package/dist/browser/core/client.js +667 -0
  23. package/dist/browser/core/errors.d.ts +142 -0
  24. package/dist/browser/core/errors.js +308 -0
  25. package/dist/browser/core/index.d.ts +5 -0
  26. package/dist/browser/core/index.js +5 -0
  27. package/dist/browser/core/request-promise.d.ts +23 -0
  28. package/dist/browser/core/request-promise.js +82 -0
  29. package/dist/browser/core/request.d.ts +20 -0
  30. package/dist/browser/core/request.js +76 -0
  31. package/dist/browser/core/response.d.ts +34 -0
  32. package/dist/browser/core/response.js +178 -0
  33. package/dist/browser/crypto.d.ts +24 -0
  34. package/dist/browser/crypto.js +80 -0
  35. package/dist/browser/index.d.ts +31 -0
  36. package/dist/browser/index.js +31 -0
  37. package/dist/browser/plugins/auth/api-key.d.ts +8 -0
  38. package/dist/browser/plugins/auth/api-key.js +27 -0
  39. package/dist/browser/plugins/auth/auth0.d.ts +33 -0
  40. package/dist/browser/plugins/auth/auth0.js +94 -0
  41. package/dist/browser/plugins/auth/aws-sigv4.d.ts +10 -0
  42. package/dist/browser/plugins/auth/aws-sigv4.js +88 -0
  43. package/dist/browser/plugins/auth/azure-ad.d.ts +48 -0
  44. package/dist/browser/plugins/auth/azure-ad.js +152 -0
  45. package/dist/browser/plugins/auth/basic.d.ts +7 -0
  46. package/dist/browser/plugins/auth/basic.js +13 -0
  47. package/dist/browser/plugins/auth/bearer.d.ts +8 -0
  48. package/dist/browser/plugins/auth/bearer.js +17 -0
  49. package/dist/browser/plugins/auth/cognito.d.ts +45 -0
  50. package/dist/browser/plugins/auth/cognito.js +208 -0
  51. package/dist/browser/plugins/auth/digest.d.ts +8 -0
  52. package/dist/browser/plugins/auth/digest.js +100 -0
  53. package/dist/browser/plugins/auth/firebase.d.ts +32 -0
  54. package/dist/browser/plugins/auth/firebase.js +195 -0
  55. package/dist/browser/plugins/auth/github-app.d.ts +36 -0
  56. package/dist/browser/plugins/auth/github-app.js +170 -0
  57. package/dist/browser/plugins/auth/google-service-account.d.ts +49 -0
  58. package/dist/browser/plugins/auth/google-service-account.js +172 -0
  59. package/dist/browser/plugins/auth/index.d.ts +15 -0
  60. package/dist/browser/plugins/auth/index.js +15 -0
  61. package/dist/browser/plugins/auth/mtls.d.ts +37 -0
  62. package/dist/browser/plugins/auth/mtls.js +140 -0
  63. package/dist/browser/plugins/auth/oauth2.d.ts +8 -0
  64. package/dist/browser/plugins/auth/oauth2.js +26 -0
  65. package/dist/browser/plugins/auth/oidc.d.ts +55 -0
  66. package/dist/browser/plugins/auth/oidc.js +222 -0
  67. package/dist/browser/plugins/auth/okta.d.ts +47 -0
  68. package/dist/browser/plugins/auth/okta.js +157 -0
  69. package/dist/browser/plugins/auth.d.ts +1 -0
  70. package/dist/browser/plugins/auth.js +1 -0
  71. package/dist/browser/plugins/cache.d.ts +15 -0
  72. package/dist/browser/plugins/cache.js +486 -0
  73. package/dist/browser/plugins/circuit-breaker.d.ts +13 -0
  74. package/dist/browser/plugins/circuit-breaker.js +100 -0
  75. package/dist/browser/plugins/compression.d.ts +4 -0
  76. package/dist/browser/plugins/compression.js +130 -0
  77. package/dist/browser/plugins/cookie-jar.d.ts +5 -0
  78. package/dist/browser/plugins/cookie-jar.js +72 -0
  79. package/dist/browser/plugins/dedup.d.ts +5 -0
  80. package/dist/browser/plugins/dedup.js +35 -0
  81. package/dist/browser/plugins/graphql.d.ts +13 -0
  82. package/dist/browser/plugins/graphql.js +58 -0
  83. package/dist/browser/plugins/grpc-web.d.ts +79 -0
  84. package/dist/browser/plugins/grpc-web.js +261 -0
  85. package/dist/browser/plugins/hls.d.ts +105 -0
  86. package/dist/browser/plugins/hls.js +395 -0
  87. package/dist/browser/plugins/jsonrpc.d.ts +75 -0
  88. package/dist/browser/plugins/jsonrpc.js +143 -0
  89. package/dist/browser/plugins/logger.d.ts +13 -0
  90. package/dist/browser/plugins/logger.js +108 -0
  91. package/dist/browser/plugins/odata.d.ts +181 -0
  92. package/dist/browser/plugins/odata.js +564 -0
  93. package/dist/browser/plugins/pagination.d.ts +16 -0
  94. package/dist/browser/plugins/pagination.js +105 -0
  95. package/dist/browser/plugins/rate-limit.d.ts +15 -0
  96. package/dist/browser/plugins/rate-limit.js +162 -0
  97. package/dist/browser/plugins/retry.d.ts +14 -0
  98. package/dist/browser/plugins/retry.js +116 -0
  99. package/dist/browser/plugins/scrape.d.ts +21 -0
  100. package/dist/browser/plugins/scrape.js +82 -0
  101. package/dist/browser/plugins/server-timing.d.ts +7 -0
  102. package/dist/browser/plugins/server-timing.js +24 -0
  103. package/dist/browser/plugins/soap.d.ts +72 -0
  104. package/dist/browser/plugins/soap.js +347 -0
  105. package/dist/browser/plugins/xml.d.ts +9 -0
  106. package/dist/browser/plugins/xml.js +194 -0
  107. package/dist/browser/plugins/xsrf.d.ts +9 -0
  108. package/dist/browser/plugins/xsrf.js +48 -0
  109. package/dist/browser/recker.d.ts +26 -0
  110. package/dist/browser/recker.js +61 -0
  111. package/dist/browser/runner/request-runner.d.ts +46 -0
  112. package/dist/browser/runner/request-runner.js +89 -0
  113. package/dist/browser/scrape/document.d.ts +44 -0
  114. package/dist/browser/scrape/document.js +210 -0
  115. package/dist/browser/scrape/element.d.ts +49 -0
  116. package/dist/browser/scrape/element.js +176 -0
  117. package/dist/browser/scrape/extractors.d.ts +16 -0
  118. package/dist/browser/scrape/extractors.js +356 -0
  119. package/dist/browser/scrape/types.d.ts +107 -0
  120. package/dist/browser/scrape/types.js +1 -0
  121. package/dist/browser/transport/fetch.d.ts +11 -0
  122. package/dist/browser/transport/fetch.js +143 -0
  123. package/dist/browser/transport/undici.d.ts +38 -0
  124. package/dist/browser/transport/undici.js +897 -0
  125. package/dist/browser/types/ai.d.ts +267 -0
  126. package/dist/browser/types/ai.js +1 -0
  127. package/dist/browser/types/index.d.ts +351 -0
  128. package/dist/browser/types/index.js +1 -0
  129. package/dist/browser/types/logger.d.ts +16 -0
  130. package/dist/browser/types/logger.js +66 -0
  131. package/dist/browser/types/udp.d.ts +138 -0
  132. package/dist/browser/types/udp.js +1 -0
  133. package/dist/browser/utils/agent-manager.d.ts +29 -0
  134. package/dist/browser/utils/agent-manager.js +160 -0
  135. package/dist/browser/utils/body.d.ts +10 -0
  136. package/dist/browser/utils/body.js +148 -0
  137. package/dist/browser/utils/charset.d.ts +15 -0
  138. package/dist/browser/utils/charset.js +169 -0
  139. package/dist/browser/utils/concurrency.d.ts +20 -0
  140. package/dist/browser/utils/concurrency.js +120 -0
  141. package/dist/browser/utils/dns.d.ts +6 -0
  142. package/dist/browser/utils/dns.js +26 -0
  143. package/dist/browser/utils/header-parser.d.ts +94 -0
  144. package/dist/browser/utils/header-parser.js +617 -0
  145. package/dist/browser/utils/html-cleaner.d.ts +1 -0
  146. package/dist/browser/utils/html-cleaner.js +21 -0
  147. package/dist/browser/utils/link-header.d.ts +69 -0
  148. package/dist/browser/utils/link-header.js +190 -0
  149. package/dist/browser/utils/optional-require.d.ts +19 -0
  150. package/dist/browser/utils/optional-require.js +105 -0
  151. package/dist/browser/utils/progress.d.ts +8 -0
  152. package/dist/browser/utils/progress.js +82 -0
  153. package/dist/browser/utils/request-pool.d.ts +22 -0
  154. package/dist/browser/utils/request-pool.js +101 -0
  155. package/dist/browser/utils/sse.d.ts +7 -0
  156. package/dist/browser/utils/sse.js +67 -0
  157. package/dist/browser/utils/streaming.d.ts +17 -0
  158. package/dist/browser/utils/streaming.js +84 -0
  159. package/dist/browser/utils/try-fn.d.ts +3 -0
  160. package/dist/browser/utils/try-fn.js +59 -0
  161. package/dist/browser/utils/user-agent.d.ts +44 -0
  162. package/dist/browser/utils/user-agent.js +100 -0
  163. package/dist/browser/utils/whois.d.ts +32 -0
  164. package/dist/browser/utils/whois.js +246 -0
  165. package/dist/browser/websocket/client.d.ts +65 -0
  166. package/dist/browser/websocket/client.js +313 -0
  167. package/dist/cli/index.d.ts +1 -0
  168. package/dist/cli/index.js +1 -0
  169. package/dist/transport/fetch.d.ts +7 -1
  170. package/dist/transport/fetch.js +58 -76
  171. package/package.json +34 -2
@@ -0,0 +1,667 @@
1
+ import { consoleLogger } from '../types/index.js';
2
+ import { HttpRequest } from './request.js';
3
+ import { UndiciTransport } from '../transport/undici.js';
4
+ import { RequestPromise } from './request-promise.js';
5
+ import { HttpError, MaxSizeExceededError, ConfigurationError, ValidationError, TimeoutError } from '../core/errors.js';
6
+ import { processBody, createFormData, isPlainObject } from '../utils/body.js';
7
+ import { AgentManager } from '../utils/agent-manager.js';
8
+ import { RequestPool } from '../utils/request-pool.js';
9
+ import { normalizeConcurrency } from '../utils/concurrency.js';
10
+ import { getDefaultUserAgent } from '../utils/user-agent.js';
11
+ import { paginate, streamPages } from '../plugins/pagination.js';
12
+ import { retryPlugin } from '../plugins/retry.js';
13
+ import { cachePlugin } from '../plugins/cache.js';
14
+ import { dedupPlugin } from '../plugins/dedup.js';
15
+ import { createXSRFMiddleware } from '../plugins/xsrf.js';
16
+ import { createCompressionMiddleware } from '../plugins/compression.js';
17
+ import { serializeXML } from '../plugins/xml.js';
18
+ import { MemoryStorage } from '../cache/memory-storage.js';
19
+ import { FileStorage } from '../cache/basic-file-storage.js';
20
+ import { RequestRunner } from '../runner/request-runner.js';
21
+ import { ReckerWebSocket } from '../websocket/client.js';
22
+ import { whois as performWhois, isDomainAvailable } from '../utils/whois.js';
23
+ import { MemoryCookieJar } from '../cookies/memory-cookie-jar.js';
24
+ import { scrape as scrapeHelper } from '../plugins/scrape.js';
25
+ import { HlsPromise } from '../plugins/hls.js';
26
+ export class Client {
27
+ baseUrl;
28
+ middlewares;
29
+ hooks;
30
+ transport;
31
+ defaultHeaders;
32
+ defaultParams;
33
+ paginationConfig;
34
+ handler;
35
+ logger;
36
+ debugEnabled;
37
+ agentManager;
38
+ concurrencyConfig;
39
+ requestPool;
40
+ maxResponseSize;
41
+ cookieJar;
42
+ cookieIgnoreInvalid = false;
43
+ defaultTimeout;
44
+ constructor(options = {}) {
45
+ this.baseUrl = options.baseUrl || '';
46
+ this.middlewares = options.middlewares || [];
47
+ this.defaultTimeout = options.timeout;
48
+ this.hooks = {
49
+ beforeRequest: options.hooks?.beforeRequest || [],
50
+ afterResponse: options.hooks?.afterResponse || [],
51
+ onError: options.hooks?.onError || [],
52
+ onRetry: options.hooks?.onRetry || [],
53
+ onUrlResolved: options.hooks?.onUrlResolved || [],
54
+ };
55
+ this.defaultHeaders = {
56
+ 'User-Agent': getDefaultUserAgent(),
57
+ ...(options.headers || {})
58
+ };
59
+ this.defaultParams = options.defaults?.params || {};
60
+ this.paginationConfig = options.pagination;
61
+ this.maxResponseSize = options.maxResponseSize;
62
+ this.debugEnabled = options.debug === true;
63
+ if (this.debugEnabled) {
64
+ this.logger = options.logger ?? consoleLogger;
65
+ }
66
+ else if (options.logger) {
67
+ this.logger = options.logger;
68
+ }
69
+ this.concurrencyConfig = normalizeConcurrency({
70
+ concurrency: options.concurrency,
71
+ http2: options.http2
72
+ });
73
+ if (options.transport) {
74
+ this.transport = options.transport;
75
+ }
76
+ else {
77
+ let http2Options;
78
+ if (options.http2) {
79
+ if (typeof options.http2 === 'boolean') {
80
+ http2Options = { enabled: options.http2 };
81
+ }
82
+ else {
83
+ http2Options = options.http2;
84
+ }
85
+ }
86
+ this.agentManager = new AgentManager(this.concurrencyConfig.agent);
87
+ this.transport = new UndiciTransport(this.baseUrl || undefined, {
88
+ proxy: options.proxy,
89
+ http2: http2Options,
90
+ dns: options.dns,
91
+ agent: this.agentManager,
92
+ socketPath: options.socketPath,
93
+ tls: options.tls,
94
+ observability: options.observability
95
+ });
96
+ }
97
+ if (options.retry) {
98
+ retryPlugin(options.retry)(this);
99
+ }
100
+ if (this.concurrencyConfig.max < Infinity || this.concurrencyConfig.requestsPerInterval < Infinity) {
101
+ this.requestPool = new RequestPool({
102
+ concurrency: this.concurrencyConfig.max,
103
+ requestsPerInterval: this.concurrencyConfig.requestsPerInterval,
104
+ interval: this.concurrencyConfig.interval
105
+ });
106
+ this.middlewares.unshift(this.requestPool.asMiddleware());
107
+ if (this.debugEnabled && this.logger) {
108
+ this.logger.debug(`Global concurrency limit: ${this.concurrencyConfig.max} concurrent requests`);
109
+ }
110
+ }
111
+ else {
112
+ if (this.debugEnabled && this.logger) {
113
+ this.logger.debug('No global concurrency limit (allows unlimited parallel batches)');
114
+ }
115
+ }
116
+ if (options.dedup) {
117
+ dedupPlugin(options.dedup)(this);
118
+ }
119
+ if (options.cache) {
120
+ let storage;
121
+ if (options.cache.storage) {
122
+ storage = options.cache.storage;
123
+ }
124
+ else if (options.cache.driver === 'file') {
125
+ storage = new FileStorage(options.cache.fileStoragePath);
126
+ }
127
+ else {
128
+ storage = new MemoryStorage();
129
+ }
130
+ cachePlugin({
131
+ ...options.cache,
132
+ storage
133
+ })(this);
134
+ }
135
+ if (options.plugins) {
136
+ options.plugins.forEach((plugin) => plugin(this));
137
+ }
138
+ if (options.compression) {
139
+ const compressionMiddleware = createCompressionMiddleware(options.compression);
140
+ if (compressionMiddleware) {
141
+ this.middlewares.push(compressionMiddleware);
142
+ }
143
+ }
144
+ if (options.xsrf) {
145
+ const xsrfMiddleware = createXSRFMiddleware(options.xsrf);
146
+ if (xsrfMiddleware) {
147
+ this.middlewares.push(xsrfMiddleware);
148
+ }
149
+ }
150
+ if (options.cookies) {
151
+ this.setupCookieJar(options.cookies);
152
+ }
153
+ if (this.maxResponseSize !== undefined) {
154
+ this.middlewares.push(this.createMaxSizeMiddleware(this.maxResponseSize));
155
+ }
156
+ if (this.debugEnabled && this.logger) {
157
+ this.middlewares.unshift(this.createLoggingMiddleware(this.logger));
158
+ }
159
+ this.middlewares.push(this.httpErrorMiddleware);
160
+ this.handler = this.composeMiddlewares();
161
+ }
162
+ createLoggingMiddleware(logger) {
163
+ return async (req, next) => {
164
+ const startTime = Date.now();
165
+ logger.debug({ type: 'request', method: req.method, url: req.url }, `→ ${req.method} ${req.url}`);
166
+ try {
167
+ const response = await next(req);
168
+ const duration = Date.now() - startTime;
169
+ logger.debug({
170
+ type: 'response',
171
+ method: req.method,
172
+ url: req.url,
173
+ status: response.status,
174
+ duration,
175
+ timings: response.timings,
176
+ }, `← ${response.status} ${req.method} ${req.url} (${duration}ms)`);
177
+ return response;
178
+ }
179
+ catch (error) {
180
+ const duration = Date.now() - startTime;
181
+ const err = error;
182
+ logger.error({
183
+ type: 'error',
184
+ method: req.method,
185
+ url: req.url,
186
+ error: err.message,
187
+ errorName: err.name,
188
+ duration,
189
+ }, `✖ ${req.method} ${req.url} - ${err.message}`);
190
+ throw error;
191
+ }
192
+ };
193
+ }
194
+ createMaxSizeMiddleware(globalMaxSize) {
195
+ return async (req, next) => {
196
+ const response = await next(req);
197
+ const limit = req.maxResponseSize ?? globalMaxSize;
198
+ if (limit === undefined)
199
+ return response;
200
+ const contentLength = response.headers.get('Content-Length');
201
+ if (contentLength) {
202
+ const size = parseInt(contentLength, 10);
203
+ if (!isNaN(size) && size > limit) {
204
+ throw new MaxSizeExceededError(limit, size, req);
205
+ }
206
+ }
207
+ return response;
208
+ };
209
+ }
210
+ setupCookieJar(options) {
211
+ if (options === true) {
212
+ this.cookieJar = new MemoryCookieJar();
213
+ }
214
+ else if (typeof options === 'object') {
215
+ if (options.jar === true) {
216
+ this.cookieJar = new MemoryCookieJar();
217
+ }
218
+ else if (options.jar && typeof options.jar === 'object') {
219
+ this.cookieJar = options.jar;
220
+ }
221
+ this.cookieIgnoreInvalid = options.ignoreInvalid ?? false;
222
+ }
223
+ if (this.cookieJar) {
224
+ this.middlewares.push(this.createCookieMiddleware());
225
+ }
226
+ }
227
+ createCookieMiddleware() {
228
+ return async (req, next) => {
229
+ const jar = this.cookieJar;
230
+ try {
231
+ const cookieString = await jar.getCookieString(req.url);
232
+ if (cookieString) {
233
+ const existingCookie = req.headers.get('cookie');
234
+ const newCookie = existingCookie
235
+ ? `${existingCookie}; ${cookieString}`
236
+ : cookieString;
237
+ req.headers.set('cookie', newCookie);
238
+ }
239
+ }
240
+ catch (error) {
241
+ if (!this.cookieIgnoreInvalid) {
242
+ throw error;
243
+ }
244
+ }
245
+ const response = await next(req);
246
+ const setCookieHeader = response.headers.get('set-cookie');
247
+ if (setCookieHeader) {
248
+ const cookies = this.splitSetCookieHeader(setCookieHeader);
249
+ for (const cookie of cookies) {
250
+ try {
251
+ await jar.setCookie(cookie, req.url);
252
+ }
253
+ catch (error) {
254
+ if (!this.cookieIgnoreInvalid) {
255
+ throw error;
256
+ }
257
+ }
258
+ }
259
+ }
260
+ return response;
261
+ };
262
+ }
263
+ splitSetCookieHeader(header) {
264
+ return header.split(/,(?=\s*[a-zA-Z0-9_-]+=)/g).map(s => s.trim());
265
+ }
266
+ composeMiddlewares() {
267
+ const chain = [...this.middlewares];
268
+ const transportDispatch = this.transport.dispatch.bind(this.transport);
269
+ if (this.hooks.beforeRequest?.length || this.hooks.afterResponse?.length) {
270
+ chain.unshift(this.hooksMiddleware);
271
+ }
272
+ if (chain.length === 0) {
273
+ return transportDispatch;
274
+ }
275
+ return chain.reduceRight((next, middleware) => {
276
+ return (req) => middleware(req, next);
277
+ }, transportDispatch);
278
+ }
279
+ hooksMiddleware = async (req, next) => {
280
+ let modifiedReq = req;
281
+ if (this.hooks.beforeRequest && this.hooks.beforeRequest.length > 0) {
282
+ for (const hook of this.hooks.beforeRequest) {
283
+ const result = await hook(modifiedReq);
284
+ if (result) {
285
+ modifiedReq = result;
286
+ }
287
+ }
288
+ }
289
+ try {
290
+ let response = await next(modifiedReq);
291
+ if (this.hooks.afterResponse && this.hooks.afterResponse.length > 0) {
292
+ for (const hook of this.hooks.afterResponse) {
293
+ const result = await hook(modifiedReq, response);
294
+ if (result) {
295
+ response = result;
296
+ }
297
+ }
298
+ }
299
+ return response;
300
+ }
301
+ catch (error) {
302
+ if (this.hooks.onError && this.hooks.onError.length > 0) {
303
+ for (const hook of this.hooks.onError) {
304
+ const result = await hook(error, modifiedReq);
305
+ if (result) {
306
+ return result;
307
+ }
308
+ }
309
+ }
310
+ throw error;
311
+ }
312
+ };
313
+ httpErrorMiddleware = async (req, next) => {
314
+ const response = await next(req);
315
+ if (req.throwHttpErrors !== false && !response.ok && response.status !== 304) {
316
+ throw new HttpError(response, req);
317
+ }
318
+ return response;
319
+ };
320
+ use(middleware) {
321
+ this.middlewares.push(middleware);
322
+ this.handler = this.composeMiddlewares();
323
+ return this;
324
+ }
325
+ beforeRequest(hook) {
326
+ if (!this.hooks.beforeRequest) {
327
+ this.hooks.beforeRequest = [];
328
+ }
329
+ this.hooks.beforeRequest.push(hook);
330
+ this.handler = this.composeMiddlewares();
331
+ return this;
332
+ }
333
+ afterResponse(hook) {
334
+ if (!this.hooks.afterResponse) {
335
+ this.hooks.afterResponse = [];
336
+ }
337
+ this.hooks.afterResponse.push(hook);
338
+ this.handler = this.composeMiddlewares();
339
+ return this;
340
+ }
341
+ onError(hook) {
342
+ if (!this.hooks.onError) {
343
+ this.hooks.onError = [];
344
+ }
345
+ this.hooks.onError.push(hook);
346
+ this.handler = this.composeMiddlewares();
347
+ return this;
348
+ }
349
+ buildUrl(path, requestParams) {
350
+ const hasRequestParams = requestParams && Object.keys(requestParams).length > 0;
351
+ const hasDefaultParams = Object.keys(this.defaultParams).length > 0;
352
+ if (!hasRequestParams && !hasDefaultParams) {
353
+ if (path.startsWith('http://') || path.startsWith('https://')) {
354
+ return path;
355
+ }
356
+ if (this.baseUrl) {
357
+ const base = this.baseUrl.endsWith('/') ? this.baseUrl.slice(0, -1) : this.baseUrl;
358
+ const p = path.startsWith('/') ? path : '/' + path;
359
+ return base + p;
360
+ }
361
+ return path;
362
+ }
363
+ let finalPath = path;
364
+ const mergedParams = { ...this.defaultParams, ...requestParams };
365
+ const usedParams = new Set();
366
+ if (finalPath.includes(':')) {
367
+ finalPath = finalPath.replace(/:([a-zA-Z0-9_]+)/g, (match, paramName) => {
368
+ if (mergedParams && paramName in mergedParams) {
369
+ usedParams.add(paramName);
370
+ return encodeURIComponent(String(mergedParams[paramName]));
371
+ }
372
+ throw new ValidationError(`Missing required path parameter: ${paramName}`, {
373
+ field: paramName,
374
+ value: undefined,
375
+ });
376
+ });
377
+ }
378
+ let finalUrl;
379
+ if (finalPath.startsWith('http://') || finalPath.startsWith('https://')) {
380
+ finalUrl = finalPath;
381
+ }
382
+ else if (this.baseUrl) {
383
+ const base = this.baseUrl.endsWith('/') ? this.baseUrl.slice(0, -1) : this.baseUrl;
384
+ const p = finalPath.startsWith('/') ? finalPath : '/' + finalPath;
385
+ finalUrl = base + p;
386
+ }
387
+ else {
388
+ throw new ConfigurationError('Relative path provided without a baseUrl or explicit transport.', {
389
+ configKey: 'baseUrl',
390
+ });
391
+ }
392
+ const remainingKeys = Object.keys(mergedParams).filter((k) => !usedParams.has(k));
393
+ if (remainingKeys.length > 0) {
394
+ const queryParts = remainingKeys.map(key => `${encodeURIComponent(key)}=${encodeURIComponent(String(mergedParams[key]))}`);
395
+ const separator = finalUrl.includes('?') ? '&' : '?';
396
+ return finalUrl + separator + queryParts.join('&');
397
+ }
398
+ return finalUrl;
399
+ }
400
+ request(path, options = {}) {
401
+ const url = this.buildUrl(path, options.params);
402
+ let mergedHeaders;
403
+ if (options.headers) {
404
+ mergedHeaders = this.defaultHeaders instanceof Headers
405
+ ? new Headers(this.defaultHeaders)
406
+ : new Headers(this.defaultHeaders);
407
+ const optHeaders = options.headers instanceof Headers
408
+ ? options.headers
409
+ : new Headers(options.headers);
410
+ optHeaders.forEach((value, key) => mergedHeaders.append(key, value));
411
+ }
412
+ else {
413
+ mergedHeaders = this.defaultHeaders instanceof Headers
414
+ ? this.defaultHeaders
415
+ : new Headers(this.defaultHeaders);
416
+ }
417
+ const needsController = options.timeout || options.signal || this.defaultTimeout;
418
+ let controller;
419
+ let signal = options.signal;
420
+ let timeoutId;
421
+ let externalAbortCleanup;
422
+ if (needsController) {
423
+ controller = new AbortController();
424
+ signal = controller.signal;
425
+ if (options.signal) {
426
+ const externalSignal = options.signal;
427
+ const abortHandler = () => controller.abort(externalSignal.reason);
428
+ if (externalSignal.aborted) {
429
+ abortHandler();
430
+ }
431
+ else {
432
+ externalSignal.addEventListener('abort', abortHandler, { once: true });
433
+ externalAbortCleanup = () => externalSignal.removeEventListener('abort', abortHandler);
434
+ }
435
+ }
436
+ const timeout = options.timeout ?? this.defaultTimeout;
437
+ if (timeout) {
438
+ const totalTimeout = typeof timeout === 'number' ? timeout : timeout.request;
439
+ if (totalTimeout) {
440
+ timeoutId = setTimeout(() => controller.abort(new TimeoutError(req, {
441
+ phase: 'request',
442
+ timeout: totalTimeout,
443
+ })), totalTimeout);
444
+ }
445
+ }
446
+ }
447
+ const req = new HttpRequest(url, {
448
+ ...options,
449
+ headers: mergedHeaders,
450
+ signal,
451
+ maxResponseSize: options.maxResponseSize ?? this.maxResponseSize
452
+ });
453
+ const responsePromise = this.handler(req);
454
+ if (timeoutId || externalAbortCleanup) {
455
+ responsePromise.finally(() => {
456
+ if (timeoutId)
457
+ clearTimeout(timeoutId);
458
+ externalAbortCleanup?.();
459
+ }).catch(() => {
460
+ });
461
+ }
462
+ return new RequestPromise(responsePromise, controller);
463
+ }
464
+ get(path, options = {}) {
465
+ return this.request(path, { ...options, method: 'GET' });
466
+ }
467
+ async batch(requests, options = {}) {
468
+ const mapResponse = options.mapResponse ?? ((res) => res);
469
+ const batchConcurrency = options.concurrency ?? this.concurrencyConfig.runner.concurrency;
470
+ const runner = new RequestRunner({
471
+ concurrency: batchConcurrency,
472
+ retries: this.concurrencyConfig.runner.retries,
473
+ retryDelay: this.concurrencyConfig.runner.retryDelay
474
+ });
475
+ const runnerResult = await runner.run(requests, async (item) => {
476
+ const res = await this.request(item.path, item.options);
477
+ return mapResponse(res);
478
+ });
479
+ return runnerResult;
480
+ }
481
+ multi(requests, options = {}) {
482
+ return this.batch(requests, options);
483
+ }
484
+ requestWithBody(method, path, bodyOrOptions, options) {
485
+ let actualBody = bodyOrOptions;
486
+ let actualOptions = options;
487
+ const isOptionsEmpty = actualOptions === undefined ||
488
+ (typeof actualOptions === 'object' && actualOptions !== null && Object.keys(actualOptions).length === 0);
489
+ if (isOptionsEmpty && isPlainObject(bodyOrOptions)) {
490
+ const potentialOptions = bodyOrOptions;
491
+ if (potentialOptions.json !== undefined ||
492
+ potentialOptions.form !== undefined ||
493
+ potentialOptions.xml !== undefined ||
494
+ potentialOptions.body !== undefined ||
495
+ potentialOptions.headers !== undefined ||
496
+ potentialOptions.timeout !== undefined ||
497
+ potentialOptions.retry !== undefined ||
498
+ potentialOptions.hooks !== undefined ||
499
+ potentialOptions.searchParams !== undefined ||
500
+ potentialOptions.params !== undefined) {
501
+ actualOptions = bodyOrOptions;
502
+ actualBody = undefined;
503
+ }
504
+ }
505
+ actualOptions = actualOptions || {};
506
+ const { json, form, xml, ...restOptions } = actualOptions;
507
+ let finalBody = actualBody;
508
+ let explicitContentType;
509
+ if (form !== undefined) {
510
+ finalBody = createFormData(form);
511
+ explicitContentType = undefined;
512
+ }
513
+ else if (json !== undefined) {
514
+ finalBody = JSON.stringify(json);
515
+ explicitContentType = 'application/json';
516
+ }
517
+ else if (xml !== undefined) {
518
+ finalBody = '<?xml version="1.0" encoding="UTF-8"?>\n' + serializeXML(xml);
519
+ explicitContentType = 'application/xml';
520
+ }
521
+ else if (restOptions.body !== undefined) {
522
+ finalBody = restOptions.body;
523
+ }
524
+ const { body: processedBody, contentType } = processBody(finalBody);
525
+ const headers = new Headers(restOptions.headers);
526
+ const finalContentType = explicitContentType ?? contentType;
527
+ if (finalContentType && !headers.has('Content-Type')) {
528
+ headers.set('Content-Type', finalContentType);
529
+ }
530
+ return this.request(path, { ...restOptions, method, body: processedBody, headers });
531
+ }
532
+ post(path, body, options = {}) {
533
+ return this.requestWithBody('POST', path, body, options);
534
+ }
535
+ put(path, body, options = {}) {
536
+ return this.requestWithBody('PUT', path, body, options);
537
+ }
538
+ patch(path, body, options = {}) {
539
+ return this.requestWithBody('PATCH', path, body, options);
540
+ }
541
+ delete(path, options = {}) {
542
+ return this.request(path, { ...options, method: 'DELETE' });
543
+ }
544
+ head(path, options = {}) {
545
+ return this.request(path, { ...options, method: 'HEAD' });
546
+ }
547
+ options(path, options = {}) {
548
+ return this.request(path, { ...options, method: 'OPTIONS' });
549
+ }
550
+ trace(path, options = {}) {
551
+ return this.request(path, { ...options, method: 'TRACE' });
552
+ }
553
+ connect(path, options = {}) {
554
+ return this.request(path, { ...options, method: 'CONNECT' });
555
+ }
556
+ purge(path, options = {}) {
557
+ return this.request(path, { ...options, method: 'PURGE' });
558
+ }
559
+ propfind(path, body, options = {}) {
560
+ return this.requestWithBody('PROPFIND', path, body, options);
561
+ }
562
+ proppatch(path, body, options = {}) {
563
+ return this.requestWithBody('PROPPATCH', path, body, options);
564
+ }
565
+ mkcol(path, options = {}) {
566
+ return this.request(path, { ...options, method: 'MKCOL' });
567
+ }
568
+ copy(path, options = {}) {
569
+ return this.request(path, { ...options, method: 'COPY' });
570
+ }
571
+ move(path, options = {}) {
572
+ return this.request(path, { ...options, method: 'MOVE' });
573
+ }
574
+ lock(path, body, options = {}) {
575
+ return this.requestWithBody('LOCK', path, body, options);
576
+ }
577
+ unlock(path, options = {}) {
578
+ return this.request(path, { ...options, method: 'UNLOCK' });
579
+ }
580
+ link(path, body, options = {}) {
581
+ return this.requestWithBody('LINK', path, body, options);
582
+ }
583
+ unlink(path, body, options = {}) {
584
+ return this.requestWithBody('UNLINK', path, body, options);
585
+ }
586
+ scrape(path, options = {}) {
587
+ const method = options.method || 'GET';
588
+ const requestPromise = this.request(path, { ...options, method });
589
+ return scrapeHelper(requestPromise);
590
+ }
591
+ paginate(path, options = {}) {
592
+ const { getItems, getNextUrl, maxPages, pageParam, limitParam, resultsPath, nextCursorPath, ...reqOptions } = options;
593
+ const paginationOpts = {
594
+ getItems,
595
+ getNextUrl,
596
+ maxPages,
597
+ pageParam: pageParam || this.paginationConfig?.pageParam,
598
+ limitParam: limitParam || this.paginationConfig?.limitParam,
599
+ resultsPath: resultsPath || this.paginationConfig?.resultsPath,
600
+ nextCursorPath: nextCursorPath || this.paginationConfig?.nextCursorPath,
601
+ };
602
+ return paginate(this, path, reqOptions, paginationOpts);
603
+ }
604
+ pages(path, options = {}) {
605
+ const { getNextUrl, maxPages, pageParam, limitParam, resultsPath, nextCursorPath, ...reqOptions } = options;
606
+ const paginationOpts = {
607
+ getNextUrl,
608
+ maxPages,
609
+ pageParam: pageParam || this.paginationConfig?.pageParam,
610
+ limitParam: limitParam || this.paginationConfig?.limitParam,
611
+ nextCursorPath: nextCursorPath || this.paginationConfig?.nextCursorPath,
612
+ };
613
+ return streamPages(this, path, reqOptions, paginationOpts);
614
+ }
615
+ page(path, pageNumber, options = {}) {
616
+ const pageParam = options.pageParam || this.paginationConfig?.pageParam || 'page';
617
+ const url = new URL(path.startsWith('http') ? path : `http://base${path}`);
618
+ const params = { ...options.params, [pageParam]: pageNumber };
619
+ return this.request(path, { ...options, params });
620
+ }
621
+ async getAll(path, options = {}) {
622
+ const items = [];
623
+ for await (const item of this.paginate(path, options)) {
624
+ items.push(item);
625
+ }
626
+ return items;
627
+ }
628
+ websocket(path, options = {}) {
629
+ let wsUrl;
630
+ if (path.startsWith('ws://') || path.startsWith('wss://')) {
631
+ wsUrl = path;
632
+ }
633
+ else if (this.baseUrl) {
634
+ const base = this.baseUrl.replace(/^http/, 'ws');
635
+ wsUrl = new URL(path, base).toString();
636
+ }
637
+ else {
638
+ throw new ConfigurationError('WebSocket requires either a full ws:// URL or a baseUrl', {
639
+ configKey: 'baseUrl',
640
+ });
641
+ }
642
+ const headersObj = {};
643
+ if (this.defaultHeaders) {
644
+ const headers = new Headers(this.defaultHeaders);
645
+ headers.forEach((value, key) => {
646
+ headersObj[key] = value;
647
+ });
648
+ }
649
+ const finalHeaders = { ...headersObj, ...options.headers };
650
+ return new ReckerWebSocket(wsUrl, { ...options, headers: finalHeaders });
651
+ }
652
+ ws(path, options = {}) {
653
+ return this.websocket(path, options);
654
+ }
655
+ async whois(query, options) {
656
+ return performWhois(query, options);
657
+ }
658
+ async isDomainAvailable(domain, options) {
659
+ return isDomainAvailable(domain, options);
660
+ }
661
+ hls(manifestUrl, options = {}) {
662
+ return new HlsPromise(this, manifestUrl, options);
663
+ }
664
+ }
665
+ export function createClient(options = {}) {
666
+ return new Client(options);
667
+ }