recker 1.0.2-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.
Files changed (158) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +109 -0
  3. package/dist/cache/file-storage.d.ts +13 -0
  4. package/dist/cache/file-storage.d.ts.map +1 -0
  5. package/dist/cache/file-storage.js +50 -0
  6. package/dist/cache/memory-storage.d.ts +10 -0
  7. package/dist/cache/memory-storage.d.ts.map +1 -0
  8. package/dist/cache/memory-storage.js +29 -0
  9. package/dist/cache/redis-storage.d.ts +16 -0
  10. package/dist/cache/redis-storage.d.ts.map +1 -0
  11. package/dist/cache/redis-storage.js +25 -0
  12. package/dist/constants.d.ts +19 -0
  13. package/dist/constants.d.ts.map +1 -0
  14. package/dist/constants.js +18 -0
  15. package/dist/contract/index.d.ts +32 -0
  16. package/dist/contract/index.d.ts.map +1 -0
  17. package/dist/contract/index.js +67 -0
  18. package/dist/core/client.d.ts +107 -0
  19. package/dist/core/client.d.ts.map +1 -0
  20. package/dist/core/client.js +475 -0
  21. package/dist/core/errors.d.ts +19 -0
  22. package/dist/core/errors.d.ts.map +1 -0
  23. package/dist/core/errors.js +34 -0
  24. package/dist/core/request-promise.d.ts +24 -0
  25. package/dist/core/request-promise.d.ts.map +1 -0
  26. package/dist/core/request-promise.js +77 -0
  27. package/dist/core/request.d.ts +15 -0
  28. package/dist/core/request.d.ts.map +1 -0
  29. package/dist/core/request.js +44 -0
  30. package/dist/core/response.d.ts +33 -0
  31. package/dist/core/response.d.ts.map +1 -0
  32. package/dist/core/response.js +154 -0
  33. package/dist/index.d.ts +40 -0
  34. package/dist/index.d.ts.map +1 -0
  35. package/dist/index.js +39 -0
  36. package/dist/mcp/client.d.ts +59 -0
  37. package/dist/mcp/client.d.ts.map +1 -0
  38. package/dist/mcp/client.js +195 -0
  39. package/dist/mcp/index.d.ts +3 -0
  40. package/dist/mcp/index.d.ts.map +1 -0
  41. package/dist/mcp/index.js +2 -0
  42. package/dist/mcp/types.d.ts +151 -0
  43. package/dist/mcp/types.d.ts.map +1 -0
  44. package/dist/mcp/types.js +1 -0
  45. package/dist/plugins/cache.d.ts +10 -0
  46. package/dist/plugins/cache.d.ts.map +1 -0
  47. package/dist/plugins/cache.js +72 -0
  48. package/dist/plugins/circuit-breaker.d.ts +14 -0
  49. package/dist/plugins/circuit-breaker.d.ts.map +1 -0
  50. package/dist/plugins/circuit-breaker.js +100 -0
  51. package/dist/plugins/compression.d.ts +5 -0
  52. package/dist/plugins/compression.d.ts.map +1 -0
  53. package/dist/plugins/compression.js +128 -0
  54. package/dist/plugins/cookie-jar.d.ts +6 -0
  55. package/dist/plugins/cookie-jar.d.ts.map +1 -0
  56. package/dist/plugins/cookie-jar.js +72 -0
  57. package/dist/plugins/dedup.d.ts +6 -0
  58. package/dist/plugins/dedup.d.ts.map +1 -0
  59. package/dist/plugins/dedup.js +34 -0
  60. package/dist/plugins/graphql.d.ts +13 -0
  61. package/dist/plugins/graphql.d.ts.map +1 -0
  62. package/dist/plugins/graphql.js +39 -0
  63. package/dist/plugins/har-player.d.ts +7 -0
  64. package/dist/plugins/har-player.d.ts.map +1 -0
  65. package/dist/plugins/har-player.js +53 -0
  66. package/dist/plugins/har-recorder.d.ts +7 -0
  67. package/dist/plugins/har-recorder.d.ts.map +1 -0
  68. package/dist/plugins/har-recorder.js +67 -0
  69. package/dist/plugins/logger.d.ts +11 -0
  70. package/dist/plugins/logger.d.ts.map +1 -0
  71. package/dist/plugins/logger.js +72 -0
  72. package/dist/plugins/pagination.d.ts +17 -0
  73. package/dist/plugins/pagination.d.ts.map +1 -0
  74. package/dist/plugins/pagination.js +105 -0
  75. package/dist/plugins/proxy-rotator.d.ts +8 -0
  76. package/dist/plugins/proxy-rotator.d.ts.map +1 -0
  77. package/dist/plugins/proxy-rotator.js +35 -0
  78. package/dist/plugins/rate-limit.d.ts +8 -0
  79. package/dist/plugins/rate-limit.d.ts.map +1 -0
  80. package/dist/plugins/rate-limit.js +57 -0
  81. package/dist/plugins/retry.d.ts +14 -0
  82. package/dist/plugins/retry.d.ts.map +1 -0
  83. package/dist/plugins/retry.js +92 -0
  84. package/dist/plugins/server-timing.d.ts +8 -0
  85. package/dist/plugins/server-timing.d.ts.map +1 -0
  86. package/dist/plugins/server-timing.js +24 -0
  87. package/dist/plugins/xsrf.d.ts +10 -0
  88. package/dist/plugins/xsrf.d.ts.map +1 -0
  89. package/dist/plugins/xsrf.js +48 -0
  90. package/dist/runner/request-runner.d.ts +47 -0
  91. package/dist/runner/request-runner.d.ts.map +1 -0
  92. package/dist/runner/request-runner.js +89 -0
  93. package/dist/transport/fetch.d.ts +6 -0
  94. package/dist/transport/fetch.d.ts.map +1 -0
  95. package/dist/transport/fetch.js +153 -0
  96. package/dist/transport/undici.d.ts +23 -0
  97. package/dist/transport/undici.d.ts.map +1 -0
  98. package/dist/transport/undici.js +218 -0
  99. package/dist/types/index.d.ts +251 -0
  100. package/dist/types/index.d.ts.map +1 -0
  101. package/dist/types/index.js +1 -0
  102. package/dist/utils/agent-manager.d.ts +29 -0
  103. package/dist/utils/agent-manager.d.ts.map +1 -0
  104. package/dist/utils/agent-manager.js +133 -0
  105. package/dist/utils/body.d.ts +11 -0
  106. package/dist/utils/body.d.ts.map +1 -0
  107. package/dist/utils/body.js +136 -0
  108. package/dist/utils/cert.d.ts +12 -0
  109. package/dist/utils/cert.d.ts.map +1 -0
  110. package/dist/utils/cert.js +32 -0
  111. package/dist/utils/concurrency.d.ts +21 -0
  112. package/dist/utils/concurrency.d.ts.map +1 -0
  113. package/dist/utils/concurrency.js +116 -0
  114. package/dist/utils/dns.d.ts +7 -0
  115. package/dist/utils/dns.d.ts.map +1 -0
  116. package/dist/utils/dns.js +26 -0
  117. package/dist/utils/doh.d.ts +3 -0
  118. package/dist/utils/doh.d.ts.map +1 -0
  119. package/dist/utils/doh.js +35 -0
  120. package/dist/utils/header-parser.d.ts +81 -0
  121. package/dist/utils/header-parser.d.ts.map +1 -0
  122. package/dist/utils/header-parser.js +457 -0
  123. package/dist/utils/html-cleaner.d.ts +2 -0
  124. package/dist/utils/html-cleaner.d.ts.map +1 -0
  125. package/dist/utils/html-cleaner.js +21 -0
  126. package/dist/utils/logger.d.ts +33 -0
  127. package/dist/utils/logger.d.ts.map +1 -0
  128. package/dist/utils/logger.js +160 -0
  129. package/dist/utils/progress.d.ts +4 -0
  130. package/dist/utils/progress.d.ts.map +1 -0
  131. package/dist/utils/progress.js +49 -0
  132. package/dist/utils/request-pool.d.ts +23 -0
  133. package/dist/utils/request-pool.d.ts.map +1 -0
  134. package/dist/utils/request-pool.js +100 -0
  135. package/dist/utils/sse.d.ts +8 -0
  136. package/dist/utils/sse.d.ts.map +1 -0
  137. package/dist/utils/sse.js +62 -0
  138. package/dist/utils/streaming.d.ts +18 -0
  139. package/dist/utils/streaming.d.ts.map +1 -0
  140. package/dist/utils/streaming.js +83 -0
  141. package/dist/utils/task-pool.d.ts +38 -0
  142. package/dist/utils/task-pool.js +104 -0
  143. package/dist/utils/try-fn.d.ts +4 -0
  144. package/dist/utils/try-fn.d.ts.map +1 -0
  145. package/dist/utils/try-fn.js +53 -0
  146. package/dist/utils/upload.d.ts +10 -0
  147. package/dist/utils/upload.d.ts.map +1 -0
  148. package/dist/utils/upload.js +45 -0
  149. package/dist/utils/user-agent.d.ts +45 -0
  150. package/dist/utils/user-agent.d.ts.map +1 -0
  151. package/dist/utils/user-agent.js +100 -0
  152. package/dist/utils/whois.d.ts +15 -0
  153. package/dist/utils/whois.d.ts.map +1 -0
  154. package/dist/utils/whois.js +159 -0
  155. package/dist/websocket/client.d.ts +38 -0
  156. package/dist/websocket/client.d.ts.map +1 -0
  157. package/dist/websocket/client.js +184 -0
  158. package/package.json +100 -0
@@ -0,0 +1,475 @@
1
+ import { HttpRequest } from './request.js';
2
+ import { UndiciTransport } from '../transport/undici.js';
3
+ import { RequestPromise } from './request-promise.js';
4
+ import { HttpError } from '../core/errors.js';
5
+ import { getLogger } from '../utils/logger.js';
6
+ import { processBody } 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 { retry } from '../plugins/retry.js';
13
+ import { cache } from '../plugins/cache.js';
14
+ import { dedup } from '../plugins/dedup.js';
15
+ import { createXSRFMiddleware } from '../plugins/xsrf.js';
16
+ import { createCompressionMiddleware } from '../plugins/compression.js';
17
+ import { MemoryStorage } from '../cache/memory-storage.js';
18
+ import { FileStorage } from '../cache/file-storage.js';
19
+ import { RequestRunner } from '../runner/request-runner.js';
20
+ import { ReckerWebSocket } from '../websocket/client.js';
21
+ import { whois as performWhois, isDomainAvailable } from '../utils/whois.js';
22
+ export class Client {
23
+ baseUrl;
24
+ middlewares;
25
+ hooks;
26
+ transport;
27
+ defaultHeaders;
28
+ defaultParams;
29
+ paginationConfig;
30
+ handler;
31
+ logger;
32
+ debugEnabled;
33
+ agentManager;
34
+ concurrencyConfig;
35
+ requestPool;
36
+ constructor(options = {}) {
37
+ this.baseUrl = options.baseUrl || '';
38
+ this.middlewares = options.middlewares || [];
39
+ this.hooks = {
40
+ beforeRequest: options.hooks?.beforeRequest || [],
41
+ afterResponse: options.hooks?.afterResponse || [],
42
+ onError: options.hooks?.onError || [],
43
+ onRetry: options.hooks?.onRetry || [],
44
+ onUrlResolved: options.hooks?.onUrlResolved || [],
45
+ };
46
+ this.defaultHeaders = {
47
+ 'User-Agent': getDefaultUserAgent(),
48
+ ...(options.headers || {})
49
+ };
50
+ this.defaultParams = options.defaults?.params || {};
51
+ this.paginationConfig = options.pagination;
52
+ this.debugEnabled = options.debug === true;
53
+ if (this.debugEnabled) {
54
+ this.logger = getLogger();
55
+ }
56
+ this.concurrencyConfig = normalizeConcurrency({
57
+ concurrency: options.concurrency,
58
+ http2: options.http2
59
+ });
60
+ if (options.transport) {
61
+ this.transport = options.transport;
62
+ }
63
+ else if (this.baseUrl) {
64
+ let http2Options;
65
+ if (options.http2) {
66
+ if (typeof options.http2 === 'boolean') {
67
+ http2Options = { enabled: options.http2 };
68
+ }
69
+ else {
70
+ http2Options = options.http2;
71
+ }
72
+ }
73
+ this.agentManager = new AgentManager(this.concurrencyConfig.agent);
74
+ this.transport = new UndiciTransport(this.baseUrl, {
75
+ proxy: options.proxy,
76
+ http2: http2Options,
77
+ dns: options.dns,
78
+ agent: this.agentManager
79
+ });
80
+ }
81
+ else {
82
+ throw new Error('baseUrl is required for default UndiciTransport, or provide a custom transport.');
83
+ }
84
+ if (options.retry) {
85
+ retry(options.retry)(this);
86
+ }
87
+ if (this.concurrencyConfig.max < Infinity || this.concurrencyConfig.requestsPerInterval < Infinity) {
88
+ this.requestPool = new RequestPool({
89
+ concurrency: this.concurrencyConfig.max,
90
+ requestsPerInterval: this.concurrencyConfig.requestsPerInterval,
91
+ interval: this.concurrencyConfig.interval
92
+ });
93
+ this.middlewares.unshift(this.requestPool.asMiddleware());
94
+ if (this.debugEnabled) {
95
+ console.log(`[Recker] Global concurrency limit: ${this.concurrencyConfig.max} concurrent requests`);
96
+ }
97
+ }
98
+ else {
99
+ if (this.debugEnabled) {
100
+ console.log('[Recker] No global concurrency limit (allows unlimited parallel batches)');
101
+ }
102
+ }
103
+ if (options.dedup) {
104
+ dedup(options.dedup)(this);
105
+ }
106
+ if (options.cache) {
107
+ let storage;
108
+ if (options.cache.storage) {
109
+ storage = options.cache.storage;
110
+ }
111
+ else if (options.cache.driver === 'file') {
112
+ storage = new FileStorage(options.cache.fileStoragePath);
113
+ }
114
+ else {
115
+ storage = new MemoryStorage();
116
+ }
117
+ cache({
118
+ ...options.cache,
119
+ storage
120
+ })(this);
121
+ }
122
+ if (options.plugins) {
123
+ options.plugins.forEach((plugin) => plugin(this));
124
+ }
125
+ if (options.compression) {
126
+ const compressionMiddleware = createCompressionMiddleware(options.compression);
127
+ if (compressionMiddleware) {
128
+ this.middlewares.push(compressionMiddleware);
129
+ }
130
+ }
131
+ if (options.xsrf) {
132
+ const xsrfMiddleware = createXSRFMiddleware(options.xsrf);
133
+ if (xsrfMiddleware) {
134
+ this.middlewares.push(xsrfMiddleware);
135
+ }
136
+ }
137
+ if (this.debugEnabled && this.logger) {
138
+ this.middlewares.unshift(this.createLoggingMiddleware(this.logger));
139
+ }
140
+ this.middlewares.push(this.httpErrorMiddleware);
141
+ this.handler = this.composeMiddlewares();
142
+ }
143
+ createLoggingMiddleware(logger) {
144
+ return async (req, next) => {
145
+ const startTime = Date.now();
146
+ logger.logRequest(req);
147
+ try {
148
+ const response = await next(req);
149
+ logger.logResponse(req, response, startTime);
150
+ return response;
151
+ }
152
+ catch (error) {
153
+ logger.logError(req, error);
154
+ throw error;
155
+ }
156
+ };
157
+ }
158
+ composeMiddlewares() {
159
+ const chain = [...this.middlewares];
160
+ const transportDispatch = this.transport.dispatch.bind(this.transport);
161
+ if (this.hooks.beforeRequest?.length || this.hooks.afterResponse?.length) {
162
+ chain.unshift(this.hooksMiddleware);
163
+ }
164
+ if (chain.length === 0) {
165
+ return transportDispatch;
166
+ }
167
+ return chain.reduceRight((next, middleware) => {
168
+ return (req) => middleware(req, next);
169
+ }, transportDispatch);
170
+ }
171
+ hooksMiddleware = async (req, next) => {
172
+ let modifiedReq = req;
173
+ if (this.hooks.beforeRequest && this.hooks.beforeRequest.length > 0) {
174
+ for (const hook of this.hooks.beforeRequest) {
175
+ const result = await hook(modifiedReq);
176
+ if (result) {
177
+ modifiedReq = result;
178
+ }
179
+ }
180
+ }
181
+ try {
182
+ let response = await next(modifiedReq);
183
+ if (this.hooks.afterResponse && this.hooks.afterResponse.length > 0) {
184
+ for (const hook of this.hooks.afterResponse) {
185
+ const result = await hook(modifiedReq, response);
186
+ if (result) {
187
+ response = result;
188
+ }
189
+ }
190
+ }
191
+ return response;
192
+ }
193
+ catch (error) {
194
+ if (this.hooks.onError && this.hooks.onError.length > 0) {
195
+ for (const hook of this.hooks.onError) {
196
+ const result = await hook(error, modifiedReq);
197
+ if (result) {
198
+ return result;
199
+ }
200
+ }
201
+ }
202
+ throw error;
203
+ }
204
+ };
205
+ httpErrorMiddleware = async (req, next) => {
206
+ const response = await next(req);
207
+ if (req.throwHttpErrors !== false && !response.ok) {
208
+ throw new HttpError(response, req);
209
+ }
210
+ return response;
211
+ };
212
+ use(middleware) {
213
+ this.middlewares.push(middleware);
214
+ this.handler = this.composeMiddlewares();
215
+ return this;
216
+ }
217
+ beforeRequest(hook) {
218
+ if (!this.hooks.beforeRequest) {
219
+ this.hooks.beforeRequest = [];
220
+ }
221
+ this.hooks.beforeRequest.push(hook);
222
+ this.handler = this.composeMiddlewares();
223
+ return this;
224
+ }
225
+ afterResponse(hook) {
226
+ if (!this.hooks.afterResponse) {
227
+ this.hooks.afterResponse = [];
228
+ }
229
+ this.hooks.afterResponse.push(hook);
230
+ this.handler = this.composeMiddlewares();
231
+ return this;
232
+ }
233
+ onError(hook) {
234
+ if (!this.hooks.onError) {
235
+ this.hooks.onError = [];
236
+ }
237
+ this.hooks.onError.push(hook);
238
+ this.handler = this.composeMiddlewares();
239
+ return this;
240
+ }
241
+ buildUrl(path, requestParams) {
242
+ const hasRequestParams = requestParams && Object.keys(requestParams).length > 0;
243
+ const hasDefaultParams = Object.keys(this.defaultParams).length > 0;
244
+ if (!hasRequestParams && !hasDefaultParams) {
245
+ if (this.baseUrl && !path.startsWith('http')) {
246
+ return new URL(path, this.baseUrl).toString();
247
+ }
248
+ return path;
249
+ }
250
+ let finalPath = path;
251
+ const mergedParams = { ...this.defaultParams, ...requestParams };
252
+ const usedParams = new Set();
253
+ if (finalPath.includes(':')) {
254
+ finalPath = finalPath.replace(/:([a-zA-Z0-9_]+)/g, (match, paramName) => {
255
+ if (mergedParams && paramName in mergedParams) {
256
+ usedParams.add(paramName);
257
+ return String(mergedParams[paramName]);
258
+ }
259
+ throw new Error(`Missing required path parameter: ${paramName}`);
260
+ });
261
+ }
262
+ let finalUrl = finalPath;
263
+ if (this.baseUrl && !finalPath.startsWith('http://') && !finalPath.startsWith('https://')) {
264
+ finalUrl = new URL(finalPath, this.baseUrl).toString();
265
+ }
266
+ else if (!this.baseUrl && !finalPath.startsWith('http://') && !finalPath.startsWith('https://')) {
267
+ throw new Error('Relative path provided without a baseUrl or explicit transport.');
268
+ }
269
+ const remainingKeys = Object.keys(mergedParams).filter((k) => !usedParams.has(k));
270
+ if (remainingKeys.length > 0) {
271
+ const urlObj = new URL(finalUrl);
272
+ remainingKeys.forEach((key) => {
273
+ urlObj.searchParams.append(key, String(mergedParams[key]));
274
+ });
275
+ return urlObj.toString();
276
+ }
277
+ return finalUrl;
278
+ }
279
+ request(path, options = {}) {
280
+ const url = this.buildUrl(path, options.params);
281
+ let mergedHeaders = this.defaultHeaders;
282
+ if (options.headers) {
283
+ mergedHeaders = new Headers(this.defaultHeaders);
284
+ new Headers(options.headers).forEach((value, key) => mergedHeaders.append(key, value));
285
+ }
286
+ else if (!(mergedHeaders instanceof Headers)) {
287
+ mergedHeaders = new Headers(mergedHeaders);
288
+ }
289
+ const controller = new AbortController();
290
+ let signal = controller.signal;
291
+ let timeoutId;
292
+ let externalAbortCleanup;
293
+ if (options.signal) {
294
+ const externalSignal = options.signal;
295
+ const abortHandler = () => controller.abort(externalSignal.reason);
296
+ if (externalSignal.aborted) {
297
+ abortHandler();
298
+ }
299
+ else {
300
+ externalSignal.addEventListener('abort', abortHandler, { once: true });
301
+ externalAbortCleanup = () => externalSignal.removeEventListener('abort', abortHandler);
302
+ }
303
+ }
304
+ if (options.timeout) {
305
+ timeoutId = setTimeout(() => controller.abort(new Error('Request timed out')), options.timeout);
306
+ }
307
+ const req = new HttpRequest(url, {
308
+ ...options,
309
+ headers: mergedHeaders,
310
+ signal,
311
+ });
312
+ const responsePromise = this.handler(req);
313
+ if (timeoutId || externalAbortCleanup) {
314
+ responsePromise.finally(() => {
315
+ if (timeoutId)
316
+ clearTimeout(timeoutId);
317
+ externalAbortCleanup?.();
318
+ });
319
+ }
320
+ return new RequestPromise(responsePromise, controller);
321
+ }
322
+ get(path, options = {}) {
323
+ return this.request(path, { ...options, method: 'GET' });
324
+ }
325
+ async batch(requests, options = {}) {
326
+ const mapResponse = options.mapResponse ?? ((res) => res);
327
+ const batchConcurrency = options.concurrency ?? this.concurrencyConfig.runner.concurrency;
328
+ const runner = new RequestRunner({
329
+ concurrency: batchConcurrency,
330
+ retries: this.concurrencyConfig.runner.retries,
331
+ retryDelay: this.concurrencyConfig.runner.retryDelay
332
+ });
333
+ const runnerResult = await runner.run(requests, async (item) => {
334
+ const res = await this.request(item.path, item.options);
335
+ return mapResponse(res);
336
+ });
337
+ return runnerResult;
338
+ }
339
+ multi(requests, options = {}) {
340
+ return this.batch(requests, options);
341
+ }
342
+ requestWithBody(method, path, body, options = {}) {
343
+ const { body: processedBody, contentType } = processBody(body);
344
+ const headers = new Headers(options.headers);
345
+ if (contentType && !headers.has('Content-Type')) {
346
+ headers.set('Content-Type', contentType);
347
+ }
348
+ return this.request(path, { ...options, method, body: processedBody, headers });
349
+ }
350
+ post(path, body, options = {}) {
351
+ return this.requestWithBody('POST', path, body, options);
352
+ }
353
+ put(path, body, options = {}) {
354
+ return this.requestWithBody('PUT', path, body, options);
355
+ }
356
+ patch(path, body, options = {}) {
357
+ return this.requestWithBody('PATCH', path, body, options);
358
+ }
359
+ delete(path, options = {}) {
360
+ return this.request(path, { ...options, method: 'DELETE' });
361
+ }
362
+ head(path, options = {}) {
363
+ return this.request(path, { ...options, method: 'HEAD' });
364
+ }
365
+ options(path, options = {}) {
366
+ return this.request(path, { ...options, method: 'OPTIONS' });
367
+ }
368
+ trace(path, options = {}) {
369
+ return this.request(path, { ...options, method: 'TRACE' });
370
+ }
371
+ connect(path, options = {}) {
372
+ return this.request(path, { ...options, method: 'CONNECT' });
373
+ }
374
+ purge(path, options = {}) {
375
+ return this.request(path, { ...options, method: 'PURGE' });
376
+ }
377
+ propfind(path, body, options = {}) {
378
+ return this.requestWithBody('PROPFIND', path, body, options);
379
+ }
380
+ proppatch(path, body, options = {}) {
381
+ return this.requestWithBody('PROPPATCH', path, body, options);
382
+ }
383
+ mkcol(path, options = {}) {
384
+ return this.request(path, { ...options, method: 'MKCOL' });
385
+ }
386
+ copy(path, options = {}) {
387
+ return this.request(path, { ...options, method: 'COPY' });
388
+ }
389
+ move(path, options = {}) {
390
+ return this.request(path, { ...options, method: 'MOVE' });
391
+ }
392
+ lock(path, body, options = {}) {
393
+ return this.requestWithBody('LOCK', path, body, options);
394
+ }
395
+ unlock(path, options = {}) {
396
+ return this.request(path, { ...options, method: 'UNLOCK' });
397
+ }
398
+ link(path, body, options = {}) {
399
+ return this.requestWithBody('LINK', path, body, options);
400
+ }
401
+ unlink(path, body, options = {}) {
402
+ return this.requestWithBody('UNLINK', path, body, options);
403
+ }
404
+ paginate(path, options = {}) {
405
+ const { getItems, getNextUrl, maxPages, pageParam, limitParam, resultsPath, nextCursorPath, ...reqOptions } = options;
406
+ const paginationOpts = {
407
+ getItems,
408
+ getNextUrl,
409
+ maxPages,
410
+ pageParam: pageParam || this.paginationConfig?.pageParam,
411
+ limitParam: limitParam || this.paginationConfig?.limitParam,
412
+ resultsPath: resultsPath || this.paginationConfig?.resultsPath,
413
+ nextCursorPath: nextCursorPath || this.paginationConfig?.nextCursorPath,
414
+ };
415
+ return paginate(this, path, reqOptions, paginationOpts);
416
+ }
417
+ pages(path, options = {}) {
418
+ const { getNextUrl, maxPages, pageParam, limitParam, resultsPath, nextCursorPath, ...reqOptions } = options;
419
+ const paginationOpts = {
420
+ getNextUrl,
421
+ maxPages,
422
+ pageParam: pageParam || this.paginationConfig?.pageParam,
423
+ limitParam: limitParam || this.paginationConfig?.limitParam,
424
+ nextCursorPath: nextCursorPath || this.paginationConfig?.nextCursorPath,
425
+ };
426
+ return streamPages(this, path, reqOptions, paginationOpts);
427
+ }
428
+ page(path, pageNumber, options = {}) {
429
+ const pageParam = options.pageParam || this.paginationConfig?.pageParam || 'page';
430
+ const url = new URL(path.startsWith('http') ? path : `http://base${path}`);
431
+ const params = { ...options.params, [pageParam]: pageNumber };
432
+ return this.request(path, { ...options, params });
433
+ }
434
+ async getAll(path, options = {}) {
435
+ const items = [];
436
+ for await (const item of this.paginate(path, options)) {
437
+ items.push(item);
438
+ }
439
+ return items;
440
+ }
441
+ websocket(path, options = {}) {
442
+ let wsUrl;
443
+ if (path.startsWith('ws://') || path.startsWith('wss://')) {
444
+ wsUrl = path;
445
+ }
446
+ else if (this.baseUrl) {
447
+ const base = this.baseUrl.replace(/^http/, 'ws');
448
+ wsUrl = new URL(path, base).toString();
449
+ }
450
+ else {
451
+ throw new Error('WebSocket requires either a full ws:// URL or a baseUrl');
452
+ }
453
+ const headersObj = {};
454
+ if (this.defaultHeaders) {
455
+ const headers = new Headers(this.defaultHeaders);
456
+ headers.forEach((value, key) => {
457
+ headersObj[key] = value;
458
+ });
459
+ }
460
+ const finalHeaders = { ...headersObj, ...options.headers };
461
+ return new ReckerWebSocket(wsUrl, { ...options, headers: finalHeaders });
462
+ }
463
+ ws(path, options = {}) {
464
+ return this.websocket(path, options);
465
+ }
466
+ async whois(query, options) {
467
+ return performWhois(query, options);
468
+ }
469
+ async isDomainAvailable(domain, options) {
470
+ return isDomainAvailable(domain, options);
471
+ }
472
+ }
473
+ export function createClient(options = {}) {
474
+ return new Client(options);
475
+ }
@@ -0,0 +1,19 @@
1
+ import { ReckerRequest, ReckerResponse } from '../types/index.js';
2
+ export declare class ReckerError extends Error {
3
+ request?: ReckerRequest;
4
+ response?: ReckerResponse;
5
+ constructor(message: string, request?: ReckerRequest, response?: ReckerResponse);
6
+ }
7
+ export declare class HttpError extends ReckerError {
8
+ status: number;
9
+ statusText: string;
10
+ constructor(response: ReckerResponse, request?: ReckerRequest);
11
+ }
12
+ export declare class TimeoutError extends ReckerError {
13
+ constructor(request?: ReckerRequest);
14
+ }
15
+ export declare class NetworkError extends ReckerError {
16
+ code?: string;
17
+ constructor(message: string, code?: string, request?: ReckerRequest);
18
+ }
19
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAElE,qBAAa,WAAY,SAAQ,KAAK;IACpC,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,QAAQ,CAAC,EAAE,cAAc,CAAC;gBAEd,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,EAAE,QAAQ,CAAC,EAAE,cAAc;CAMhF;AAED,qBAAa,SAAU,SAAQ,WAAW;IACxC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;gBAEP,QAAQ,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,aAAa;CAM9D;AAED,qBAAa,YAAa,SAAQ,WAAW;gBAC/B,OAAO,CAAC,EAAE,aAAa;CAIpC;AAED,qBAAa,YAAa,SAAQ,WAAW;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAC;gBAEF,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa;CAKpE"}
@@ -0,0 +1,34 @@
1
+ export class ReckerError extends Error {
2
+ request;
3
+ response;
4
+ constructor(message, request, response) {
5
+ super(message);
6
+ this.name = 'ReckerError';
7
+ this.request = request;
8
+ this.response = response;
9
+ }
10
+ }
11
+ export class HttpError extends ReckerError {
12
+ status;
13
+ statusText;
14
+ constructor(response, request) {
15
+ super(`Request failed with status code ${response.status} ${response.statusText}`, request, response);
16
+ this.name = 'HttpError';
17
+ this.status = response.status;
18
+ this.statusText = response.statusText;
19
+ }
20
+ }
21
+ export class TimeoutError extends ReckerError {
22
+ constructor(request) {
23
+ super('Request timed out', request);
24
+ this.name = 'TimeoutError';
25
+ }
26
+ }
27
+ export class NetworkError extends ReckerError {
28
+ code;
29
+ constructor(message, code, request) {
30
+ super(message, request);
31
+ this.name = 'NetworkError';
32
+ this.code = code;
33
+ }
34
+ }
@@ -0,0 +1,24 @@
1
+ import { ReckerResponse, SSEEvent, ProgressEvent } from '../types/index.js';
2
+ import { ZodSchema } from 'zod';
3
+ export declare class RequestPromise<T = unknown> implements Promise<ReckerResponse<T>> {
4
+ private promise;
5
+ private abortController?;
6
+ constructor(promise: Promise<ReckerResponse<T>>, abortController?: AbortController);
7
+ get [Symbol.toStringTag](): string;
8
+ then<TResult1 = ReckerResponse<T>, TResult2 = never>(onfulfilled?: ((value: ReckerResponse<T>) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null): Promise<TResult1 | TResult2>;
9
+ catch<TResult = never>(onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | null): Promise<ReckerResponse<T> | TResult>;
10
+ finally(onfinally?: (() => void) | null): Promise<ReckerResponse<T>>;
11
+ cancel(): void;
12
+ json<R = T>(): Promise<R>;
13
+ text(): Promise<string>;
14
+ cleanText(): Promise<string>;
15
+ blob(): Promise<Blob>;
16
+ read(): Promise<ReadableStream<Uint8Array> | null>;
17
+ write(path: string): Promise<void>;
18
+ parse<R>(schema: ZodSchema<R>): Promise<R>;
19
+ safe(): Promise<[boolean, Error | null, T | undefined]>;
20
+ sse(): AsyncGenerator<SSEEvent>;
21
+ download(): AsyncGenerator<ProgressEvent>;
22
+ [Symbol.asyncIterator](): AsyncGenerator<Uint8Array>;
23
+ }
24
+ //# sourceMappingURL=request-promise.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-promise.d.ts","sourceRoot":"","sources":["../../src/core/request-promise.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAC5E,OAAO,EAAE,SAAS,EAAE,MAAM,KAAK,CAAC;AAMhC,qBAAa,cAAc,CAAC,CAAC,GAAG,OAAO,CAAE,YAAW,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;IAC5E,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,eAAe,CAAC,CAAkB;gBAE9B,OAAO,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,EAAE,eAAe,CAAC,EAAE,eAAe;IAKlF,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,WAEvB;IAED,IAAI,CAAC,QAAQ,GAAG,cAAc,CAAC,CAAC,CAAC,EAAE,QAAQ,GAAG,KAAK,EACjD,WAAW,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,KAAK,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC,GAAG,IAAI,EACrF,UAAU,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,GAAG,KAAK,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC,GAAG,IAAI,GACtE,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAI/B,KAAK,CAAC,OAAO,GAAG,KAAK,EACnB,UAAU,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,GAAG,KAAK,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC,GAAG,IAAI,GACpE,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC;IAIvC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;IAKpE,MAAM,IAAI,IAAI;IAMR,IAAI,CAAC,CAAC,GAAG,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC;IAKzB,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC;IAKvB,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC;IAK5B,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAKrB,IAAI,IAAI,OAAO,CAAC,cAAc,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC;IAKlD,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAalC,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAK1C,IAAI,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,KAAK,GAAG,IAAI,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC;IAKtD,GAAG,IAAI,cAAc,CAAC,QAAQ,CAAC;IAK/B,QAAQ,IAAI,cAAc,CAAC,aAAa,CAAC;IAKzC,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,cAAc,CAAC,UAAU,CAAC;CAI5D"}
@@ -0,0 +1,77 @@
1
+ import { createWriteStream } from 'node:fs';
2
+ import { pipeline } from 'node:stream/promises';
3
+ import { Readable } from 'node:stream';
4
+ import { tryFn } from '../utils/try-fn.js';
5
+ export class RequestPromise {
6
+ promise;
7
+ abortController;
8
+ constructor(promise, abortController) {
9
+ this.promise = promise;
10
+ this.abortController = abortController;
11
+ }
12
+ get [Symbol.toStringTag]() {
13
+ return 'RequestPromise';
14
+ }
15
+ then(onfulfilled, onrejected) {
16
+ return this.promise.then(onfulfilled, onrejected);
17
+ }
18
+ catch(onrejected) {
19
+ return this.promise.catch(onrejected);
20
+ }
21
+ finally(onfinally) {
22
+ return this.promise.finally(onfinally);
23
+ }
24
+ cancel() {
25
+ if (this.abortController) {
26
+ this.abortController.abort();
27
+ }
28
+ }
29
+ async json() {
30
+ const response = await this.promise;
31
+ return response.json();
32
+ }
33
+ async text() {
34
+ const response = await this.promise;
35
+ return response.text();
36
+ }
37
+ async cleanText() {
38
+ const response = await this.promise;
39
+ return response.cleanText();
40
+ }
41
+ async blob() {
42
+ const response = await this.promise;
43
+ return response.blob();
44
+ }
45
+ async read() {
46
+ const response = await this.promise;
47
+ return response.read();
48
+ }
49
+ async write(path) {
50
+ const response = await this.promise;
51
+ const body = response.read();
52
+ if (!body)
53
+ throw new Error('Response has no body');
54
+ const nodeStream = Readable.fromWeb(body);
55
+ const fileStream = createWriteStream(path);
56
+ await pipeline(nodeStream, fileStream);
57
+ }
58
+ async parse(schema) {
59
+ const data = await this.json();
60
+ return schema.parse(data);
61
+ }
62
+ async safe() {
63
+ return tryFn(() => this.json());
64
+ }
65
+ async *sse() {
66
+ const response = await this.promise;
67
+ yield* response.sse();
68
+ }
69
+ async *download() {
70
+ const response = await this.promise;
71
+ yield* response.download();
72
+ }
73
+ async *[Symbol.asyncIterator]() {
74
+ const response = await this.promise;
75
+ yield* response;
76
+ }
77
+ }
@@ -0,0 +1,15 @@
1
+ import { Method, ReckerRequest, RequestOptions, ProgressCallback } from '../types/index.js';
2
+ export declare class HttpRequest implements ReckerRequest {
3
+ readonly url: string;
4
+ readonly method: Method;
5
+ readonly headers: Headers;
6
+ readonly body: BodyInit | null;
7
+ readonly signal?: AbortSignal;
8
+ readonly throwHttpErrors?: boolean;
9
+ readonly onUploadProgress?: ProgressCallback;
10
+ readonly onDownloadProgress?: ProgressCallback;
11
+ constructor(url: string, options?: RequestOptions);
12
+ withHeader(name: string, value: string): ReckerRequest;
13
+ withBody(body: BodyInit): ReckerRequest;
14
+ }
15
+ //# sourceMappingURL=request.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../../src/core/request.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE5F,qBAAa,WAAY,YAAW,aAAa;IAC/C,SAAgB,GAAG,EAAE,MAAM,CAAC;IAC5B,SAAgB,MAAM,EAAE,MAAM,CAAC;IAC/B,SAAgB,OAAO,EAAE,OAAO,CAAC;IACjC,SAAgB,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAC;IACtC,SAAgB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrC,SAAgB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1C,SAAgB,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpD,SAAgB,kBAAkB,CAAC,EAAE,gBAAgB,CAAC;gBAE1C,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,cAAmB;IAWrD,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,aAAa;IActD,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,aAAa;CAWxC"}