@crawlora-org/sdk 1.2.0-sdk.18 → 1.3.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 +18 -0
- package/README.md +17 -0
- package/docs/operations.md +12 -1
- package/openapi/public.json +6594 -4936
- package/package.json +1 -1
- package/src/client.js +79 -5
- package/src/index.d.ts +25 -0
- package/src/index.js +9 -2
- package/src/operations.js +732 -1
- package/src/types.d.ts +736 -0
package/package.json
CHANGED
package/src/client.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
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.3.0-sdk.1";
|
|
5
5
|
const DEFAULT_USER_AGENT = `crawlora-js-sdk/${VERSION}`;
|
|
6
6
|
|
|
7
7
|
export class CrawloraError extends Error {
|
|
@@ -18,6 +18,35 @@ export class CrawloraError extends Error {
|
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
// Response status 4xx: the request was rejected by the API (bad params, auth,
|
|
22
|
+
// not found). Usually not retryable.
|
|
23
|
+
export class CrawloraClientError extends CrawloraError {
|
|
24
|
+
constructor(message, options) {
|
|
25
|
+
super(message, options);
|
|
26
|
+
this.name = "CrawloraClientError";
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Response status 5xx: the API failed to handle a valid request. Retryable.
|
|
31
|
+
export class CrawloraServerError extends CrawloraError {
|
|
32
|
+
constructor(message, options) {
|
|
33
|
+
super(message, options);
|
|
34
|
+
this.name = "CrawloraServerError";
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Transport failure, timeout, or abort before a response was received.
|
|
39
|
+
export class CrawloraNetworkError extends CrawloraError {
|
|
40
|
+
constructor(message, options) {
|
|
41
|
+
super(message, options);
|
|
42
|
+
this.name = "CrawloraNetworkError";
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function apiErrorClass(status) {
|
|
47
|
+
return status >= 500 ? CrawloraServerError : CrawloraClientError;
|
|
48
|
+
}
|
|
49
|
+
|
|
21
50
|
export class CrawloraClient {
|
|
22
51
|
constructor(options = {}) {
|
|
23
52
|
this.apiKey = options.apiKey || "";
|
|
@@ -98,12 +127,12 @@ export class CrawloraClient {
|
|
|
98
127
|
});
|
|
99
128
|
} catch (error) {
|
|
100
129
|
if (options.signal?.aborted) {
|
|
101
|
-
throw new
|
|
130
|
+
throw new CrawloraNetworkError("Crawlora request aborted", { cause: error, retryable: false });
|
|
102
131
|
}
|
|
103
132
|
if (timedOut) {
|
|
104
|
-
throw new
|
|
133
|
+
throw new CrawloraNetworkError("Crawlora request timed out", { cause: error, retryable: false });
|
|
105
134
|
}
|
|
106
|
-
throw new
|
|
135
|
+
throw new CrawloraNetworkError("Crawlora transport error", { cause: error });
|
|
107
136
|
} finally {
|
|
108
137
|
if (timeout) clearTimeout(timeout);
|
|
109
138
|
}
|
|
@@ -113,7 +142,8 @@ export class CrawloraClient {
|
|
|
113
142
|
if (!response.ok) {
|
|
114
143
|
const code = parsed && typeof parsed === "object" ? parsed.code : undefined;
|
|
115
144
|
const message = parsed && typeof parsed === "object" && parsed.msg ? parsed.msg : response.statusText;
|
|
116
|
-
|
|
145
|
+
const ApiError = apiErrorClass(response.status);
|
|
146
|
+
throw new ApiError(message || `Crawlora request failed with status ${response.status}`, {
|
|
117
147
|
status: response.status,
|
|
118
148
|
code,
|
|
119
149
|
body: parsed,
|
|
@@ -123,6 +153,50 @@ export class CrawloraClient {
|
|
|
123
153
|
}
|
|
124
154
|
return parsed;
|
|
125
155
|
}
|
|
156
|
+
|
|
157
|
+
// Async iterator over pages of a paginated operation. Advances the numeric
|
|
158
|
+
// page/offset query parameter and stops when a page returns no data.
|
|
159
|
+
// for await (const page of client.paginate("ebay-seller-feedback", { seller })) { ... }
|
|
160
|
+
async *paginate(operationId, params = {}, options = {}) {
|
|
161
|
+
const operation = operations[operationId];
|
|
162
|
+
if (!operation) {
|
|
163
|
+
throw new TypeError(`Unknown Crawlora operation: ${operationId}`);
|
|
164
|
+
}
|
|
165
|
+
const pageParam = options.pageParam || detectPageParam(operation);
|
|
166
|
+
if (!pageParam) {
|
|
167
|
+
throw new TypeError(`Operation ${operationId} has no page or offset query parameter to paginate`);
|
|
168
|
+
}
|
|
169
|
+
const step = options.step ?? 1;
|
|
170
|
+
const maxPages = options.maxPages ?? Infinity;
|
|
171
|
+
let pageValue = options.start ?? (pageParam === "offset" ? 0 : 1);
|
|
172
|
+
for (let i = 0; i < maxPages; i++) {
|
|
173
|
+
const response = await this.request(operationId, { ...params, [pageParam]: pageValue }, options);
|
|
174
|
+
yield response;
|
|
175
|
+
if (pageIsEmpty(response)) break;
|
|
176
|
+
pageValue += step;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const PAGE_PARAM_NAMES = ["page", "offset"];
|
|
182
|
+
|
|
183
|
+
function detectPageParam(operation) {
|
|
184
|
+
for (const name of PAGE_PARAM_NAMES) {
|
|
185
|
+
if (operation.queryParams.some((parameter) => parameter.name === name)) return name;
|
|
186
|
+
}
|
|
187
|
+
return undefined;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function pageIsEmpty(response) {
|
|
191
|
+
if (response === undefined || response === null) return true;
|
|
192
|
+
let data = response;
|
|
193
|
+
if (typeof response === "object" && !Array.isArray(response) && "data" in response) {
|
|
194
|
+
data = response.data;
|
|
195
|
+
}
|
|
196
|
+
if (data === undefined || data === null) return true;
|
|
197
|
+
if (Array.isArray(data)) return data.length === 0;
|
|
198
|
+
if (typeof data === "object") return Object.keys(data).length === 0;
|
|
199
|
+
return !data;
|
|
126
200
|
}
|
|
127
201
|
|
|
128
202
|
function buildRequest(operation, baseUrl, params) {
|
package/src/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
CrawloraGeneratedGroups,
|
|
3
3
|
OperationId,
|
|
4
|
+
OperationParamsMap,
|
|
4
5
|
OperationRequestArgs,
|
|
5
6
|
OperationResponseMap
|
|
6
7
|
} from "./types.js";
|
|
@@ -55,6 +56,24 @@ export class CrawloraError extends Error {
|
|
|
55
56
|
retryable?: boolean;
|
|
56
57
|
}
|
|
57
58
|
|
|
59
|
+
// Thrown for 4xx API responses (request rejected by the API).
|
|
60
|
+
export class CrawloraClientError extends CrawloraError {}
|
|
61
|
+
// Thrown for 5xx API responses (API failed to handle a valid request).
|
|
62
|
+
export class CrawloraServerError extends CrawloraError {}
|
|
63
|
+
// Thrown for transport failures, timeouts, and aborts before a response.
|
|
64
|
+
export class CrawloraNetworkError extends CrawloraError {}
|
|
65
|
+
|
|
66
|
+
export interface CrawloraPaginateOptions extends CrawloraRequestOptions {
|
|
67
|
+
// Query parameter to advance. Auto-detected as "page" or "offset" when omitted.
|
|
68
|
+
pageParam?: string;
|
|
69
|
+
// First value for the page parameter. Defaults to 1 for "page", 0 for "offset".
|
|
70
|
+
start?: number;
|
|
71
|
+
// Amount added to the page parameter after each page. Defaults to 1.
|
|
72
|
+
step?: number;
|
|
73
|
+
// Maximum number of pages to fetch. Defaults to unbounded.
|
|
74
|
+
maxPages?: number;
|
|
75
|
+
}
|
|
76
|
+
|
|
58
77
|
export class CrawloraClient {
|
|
59
78
|
constructor(options?: CrawloraClientOptions);
|
|
60
79
|
request<I extends OperationId>(
|
|
@@ -65,6 +84,11 @@ export class CrawloraClient {
|
|
|
65
84
|
operationId: I,
|
|
66
85
|
...args: OperationRequestArgs<I>
|
|
67
86
|
): Promise<OperationResponseMap[I]>;
|
|
87
|
+
paginate<I extends OperationId>(
|
|
88
|
+
operationId: I,
|
|
89
|
+
params?: OperationParamsMap[I],
|
|
90
|
+
options?: CrawloraPaginateOptions
|
|
91
|
+
): AsyncGenerator<OperationResponseMap[I], void, unknown>;
|
|
68
92
|
[group: string]: unknown;
|
|
69
93
|
}
|
|
70
94
|
|
|
@@ -73,5 +97,6 @@ export interface CrawloraClient extends CrawloraGeneratedGroups {}
|
|
|
73
97
|
export const operations: Record<string, OperationDefinition>;
|
|
74
98
|
export const groups: Record<string, Record<string, string>>;
|
|
75
99
|
export const operationCount: number;
|
|
100
|
+
export const OperationIds: Readonly<Record<string, OperationId>>;
|
|
76
101
|
export const VERSION: string;
|
|
77
102
|
export * from "./types.js";
|
package/src/index.js
CHANGED
|
@@ -1,2 +1,9 @@
|
|
|
1
|
-
export {
|
|
2
|
-
|
|
1
|
+
export {
|
|
2
|
+
CrawloraClient,
|
|
3
|
+
CrawloraError,
|
|
4
|
+
CrawloraClientError,
|
|
5
|
+
CrawloraServerError,
|
|
6
|
+
CrawloraNetworkError,
|
|
7
|
+
VERSION
|
|
8
|
+
} from "./client.js";
|
|
9
|
+
export { operations, groups, operationCount, OperationIds } from "./operations.js";
|