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,564 @@
1
+ import { UnsupportedError, HttpError } from '../core/errors.js';
2
+ export class ODataException extends Error {
3
+ code;
4
+ target;
5
+ details;
6
+ innererror;
7
+ constructor(error) {
8
+ super(error.message);
9
+ this.name = 'ODataException';
10
+ this.code = error.code;
11
+ this.target = error.target;
12
+ this.details = error.details;
13
+ this.innererror = error.innererror;
14
+ }
15
+ }
16
+ export class ODataQueryBuilder {
17
+ client;
18
+ entitySet;
19
+ entityKey;
20
+ queryOptions = {};
21
+ requestOptions;
22
+ constructor(client, entitySet) {
23
+ this.client = client;
24
+ this.entitySet = entitySet;
25
+ }
26
+ key(key) {
27
+ this.entityKey = key;
28
+ return this;
29
+ }
30
+ select(...properties) {
31
+ this.queryOptions.$select = properties;
32
+ return this;
33
+ }
34
+ expand(...properties) {
35
+ const hasExpandOptions = properties.some((p) => typeof p !== 'string');
36
+ if (hasExpandOptions) {
37
+ this.queryOptions.$expand = properties;
38
+ }
39
+ else {
40
+ this.queryOptions.$expand = properties;
41
+ }
42
+ return this;
43
+ }
44
+ filter(filter) {
45
+ if (typeof filter === 'function') {
46
+ const builder = new FilterBuilder();
47
+ this.queryOptions.$filter = filter(builder).build();
48
+ }
49
+ else {
50
+ this.queryOptions.$filter = filter;
51
+ }
52
+ return this;
53
+ }
54
+ orderBy(property, direction = 'asc') {
55
+ const existing = this.queryOptions.$orderby;
56
+ const option = { property, direction };
57
+ if (Array.isArray(existing)) {
58
+ existing.push(option);
59
+ }
60
+ else if (existing) {
61
+ this.queryOptions.$orderby = [{ property: existing, direction: 'asc' }, option];
62
+ }
63
+ else {
64
+ this.queryOptions.$orderby = [option];
65
+ }
66
+ return this;
67
+ }
68
+ top(count) {
69
+ this.queryOptions.$top = count;
70
+ return this;
71
+ }
72
+ skip(count) {
73
+ this.queryOptions.$skip = count;
74
+ return this;
75
+ }
76
+ count(include = true) {
77
+ this.queryOptions.$count = include;
78
+ return this;
79
+ }
80
+ search(term) {
81
+ this.queryOptions.$search = term;
82
+ return this;
83
+ }
84
+ custom(key, value) {
85
+ this.queryOptions[key] = value;
86
+ return this;
87
+ }
88
+ options(options) {
89
+ this.requestOptions = options;
90
+ return this;
91
+ }
92
+ async get() {
93
+ return this.client.get(this.entitySet, this.entityKey, this.queryOptions, this.requestOptions);
94
+ }
95
+ async *getAll() {
96
+ let response = await this.get();
97
+ while (response.value) {
98
+ for (const item of response.value) {
99
+ yield item;
100
+ }
101
+ if (response['@odata.nextLink']) {
102
+ response = await this.client.getNextPage(response['@odata.nextLink']);
103
+ }
104
+ else {
105
+ break;
106
+ }
107
+ }
108
+ }
109
+ toUrl() {
110
+ return this.client.buildUrl(this.entitySet, this.entityKey, this.queryOptions);
111
+ }
112
+ }
113
+ export class FilterBuilder {
114
+ parts = [];
115
+ eq(property, value) {
116
+ this.parts.push(`${property} eq ${this.formatValue(value)}`);
117
+ return this;
118
+ }
119
+ ne(property, value) {
120
+ this.parts.push(`${property} ne ${this.formatValue(value)}`);
121
+ return this;
122
+ }
123
+ gt(property, value) {
124
+ this.parts.push(`${property} gt ${this.formatValue(value)}`);
125
+ return this;
126
+ }
127
+ ge(property, value) {
128
+ this.parts.push(`${property} ge ${this.formatValue(value)}`);
129
+ return this;
130
+ }
131
+ lt(property, value) {
132
+ this.parts.push(`${property} lt ${this.formatValue(value)}`);
133
+ return this;
134
+ }
135
+ le(property, value) {
136
+ this.parts.push(`${property} le ${this.formatValue(value)}`);
137
+ return this;
138
+ }
139
+ contains(property, value) {
140
+ this.parts.push(`contains(${property},'${this.escapeString(value)}')`);
141
+ return this;
142
+ }
143
+ startswith(property, value) {
144
+ this.parts.push(`startswith(${property},'${this.escapeString(value)}')`);
145
+ return this;
146
+ }
147
+ endswith(property, value) {
148
+ this.parts.push(`endswith(${property},'${this.escapeString(value)}')`);
149
+ return this;
150
+ }
151
+ isNull(property) {
152
+ this.parts.push(`${property} eq null`);
153
+ return this;
154
+ }
155
+ isNotNull(property) {
156
+ this.parts.push(`${property} ne null`);
157
+ return this;
158
+ }
159
+ in(property, values) {
160
+ const formatted = values.map((v) => this.formatValue(v)).join(',');
161
+ this.parts.push(`${property} in (${formatted})`);
162
+ return this;
163
+ }
164
+ and() {
165
+ if (this.parts.length > 0) {
166
+ this.parts.push('and');
167
+ }
168
+ return this;
169
+ }
170
+ or() {
171
+ if (this.parts.length > 0) {
172
+ this.parts.push('or');
173
+ }
174
+ return this;
175
+ }
176
+ not() {
177
+ this.parts.push('not');
178
+ return this;
179
+ }
180
+ group(builder) {
181
+ const inner = new FilterBuilder();
182
+ const result = builder(inner).build();
183
+ this.parts.push(`(${result})`);
184
+ return this;
185
+ }
186
+ raw(expression) {
187
+ this.parts.push(expression);
188
+ return this;
189
+ }
190
+ build() {
191
+ return this.parts.join(' ');
192
+ }
193
+ formatValue(value) {
194
+ if (value === null)
195
+ return 'null';
196
+ if (typeof value === 'string')
197
+ return `'${this.escapeString(value)}'`;
198
+ if (typeof value === 'boolean')
199
+ return value.toString();
200
+ if (typeof value === 'number')
201
+ return value.toString();
202
+ if (value instanceof Date)
203
+ return value.toISOString();
204
+ if (typeof value === 'object')
205
+ return JSON.stringify(value);
206
+ return String(value);
207
+ }
208
+ escapeString(str) {
209
+ return str.replace(/'/g, "''");
210
+ }
211
+ }
212
+ export class ODataClient {
213
+ client;
214
+ options;
215
+ constructor(client, options) {
216
+ this.client = client;
217
+ this.options = {
218
+ serviceRoot: options.serviceRoot.replace(/\/$/, ''),
219
+ version: options.version ?? '4.0',
220
+ maxPageSize: options.maxPageSize ?? 100,
221
+ requestOptions: options.requestOptions ?? {},
222
+ };
223
+ }
224
+ query(entitySet) {
225
+ return new ODataQueryBuilder(this, entitySet);
226
+ }
227
+ async get(entitySet, key, queryOptions, requestOptions) {
228
+ const url = this.buildUrl(entitySet, key, queryOptions);
229
+ const response = await this.request('GET', url, undefined, requestOptions);
230
+ return response;
231
+ }
232
+ async getById(entitySet, key, queryOptions, requestOptions) {
233
+ const response = await this.get(entitySet, key, queryOptions, requestOptions);
234
+ return response;
235
+ }
236
+ async getNextPage(nextLink) {
237
+ const response = await this.client.get(nextLink, {
238
+ ...this.options.requestOptions,
239
+ headers: this.getHeaders(),
240
+ });
241
+ return this.handleResponse(response);
242
+ }
243
+ async create(entitySet, entity, requestOptions) {
244
+ const url = this.buildUrl(entitySet);
245
+ return this.request('POST', url, entity, requestOptions);
246
+ }
247
+ async update(entitySet, key, entity, requestOptions) {
248
+ const url = this.buildUrl(entitySet, key);
249
+ return this.request('PATCH', url, entity, requestOptions);
250
+ }
251
+ async replace(entitySet, key, entity, requestOptions) {
252
+ const url = this.buildUrl(entitySet, key);
253
+ return this.request('PUT', url, entity, requestOptions);
254
+ }
255
+ async delete(entitySet, key, requestOptions) {
256
+ const url = this.buildUrl(entitySet, key);
257
+ await this.request('DELETE', url, undefined, requestOptions);
258
+ }
259
+ async action(action, params, requestOptions) {
260
+ const url = `${this.options.serviceRoot}/${action}`;
261
+ return this.request('POST', url, params, requestOptions);
262
+ }
263
+ async function(func, params, requestOptions) {
264
+ let url = `${this.options.serviceRoot}/${func}`;
265
+ if (params && Object.keys(params).length > 0) {
266
+ const paramString = Object.entries(params)
267
+ .map(([k, v]) => `${k}=${this.formatKeyValue(v)}`)
268
+ .join(',');
269
+ url += `(${paramString})`;
270
+ }
271
+ return this.request('GET', url, undefined, requestOptions);
272
+ }
273
+ async batch(requests, requestOptions) {
274
+ const boundary = `batch_${Date.now()}_${Math.random().toString(36).slice(2)}`;
275
+ const batchUrl = `${this.options.serviceRoot}/$batch`;
276
+ let body = '';
277
+ for (const req of requests) {
278
+ body += `--${boundary}\r\n`;
279
+ body += 'Content-Type: application/http\r\n';
280
+ body += 'Content-Transfer-Encoding: binary\r\n\r\n';
281
+ body += `${req.method} ${req.url} HTTP/1.1\r\n`;
282
+ if (req.headers) {
283
+ for (const [key, value] of Object.entries(req.headers)) {
284
+ body += `${key}: ${value}\r\n`;
285
+ }
286
+ }
287
+ if (req.body) {
288
+ body += 'Content-Type: application/json\r\n\r\n';
289
+ body += JSON.stringify(req.body);
290
+ }
291
+ body += '\r\n';
292
+ }
293
+ body += `--${boundary}--\r\n`;
294
+ const response = await this.client.post(batchUrl, body, {
295
+ ...this.options.requestOptions,
296
+ ...requestOptions,
297
+ headers: {
298
+ ...this.getHeaders(),
299
+ 'Content-Type': `multipart/mixed; boundary=${boundary}`,
300
+ ...requestOptions?.headers,
301
+ },
302
+ });
303
+ const responseText = await response.text();
304
+ return this.parseBatchResponse(responseText);
305
+ }
306
+ async getMetadata() {
307
+ const response = await this.client.get(`${this.options.serviceRoot}/$metadata`, {
308
+ ...this.options.requestOptions,
309
+ headers: {
310
+ Accept: 'application/xml',
311
+ },
312
+ });
313
+ return response.text();
314
+ }
315
+ buildUrl(entitySet, key, queryOptions) {
316
+ let url = `${this.options.serviceRoot}/${entitySet}`;
317
+ if (key !== undefined) {
318
+ url += `(${this.formatKey(key)})`;
319
+ }
320
+ if (queryOptions) {
321
+ const params = this.buildQueryString(queryOptions);
322
+ if (params) {
323
+ url += `?${params}`;
324
+ }
325
+ }
326
+ return url;
327
+ }
328
+ getHeaders() {
329
+ return {
330
+ 'Accept': 'application/json',
331
+ 'Content-Type': 'application/json',
332
+ 'OData-Version': this.options.version,
333
+ 'OData-MaxVersion': '4.01',
334
+ };
335
+ }
336
+ async request(method, url, body, requestOptions) {
337
+ const options = {
338
+ ...this.options.requestOptions,
339
+ ...requestOptions,
340
+ throwHttpErrors: false,
341
+ headers: {
342
+ ...this.getHeaders(),
343
+ ...requestOptions?.headers,
344
+ },
345
+ };
346
+ let response;
347
+ switch (method) {
348
+ case 'GET':
349
+ response = await this.client.get(url, options);
350
+ break;
351
+ case 'POST':
352
+ response = await this.client.post(url, body, options);
353
+ break;
354
+ case 'PUT':
355
+ response = await this.client.put(url, body, options);
356
+ break;
357
+ case 'PATCH':
358
+ response = await this.client.patch(url, body, options);
359
+ break;
360
+ case 'DELETE':
361
+ response = await this.client.delete(url, options);
362
+ break;
363
+ default:
364
+ throw new UnsupportedError(`Unsupported HTTP method: ${method}`, {
365
+ feature: method,
366
+ });
367
+ }
368
+ return this.handleResponse(response);
369
+ }
370
+ async handleResponse(response) {
371
+ if (response.status === 204) {
372
+ return undefined;
373
+ }
374
+ const data = await response.json();
375
+ if (!response.ok) {
376
+ const error = data;
377
+ if (error.error) {
378
+ throw new ODataException(error.error);
379
+ }
380
+ throw new HttpError(response);
381
+ }
382
+ return data;
383
+ }
384
+ formatKey(key) {
385
+ if (typeof key === 'string') {
386
+ return `'${key.replace(/'/g, "''")}'`;
387
+ }
388
+ if (typeof key === 'number') {
389
+ return key.toString();
390
+ }
391
+ return Object.entries(key)
392
+ .map(([k, v]) => `${k}=${this.formatKeyValue(v)}`)
393
+ .join(',');
394
+ }
395
+ formatKeyValue(value) {
396
+ if (typeof value === 'string')
397
+ return `'${value.replace(/'/g, "''")}'`;
398
+ if (value === null)
399
+ return 'null';
400
+ if (value instanceof Date)
401
+ return value.toISOString();
402
+ return String(value);
403
+ }
404
+ buildQueryString(options) {
405
+ const params = [];
406
+ if (options.$select) {
407
+ const select = Array.isArray(options.$select) ? options.$select.join(',') : options.$select;
408
+ params.push(`$select=${encodeURIComponent(select)}`);
409
+ }
410
+ if (options.$expand) {
411
+ const expand = this.formatExpand(options.$expand);
412
+ params.push(`$expand=${encodeURIComponent(expand)}`);
413
+ }
414
+ if (options.$filter) {
415
+ const filter = typeof options.$filter === 'string'
416
+ ? options.$filter
417
+ : this.formatFilterExpression(options.$filter);
418
+ params.push(`$filter=${encodeURIComponent(filter)}`);
419
+ }
420
+ if (options.$orderby) {
421
+ const orderby = this.formatOrderBy(options.$orderby);
422
+ params.push(`$orderby=${encodeURIComponent(orderby)}`);
423
+ }
424
+ if (options.$top !== undefined) {
425
+ params.push(`$top=${options.$top}`);
426
+ }
427
+ if (options.$skip !== undefined) {
428
+ params.push(`$skip=${options.$skip}`);
429
+ }
430
+ if (options.$count !== undefined) {
431
+ params.push(`$count=${options.$count}`);
432
+ }
433
+ if (options.$search) {
434
+ params.push(`$search=${encodeURIComponent(options.$search)}`);
435
+ }
436
+ if (options.$format) {
437
+ params.push(`$format=${options.$format}`);
438
+ }
439
+ for (const [key, value] of Object.entries(options)) {
440
+ if (!key.startsWith('$') && value !== undefined) {
441
+ params.push(`${key}=${encodeURIComponent(String(value))}`);
442
+ }
443
+ }
444
+ return params.join('&');
445
+ }
446
+ formatExpand(expand) {
447
+ if (typeof expand === 'string')
448
+ return expand;
449
+ if (Array.isArray(expand)) {
450
+ return expand.map((e) => {
451
+ if (typeof e === 'string')
452
+ return e;
453
+ return this.formatExpandOption(e);
454
+ }).join(',');
455
+ }
456
+ return '';
457
+ }
458
+ formatExpandOption(option) {
459
+ let result = option.property;
460
+ const nested = [];
461
+ if (option.select)
462
+ nested.push(`$select=${option.select.join(',')}`);
463
+ if (option.filter) {
464
+ const filter = typeof option.filter === 'string'
465
+ ? option.filter
466
+ : this.formatFilterExpression(option.filter);
467
+ nested.push(`$filter=${filter}`);
468
+ }
469
+ if (option.orderby)
470
+ nested.push(`$orderby=${this.formatOrderBy(option.orderby)}`);
471
+ if (option.top !== undefined)
472
+ nested.push(`$top=${option.top}`);
473
+ if (option.skip !== undefined)
474
+ nested.push(`$skip=${option.skip}`);
475
+ if (option.count !== undefined)
476
+ nested.push(`$count=${option.count}`);
477
+ if (option.expand)
478
+ nested.push(`$expand=${this.formatExpand(option.expand)}`);
479
+ if (nested.length > 0) {
480
+ result += `(${nested.join(';')})`;
481
+ }
482
+ return result;
483
+ }
484
+ formatOrderBy(orderby) {
485
+ if (typeof orderby === 'string')
486
+ return orderby;
487
+ return orderby.map((o) => `${o.property} ${o.direction ?? 'asc'}`).join(',');
488
+ }
489
+ formatFilterExpression(filter) {
490
+ if (filter.raw)
491
+ return filter.raw;
492
+ const parts = [];
493
+ if (filter.eq)
494
+ parts.push(`${filter.eq[0]} eq ${this.formatFilterValue(filter.eq[1])}`);
495
+ if (filter.ne)
496
+ parts.push(`${filter.ne[0]} ne ${this.formatFilterValue(filter.ne[1])}`);
497
+ if (filter.gt)
498
+ parts.push(`${filter.gt[0]} gt ${this.formatFilterValue(filter.gt[1])}`);
499
+ if (filter.ge)
500
+ parts.push(`${filter.ge[0]} ge ${this.formatFilterValue(filter.ge[1])}`);
501
+ if (filter.lt)
502
+ parts.push(`${filter.lt[0]} lt ${this.formatFilterValue(filter.lt[1])}`);
503
+ if (filter.le)
504
+ parts.push(`${filter.le[0]} le ${this.formatFilterValue(filter.le[1])}`);
505
+ if (filter.contains)
506
+ parts.push(`contains(${filter.contains[0]},'${filter.contains[1]}')`);
507
+ if (filter.startswith)
508
+ parts.push(`startswith(${filter.startswith[0]},'${filter.startswith[1]}')`);
509
+ if (filter.endswith)
510
+ parts.push(`endswith(${filter.endswith[0]},'${filter.endswith[1]}')`);
511
+ if (filter.and) {
512
+ const andParts = filter.and.map((f) => this.formatFilterExpression(f));
513
+ parts.push(`(${andParts.join(' and ')})`);
514
+ }
515
+ if (filter.or) {
516
+ const orParts = filter.or.map((f) => this.formatFilterExpression(f));
517
+ parts.push(`(${orParts.join(' or ')})`);
518
+ }
519
+ if (filter.not) {
520
+ parts.push(`not (${this.formatFilterExpression(filter.not)})`);
521
+ }
522
+ return parts.join(' and ');
523
+ }
524
+ formatFilterValue(value) {
525
+ if (value === null)
526
+ return 'null';
527
+ if (typeof value === 'string')
528
+ return `'${value.replace(/'/g, "''")}'`;
529
+ if (typeof value === 'boolean')
530
+ return value.toString();
531
+ if (typeof value === 'number')
532
+ return value.toString();
533
+ if (value instanceof Date)
534
+ return value.toISOString();
535
+ return String(value);
536
+ }
537
+ parseBatchResponse(responseText) {
538
+ const results = [];
539
+ const boundaryMatch = responseText.match(/--batch[^\r\n]+/);
540
+ if (!boundaryMatch)
541
+ return results;
542
+ const boundary = boundaryMatch[0];
543
+ const parts = responseText.split(boundary).slice(1, -1);
544
+ for (const part of parts) {
545
+ const statusMatch = part.match(/HTTP\/\d\.\d\s+(\d+)/);
546
+ const bodyMatch = part.match(/\r\n\r\n({[\s\S]*})/);
547
+ results.push({
548
+ status: statusMatch ? parseInt(statusMatch[1], 10) : 0,
549
+ body: bodyMatch ? JSON.parse(bodyMatch[1]) : null,
550
+ });
551
+ }
552
+ return results;
553
+ }
554
+ }
555
+ export function createODataClient(client, options) {
556
+ return new ODataClient(client, options);
557
+ }
558
+ export function odata() {
559
+ return (client) => {
560
+ client.odata = (serviceRoot, options) => {
561
+ return createODataClient(client, { serviceRoot, ...options });
562
+ };
563
+ };
564
+ }
@@ -0,0 +1,16 @@
1
+ import { ReckerResponse, PageResult } from '../types/index.js';
2
+ interface IClient {
3
+ request(url: string, options?: any): Promise<ReckerResponse>;
4
+ }
5
+ export interface PaginationOptions<T = any> {
6
+ getItems?: (data: any) => T[];
7
+ getNextUrl?: (response: ReckerResponse, data: any, currentUrl: string) => string | null;
8
+ maxPages?: number;
9
+ pageParam?: string;
10
+ limitParam?: string;
11
+ resultsPath?: string;
12
+ nextCursorPath?: string;
13
+ }
14
+ export declare function streamPages<T = any>(client: IClient, url: string, requestOptions?: any, paginationOptions?: PaginationOptions): AsyncGenerator<PageResult<T>>;
15
+ export declare function paginate<T>(client: IClient, url: string, requestOptions?: any, paginationOptions?: PaginationOptions<T>): AsyncGenerator<T>;
16
+ export {};
@@ -0,0 +1,105 @@
1
+ export async function* streamPages(client, url, requestOptions = {}, paginationOptions = {}) {
2
+ let currentUrl = url;
3
+ let pageCount = 1;
4
+ const maxPages = paginationOptions.maxPages || Infinity;
5
+ while (currentUrl && pageCount <= maxPages) {
6
+ const response = await client.request(currentUrl, { ...requestOptions, method: 'GET' });
7
+ const data = await response.json();
8
+ yield {
9
+ data,
10
+ response,
11
+ pageNumber: pageCount
12
+ };
13
+ pageCount++;
14
+ if (paginationOptions.getNextUrl) {
15
+ currentUrl = paginationOptions.getNextUrl(response, data, currentUrl);
16
+ continue;
17
+ }
18
+ if (paginationOptions.nextCursorPath) {
19
+ const parts = paginationOptions.nextCursorPath.split('.');
20
+ let cursor = data;
21
+ for (const part of parts) {
22
+ if (cursor && typeof cursor === 'object') {
23
+ cursor = cursor[part];
24
+ }
25
+ else {
26
+ cursor = undefined;
27
+ break;
28
+ }
29
+ }
30
+ if (cursor) {
31
+ const cursorParamName = paginationOptions.pageParam || 'cursor';
32
+ const isAbsolute = currentUrl.startsWith('http');
33
+ const urlObj = new URL(isAbsolute ? currentUrl : `http://dummy-base${currentUrl.startsWith('/') ? '' : '/'}${currentUrl}`);
34
+ urlObj.searchParams.set(cursorParamName, String(cursor));
35
+ if (isAbsolute) {
36
+ currentUrl = urlObj.toString();
37
+ }
38
+ else {
39
+ currentUrl = urlObj.pathname + urlObj.search;
40
+ }
41
+ }
42
+ else {
43
+ currentUrl = null;
44
+ }
45
+ continue;
46
+ }
47
+ if (paginationOptions.pageParam) {
48
+ const isAbsolute = currentUrl.startsWith('http');
49
+ const urlObj = new URL(isAbsolute ? currentUrl : `http://dummy-base${currentUrl.startsWith('/') ? '' : '/'}${currentUrl}`);
50
+ const paramName = paginationOptions.pageParam;
51
+ const currentVal = parseInt(urlObj.searchParams.get(paramName) || String(pageCount - 1), 10);
52
+ let isEmpty = false;
53
+ if (Array.isArray(data) && data.length === 0)
54
+ isEmpty = true;
55
+ if (data && Array.isArray(data.data) && data.data.length === 0)
56
+ isEmpty = true;
57
+ if (data && Array.isArray(data.items) && data.items.length === 0)
58
+ isEmpty = true;
59
+ if (isEmpty) {
60
+ currentUrl = null;
61
+ }
62
+ else {
63
+ const nextPage = (isNaN(currentVal) ? 1 : currentVal) + 1;
64
+ urlObj.searchParams.set(paramName, String(nextPage));
65
+ currentUrl = isAbsolute ? urlObj.toString() : (urlObj.pathname + urlObj.search);
66
+ }
67
+ continue;
68
+ }
69
+ const linkHeader = response.headers.get('link');
70
+ if (linkHeader) {
71
+ const match = linkHeader.match(/<([^>]+)>;\s*rel="next"/);
72
+ currentUrl = match ? match[1] : null;
73
+ }
74
+ else {
75
+ currentUrl = null;
76
+ }
77
+ }
78
+ }
79
+ export async function* paginate(client, url, requestOptions = {}, paginationOptions = {}) {
80
+ for await (const page of streamPages(client, url, requestOptions, paginationOptions)) {
81
+ const data = page.data;
82
+ let items = [];
83
+ if (paginationOptions.getItems) {
84
+ items = paginationOptions.getItems(data);
85
+ }
86
+ else if (paginationOptions.resultsPath) {
87
+ items = paginationOptions.resultsPath.split('.').reduce((o, i) => o?.[i], data) || [];
88
+ }
89
+ else if (Array.isArray(data)) {
90
+ items = data;
91
+ }
92
+ else if (data && Array.isArray(data.data)) {
93
+ items = data.data;
94
+ }
95
+ else if (data && Array.isArray(data.items)) {
96
+ items = data.items;
97
+ }
98
+ else {
99
+ items = [data];
100
+ }
101
+ for (const item of items) {
102
+ yield item;
103
+ }
104
+ }
105
+ }
@@ -0,0 +1,15 @@
1
+ import { Plugin, ReckerRequest } from '../types/index.js';
2
+ export interface RateLimitOptions {
3
+ limit: number;
4
+ window?: number;
5
+ strategy?: 'queue' | 'throw' | 'drop';
6
+ keyGenerator?: (req: ReckerRequest) => string;
7
+ adaptive?: boolean;
8
+ }
9
+ export declare class RateLimitExceededError extends Error {
10
+ limit: number;
11
+ window: number;
12
+ key: string;
13
+ constructor(limit: number, window: number, key: string);
14
+ }
15
+ export declare function rateLimitPlugin(options: RateLimitOptions): Plugin;