@crawlora-org/sdk 1.3.0-sdk.1 → 1.4.0-sdk.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/docs/recipes.md +45 -0
- package/package.json +1 -1
- package/src/client.js +103 -25
- package/src/index.d.ts +35 -4
- package/src/operations.js +120 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v1.4.0-sdk.1
|
|
4
|
+
|
|
5
|
+
- Configurable retries: `maxRetryDelay`, `retryStatuses`, and an `isRetryable`
|
|
6
|
+
predicate; added an `onRetry` hook, opt-in `requestId` (x-request-id, also on
|
|
7
|
+
`error.requestId`), and a `logger` event sink.
|
|
8
|
+
- Pagination: cursor/token mode (`cursorParam` + `nextCursor`) and a
|
|
9
|
+
`paginateItems` per-item async iterator; operation metadata now exposes
|
|
10
|
+
`paginatable` and `cursorParams`.
|
|
11
|
+
- Streaming: `responseType: "stream"` returns the raw `Response` on success.
|
|
12
|
+
- Config: `CRAWLORA_API_KEY` / `CRAWLORA_BASE_URL` environment fallback.
|
|
13
|
+
|
|
3
14
|
## v1.3.0-sdk.1
|
|
4
15
|
|
|
5
16
|
- Added `CrawloraClientError`, `CrawloraServerError`, and `CrawloraNetworkError`
|
package/docs/recipes.md
CHANGED
|
@@ -74,6 +74,51 @@ try {
|
|
|
74
74
|
}
|
|
75
75
|
```
|
|
76
76
|
|
|
77
|
+
## Custom Retries And Observability
|
|
78
|
+
|
|
79
|
+
```js
|
|
80
|
+
const crawlora = new CrawloraClient({
|
|
81
|
+
retries: 3,
|
|
82
|
+
maxRetryDelay: 10000,
|
|
83
|
+
retryStatuses: [429, 503], // or:
|
|
84
|
+
isRetryable: (status, error) => status >= 500,
|
|
85
|
+
onRetry: (attempt, error, delay) => console.warn(`retry ${attempt} after ${delay}ms`, error.status),
|
|
86
|
+
requestId: true, // sets x-request-id; available as error.requestId
|
|
87
|
+
logger: (event) => console.debug(event)
|
|
88
|
+
});
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Branch on `CrawloraClientError` (4xx), `CrawloraServerError` (5xx), and
|
|
92
|
+
`CrawloraNetworkError` (transport).
|
|
93
|
+
|
|
94
|
+
## Pagination
|
|
95
|
+
|
|
96
|
+
```js
|
|
97
|
+
// page/offset (auto-detected)
|
|
98
|
+
for await (const page of crawlora.paginate("ebay-seller-feedback", { seller: "acme" })) { /* ... */ }
|
|
99
|
+
|
|
100
|
+
// per-item iteration
|
|
101
|
+
for await (const item of crawlora.paginateItems("ebay-seller-feedback", { seller: "acme" })) { /* ... */ }
|
|
102
|
+
|
|
103
|
+
// cursor/token pagination
|
|
104
|
+
for await (const page of crawlora.paginate("producthunt-leaderboard", {}, {
|
|
105
|
+
cursorParam: "cursor",
|
|
106
|
+
nextCursor: (p) => p.next_cursor
|
|
107
|
+
})) { /* ... */ }
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Streaming Responses
|
|
111
|
+
|
|
112
|
+
```js
|
|
113
|
+
const res = await crawlora.request("bing-search", { q: "coffee" }, { responseType: "stream" });
|
|
114
|
+
for await (const chunk of res.body) { /* ... */ }
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Environment Variables
|
|
118
|
+
|
|
119
|
+
`CRAWLORA_API_KEY` and `CRAWLORA_BASE_URL` are used when not set explicitly
|
|
120
|
+
(precedence: option > env > default).
|
|
121
|
+
|
|
77
122
|
## Optional Live Smoke Tests
|
|
78
123
|
|
|
79
124
|
```sh
|
package/package.json
CHANGED
package/src/client.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { operations, groups } from "./operations.js";
|
|
2
2
|
|
|
3
3
|
const DEFAULT_BASE_URL = "https://api.crawlora.net/api/v1";
|
|
4
|
-
export const VERSION = "1.
|
|
4
|
+
export const VERSION = "1.4.0-sdk.1";
|
|
5
5
|
const DEFAULT_USER_AGENT = `crawlora-js-sdk/${VERSION}`;
|
|
6
6
|
|
|
7
7
|
export class CrawloraError extends Error {
|
|
8
|
-
constructor(message, { status = 0, code, body, headers = {}, response, cause, retryable } = {}) {
|
|
8
|
+
constructor(message, { status = 0, code, body, headers = {}, response, cause, retryable, requestId } = {}) {
|
|
9
9
|
super(message);
|
|
10
10
|
this.name = "CrawloraError";
|
|
11
11
|
this.status = status;
|
|
@@ -15,6 +15,7 @@ export class CrawloraError extends Error {
|
|
|
15
15
|
this.response = response;
|
|
16
16
|
this.cause = cause;
|
|
17
17
|
this.retryable = retryable;
|
|
18
|
+
this.requestId = requestId;
|
|
18
19
|
}
|
|
19
20
|
}
|
|
20
21
|
|
|
@@ -49,12 +50,19 @@ function apiErrorClass(status) {
|
|
|
49
50
|
|
|
50
51
|
export class CrawloraClient {
|
|
51
52
|
constructor(options = {}) {
|
|
52
|
-
|
|
53
|
+
// Precedence: explicit option > environment variable > default.
|
|
54
|
+
this.apiKey = options.apiKey || envVar("CRAWLORA_API_KEY") || "";
|
|
53
55
|
this.jwtToken = options.jwtToken || "";
|
|
54
|
-
this.baseUrl = (options.baseUrl || DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
56
|
+
this.baseUrl = (options.baseUrl || envVar("CRAWLORA_BASE_URL") || DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
55
57
|
this.timeout = options.timeout ?? 30000;
|
|
56
58
|
this.retries = normalizeNonNegativeInteger(options.retries ?? 0);
|
|
57
59
|
this.retryDelay = normalizeNonNegativeNumber(options.retryDelay ?? 250);
|
|
60
|
+
this.maxRetryDelay = normalizeNonNegativeNumber(options.maxRetryDelay ?? 30000);
|
|
61
|
+
this.retryStatuses = options.retryStatuses ? new Set(options.retryStatuses) : null;
|
|
62
|
+
this.isRetryable = typeof options.isRetryable === "function" ? options.isRetryable : null;
|
|
63
|
+
this.onRetry = typeof options.onRetry === "function" ? options.onRetry : null;
|
|
64
|
+
this.requestId = options.requestId === true;
|
|
65
|
+
this.logger = typeof options.logger === "function" ? options.logger : null;
|
|
58
66
|
this.headers = { ...(options.headers || {}) };
|
|
59
67
|
this.userAgent = options.userAgent === false ? "" : (options.userAgent || DEFAULT_USER_AGENT);
|
|
60
68
|
this.fetch = options.fetch || globalThis.fetch;
|
|
@@ -84,21 +92,40 @@ export class CrawloraClient {
|
|
|
84
92
|
params = params ?? {};
|
|
85
93
|
options = options ?? {};
|
|
86
94
|
const responseType = validateResponseType(options.responseType || "auto");
|
|
95
|
+
this.#log({ event: "request", operation: operationId });
|
|
87
96
|
|
|
88
97
|
let attempt = 0;
|
|
89
98
|
for (;;) {
|
|
90
99
|
try {
|
|
91
100
|
return await this.#send(operation, params, options, responseType);
|
|
92
101
|
} catch (error) {
|
|
93
|
-
if (!(error instanceof CrawloraError) || error.retryable === false || attempt >= this.retries || !
|
|
102
|
+
if (!(error instanceof CrawloraError) || error.retryable === false || attempt >= this.retries || !this.#isRetryable(error.status, error)) {
|
|
94
103
|
throw error;
|
|
95
104
|
}
|
|
96
105
|
attempt++;
|
|
97
|
-
|
|
106
|
+
const delay = this.#retryDelayFor(error, attempt);
|
|
107
|
+
this.#log({ event: "retry", operation: operationId, attempt, status: error.status, delay });
|
|
108
|
+
if (this.onRetry) this.onRetry(attempt, error, delay);
|
|
109
|
+
await sleep(delay, options.signal);
|
|
98
110
|
}
|
|
99
111
|
}
|
|
100
112
|
}
|
|
101
113
|
|
|
114
|
+
#isRetryable(status, error) {
|
|
115
|
+
if (this.isRetryable) return !!this.isRetryable(status, error);
|
|
116
|
+
if (this.retryStatuses) return status === 0 || this.retryStatuses.has(status);
|
|
117
|
+
return shouldRetry(status);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
#retryDelayFor(error, attempt) {
|
|
121
|
+
const retryAfter = parseRetryAfter(error.headers, this.maxRetryDelay);
|
|
122
|
+
return retryAfter ?? retryDelay(this.retryDelay, attempt);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
#log(event) {
|
|
126
|
+
if (this.logger) this.logger(event);
|
|
127
|
+
}
|
|
128
|
+
|
|
102
129
|
async #send(operation, params, options, responseType) {
|
|
103
130
|
const { url, body, bodyHeaders } = buildRequest(operation, this.baseUrl, params);
|
|
104
131
|
const headers = mergeHeaders(
|
|
@@ -108,6 +135,7 @@ export class CrawloraClient {
|
|
|
108
135
|
bodyHeaders,
|
|
109
136
|
options.headers
|
|
110
137
|
);
|
|
138
|
+
const requestId = this.requestId ? ensureRequestId(headers) : (headerValue(headers, "x-request-id") || undefined);
|
|
111
139
|
|
|
112
140
|
const controller = new AbortController();
|
|
113
141
|
const timeoutMs = options.timeout ?? this.timeout;
|
|
@@ -127,18 +155,22 @@ export class CrawloraClient {
|
|
|
127
155
|
});
|
|
128
156
|
} catch (error) {
|
|
129
157
|
if (options.signal?.aborted) {
|
|
130
|
-
throw new CrawloraNetworkError("Crawlora request aborted", { cause: error, retryable: false });
|
|
158
|
+
throw new CrawloraNetworkError("Crawlora request aborted", { cause: error, retryable: false, requestId });
|
|
131
159
|
}
|
|
132
160
|
if (timedOut) {
|
|
133
|
-
throw new CrawloraNetworkError("Crawlora request timed out", { cause: error, retryable: false });
|
|
161
|
+
throw new CrawloraNetworkError("Crawlora request timed out", { cause: error, retryable: false, requestId });
|
|
134
162
|
}
|
|
135
|
-
throw new CrawloraNetworkError("Crawlora transport error", { cause: error });
|
|
163
|
+
throw new CrawloraNetworkError("Crawlora transport error", { cause: error, requestId });
|
|
136
164
|
} finally {
|
|
137
165
|
if (timeout) clearTimeout(timeout);
|
|
138
166
|
}
|
|
139
167
|
|
|
140
168
|
const headersObject = responseHeaders(response);
|
|
141
|
-
|
|
169
|
+
// Streaming success returns the raw Response; the caller reads response.body.
|
|
170
|
+
if (responseType === "stream" && response.ok) {
|
|
171
|
+
return response;
|
|
172
|
+
}
|
|
173
|
+
const parsed = await parseResponse(response, responseType === "stream" ? "auto" : responseType, headersObject, requestId);
|
|
142
174
|
if (!response.ok) {
|
|
143
175
|
const code = parsed && typeof parsed === "object" ? parsed.code : undefined;
|
|
144
176
|
const message = parsed && typeof parsed === "object" && parsed.msg ? parsed.msg : response.statusText;
|
|
@@ -148,26 +180,48 @@ export class CrawloraClient {
|
|
|
148
180
|
code,
|
|
149
181
|
body: parsed,
|
|
150
182
|
headers: headersObject,
|
|
151
|
-
response
|
|
183
|
+
response,
|
|
184
|
+
requestId
|
|
152
185
|
});
|
|
153
186
|
}
|
|
154
187
|
return parsed;
|
|
155
188
|
}
|
|
156
189
|
|
|
157
|
-
// Async iterator over pages of a paginated operation.
|
|
158
|
-
// page/offset query parameter and stops
|
|
190
|
+
// Async iterator over pages of a paginated operation. Numeric mode advances
|
|
191
|
+
// the page/offset query parameter and stops on an empty page; cursor mode
|
|
192
|
+
// (cursorParam + nextCursor) sends the cursor and stops when nextCursor is falsy.
|
|
159
193
|
// for await (const page of client.paginate("ebay-seller-feedback", { seller })) { ... }
|
|
160
194
|
async *paginate(operationId, params = {}, options = {}) {
|
|
161
195
|
const operation = operations[operationId];
|
|
162
196
|
if (!operation) {
|
|
163
197
|
throw new TypeError(`Unknown Crawlora operation: ${operationId}`);
|
|
164
198
|
}
|
|
199
|
+
const maxPages = options.maxPages ?? Infinity;
|
|
200
|
+
|
|
201
|
+
if (options.cursorParam || options.nextCursor) {
|
|
202
|
+
if (!(options.cursorParam && options.nextCursor)) {
|
|
203
|
+
throw new TypeError("cursor pagination requires both cursorParam and nextCursor");
|
|
204
|
+
}
|
|
205
|
+
if (!operation.queryParams.some((parameter) => parameter.name === options.cursorParam)) {
|
|
206
|
+
throw new TypeError(`cursorParam ${options.cursorParam} is not a query parameter of ${operationId}`);
|
|
207
|
+
}
|
|
208
|
+
let cursor = options.start;
|
|
209
|
+
for (let i = 0; i < maxPages; i++) {
|
|
210
|
+
const pageParams = { ...params };
|
|
211
|
+
if (cursor !== undefined && cursor !== null) pageParams[options.cursorParam] = cursor;
|
|
212
|
+
const response = await this.request(operationId, pageParams, options);
|
|
213
|
+
yield response;
|
|
214
|
+
cursor = options.nextCursor(response);
|
|
215
|
+
if (!cursor) break;
|
|
216
|
+
}
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
|
|
165
220
|
const pageParam = options.pageParam || detectPageParam(operation);
|
|
166
221
|
if (!pageParam) {
|
|
167
222
|
throw new TypeError(`Operation ${operationId} has no page or offset query parameter to paginate`);
|
|
168
223
|
}
|
|
169
224
|
const step = options.step ?? 1;
|
|
170
|
-
const maxPages = options.maxPages ?? Infinity;
|
|
171
225
|
let pageValue = options.start ?? (pageParam === "offset" ? 0 : 1);
|
|
172
226
|
for (let i = 0; i < maxPages; i++) {
|
|
173
227
|
const response = await this.request(operationId, { ...params, [pageParam]: pageValue }, options);
|
|
@@ -176,10 +230,25 @@ export class CrawloraClient {
|
|
|
176
230
|
pageValue += step;
|
|
177
231
|
}
|
|
178
232
|
}
|
|
233
|
+
|
|
234
|
+
// Async iterator over individual items across pages. `items` extracts the list
|
|
235
|
+
// from a page (default: the Crawlora `data` array).
|
|
236
|
+
async *paginateItems(operationId, params = {}, options = {}) {
|
|
237
|
+
const extract = options.items || defaultItems;
|
|
238
|
+
for await (const page of this.paginate(operationId, params, options)) {
|
|
239
|
+
for (const item of extract(page)) yield item;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
179
242
|
}
|
|
180
243
|
|
|
181
244
|
const PAGE_PARAM_NAMES = ["page", "offset"];
|
|
182
245
|
|
|
246
|
+
function defaultItems(response) {
|
|
247
|
+
if (response && typeof response === "object" && Array.isArray(response.data)) return response.data;
|
|
248
|
+
if (Array.isArray(response)) return response;
|
|
249
|
+
return [];
|
|
250
|
+
}
|
|
251
|
+
|
|
183
252
|
function detectPageParam(operation) {
|
|
184
253
|
for (const name of PAGE_PARAM_NAMES) {
|
|
185
254
|
if (operation.queryParams.some((parameter) => parameter.name === name)) return name;
|
|
@@ -316,13 +385,13 @@ function composeSignal(controller, signal) {
|
|
|
316
385
|
}
|
|
317
386
|
|
|
318
387
|
function validateResponseType(responseType) {
|
|
319
|
-
if (responseType === "auto" || responseType === "json" || responseType === "text") {
|
|
388
|
+
if (responseType === "auto" || responseType === "json" || responseType === "text" || responseType === "stream") {
|
|
320
389
|
return responseType;
|
|
321
390
|
}
|
|
322
|
-
throw new TypeError("Invalid responseType: expected one of auto, json, text");
|
|
391
|
+
throw new TypeError("Invalid responseType: expected one of auto, json, text, stream");
|
|
323
392
|
}
|
|
324
393
|
|
|
325
|
-
async function parseResponse(response, responseType, headers) {
|
|
394
|
+
async function parseResponse(response, responseType, headers, requestId) {
|
|
326
395
|
if (responseType === "text") return response.text();
|
|
327
396
|
const contentType = response.headers.get("content-type") || "";
|
|
328
397
|
if (responseType === "json" || contentType.toLowerCase().includes("application/json")) {
|
|
@@ -335,7 +404,8 @@ async function parseResponse(response, responseType, headers) {
|
|
|
335
404
|
body: text,
|
|
336
405
|
headers,
|
|
337
406
|
response,
|
|
338
|
-
cause: error
|
|
407
|
+
cause: error,
|
|
408
|
+
requestId
|
|
339
409
|
});
|
|
340
410
|
}
|
|
341
411
|
}
|
|
@@ -353,25 +423,33 @@ function retryDelay(baseDelay, attempt) {
|
|
|
353
423
|
return delay + jitter;
|
|
354
424
|
}
|
|
355
425
|
|
|
356
|
-
function
|
|
357
|
-
return parseRetryAfter(error.headers) ?? retryDelay(baseDelay, attempt);
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
function parseRetryAfter(headers) {
|
|
426
|
+
function parseRetryAfter(headers, cap = 30000) {
|
|
361
427
|
const value = headerValue(headers, "retry-after");
|
|
362
428
|
if (!value) return undefined;
|
|
363
429
|
const seconds = Number(value);
|
|
364
430
|
if (Number.isFinite(seconds) && seconds > 0) {
|
|
365
|
-
return Math.min(seconds * 1000,
|
|
431
|
+
return Math.min(seconds * 1000, cap);
|
|
366
432
|
}
|
|
367
433
|
const date = Date.parse(value);
|
|
368
434
|
if (Number.isFinite(date)) {
|
|
369
435
|
const delay = date - Date.now();
|
|
370
|
-
if (delay > 0) return Math.min(delay,
|
|
436
|
+
if (delay > 0) return Math.min(delay, cap);
|
|
371
437
|
}
|
|
372
438
|
return undefined;
|
|
373
439
|
}
|
|
374
440
|
|
|
441
|
+
function envVar(name) {
|
|
442
|
+
return (typeof process !== "undefined" && process.env && process.env[name]) || undefined;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
function ensureRequestId(headers) {
|
|
446
|
+
const existing = headerValue(headers, "x-request-id");
|
|
447
|
+
if (existing) return existing;
|
|
448
|
+
const id = (typeof crypto !== "undefined" && crypto.randomUUID) ? crypto.randomUUID() : `req-${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
|
449
|
+
headers["x-request-id"] = id;
|
|
450
|
+
return id;
|
|
451
|
+
}
|
|
452
|
+
|
|
375
453
|
function headerValue(headers, name) {
|
|
376
454
|
for (const [key, value] of Object.entries(headers || {})) {
|
|
377
455
|
if (key.toLowerCase() === name.toLowerCase()) return value;
|
package/src/index.d.ts
CHANGED
|
@@ -8,6 +8,8 @@ import type {
|
|
|
8
8
|
|
|
9
9
|
export type CrawloraParams = Record<string, unknown>;
|
|
10
10
|
|
|
11
|
+
export type CrawloraLogEvent = { event: string; [key: string]: unknown };
|
|
12
|
+
|
|
11
13
|
export interface CrawloraClientOptions {
|
|
12
14
|
apiKey?: string;
|
|
13
15
|
jwtToken?: string;
|
|
@@ -15,6 +17,18 @@ export interface CrawloraClientOptions {
|
|
|
15
17
|
timeout?: number;
|
|
16
18
|
retries?: number;
|
|
17
19
|
retryDelay?: number;
|
|
20
|
+
/** Cap on backoff and Retry-After delays in ms (default 30000). */
|
|
21
|
+
maxRetryDelay?: number;
|
|
22
|
+
/** Override the retryable HTTP status set (network status 0 stays retryable). */
|
|
23
|
+
retryStatuses?: Iterable<number>;
|
|
24
|
+
/** Full predicate; supersedes retryStatuses when set. */
|
|
25
|
+
isRetryable?: (status: number, error: CrawloraError) => boolean;
|
|
26
|
+
/** Called before each retry sleep with (attempt, error, delayMs). */
|
|
27
|
+
onRetry?: (attempt: number, error: CrawloraError, delay: number) => void;
|
|
28
|
+
/** Generate an x-request-id header when absent. */
|
|
29
|
+
requestId?: boolean;
|
|
30
|
+
/** Structured event sink (request/retry); never logs on its own. */
|
|
31
|
+
logger?: (event: CrawloraLogEvent) => void;
|
|
18
32
|
headers?: Record<string, string>;
|
|
19
33
|
userAgent?: string | false;
|
|
20
34
|
fetch?: typeof globalThis.fetch;
|
|
@@ -22,7 +36,7 @@ export interface CrawloraClientOptions {
|
|
|
22
36
|
|
|
23
37
|
export interface CrawloraRequestOptions {
|
|
24
38
|
headers?: Record<string, string>;
|
|
25
|
-
responseType?: "auto" | "json" | "text";
|
|
39
|
+
responseType?: "auto" | "json" | "text" | "stream";
|
|
26
40
|
timeout?: number;
|
|
27
41
|
signal?: AbortSignal;
|
|
28
42
|
}
|
|
@@ -44,6 +58,8 @@ export interface OperationDefinition {
|
|
|
44
58
|
consumes: string[];
|
|
45
59
|
produces: string[];
|
|
46
60
|
security: string[];
|
|
61
|
+
paginatable?: boolean;
|
|
62
|
+
cursorParams?: string[];
|
|
47
63
|
}
|
|
48
64
|
|
|
49
65
|
export class CrawloraError extends Error {
|
|
@@ -54,6 +70,7 @@ export class CrawloraError extends Error {
|
|
|
54
70
|
response?: Response;
|
|
55
71
|
cause?: unknown;
|
|
56
72
|
retryable?: boolean;
|
|
73
|
+
requestId?: string;
|
|
57
74
|
}
|
|
58
75
|
|
|
59
76
|
// Thrown for 4xx API responses (request rejected by the API).
|
|
@@ -64,16 +81,25 @@ export class CrawloraServerError extends CrawloraError {}
|
|
|
64
81
|
export class CrawloraNetworkError extends CrawloraError {}
|
|
65
82
|
|
|
66
83
|
export interface CrawloraPaginateOptions extends CrawloraRequestOptions {
|
|
67
|
-
//
|
|
84
|
+
// Numeric query parameter to advance. Auto-detected as "page" or "offset".
|
|
68
85
|
pageParam?: string;
|
|
69
|
-
//
|
|
70
|
-
|
|
86
|
+
// Cursor/token query parameter (cursor mode). Requires nextCursor.
|
|
87
|
+
cursorParam?: string;
|
|
88
|
+
// Extracts the next cursor from a page; iteration stops when it returns falsy.
|
|
89
|
+
nextCursor?: (page: unknown) => unknown;
|
|
90
|
+
// First page value (numeric) or initial cursor value.
|
|
91
|
+
start?: unknown;
|
|
71
92
|
// Amount added to the page parameter after each page. Defaults to 1.
|
|
72
93
|
step?: number;
|
|
73
94
|
// Maximum number of pages to fetch. Defaults to unbounded.
|
|
74
95
|
maxPages?: number;
|
|
75
96
|
}
|
|
76
97
|
|
|
98
|
+
export interface CrawloraPaginateItemsOptions extends CrawloraPaginateOptions {
|
|
99
|
+
// Extracts the item list from a page (default: the `data` array).
|
|
100
|
+
items?: (page: unknown) => Iterable<unknown>;
|
|
101
|
+
}
|
|
102
|
+
|
|
77
103
|
export class CrawloraClient {
|
|
78
104
|
constructor(options?: CrawloraClientOptions);
|
|
79
105
|
request<I extends OperationId>(
|
|
@@ -89,6 +115,11 @@ export class CrawloraClient {
|
|
|
89
115
|
params?: OperationParamsMap[I],
|
|
90
116
|
options?: CrawloraPaginateOptions
|
|
91
117
|
): AsyncGenerator<OperationResponseMap[I], void, unknown>;
|
|
118
|
+
paginateItems<I extends OperationId>(
|
|
119
|
+
operationId: I,
|
|
120
|
+
params?: OperationParamsMap[I],
|
|
121
|
+
options?: CrawloraPaginateItemsOptions
|
|
122
|
+
): AsyncGenerator<unknown, void, unknown>;
|
|
92
123
|
[group: string]: unknown;
|
|
93
124
|
}
|
|
94
125
|
|
package/src/operations.js
CHANGED
|
@@ -51,6 +51,7 @@ export const operations = {
|
|
|
51
51
|
"formParams": [],
|
|
52
52
|
"id": "airbnb-room-reviews",
|
|
53
53
|
"method": "GET",
|
|
54
|
+
"paginatable": true,
|
|
54
55
|
"path": "/airbnb/room/{id}/reviews",
|
|
55
56
|
"pathParams": [
|
|
56
57
|
"id"
|
|
@@ -78,6 +79,7 @@ export const operations = {
|
|
|
78
79
|
"formParams": [],
|
|
79
80
|
"id": "airbnb-search",
|
|
80
81
|
"method": "GET",
|
|
82
|
+
"paginatable": true,
|
|
81
83
|
"path": "/airbnb/search",
|
|
82
84
|
"pathParams": [],
|
|
83
85
|
"produces": [
|
|
@@ -192,6 +194,7 @@ export const operations = {
|
|
|
192
194
|
"formParams": [],
|
|
193
195
|
"id": "amazon-search",
|
|
194
196
|
"method": "GET",
|
|
197
|
+
"paginatable": true,
|
|
195
198
|
"path": "/amazon/search",
|
|
196
199
|
"pathParams": [],
|
|
197
200
|
"produces": [
|
|
@@ -289,6 +292,7 @@ export const operations = {
|
|
|
289
292
|
"formParams": [],
|
|
290
293
|
"id": "apple-podcasts-episodes-search",
|
|
291
294
|
"method": "GET",
|
|
295
|
+
"paginatable": true,
|
|
292
296
|
"path": "/apple-podcasts/episodes/search",
|
|
293
297
|
"pathParams": [],
|
|
294
298
|
"produces": [
|
|
@@ -335,6 +339,7 @@ export const operations = {
|
|
|
335
339
|
"formParams": [],
|
|
336
340
|
"id": "apple-podcasts-search",
|
|
337
341
|
"method": "GET",
|
|
342
|
+
"paginatable": true,
|
|
338
343
|
"path": "/apple-podcasts/search",
|
|
339
344
|
"pathParams": [],
|
|
340
345
|
"produces": [
|
|
@@ -649,6 +654,7 @@ export const operations = {
|
|
|
649
654
|
"formParams": [],
|
|
650
655
|
"id": "appstore-reviews",
|
|
651
656
|
"method": "GET",
|
|
657
|
+
"paginatable": true,
|
|
652
658
|
"path": "/appstore/reviews",
|
|
653
659
|
"pathParams": [],
|
|
654
660
|
"produces": [
|
|
@@ -703,6 +709,7 @@ export const operations = {
|
|
|
703
709
|
"formParams": [],
|
|
704
710
|
"id": "appstore-search",
|
|
705
711
|
"method": "GET",
|
|
712
|
+
"paginatable": true,
|
|
706
713
|
"path": "/appstore/search",
|
|
707
714
|
"pathParams": [],
|
|
708
715
|
"produces": [
|
|
@@ -1070,6 +1077,7 @@ export const operations = {
|
|
|
1070
1077
|
"formParams": [],
|
|
1071
1078
|
"id": "bing-images",
|
|
1072
1079
|
"method": "GET",
|
|
1080
|
+
"paginatable": true,
|
|
1073
1081
|
"path": "/bing/images",
|
|
1074
1082
|
"pathParams": [],
|
|
1075
1083
|
"produces": [
|
|
@@ -1116,6 +1124,7 @@ export const operations = {
|
|
|
1116
1124
|
"formParams": [],
|
|
1117
1125
|
"id": "bing-news",
|
|
1118
1126
|
"method": "GET",
|
|
1127
|
+
"paginatable": true,
|
|
1119
1128
|
"path": "/bing/news",
|
|
1120
1129
|
"pathParams": [],
|
|
1121
1130
|
"produces": [
|
|
@@ -1162,6 +1171,7 @@ export const operations = {
|
|
|
1162
1171
|
"formParams": [],
|
|
1163
1172
|
"id": "bing-search",
|
|
1164
1173
|
"method": "GET",
|
|
1174
|
+
"paginatable": true,
|
|
1165
1175
|
"path": "/bing/search",
|
|
1166
1176
|
"pathParams": [],
|
|
1167
1177
|
"produces": [
|
|
@@ -1249,6 +1259,7 @@ export const operations = {
|
|
|
1249
1259
|
"formParams": [],
|
|
1250
1260
|
"id": "bing-videos",
|
|
1251
1261
|
"method": "GET",
|
|
1262
|
+
"paginatable": true,
|
|
1252
1263
|
"path": "/bing/videos",
|
|
1253
1264
|
"pathParams": [],
|
|
1254
1265
|
"produces": [
|
|
@@ -1295,6 +1306,7 @@ export const operations = {
|
|
|
1295
1306
|
"formParams": [],
|
|
1296
1307
|
"id": "brave-images",
|
|
1297
1308
|
"method": "GET",
|
|
1309
|
+
"paginatable": true,
|
|
1298
1310
|
"path": "/brave/images",
|
|
1299
1311
|
"pathParams": [],
|
|
1300
1312
|
"produces": [
|
|
@@ -1397,6 +1409,7 @@ export const operations = {
|
|
|
1397
1409
|
"formParams": [],
|
|
1398
1410
|
"id": "brave-news",
|
|
1399
1411
|
"method": "GET",
|
|
1412
|
+
"paginatable": true,
|
|
1400
1413
|
"path": "/brave/news",
|
|
1401
1414
|
"pathParams": [],
|
|
1402
1415
|
"produces": [
|
|
@@ -1522,6 +1535,7 @@ export const operations = {
|
|
|
1522
1535
|
"formParams": [],
|
|
1523
1536
|
"id": "brave-search",
|
|
1524
1537
|
"method": "GET",
|
|
1538
|
+
"paginatable": true,
|
|
1525
1539
|
"path": "/brave/search",
|
|
1526
1540
|
"pathParams": [],
|
|
1527
1541
|
"produces": [
|
|
@@ -1739,6 +1753,7 @@ export const operations = {
|
|
|
1739
1753
|
"formParams": [],
|
|
1740
1754
|
"id": "brave-videos",
|
|
1741
1755
|
"method": "GET",
|
|
1756
|
+
"paginatable": true,
|
|
1742
1757
|
"path": "/brave/videos",
|
|
1743
1758
|
"pathParams": [],
|
|
1744
1759
|
"produces": [
|
|
@@ -1959,6 +1974,7 @@ export const operations = {
|
|
|
1959
1974
|
"formParams": [],
|
|
1960
1975
|
"id": "coingecko-category-coins",
|
|
1961
1976
|
"method": "GET",
|
|
1977
|
+
"paginatable": true,
|
|
1962
1978
|
"path": "/coingecko/category/{slug}/coins",
|
|
1963
1979
|
"pathParams": [
|
|
1964
1980
|
"slug"
|
|
@@ -2548,6 +2564,7 @@ export const operations = {
|
|
|
2548
2564
|
"formParams": [],
|
|
2549
2565
|
"id": "coingecko-exchanges",
|
|
2550
2566
|
"method": "GET",
|
|
2567
|
+
"paginatable": true,
|
|
2551
2568
|
"path": "/coingecko/exchanges",
|
|
2552
2569
|
"pathParams": [],
|
|
2553
2570
|
"produces": [
|
|
@@ -2863,6 +2880,7 @@ export const operations = {
|
|
|
2863
2880
|
"formParams": [],
|
|
2864
2881
|
"id": "coingecko-markets",
|
|
2865
2882
|
"method": "GET",
|
|
2883
|
+
"paginatable": true,
|
|
2866
2884
|
"path": "/coingecko/markets",
|
|
2867
2885
|
"pathParams": [],
|
|
2868
2886
|
"produces": [
|
|
@@ -2963,6 +2981,7 @@ export const operations = {
|
|
|
2963
2981
|
"formParams": [],
|
|
2964
2982
|
"id": "coingecko-new-coins",
|
|
2965
2983
|
"method": "GET",
|
|
2984
|
+
"paginatable": true,
|
|
2966
2985
|
"path": "/coingecko/new-coins",
|
|
2967
2986
|
"pathParams": [],
|
|
2968
2987
|
"produces": [
|
|
@@ -3088,6 +3107,7 @@ export const operations = {
|
|
|
3088
3107
|
"formParams": [],
|
|
3089
3108
|
"id": "coingecko-nft-category",
|
|
3090
3109
|
"method": "GET",
|
|
3110
|
+
"paginatable": true,
|
|
3091
3111
|
"path": "/coingecko/nft/category/{slug}",
|
|
3092
3112
|
"pathParams": [
|
|
3093
3113
|
"slug"
|
|
@@ -3190,6 +3210,7 @@ export const operations = {
|
|
|
3190
3210
|
"formParams": [],
|
|
3191
3211
|
"id": "coingecko-nfts",
|
|
3192
3212
|
"method": "GET",
|
|
3213
|
+
"paginatable": true,
|
|
3193
3214
|
"path": "/coingecko/nfts",
|
|
3194
3215
|
"pathParams": [],
|
|
3195
3216
|
"produces": [
|
|
@@ -3682,6 +3703,7 @@ export const operations = {
|
|
|
3682
3703
|
"formParams": [],
|
|
3683
3704
|
"id": "datasets-google-map-businesses-nearby",
|
|
3684
3705
|
"method": "GET",
|
|
3706
|
+
"paginatable": true,
|
|
3685
3707
|
"path": "/datasets/google-map-businesses/nearby",
|
|
3686
3708
|
"pathParams": [],
|
|
3687
3709
|
"produces": [
|
|
@@ -3745,6 +3767,7 @@ export const operations = {
|
|
|
3745
3767
|
"formParams": [],
|
|
3746
3768
|
"id": "datasets-google-map-businesses-search",
|
|
3747
3769
|
"method": "GET",
|
|
3770
|
+
"paginatable": true,
|
|
3748
3771
|
"path": "/datasets/google-map-businesses/search",
|
|
3749
3772
|
"pathParams": [],
|
|
3750
3773
|
"produces": [
|
|
@@ -3951,6 +3974,7 @@ export const operations = {
|
|
|
3951
3974
|
"formParams": [],
|
|
3952
3975
|
"id": "ebay-seller-feedback",
|
|
3953
3976
|
"method": "GET",
|
|
3977
|
+
"paginatable": true,
|
|
3954
3978
|
"path": "/ebay/seller/{seller}/feedback",
|
|
3955
3979
|
"pathParams": [
|
|
3956
3980
|
"seller"
|
|
@@ -3988,6 +4012,7 @@ export const operations = {
|
|
|
3988
4012
|
"formParams": [],
|
|
3989
4013
|
"id": "ebay-seller-shop",
|
|
3990
4014
|
"method": "GET",
|
|
4015
|
+
"paginatable": true,
|
|
3991
4016
|
"path": "/ebay/seller/{seller}/shop",
|
|
3992
4017
|
"pathParams": [
|
|
3993
4018
|
"seller"
|
|
@@ -4340,6 +4365,7 @@ export const operations = {
|
|
|
4340
4365
|
"formParams": [],
|
|
4341
4366
|
"id": "google-finance-markets-category-news",
|
|
4342
4367
|
"method": "GET",
|
|
4368
|
+
"paginatable": true,
|
|
4343
4369
|
"path": "/google/finance/markets/categories/{category}/news",
|
|
4344
4370
|
"pathParams": [
|
|
4345
4371
|
"category"
|
|
@@ -4367,6 +4393,7 @@ export const operations = {
|
|
|
4367
4393
|
"formParams": [],
|
|
4368
4394
|
"id": "google-finance-markets-category-stocks",
|
|
4369
4395
|
"method": "GET",
|
|
4396
|
+
"paginatable": true,
|
|
4370
4397
|
"path": "/google/finance/markets/categories/{category}/stocks",
|
|
4371
4398
|
"pathParams": [
|
|
4372
4399
|
"category"
|
|
@@ -4470,6 +4497,7 @@ export const operations = {
|
|
|
4470
4497
|
"formParams": [],
|
|
4471
4498
|
"id": "google-finance-markets-movers",
|
|
4472
4499
|
"method": "GET",
|
|
4500
|
+
"paginatable": true,
|
|
4473
4501
|
"path": "/google/finance/markets/movers",
|
|
4474
4502
|
"pathParams": [],
|
|
4475
4503
|
"produces": [
|
|
@@ -4505,6 +4533,7 @@ export const operations = {
|
|
|
4505
4533
|
"formParams": [],
|
|
4506
4534
|
"id": "google-finance-markets-top",
|
|
4507
4535
|
"method": "GET",
|
|
4536
|
+
"paginatable": true,
|
|
4508
4537
|
"path": "/google/finance/markets/top",
|
|
4509
4538
|
"pathParams": [],
|
|
4510
4539
|
"produces": [
|
|
@@ -6773,9 +6802,13 @@ export const operations = {
|
|
|
6773
6802
|
"consumes": [
|
|
6774
6803
|
"application/json"
|
|
6775
6804
|
],
|
|
6805
|
+
"cursorParams": [
|
|
6806
|
+
"cursor"
|
|
6807
|
+
],
|
|
6776
6808
|
"formParams": [],
|
|
6777
6809
|
"id": "producthunt-alternatives",
|
|
6778
6810
|
"method": "GET",
|
|
6811
|
+
"paginatable": true,
|
|
6779
6812
|
"path": "/producthunt/product/{id}/alternatives",
|
|
6780
6813
|
"pathParams": [
|
|
6781
6814
|
"id"
|
|
@@ -6839,6 +6872,7 @@ export const operations = {
|
|
|
6839
6872
|
"formParams": [],
|
|
6840
6873
|
"id": "producthunt-category-products",
|
|
6841
6874
|
"method": "GET",
|
|
6875
|
+
"paginatable": true,
|
|
6842
6876
|
"path": "/producthunt/category/{slug}/products",
|
|
6843
6877
|
"pathParams": [
|
|
6844
6878
|
"slug"
|
|
@@ -6886,6 +6920,7 @@ export const operations = {
|
|
|
6886
6920
|
"formParams": [],
|
|
6887
6921
|
"id": "producthunt-customers",
|
|
6888
6922
|
"method": "GET",
|
|
6923
|
+
"paginatable": true,
|
|
6889
6924
|
"path": "/producthunt/product/{id}/customers",
|
|
6890
6925
|
"pathParams": [
|
|
6891
6926
|
"id"
|
|
@@ -6924,9 +6959,13 @@ export const operations = {
|
|
|
6924
6959
|
"consumes": [
|
|
6925
6960
|
"application/json"
|
|
6926
6961
|
],
|
|
6962
|
+
"cursorParams": [
|
|
6963
|
+
"cursor"
|
|
6964
|
+
],
|
|
6927
6965
|
"formParams": [],
|
|
6928
6966
|
"id": "producthunt-launches",
|
|
6929
6967
|
"method": "GET",
|
|
6968
|
+
"paginatable": true,
|
|
6930
6969
|
"path": "/producthunt/product/{id}/launches",
|
|
6931
6970
|
"pathParams": [
|
|
6932
6971
|
"id"
|
|
@@ -6956,9 +6995,13 @@ export const operations = {
|
|
|
6956
6995
|
"consumes": [
|
|
6957
6996
|
"application/json"
|
|
6958
6997
|
],
|
|
6998
|
+
"cursorParams": [
|
|
6999
|
+
"cursor"
|
|
7000
|
+
],
|
|
6959
7001
|
"formParams": [],
|
|
6960
7002
|
"id": "producthunt-leaderboard",
|
|
6961
7003
|
"method": "GET",
|
|
7004
|
+
"paginatable": true,
|
|
6962
7005
|
"path": "/producthunt/leaderboard",
|
|
6963
7006
|
"pathParams": [],
|
|
6964
7007
|
"produces": [
|
|
@@ -7027,9 +7070,13 @@ export const operations = {
|
|
|
7027
7070
|
"consumes": [
|
|
7028
7071
|
"application/json"
|
|
7029
7072
|
],
|
|
7073
|
+
"cursorParams": [
|
|
7074
|
+
"cursor"
|
|
7075
|
+
],
|
|
7030
7076
|
"formParams": [],
|
|
7031
7077
|
"id": "producthunt-makers",
|
|
7032
7078
|
"method": "GET",
|
|
7079
|
+
"paginatable": true,
|
|
7033
7080
|
"path": "/producthunt/product/{id}/makers",
|
|
7034
7081
|
"pathParams": [
|
|
7035
7082
|
"id"
|
|
@@ -7099,6 +7146,7 @@ export const operations = {
|
|
|
7099
7146
|
"formParams": [],
|
|
7100
7147
|
"id": "producthunt-search",
|
|
7101
7148
|
"method": "GET",
|
|
7149
|
+
"paginatable": true,
|
|
7102
7150
|
"path": "/producthunt/search",
|
|
7103
7151
|
"pathParams": [],
|
|
7104
7152
|
"produces": [
|
|
@@ -7726,6 +7774,7 @@ export const operations = {
|
|
|
7726
7774
|
"formParams": [],
|
|
7727
7775
|
"id": "shopify-collection-products",
|
|
7728
7776
|
"method": "GET",
|
|
7777
|
+
"paginatable": true,
|
|
7729
7778
|
"path": "/shopify/collections/{handle}/products",
|
|
7730
7779
|
"pathParams": [
|
|
7731
7780
|
"handle"
|
|
@@ -7764,6 +7813,7 @@ export const operations = {
|
|
|
7764
7813
|
"formParams": [],
|
|
7765
7814
|
"id": "shopify-collections",
|
|
7766
7815
|
"method": "GET",
|
|
7816
|
+
"paginatable": true,
|
|
7767
7817
|
"path": "/shopify/collections",
|
|
7768
7818
|
"pathParams": [],
|
|
7769
7819
|
"produces": [
|
|
@@ -7828,6 +7878,7 @@ export const operations = {
|
|
|
7828
7878
|
"formParams": [],
|
|
7829
7879
|
"id": "shopify-pages",
|
|
7830
7880
|
"method": "GET",
|
|
7881
|
+
"paginatable": true,
|
|
7831
7882
|
"path": "/shopify/pages",
|
|
7832
7883
|
"pathParams": [],
|
|
7833
7884
|
"produces": [
|
|
@@ -7934,6 +7985,7 @@ export const operations = {
|
|
|
7934
7985
|
"formParams": [],
|
|
7935
7986
|
"id": "shopify-products",
|
|
7936
7987
|
"method": "GET",
|
|
7988
|
+
"paginatable": true,
|
|
7937
7989
|
"path": "/shopify/products",
|
|
7938
7990
|
"pathParams": [],
|
|
7939
7991
|
"produces": [
|
|
@@ -8156,6 +8208,7 @@ export const operations = {
|
|
|
8156
8208
|
"formParams": [],
|
|
8157
8209
|
"id": "spotify-album",
|
|
8158
8210
|
"method": "GET",
|
|
8211
|
+
"paginatable": true,
|
|
8159
8212
|
"path": "/spotify/album",
|
|
8160
8213
|
"pathParams": [],
|
|
8161
8214
|
"produces": [
|
|
@@ -8196,6 +8249,7 @@ export const operations = {
|
|
|
8196
8249
|
"formParams": [],
|
|
8197
8250
|
"id": "spotify-album-tracks",
|
|
8198
8251
|
"method": "GET",
|
|
8252
|
+
"paginatable": true,
|
|
8199
8253
|
"path": "/spotify/album/tracks",
|
|
8200
8254
|
"pathParams": [],
|
|
8201
8255
|
"produces": [
|
|
@@ -8236,6 +8290,7 @@ export const operations = {
|
|
|
8236
8290
|
"formParams": [],
|
|
8237
8291
|
"id": "spotify-albums-search",
|
|
8238
8292
|
"method": "GET",
|
|
8293
|
+
"paginatable": true,
|
|
8239
8294
|
"path": "/spotify/albums/search",
|
|
8240
8295
|
"pathParams": [],
|
|
8241
8296
|
"produces": [
|
|
@@ -8332,6 +8387,7 @@ export const operations = {
|
|
|
8332
8387
|
"formParams": [],
|
|
8333
8388
|
"id": "spotify-artist-albums",
|
|
8334
8389
|
"method": "GET",
|
|
8390
|
+
"paginatable": true,
|
|
8335
8391
|
"path": "/spotify/artist/albums",
|
|
8336
8392
|
"pathParams": [],
|
|
8337
8393
|
"produces": [
|
|
@@ -8442,6 +8498,7 @@ export const operations = {
|
|
|
8442
8498
|
"formParams": [],
|
|
8443
8499
|
"id": "spotify-artists-search",
|
|
8444
8500
|
"method": "GET",
|
|
8501
|
+
"paginatable": true,
|
|
8445
8502
|
"path": "/spotify/artists/search",
|
|
8446
8503
|
"pathParams": [],
|
|
8447
8504
|
"produces": [
|
|
@@ -8508,6 +8565,7 @@ export const operations = {
|
|
|
8508
8565
|
"formParams": [],
|
|
8509
8566
|
"id": "spotify-audiobook-chapters",
|
|
8510
8567
|
"method": "GET",
|
|
8568
|
+
"paginatable": true,
|
|
8511
8569
|
"path": "/spotify/audiobook/chapters",
|
|
8512
8570
|
"pathParams": [],
|
|
8513
8571
|
"produces": [
|
|
@@ -8548,6 +8606,7 @@ export const operations = {
|
|
|
8548
8606
|
"formParams": [],
|
|
8549
8607
|
"id": "spotify-audiobooks-search",
|
|
8550
8608
|
"method": "GET",
|
|
8609
|
+
"paginatable": true,
|
|
8551
8610
|
"path": "/spotify/audiobooks/search",
|
|
8552
8611
|
"pathParams": [],
|
|
8553
8612
|
"produces": [
|
|
@@ -8644,6 +8703,7 @@ export const operations = {
|
|
|
8644
8703
|
"formParams": [],
|
|
8645
8704
|
"id": "spotify-episodes-search",
|
|
8646
8705
|
"method": "GET",
|
|
8706
|
+
"paginatable": true,
|
|
8647
8707
|
"path": "/spotify/episodes/search",
|
|
8648
8708
|
"pathParams": [],
|
|
8649
8709
|
"produces": [
|
|
@@ -8805,6 +8865,7 @@ export const operations = {
|
|
|
8805
8865
|
"formParams": [],
|
|
8806
8866
|
"id": "spotify-playlist",
|
|
8807
8867
|
"method": "GET",
|
|
8868
|
+
"paginatable": true,
|
|
8808
8869
|
"path": "/spotify/playlist",
|
|
8809
8870
|
"pathParams": [],
|
|
8810
8871
|
"produces": [
|
|
@@ -8855,6 +8916,7 @@ export const operations = {
|
|
|
8855
8916
|
"formParams": [],
|
|
8856
8917
|
"id": "spotify-playlists-search",
|
|
8857
8918
|
"method": "GET",
|
|
8919
|
+
"paginatable": true,
|
|
8858
8920
|
"path": "/spotify/playlists/search",
|
|
8859
8921
|
"pathParams": [],
|
|
8860
8922
|
"produces": [
|
|
@@ -9086,6 +9148,7 @@ export const operations = {
|
|
|
9086
9148
|
"formParams": [],
|
|
9087
9149
|
"id": "spotify-podcasts-search",
|
|
9088
9150
|
"method": "GET",
|
|
9151
|
+
"paginatable": true,
|
|
9089
9152
|
"path": "/spotify-podcasts/search",
|
|
9090
9153
|
"pathParams": [],
|
|
9091
9154
|
"produces": [
|
|
@@ -9187,6 +9250,7 @@ export const operations = {
|
|
|
9187
9250
|
"formParams": [],
|
|
9188
9251
|
"id": "spotify-podcasts-show-episodes",
|
|
9189
9252
|
"method": "GET",
|
|
9253
|
+
"paginatable": true,
|
|
9190
9254
|
"path": "/spotify-podcasts/show/episodes",
|
|
9191
9255
|
"pathParams": [],
|
|
9192
9256
|
"produces": [
|
|
@@ -9327,6 +9391,7 @@ export const operations = {
|
|
|
9327
9391
|
"formParams": [],
|
|
9328
9392
|
"id": "spotify-profile-followers",
|
|
9329
9393
|
"method": "GET",
|
|
9394
|
+
"paginatable": true,
|
|
9330
9395
|
"path": "/spotify/profile/followers",
|
|
9331
9396
|
"pathParams": [],
|
|
9332
9397
|
"produces": [
|
|
@@ -9372,6 +9437,7 @@ export const operations = {
|
|
|
9372
9437
|
"formParams": [],
|
|
9373
9438
|
"id": "spotify-profile-playlists",
|
|
9374
9439
|
"method": "GET",
|
|
9440
|
+
"paginatable": true,
|
|
9375
9441
|
"path": "/spotify/profile/playlists",
|
|
9376
9442
|
"pathParams": [],
|
|
9377
9443
|
"produces": [
|
|
@@ -9417,6 +9483,7 @@ export const operations = {
|
|
|
9417
9483
|
"formParams": [],
|
|
9418
9484
|
"id": "spotify-profiles-search",
|
|
9419
9485
|
"method": "GET",
|
|
9486
|
+
"paginatable": true,
|
|
9420
9487
|
"path": "/spotify/profiles/search",
|
|
9421
9488
|
"pathParams": [],
|
|
9422
9489
|
"produces": [
|
|
@@ -9483,6 +9550,7 @@ export const operations = {
|
|
|
9483
9550
|
"formParams": [],
|
|
9484
9551
|
"id": "spotify-search",
|
|
9485
9552
|
"method": "GET",
|
|
9553
|
+
"paginatable": true,
|
|
9486
9554
|
"path": "/spotify/search",
|
|
9487
9555
|
"pathParams": [],
|
|
9488
9556
|
"produces": [
|
|
@@ -9559,6 +9627,7 @@ export const operations = {
|
|
|
9559
9627
|
"formParams": [],
|
|
9560
9628
|
"id": "spotify-section",
|
|
9561
9629
|
"method": "GET",
|
|
9630
|
+
"paginatable": true,
|
|
9562
9631
|
"path": "/spotify/section",
|
|
9563
9632
|
"pathParams": [],
|
|
9564
9633
|
"produces": [
|
|
@@ -9599,6 +9668,7 @@ export const operations = {
|
|
|
9599
9668
|
"formParams": [],
|
|
9600
9669
|
"id": "spotify-shows-search",
|
|
9601
9670
|
"method": "GET",
|
|
9671
|
+
"paginatable": true,
|
|
9602
9672
|
"path": "/spotify/shows/search",
|
|
9603
9673
|
"pathParams": [],
|
|
9604
9674
|
"produces": [
|
|
@@ -9740,6 +9810,7 @@ export const operations = {
|
|
|
9740
9810
|
"formParams": [],
|
|
9741
9811
|
"id": "spotify-tracks-search",
|
|
9742
9812
|
"method": "GET",
|
|
9813
|
+
"paginatable": true,
|
|
9743
9814
|
"path": "/spotify/tracks/search",
|
|
9744
9815
|
"pathParams": [],
|
|
9745
9816
|
"produces": [
|
|
@@ -9843,9 +9914,13 @@ export const operations = {
|
|
|
9843
9914
|
"consumes": [
|
|
9844
9915
|
"application/json"
|
|
9845
9916
|
],
|
|
9917
|
+
"cursorParams": [
|
|
9918
|
+
"cursor"
|
|
9919
|
+
],
|
|
9846
9920
|
"formParams": [],
|
|
9847
9921
|
"id": "tiktok-challenge-list",
|
|
9848
9922
|
"method": "GET",
|
|
9923
|
+
"paginatable": true,
|
|
9849
9924
|
"path": "/tiktok/hashtags",
|
|
9850
9925
|
"pathParams": [],
|
|
9851
9926
|
"produces": [
|
|
@@ -9917,6 +9992,7 @@ export const operations = {
|
|
|
9917
9992
|
"formParams": [],
|
|
9918
9993
|
"id": "tiktok-popular-trend-creator",
|
|
9919
9994
|
"method": "GET",
|
|
9995
|
+
"paginatable": true,
|
|
9920
9996
|
"path": "/tiktok/popular-trend/creator",
|
|
9921
9997
|
"pathParams": [],
|
|
9922
9998
|
"produces": [
|
|
@@ -10012,9 +10088,13 @@ export const operations = {
|
|
|
10012
10088
|
"consumes": [
|
|
10013
10089
|
"application/json"
|
|
10014
10090
|
],
|
|
10091
|
+
"cursorParams": [
|
|
10092
|
+
"cursor"
|
|
10093
|
+
],
|
|
10015
10094
|
"formParams": [],
|
|
10016
10095
|
"id": "tiktok-profile-post",
|
|
10017
10096
|
"method": "GET",
|
|
10097
|
+
"paginatable": true,
|
|
10018
10098
|
"path": "/tiktok/posts",
|
|
10019
10099
|
"pathParams": [],
|
|
10020
10100
|
"produces": [
|
|
@@ -10053,9 +10133,13 @@ export const operations = {
|
|
|
10053
10133
|
"consumes": [
|
|
10054
10134
|
"application/json"
|
|
10055
10135
|
],
|
|
10136
|
+
"cursorParams": [
|
|
10137
|
+
"cursor"
|
|
10138
|
+
],
|
|
10056
10139
|
"formParams": [],
|
|
10057
10140
|
"id": "tiktok-search",
|
|
10058
10141
|
"method": "GET",
|
|
10142
|
+
"paginatable": true,
|
|
10059
10143
|
"path": "/tiktok/search",
|
|
10060
10144
|
"pathParams": [],
|
|
10061
10145
|
"produces": [
|
|
@@ -10089,9 +10173,13 @@ export const operations = {
|
|
|
10089
10173
|
"consumes": [
|
|
10090
10174
|
"application/json"
|
|
10091
10175
|
],
|
|
10176
|
+
"cursorParams": [
|
|
10177
|
+
"cursor"
|
|
10178
|
+
],
|
|
10092
10179
|
"formParams": [],
|
|
10093
10180
|
"id": "tiktok-search-hashtag",
|
|
10094
10181
|
"method": "GET",
|
|
10182
|
+
"paginatable": true,
|
|
10095
10183
|
"path": "/tiktok/search/hashtag",
|
|
10096
10184
|
"pathParams": [],
|
|
10097
10185
|
"produces": [
|
|
@@ -10125,9 +10213,13 @@ export const operations = {
|
|
|
10125
10213
|
"consumes": [
|
|
10126
10214
|
"application/json"
|
|
10127
10215
|
],
|
|
10216
|
+
"cursorParams": [
|
|
10217
|
+
"cursor"
|
|
10218
|
+
],
|
|
10128
10219
|
"formParams": [],
|
|
10129
10220
|
"id": "tiktok-search-user",
|
|
10130
10221
|
"method": "GET",
|
|
10222
|
+
"paginatable": true,
|
|
10131
10223
|
"path": "/tiktok/search/user",
|
|
10132
10224
|
"pathParams": [],
|
|
10133
10225
|
"produces": [
|
|
@@ -10252,6 +10344,7 @@ export const operations = {
|
|
|
10252
10344
|
"formParams": [],
|
|
10253
10345
|
"id": "tiktok-top-ads-list",
|
|
10254
10346
|
"method": "GET",
|
|
10347
|
+
"paginatable": true,
|
|
10255
10348
|
"path": "/tiktok/top-ads/list",
|
|
10256
10349
|
"pathParams": [],
|
|
10257
10350
|
"produces": [
|
|
@@ -10414,6 +10507,7 @@ export const operations = {
|
|
|
10414
10507
|
"formParams": [],
|
|
10415
10508
|
"id": "tiktok-top-ads-recommend",
|
|
10416
10509
|
"method": "GET",
|
|
10510
|
+
"paginatable": true,
|
|
10417
10511
|
"path": "/tiktok/top-ads/recommend",
|
|
10418
10512
|
"pathParams": [],
|
|
10419
10513
|
"produces": [
|
|
@@ -10469,6 +10563,7 @@ export const operations = {
|
|
|
10469
10563
|
"formParams": [],
|
|
10470
10564
|
"id": "tiktok-top-ads-spotlight",
|
|
10471
10565
|
"method": "GET",
|
|
10566
|
+
"paginatable": true,
|
|
10472
10567
|
"path": "/tiktok/top-ads/spotlight",
|
|
10473
10568
|
"pathParams": [],
|
|
10474
10569
|
"produces": [
|
|
@@ -10545,9 +10640,13 @@ export const operations = {
|
|
|
10545
10640
|
"consumes": [
|
|
10546
10641
|
"application/json"
|
|
10547
10642
|
],
|
|
10643
|
+
"cursorParams": [
|
|
10644
|
+
"cursor"
|
|
10645
|
+
],
|
|
10548
10646
|
"formParams": [],
|
|
10549
10647
|
"id": "tiktok-video-comments",
|
|
10550
10648
|
"method": "GET",
|
|
10649
|
+
"paginatable": true,
|
|
10551
10650
|
"path": "/tiktok/comments",
|
|
10552
10651
|
"pathParams": [],
|
|
10553
10652
|
"produces": [
|
|
@@ -10657,6 +10756,7 @@ export const operations = {
|
|
|
10657
10756
|
"formParams": [],
|
|
10658
10757
|
"id": "tripadvisor-hotels",
|
|
10659
10758
|
"method": "GET",
|
|
10759
|
+
"paginatable": true,
|
|
10660
10760
|
"path": "/tripadvisor/hotels",
|
|
10661
10761
|
"pathParams": [],
|
|
10662
10762
|
"produces": [
|
|
@@ -10774,6 +10874,7 @@ export const operations = {
|
|
|
10774
10874
|
"formParams": [],
|
|
10775
10875
|
"id": "tripadvisor-reviews",
|
|
10776
10876
|
"method": "GET",
|
|
10877
|
+
"paginatable": true,
|
|
10777
10878
|
"path": "/tripadvisor/reviews",
|
|
10778
10879
|
"pathParams": [],
|
|
10779
10880
|
"produces": [
|
|
@@ -10845,6 +10946,7 @@ export const operations = {
|
|
|
10845
10946
|
"formParams": [],
|
|
10846
10947
|
"id": "tripadvisor-search",
|
|
10847
10948
|
"method": "GET",
|
|
10949
|
+
"paginatable": true,
|
|
10848
10950
|
"path": "/tripadvisor/search",
|
|
10849
10951
|
"pathParams": [],
|
|
10850
10952
|
"produces": [
|
|
@@ -11012,6 +11114,7 @@ export const operations = {
|
|
|
11012
11114
|
"formParams": [],
|
|
11013
11115
|
"id": "trustpilot-business-reviews",
|
|
11014
11116
|
"method": "GET",
|
|
11117
|
+
"paginatable": true,
|
|
11015
11118
|
"path": "/trustpilot/business/{slug}/reviews",
|
|
11016
11119
|
"pathParams": [
|
|
11017
11120
|
"slug"
|
|
@@ -11074,6 +11177,7 @@ export const operations = {
|
|
|
11074
11177
|
"formParams": [],
|
|
11075
11178
|
"id": "trustpilot-business-search",
|
|
11076
11179
|
"method": "GET",
|
|
11180
|
+
"paginatable": true,
|
|
11077
11181
|
"path": "/trustpilot/business-units/search",
|
|
11078
11182
|
"pathParams": [],
|
|
11079
11183
|
"produces": [
|
|
@@ -11134,6 +11238,7 @@ export const operations = {
|
|
|
11134
11238
|
"formParams": [],
|
|
11135
11239
|
"id": "trustpilot-category",
|
|
11136
11240
|
"method": "GET",
|
|
11241
|
+
"paginatable": true,
|
|
11137
11242
|
"path": "/trustpilot/category/{slug}",
|
|
11138
11243
|
"pathParams": [
|
|
11139
11244
|
"slug"
|
|
@@ -11469,9 +11574,13 @@ export const operations = {
|
|
|
11469
11574
|
"consumes": [
|
|
11470
11575
|
"application/json"
|
|
11471
11576
|
],
|
|
11577
|
+
"cursorParams": [
|
|
11578
|
+
"start"
|
|
11579
|
+
],
|
|
11472
11580
|
"formParams": [],
|
|
11473
11581
|
"id": "yahoo-finance-calendar",
|
|
11474
11582
|
"method": "GET",
|
|
11583
|
+
"paginatable": true,
|
|
11475
11584
|
"path": "/yahoo-finance/calendars/{type}",
|
|
11476
11585
|
"pathParams": [
|
|
11477
11586
|
"type"
|
|
@@ -11644,6 +11753,7 @@ export const operations = {
|
|
|
11644
11753
|
"formParams": [],
|
|
11645
11754
|
"id": "yahoo-finance-screener",
|
|
11646
11755
|
"method": "GET",
|
|
11756
|
+
"paginatable": true,
|
|
11647
11757
|
"path": "/yahoo-finance/screener/{id}",
|
|
11648
11758
|
"pathParams": [
|
|
11649
11759
|
"id"
|
|
@@ -11941,6 +12051,7 @@ export const operations = {
|
|
|
11941
12051
|
"formParams": [],
|
|
11942
12052
|
"id": "yahoo-finance-ticker-earnings-dates",
|
|
11943
12053
|
"method": "GET",
|
|
12054
|
+
"paginatable": true,
|
|
11944
12055
|
"path": "/yahoo-finance/ticker/{symbol}/earnings-dates",
|
|
11945
12056
|
"pathParams": [
|
|
11946
12057
|
"symbol"
|
|
@@ -12023,9 +12134,13 @@ export const operations = {
|
|
|
12023
12134
|
"consumes": [
|
|
12024
12135
|
"application/json"
|
|
12025
12136
|
],
|
|
12137
|
+
"cursorParams": [
|
|
12138
|
+
"start"
|
|
12139
|
+
],
|
|
12026
12140
|
"formParams": [],
|
|
12027
12141
|
"id": "yahoo-finance-ticker-history",
|
|
12028
12142
|
"method": "GET",
|
|
12143
|
+
"paginatable": true,
|
|
12029
12144
|
"path": "/yahoo-finance/ticker/{symbol}/history",
|
|
12030
12145
|
"pathParams": [
|
|
12031
12146
|
"symbol"
|
|
@@ -12317,9 +12432,13 @@ export const operations = {
|
|
|
12317
12432
|
"consumes": [
|
|
12318
12433
|
"application/json"
|
|
12319
12434
|
],
|
|
12435
|
+
"cursorParams": [
|
|
12436
|
+
"start"
|
|
12437
|
+
],
|
|
12320
12438
|
"formParams": [],
|
|
12321
12439
|
"id": "yahoo-finance-ticker-shares-full",
|
|
12322
12440
|
"method": "GET",
|
|
12441
|
+
"paginatable": true,
|
|
12323
12442
|
"path": "/yahoo-finance/ticker/{symbol}/shares-full",
|
|
12324
12443
|
"pathParams": [
|
|
12325
12444
|
"symbol"
|
|
@@ -12925,6 +13044,7 @@ export const operations = {
|
|
|
12925
13044
|
"formParams": [],
|
|
12926
13045
|
"id": "zillow-search",
|
|
12927
13046
|
"method": "GET",
|
|
13047
|
+
"paginatable": true,
|
|
12928
13048
|
"path": "/zillow/search",
|
|
12929
13049
|
"pathParams": [],
|
|
12930
13050
|
"produces": [
|