@bycrawl/nodejs-sdk 0.1.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/LICENSE +21 -0
- package/dist/index.cjs +1027 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +803 -0
- package/dist/index.d.ts +803 -0
- package/dist/index.js +990 -0
- package/dist/index.js.map +1 -0
- package/package.json +65 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,990 @@
|
|
|
1
|
+
// src/exceptions.ts
|
|
2
|
+
var ByCrawlError = class extends Error {
|
|
3
|
+
constructor(message) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.name = "ByCrawlError";
|
|
6
|
+
}
|
|
7
|
+
};
|
|
8
|
+
var APIError = class extends ByCrawlError {
|
|
9
|
+
statusCode;
|
|
10
|
+
body;
|
|
11
|
+
constructor(message, options) {
|
|
12
|
+
super(message);
|
|
13
|
+
this.name = "APIError";
|
|
14
|
+
this.statusCode = options.statusCode;
|
|
15
|
+
this.body = options.body ?? null;
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
var AuthenticationError = class extends APIError {
|
|
19
|
+
constructor(message = "Invalid or missing API key", body) {
|
|
20
|
+
super(message, { statusCode: 401, body });
|
|
21
|
+
this.name = "AuthenticationError";
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
var PermissionError = class extends APIError {
|
|
25
|
+
constructor(message = "Insufficient scope", body) {
|
|
26
|
+
super(message, { statusCode: 403, body });
|
|
27
|
+
this.name = "PermissionError";
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
var NotFoundError = class extends APIError {
|
|
31
|
+
constructor(message = "Resource not found", body) {
|
|
32
|
+
super(message, { statusCode: 404, body });
|
|
33
|
+
this.name = "NotFoundError";
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
var RateLimitError = class extends APIError {
|
|
37
|
+
retryAfter;
|
|
38
|
+
constructor(message = "Rate limit exceeded", options) {
|
|
39
|
+
super(message, { statusCode: 429, body: options?.body });
|
|
40
|
+
this.name = "RateLimitError";
|
|
41
|
+
this.retryAfter = options?.retryAfter ?? null;
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
var ServerError = class extends APIError {
|
|
45
|
+
constructor(message, options) {
|
|
46
|
+
super(message, options);
|
|
47
|
+
this.name = "ServerError";
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
var TimeoutError = class extends ByCrawlError {
|
|
51
|
+
constructor(message = "Request timed out") {
|
|
52
|
+
super(message);
|
|
53
|
+
this.name = "TimeoutError";
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
var ConnectionError = class extends ByCrawlError {
|
|
57
|
+
constructor(message = "Network connection error") {
|
|
58
|
+
super(message);
|
|
59
|
+
this.name = "ConnectionError";
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
// src/http.ts
|
|
64
|
+
var DEFAULT_BASE_URL = "https://api.bycrawl.com";
|
|
65
|
+
var DEFAULT_TIMEOUT = 6e4;
|
|
66
|
+
var DEFAULT_MAX_RETRIES = 2;
|
|
67
|
+
var SDK_VERSION = "0.1.1";
|
|
68
|
+
var RETRYABLE_STATUS_CODES = /* @__PURE__ */ new Set([429, 500, 502, 503, 504]);
|
|
69
|
+
function userAgent() {
|
|
70
|
+
return `bycrawl-node/${SDK_VERSION}`;
|
|
71
|
+
}
|
|
72
|
+
function makeHeaders(apiKey) {
|
|
73
|
+
return {
|
|
74
|
+
"x-api-key": apiKey,
|
|
75
|
+
"User-Agent": userAgent(),
|
|
76
|
+
Accept: "application/json"
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
function backoffDelay(attempt, base = 0.5, maxDelay = 8) {
|
|
80
|
+
const delay = Math.min(base * 2 ** attempt, maxDelay);
|
|
81
|
+
return Math.random() * delay;
|
|
82
|
+
}
|
|
83
|
+
function sleep(ms) {
|
|
84
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
85
|
+
}
|
|
86
|
+
function raiseForStatus(status, body, headers) {
|
|
87
|
+
if (status >= 200 && status < 300) return;
|
|
88
|
+
const message = body?.error ?? `HTTP ${status}`;
|
|
89
|
+
if (status === 401) {
|
|
90
|
+
throw new AuthenticationError(message, body);
|
|
91
|
+
}
|
|
92
|
+
if (status === 403) {
|
|
93
|
+
throw new PermissionError(message, body);
|
|
94
|
+
}
|
|
95
|
+
if (status === 404) {
|
|
96
|
+
throw new NotFoundError(message, body);
|
|
97
|
+
}
|
|
98
|
+
if (status === 429) {
|
|
99
|
+
const retryAfter = headers.get("retry-after");
|
|
100
|
+
throw new RateLimitError(message, {
|
|
101
|
+
retryAfter: retryAfter ? parseFloat(retryAfter) : null,
|
|
102
|
+
body
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
if (status >= 500) {
|
|
106
|
+
throw new ServerError(message, { statusCode: status, body });
|
|
107
|
+
}
|
|
108
|
+
throw new APIError(message, { statusCode: status, body });
|
|
109
|
+
}
|
|
110
|
+
function headersToRecord(headers) {
|
|
111
|
+
const result = {};
|
|
112
|
+
headers.forEach((value, key) => {
|
|
113
|
+
result[key] = value;
|
|
114
|
+
});
|
|
115
|
+
return result;
|
|
116
|
+
}
|
|
117
|
+
var Transport = class {
|
|
118
|
+
apiKey;
|
|
119
|
+
baseUrl;
|
|
120
|
+
timeout;
|
|
121
|
+
maxRetries;
|
|
122
|
+
defaultHeaders;
|
|
123
|
+
constructor(options) {
|
|
124
|
+
this.apiKey = options.apiKey;
|
|
125
|
+
this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
126
|
+
this.timeout = options.timeout ?? DEFAULT_TIMEOUT;
|
|
127
|
+
this.maxRetries = options.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
128
|
+
this.defaultHeaders = makeHeaders(this.apiKey);
|
|
129
|
+
}
|
|
130
|
+
async request(method, path, options) {
|
|
131
|
+
const url = new URL(path, this.baseUrl);
|
|
132
|
+
if (options?.params) {
|
|
133
|
+
for (const [key, value] of Object.entries(options.params)) {
|
|
134
|
+
if (value != null) {
|
|
135
|
+
url.searchParams.set(key, String(value));
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
const requestHeaders = {
|
|
140
|
+
...this.defaultHeaders,
|
|
141
|
+
...options?.headers
|
|
142
|
+
};
|
|
143
|
+
if (options?.json) {
|
|
144
|
+
requestHeaders["Content-Type"] = "application/json";
|
|
145
|
+
}
|
|
146
|
+
let lastError = null;
|
|
147
|
+
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
|
|
148
|
+
try {
|
|
149
|
+
const controller = new AbortController();
|
|
150
|
+
const timeoutId = setTimeout(
|
|
151
|
+
() => controller.abort(),
|
|
152
|
+
this.timeout
|
|
153
|
+
);
|
|
154
|
+
let response;
|
|
155
|
+
try {
|
|
156
|
+
response = await fetch(url.toString(), {
|
|
157
|
+
method,
|
|
158
|
+
headers: requestHeaders,
|
|
159
|
+
body: options?.json ? JSON.stringify(options.json) : void 0,
|
|
160
|
+
signal: controller.signal
|
|
161
|
+
});
|
|
162
|
+
} finally {
|
|
163
|
+
clearTimeout(timeoutId);
|
|
164
|
+
}
|
|
165
|
+
if (RETRYABLE_STATUS_CODES.has(response.status) && attempt < this.maxRetries) {
|
|
166
|
+
let delay = backoffDelay(attempt);
|
|
167
|
+
if (response.status === 429) {
|
|
168
|
+
const retryAfter = response.headers.get("retry-after");
|
|
169
|
+
if (retryAfter) {
|
|
170
|
+
delay = Math.max(delay, parseFloat(retryAfter) * 1e3);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
await sleep(delay);
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
let body = null;
|
|
177
|
+
try {
|
|
178
|
+
body = await response.json();
|
|
179
|
+
} catch {
|
|
180
|
+
if (!response.ok) {
|
|
181
|
+
throw new APIError("Invalid JSON response", { statusCode: 502 });
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
raiseForStatus(response.status, body, response.headers);
|
|
185
|
+
return {
|
|
186
|
+
statusCode: response.status,
|
|
187
|
+
data: body ?? {},
|
|
188
|
+
headers: headersToRecord(response.headers)
|
|
189
|
+
};
|
|
190
|
+
} catch (error) {
|
|
191
|
+
if (error instanceof AuthenticationError || error instanceof PermissionError || error instanceof NotFoundError || error instanceof RateLimitError || error instanceof ServerError || error instanceof APIError) {
|
|
192
|
+
throw error;
|
|
193
|
+
}
|
|
194
|
+
if (error instanceof DOMException && error.name === "AbortError") {
|
|
195
|
+
lastError = error;
|
|
196
|
+
if (attempt < this.maxRetries) {
|
|
197
|
+
const delay = backoffDelay(attempt);
|
|
198
|
+
await sleep(delay);
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
throw new TimeoutError(String(error));
|
|
202
|
+
}
|
|
203
|
+
if (error instanceof TypeError && error.message.includes("fetch")) {
|
|
204
|
+
lastError = error;
|
|
205
|
+
if (attempt < this.maxRetries) {
|
|
206
|
+
const delay = backoffDelay(attempt);
|
|
207
|
+
await sleep(delay);
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
throw new ConnectionError(String(error));
|
|
211
|
+
}
|
|
212
|
+
if (error instanceof ByCrawlError) {
|
|
213
|
+
throw error;
|
|
214
|
+
}
|
|
215
|
+
throw new ByCrawlError(`Unexpected error: ${error}`);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
if (lastError) {
|
|
219
|
+
throw new ConnectionError(String(lastError));
|
|
220
|
+
}
|
|
221
|
+
throw new ConnectionError("Request failed after retries");
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
// src/resource.ts
|
|
226
|
+
function parseRateLimit(headers) {
|
|
227
|
+
const limit = headers["x-ratelimit-limit"];
|
|
228
|
+
const remaining = headers["x-ratelimit-remaining"];
|
|
229
|
+
const reset = headers["x-ratelimit-reset"];
|
|
230
|
+
if (limit == null && remaining == null && reset == null) return null;
|
|
231
|
+
return {
|
|
232
|
+
limit: limit ? parseInt(limit, 10) : null,
|
|
233
|
+
remaining: remaining ? parseInt(remaining, 10) : null,
|
|
234
|
+
reset: reset ? parseFloat(reset) : null
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
function parseCredit(headers) {
|
|
238
|
+
const remaining = headers["x-credit-remaining"];
|
|
239
|
+
const used = headers["x-credit-used"];
|
|
240
|
+
if (remaining == null && used == null) return null;
|
|
241
|
+
return {
|
|
242
|
+
remaining: remaining ? parseInt(remaining, 10) : null,
|
|
243
|
+
used: used ? parseInt(used, 10) : null
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
function wrapResponse(wrapper, castTo) {
|
|
247
|
+
const data = wrapper.data;
|
|
248
|
+
let bodyData;
|
|
249
|
+
let success;
|
|
250
|
+
let error;
|
|
251
|
+
let queued;
|
|
252
|
+
if (typeof data === "object" && data !== null && "data" in data) {
|
|
253
|
+
bodyData = data.data;
|
|
254
|
+
success = data.success ?? true;
|
|
255
|
+
error = data.error ?? null;
|
|
256
|
+
queued = data.queued ?? false;
|
|
257
|
+
} else if (typeof data === "object" && data !== null && "error" in data) {
|
|
258
|
+
bodyData = null;
|
|
259
|
+
success = false;
|
|
260
|
+
error = data.error ?? null;
|
|
261
|
+
queued = false;
|
|
262
|
+
} else {
|
|
263
|
+
bodyData = data;
|
|
264
|
+
success = true;
|
|
265
|
+
error = null;
|
|
266
|
+
queued = false;
|
|
267
|
+
}
|
|
268
|
+
let parsed = bodyData;
|
|
269
|
+
if (castTo && bodyData != null) {
|
|
270
|
+
if (Array.isArray(bodyData)) {
|
|
271
|
+
parsed = bodyData.map(
|
|
272
|
+
(item) => castTo(item)
|
|
273
|
+
);
|
|
274
|
+
} else if (typeof bodyData === "object") {
|
|
275
|
+
parsed = castTo(bodyData);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
return {
|
|
279
|
+
success,
|
|
280
|
+
data: parsed,
|
|
281
|
+
error,
|
|
282
|
+
queued,
|
|
283
|
+
rateLimit: parseRateLimit(wrapper.headers),
|
|
284
|
+
credit: parseCredit(wrapper.headers)
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
var APIResource = class {
|
|
288
|
+
_transport;
|
|
289
|
+
constructor(transport) {
|
|
290
|
+
this._transport = transport;
|
|
291
|
+
}
|
|
292
|
+
async _get(path, options) {
|
|
293
|
+
return this._request("GET", path, { params: options?.params, castTo: options?.castTo });
|
|
294
|
+
}
|
|
295
|
+
async _post(path, options) {
|
|
296
|
+
return this._request("POST", path, { body: options?.body, castTo: options?.castTo });
|
|
297
|
+
}
|
|
298
|
+
async _getList(path, options) {
|
|
299
|
+
const resp = await this._get(path, {
|
|
300
|
+
params: options.params
|
|
301
|
+
});
|
|
302
|
+
const raw = resp.data;
|
|
303
|
+
let items;
|
|
304
|
+
if (raw && typeof raw === "object" && !Array.isArray(raw) && options.itemsKey in raw) {
|
|
305
|
+
const arr = raw[options.itemsKey];
|
|
306
|
+
if (Array.isArray(arr)) {
|
|
307
|
+
items = options.castTo ? arr.map((item) => options.castTo(item)) : arr;
|
|
308
|
+
} else {
|
|
309
|
+
items = [];
|
|
310
|
+
}
|
|
311
|
+
} else if (Array.isArray(raw)) {
|
|
312
|
+
items = options.castTo ? raw.map((item) => options.castTo(item)) : raw;
|
|
313
|
+
} else {
|
|
314
|
+
items = [];
|
|
315
|
+
}
|
|
316
|
+
return {
|
|
317
|
+
...resp,
|
|
318
|
+
data: items
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
async _request(method, path, options) {
|
|
322
|
+
const wrapper = await this._transport.request(method, path, {
|
|
323
|
+
params: options?.params,
|
|
324
|
+
json: options?.body
|
|
325
|
+
});
|
|
326
|
+
return wrapResponse(wrapper, options?.castTo);
|
|
327
|
+
}
|
|
328
|
+
async *_paginate(path, options) {
|
|
329
|
+
const itemsKey = options.itemsKey ?? "items";
|
|
330
|
+
const cursorKey = options.cursorKey ?? "cursor";
|
|
331
|
+
const hasMoreKey = options.hasMoreKey ?? "hasMore";
|
|
332
|
+
let params = { ...options.params };
|
|
333
|
+
while (true) {
|
|
334
|
+
const wrapper = await this._transport.request("GET", path, { params });
|
|
335
|
+
const responseData = wrapper.data;
|
|
336
|
+
const data = typeof responseData === "object" && responseData !== null && "data" in responseData ? responseData.data : responseData;
|
|
337
|
+
const items = data[itemsKey] ?? [];
|
|
338
|
+
for (const item of items) {
|
|
339
|
+
if (options.castTo) {
|
|
340
|
+
yield options.castTo(item);
|
|
341
|
+
} else {
|
|
342
|
+
yield item;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
if (!data[hasMoreKey]) break;
|
|
346
|
+
const nextCursor = data[cursorKey] ?? data["next_cursor"];
|
|
347
|
+
if (!nextCursor) break;
|
|
348
|
+
params = { ...params, [cursorKey]: nextCursor };
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
async *_paginateByPage(path, options) {
|
|
352
|
+
const itemsKey = options.itemsKey ?? "items";
|
|
353
|
+
const pageKey = options.pageKey ?? "page";
|
|
354
|
+
let page = options.params[pageKey] ?? 1;
|
|
355
|
+
while (true) {
|
|
356
|
+
const params = { ...options.params, [pageKey]: page };
|
|
357
|
+
const wrapper = await this._transport.request("GET", path, { params });
|
|
358
|
+
const responseData = wrapper.data;
|
|
359
|
+
const data = typeof responseData === "object" && responseData !== null && "data" in responseData ? responseData.data : responseData;
|
|
360
|
+
const items = data[itemsKey] ?? [];
|
|
361
|
+
if (items.length === 0) break;
|
|
362
|
+
for (const item of items) {
|
|
363
|
+
if (options.castTo) {
|
|
364
|
+
yield options.castTo(item);
|
|
365
|
+
} else {
|
|
366
|
+
yield item;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
const hasMore = data["hasMore"];
|
|
370
|
+
if (hasMore === false) break;
|
|
371
|
+
const limit = params["limit"] ?? 20;
|
|
372
|
+
if (items.length < limit) break;
|
|
373
|
+
page += 1;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
async *_paginateByOffset(path, options) {
|
|
377
|
+
const itemsKey = options.itemsKey ?? "items";
|
|
378
|
+
const countKey = options.countKey ?? "count";
|
|
379
|
+
let offset = options.params["offset"] ?? 0;
|
|
380
|
+
const limit = options.params["limit"] ?? 20;
|
|
381
|
+
while (true) {
|
|
382
|
+
const params = { ...options.params, offset, limit };
|
|
383
|
+
const wrapper = await this._transport.request("GET", path, { params });
|
|
384
|
+
const responseData = wrapper.data;
|
|
385
|
+
const data = typeof responseData === "object" && responseData !== null && "data" in responseData ? responseData.data : responseData;
|
|
386
|
+
const items = data[itemsKey] ?? [];
|
|
387
|
+
if (items.length === 0) break;
|
|
388
|
+
for (const item of items) {
|
|
389
|
+
if (options.castTo) {
|
|
390
|
+
yield options.castTo(item);
|
|
391
|
+
} else {
|
|
392
|
+
yield item;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
const total = data[countKey];
|
|
396
|
+
offset += items.length;
|
|
397
|
+
if (total != null && offset >= total) break;
|
|
398
|
+
if (items.length < limit) break;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
};
|
|
402
|
+
|
|
403
|
+
// src/platforms/dcard.ts
|
|
404
|
+
var Dcard = class extends APIResource {
|
|
405
|
+
async getForum(alias) {
|
|
406
|
+
return this._get(`/dcard/forums/${alias}`, {
|
|
407
|
+
castTo: (r) => r
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
async getForumPosts(alias, options) {
|
|
411
|
+
return this._get(`/dcard/forums/${alias}/posts`, {
|
|
412
|
+
params: { count: options?.count, popular: options?.popular }
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
async searchPosts(q, options) {
|
|
416
|
+
return this._get(`/dcard/posts/search`, {
|
|
417
|
+
params: { q, count: options?.count, offset: options?.offset }
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
async getPersona(username) {
|
|
421
|
+
return this._get(`/dcard/personas/${username}`, {
|
|
422
|
+
castTo: (r) => r
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
// -- Auto-pagination iterators --
|
|
426
|
+
iterSearchPosts(q, options) {
|
|
427
|
+
return this._paginateByOffset(`/dcard/posts/search`, {
|
|
428
|
+
params: { q, count: options?.count ?? 30 },
|
|
429
|
+
itemsKey: "posts",
|
|
430
|
+
castTo: (r) => r
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
};
|
|
434
|
+
|
|
435
|
+
// src/platforms/facebook.ts
|
|
436
|
+
var Facebook = class extends APIResource {
|
|
437
|
+
async getUser(username) {
|
|
438
|
+
return this._get(`/facebook/users/${username}`, {
|
|
439
|
+
castTo: (r) => r
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
async getUserPosts(username) {
|
|
443
|
+
return this._request("GET", `/facebook/users/${username}/posts`);
|
|
444
|
+
}
|
|
445
|
+
async getPost(options) {
|
|
446
|
+
return this._get(`/facebook/posts`, {
|
|
447
|
+
params: { url: options.url },
|
|
448
|
+
castTo: (r) => r
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
async getPostComments(options) {
|
|
452
|
+
return this._get(`/facebook/posts/comments`, {
|
|
453
|
+
params: { url: options.url, cursor: options.cursor }
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
async searchPosts(q, options) {
|
|
457
|
+
return this._get(`/facebook/posts/search`, {
|
|
458
|
+
params: { q, count: options?.count, cursor: options?.cursor }
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
async marketplaceBrowse(location, options) {
|
|
462
|
+
return this._get(`/facebook/marketplace/listings`, {
|
|
463
|
+
params: { location, category: options?.category }
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
async marketplaceSearch(q, options) {
|
|
467
|
+
return this._get(`/facebook/marketplace/search`, {
|
|
468
|
+
params: { q, location: options?.location }
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
async marketplaceItem(listingId) {
|
|
472
|
+
return this._get(`/facebook/marketplace/items/${listingId}`);
|
|
473
|
+
}
|
|
474
|
+
// -- Auto-pagination iterators --
|
|
475
|
+
iterPostComments(options) {
|
|
476
|
+
return this._paginate(`/facebook/posts/comments`, {
|
|
477
|
+
params: { url: options.url },
|
|
478
|
+
itemsKey: "comments"
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
iterSearchPosts(q, options) {
|
|
482
|
+
return this._paginate(`/facebook/posts/search`, {
|
|
483
|
+
params: { q, count: options?.count },
|
|
484
|
+
itemsKey: "posts",
|
|
485
|
+
castTo: (r) => r
|
|
486
|
+
});
|
|
487
|
+
}
|
|
488
|
+
};
|
|
489
|
+
|
|
490
|
+
// src/platforms/gmaps.ts
|
|
491
|
+
var GMaps = class extends APIResource {
|
|
492
|
+
async search(q, options) {
|
|
493
|
+
return this._get(`/gmaps/places/search`, {
|
|
494
|
+
params: { q, language: options?.language }
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
async getPlace(query, options) {
|
|
498
|
+
return this._get(`/gmaps/places`, {
|
|
499
|
+
params: { query, language: options?.language },
|
|
500
|
+
castTo: (r) => r
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
};
|
|
504
|
+
|
|
505
|
+
// src/platforms/instagram.ts
|
|
506
|
+
var Instagram = class extends APIResource {
|
|
507
|
+
async getUser(username) {
|
|
508
|
+
return this._get(`/instagram/users/${username}`, {
|
|
509
|
+
castTo: (r) => r
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
async searchTags(q) {
|
|
513
|
+
return this._get(`/instagram/tags/search`, { params: { q } });
|
|
514
|
+
}
|
|
515
|
+
async getPost(shortcode) {
|
|
516
|
+
return this._get(`/instagram/posts/${shortcode}`);
|
|
517
|
+
}
|
|
518
|
+
async getPostComments(shortcode, options) {
|
|
519
|
+
return this._get(`/instagram/posts/${shortcode}/comments`, {
|
|
520
|
+
params: { cursor: options?.cursor }
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
async getUserPosts(username, options) {
|
|
524
|
+
return this._get(`/instagram/users/${username}/posts`, {
|
|
525
|
+
params: { cursor: options?.cursor }
|
|
526
|
+
});
|
|
527
|
+
}
|
|
528
|
+
// -- Auto-pagination iterators --
|
|
529
|
+
iterUserPosts(username) {
|
|
530
|
+
return this._paginate(`/instagram/users/${username}/posts`, {
|
|
531
|
+
params: {},
|
|
532
|
+
itemsKey: "posts"
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
iterPostComments(shortcode) {
|
|
536
|
+
return this._paginate(`/instagram/posts/${shortcode}/comments`, {
|
|
537
|
+
params: {},
|
|
538
|
+
itemsKey: "comments"
|
|
539
|
+
});
|
|
540
|
+
}
|
|
541
|
+
};
|
|
542
|
+
|
|
543
|
+
// src/platforms/job104.ts
|
|
544
|
+
var Job104 = class extends APIResource {
|
|
545
|
+
async searchJobs(options) {
|
|
546
|
+
return this._getList(`/job104/jobs/search`, {
|
|
547
|
+
params: {
|
|
548
|
+
q: options?.q,
|
|
549
|
+
welfare: options?.welfare,
|
|
550
|
+
area: options?.area,
|
|
551
|
+
page: options?.page,
|
|
552
|
+
count: options?.count
|
|
553
|
+
},
|
|
554
|
+
itemsKey: "jobs",
|
|
555
|
+
castTo: (r) => r
|
|
556
|
+
});
|
|
557
|
+
}
|
|
558
|
+
async getCompany(companyId) {
|
|
559
|
+
return this._get(`/job104/companies/${companyId}`, {
|
|
560
|
+
castTo: (r) => r
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
async getJob(jobId) {
|
|
564
|
+
return this._get(`/job104/jobs/${jobId}`, {
|
|
565
|
+
castTo: (r) => r
|
|
566
|
+
});
|
|
567
|
+
}
|
|
568
|
+
// -- Auto-pagination iterators --
|
|
569
|
+
iterSearchJobs(options) {
|
|
570
|
+
return this._paginateByPage(`/job104/jobs/search`, {
|
|
571
|
+
params: {
|
|
572
|
+
q: options?.q,
|
|
573
|
+
welfare: options?.welfare,
|
|
574
|
+
area: options?.area,
|
|
575
|
+
count: options?.count ?? 20
|
|
576
|
+
},
|
|
577
|
+
itemsKey: "jobs",
|
|
578
|
+
pageKey: "page",
|
|
579
|
+
castTo: (r) => r
|
|
580
|
+
});
|
|
581
|
+
}
|
|
582
|
+
};
|
|
583
|
+
|
|
584
|
+
// src/platforms/linkedin.ts
|
|
585
|
+
var LinkedIn = class extends APIResource {
|
|
586
|
+
async getCompany(companyId) {
|
|
587
|
+
return this._get(`/linkedin/companies/${companyId}`, {
|
|
588
|
+
castTo: (r) => r
|
|
589
|
+
});
|
|
590
|
+
}
|
|
591
|
+
async getCompanyJobs(companyId, options) {
|
|
592
|
+
return this._get(`/linkedin/companies/${companyId}/jobs`, {
|
|
593
|
+
params: { count: options?.count, offset: options?.offset }
|
|
594
|
+
});
|
|
595
|
+
}
|
|
596
|
+
async searchJobs(query, options) {
|
|
597
|
+
return this._getList(`/linkedin/jobs/search`, {
|
|
598
|
+
params: {
|
|
599
|
+
q: query,
|
|
600
|
+
location: options?.location,
|
|
601
|
+
count: options?.count,
|
|
602
|
+
offset: options?.offset
|
|
603
|
+
},
|
|
604
|
+
itemsKey: "jobs",
|
|
605
|
+
castTo: (r) => r
|
|
606
|
+
});
|
|
607
|
+
}
|
|
608
|
+
async getJob(jobId) {
|
|
609
|
+
return this._get(`/linkedin/jobs/${jobId}`, {
|
|
610
|
+
castTo: (r) => r
|
|
611
|
+
});
|
|
612
|
+
}
|
|
613
|
+
async getPost(postId) {
|
|
614
|
+
return this._get(`/linkedin/posts/${postId}`, {
|
|
615
|
+
castTo: (r) => r
|
|
616
|
+
});
|
|
617
|
+
}
|
|
618
|
+
async searchUsers(query, options) {
|
|
619
|
+
return this._getList(`/linkedin/users/search`, {
|
|
620
|
+
params: { q: query, count: options?.count, offset: options?.offset },
|
|
621
|
+
itemsKey: "users",
|
|
622
|
+
castTo: (r) => r
|
|
623
|
+
});
|
|
624
|
+
}
|
|
625
|
+
async getUser(username) {
|
|
626
|
+
return this._get(`/linkedin/users/${username}`, {
|
|
627
|
+
castTo: (r) => r
|
|
628
|
+
});
|
|
629
|
+
}
|
|
630
|
+
// -- Auto-pagination iterators --
|
|
631
|
+
iterCompanyJobs(companyId, options) {
|
|
632
|
+
const count = options?.count ?? 10;
|
|
633
|
+
return this._paginateByOffset(`/linkedin/companies/${companyId}/jobs`, {
|
|
634
|
+
params: { count, limit: count },
|
|
635
|
+
itemsKey: "jobs",
|
|
636
|
+
castTo: (r) => r
|
|
637
|
+
});
|
|
638
|
+
}
|
|
639
|
+
iterSearchJobs(query, options) {
|
|
640
|
+
const count = options?.count ?? 10;
|
|
641
|
+
return this._paginateByOffset(`/linkedin/jobs/search`, {
|
|
642
|
+
params: { q: query, location: options?.location, count, limit: count },
|
|
643
|
+
itemsKey: "jobs",
|
|
644
|
+
castTo: (r) => r
|
|
645
|
+
});
|
|
646
|
+
}
|
|
647
|
+
};
|
|
648
|
+
|
|
649
|
+
// src/platforms/reddit.ts
|
|
650
|
+
var Reddit = class extends APIResource {
|
|
651
|
+
async getSubreddit(name) {
|
|
652
|
+
return this._get(`/reddit/subreddits/${name}`, {
|
|
653
|
+
castTo: (r) => r
|
|
654
|
+
});
|
|
655
|
+
}
|
|
656
|
+
async getSubredditPosts(name, options) {
|
|
657
|
+
return this._getList(`/reddit/subreddits/${name}/posts`, {
|
|
658
|
+
params: { sort: options?.sort, t: options?.t, count: options?.count },
|
|
659
|
+
itemsKey: "posts",
|
|
660
|
+
castTo: (r) => r
|
|
661
|
+
});
|
|
662
|
+
}
|
|
663
|
+
async getPost(postId) {
|
|
664
|
+
return this._get(`/reddit/posts/${postId}`, {
|
|
665
|
+
castTo: (r) => r
|
|
666
|
+
});
|
|
667
|
+
}
|
|
668
|
+
async searchPosts(q, options) {
|
|
669
|
+
return this._getList(`/reddit/posts/search`, {
|
|
670
|
+
params: { q, sort: options?.sort, count: options?.count },
|
|
671
|
+
itemsKey: "posts",
|
|
672
|
+
castTo: (r) => r
|
|
673
|
+
});
|
|
674
|
+
}
|
|
675
|
+
async getUser(username) {
|
|
676
|
+
return this._get(`/reddit/users/${username}`, {
|
|
677
|
+
castTo: (r) => r
|
|
678
|
+
});
|
|
679
|
+
}
|
|
680
|
+
async getUserPosts(username, options) {
|
|
681
|
+
return this._get(`/reddit/users/${username}/posts`, {
|
|
682
|
+
params: {
|
|
683
|
+
sort: options?.sort,
|
|
684
|
+
t: options?.t,
|
|
685
|
+
count: options?.count,
|
|
686
|
+
after: options?.after
|
|
687
|
+
}
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
};
|
|
691
|
+
|
|
692
|
+
// src/platforms/threads.ts
|
|
693
|
+
var Threads = class extends APIResource {
|
|
694
|
+
async getPost(postId, options) {
|
|
695
|
+
return this._get(`/threads/posts/${postId}`, {
|
|
696
|
+
params: { mode: options?.mode },
|
|
697
|
+
castTo: (r) => r
|
|
698
|
+
});
|
|
699
|
+
}
|
|
700
|
+
async getPosts(ids, options) {
|
|
701
|
+
const resp = await this._request("GET", `/threads/posts`, {
|
|
702
|
+
params: { ids: ids.join(","), mode: options?.mode }
|
|
703
|
+
});
|
|
704
|
+
return resp;
|
|
705
|
+
}
|
|
706
|
+
async searchPosts(q, options) {
|
|
707
|
+
return this._getList(`/threads/posts/search`, {
|
|
708
|
+
params: { q, count: options?.count },
|
|
709
|
+
itemsKey: "posts",
|
|
710
|
+
castTo: (r) => r
|
|
711
|
+
});
|
|
712
|
+
}
|
|
713
|
+
async getUser(username) {
|
|
714
|
+
return this._get(`/threads/users/${username}`, {
|
|
715
|
+
castTo: (r) => r
|
|
716
|
+
});
|
|
717
|
+
}
|
|
718
|
+
async getUserPosts(userId, options) {
|
|
719
|
+
return this._get(`/threads/users/${userId}/posts`, {
|
|
720
|
+
params: { cursor: options?.cursor, count: options?.count }
|
|
721
|
+
});
|
|
722
|
+
}
|
|
723
|
+
async getUserReplies(userId, options) {
|
|
724
|
+
return this._get(`/threads/users/${userId}/replies`, {
|
|
725
|
+
params: { cursor: options?.cursor, count: options?.count }
|
|
726
|
+
});
|
|
727
|
+
}
|
|
728
|
+
async searchUsers(q, options) {
|
|
729
|
+
return this._getList(`/threads/users/search`, {
|
|
730
|
+
params: { q, count: options?.count },
|
|
731
|
+
itemsKey: "users",
|
|
732
|
+
castTo: (r) => r
|
|
733
|
+
});
|
|
734
|
+
}
|
|
735
|
+
async getPublicFeed(options) {
|
|
736
|
+
return this._get(`/threads/feed/public`, {
|
|
737
|
+
params: { cursor: options?.cursor, count: options?.count }
|
|
738
|
+
});
|
|
739
|
+
}
|
|
740
|
+
// -- Bulk operations --
|
|
741
|
+
async bulkSubmit(ids, options) {
|
|
742
|
+
return this._post(`/threads/bulk`, {
|
|
743
|
+
body: { ids, type: options?.type ?? "content" },
|
|
744
|
+
castTo: (r) => r
|
|
745
|
+
});
|
|
746
|
+
}
|
|
747
|
+
async bulkStatus(jobId) {
|
|
748
|
+
return this._get(`/threads/bulk/${jobId}`, {
|
|
749
|
+
castTo: (r) => r
|
|
750
|
+
});
|
|
751
|
+
}
|
|
752
|
+
async bulkResults(jobId) {
|
|
753
|
+
return this._request("GET", `/threads/bulk/${jobId}/results`);
|
|
754
|
+
}
|
|
755
|
+
async bulkSubmitAndWait(ids, options) {
|
|
756
|
+
const pollInterval = options?.pollInterval ?? 2e3;
|
|
757
|
+
const timeout = options?.timeout ?? 3e5;
|
|
758
|
+
const submitResp = await this.bulkSubmit(ids);
|
|
759
|
+
const jobId = submitResp.data.jobId;
|
|
760
|
+
const deadline = Date.now() + timeout;
|
|
761
|
+
while (Date.now() < deadline) {
|
|
762
|
+
const statusResp = await this.bulkStatus(jobId);
|
|
763
|
+
const status = statusResp.data.status;
|
|
764
|
+
if (status === "completed") {
|
|
765
|
+
return this.bulkResults(jobId);
|
|
766
|
+
}
|
|
767
|
+
if (status === "failed") {
|
|
768
|
+
throw new ByCrawlError(`Bulk job ${jobId} failed`);
|
|
769
|
+
}
|
|
770
|
+
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
771
|
+
}
|
|
772
|
+
throw new TimeoutError(`Bulk job ${jobId} timed out after ${timeout}ms`);
|
|
773
|
+
}
|
|
774
|
+
// -- Auto-pagination iterators --
|
|
775
|
+
iterUserPosts(userId, options) {
|
|
776
|
+
return this._paginate(`/threads/users/${userId}/posts`, {
|
|
777
|
+
params: { count: options?.count },
|
|
778
|
+
itemsKey: "posts",
|
|
779
|
+
castTo: (r) => r
|
|
780
|
+
});
|
|
781
|
+
}
|
|
782
|
+
iterUserReplies(userId, options) {
|
|
783
|
+
return this._paginate(`/threads/users/${userId}/replies`, {
|
|
784
|
+
params: { count: options?.count },
|
|
785
|
+
itemsKey: "replies",
|
|
786
|
+
castTo: (r) => r
|
|
787
|
+
});
|
|
788
|
+
}
|
|
789
|
+
};
|
|
790
|
+
|
|
791
|
+
// src/platforms/tiktok.ts
|
|
792
|
+
var TikTok = class extends APIResource {
|
|
793
|
+
async getVideo(videoId) {
|
|
794
|
+
return this._get(`/tiktok/videos/${videoId}`, {
|
|
795
|
+
castTo: (r) => r
|
|
796
|
+
});
|
|
797
|
+
}
|
|
798
|
+
async getUser(username) {
|
|
799
|
+
return this._get(`/tiktok/users/${username}`, {
|
|
800
|
+
castTo: (r) => r
|
|
801
|
+
});
|
|
802
|
+
}
|
|
803
|
+
async getUserVideos(username, options) {
|
|
804
|
+
return this._request("GET", `/tiktok/users/${username}/videos`, {
|
|
805
|
+
params: { count: options?.count }
|
|
806
|
+
});
|
|
807
|
+
}
|
|
808
|
+
async getVideoComments(videoId, options) {
|
|
809
|
+
return this._get(`/tiktok/videos/${videoId}/comments`, {
|
|
810
|
+
params: { cursor: options?.cursor }
|
|
811
|
+
});
|
|
812
|
+
}
|
|
813
|
+
async getCategories(options) {
|
|
814
|
+
return this._get(`/tiktok/categories`, {
|
|
815
|
+
params: { category: options?.category, count: options?.count }
|
|
816
|
+
});
|
|
817
|
+
}
|
|
818
|
+
async search(keyword, options) {
|
|
819
|
+
return this._get(`/tiktok/videos/search`, {
|
|
820
|
+
params: { q: keyword, count: options?.count }
|
|
821
|
+
});
|
|
822
|
+
}
|
|
823
|
+
async getVideoSubtitles(videoId) {
|
|
824
|
+
return this._get(`/tiktok/videos/${videoId}/subtitles`);
|
|
825
|
+
}
|
|
826
|
+
// -- Auto-pagination iterators --
|
|
827
|
+
iterVideoComments(videoId) {
|
|
828
|
+
return this._paginate(`/tiktok/videos/${videoId}/comments`, {
|
|
829
|
+
params: {},
|
|
830
|
+
itemsKey: "comments",
|
|
831
|
+
castTo: (r) => r
|
|
832
|
+
});
|
|
833
|
+
}
|
|
834
|
+
};
|
|
835
|
+
|
|
836
|
+
// src/platforms/webfetch.ts
|
|
837
|
+
var WebFetch = class extends APIResource {
|
|
838
|
+
async fetch(url, options) {
|
|
839
|
+
return this._get(`/web/fetch`, {
|
|
840
|
+
params: { url, format: options?.format }
|
|
841
|
+
});
|
|
842
|
+
}
|
|
843
|
+
};
|
|
844
|
+
|
|
845
|
+
// src/platforms/x.ts
|
|
846
|
+
var X = class extends APIResource {
|
|
847
|
+
async getUser(username) {
|
|
848
|
+
return this._get(`/x/users/${username}`, {
|
|
849
|
+
castTo: (r) => r
|
|
850
|
+
});
|
|
851
|
+
}
|
|
852
|
+
async getUserPosts(username, options) {
|
|
853
|
+
return this._get(`/x/users/${username}/posts`, {
|
|
854
|
+
params: { count: options?.count, cursor: options?.cursor }
|
|
855
|
+
});
|
|
856
|
+
}
|
|
857
|
+
async getPost(postId) {
|
|
858
|
+
return this._get(`/x/posts/${postId}`, {
|
|
859
|
+
castTo: (r) => r
|
|
860
|
+
});
|
|
861
|
+
}
|
|
862
|
+
async searchPosts(q, options) {
|
|
863
|
+
return this._getList(`/x/posts/search`, {
|
|
864
|
+
params: {
|
|
865
|
+
q,
|
|
866
|
+
count: options?.count,
|
|
867
|
+
cursor: options?.cursor,
|
|
868
|
+
product: options?.product
|
|
869
|
+
},
|
|
870
|
+
itemsKey: "tweets",
|
|
871
|
+
castTo: (r) => r
|
|
872
|
+
});
|
|
873
|
+
}
|
|
874
|
+
// -- Auto-pagination iterators --
|
|
875
|
+
iterUserPosts(username, options) {
|
|
876
|
+
return this._paginate(`/x/users/${username}/posts`, {
|
|
877
|
+
params: { count: options?.count },
|
|
878
|
+
itemsKey: "posts",
|
|
879
|
+
castTo: (r) => r
|
|
880
|
+
});
|
|
881
|
+
}
|
|
882
|
+
iterSearchPosts(q, options) {
|
|
883
|
+
return this._paginate(`/x/posts/search`, {
|
|
884
|
+
params: { q, count: options?.count, product: options?.product },
|
|
885
|
+
itemsKey: "posts",
|
|
886
|
+
castTo: (r) => r
|
|
887
|
+
});
|
|
888
|
+
}
|
|
889
|
+
};
|
|
890
|
+
|
|
891
|
+
// src/platforms/youtube.ts
|
|
892
|
+
var YouTube = class extends APIResource {
|
|
893
|
+
async getVideo(videoId) {
|
|
894
|
+
return this._get(`/youtube/videos/${videoId}`, {
|
|
895
|
+
castTo: (r) => r
|
|
896
|
+
});
|
|
897
|
+
}
|
|
898
|
+
async getChannel(channelId) {
|
|
899
|
+
return this._get(`/youtube/channels/${channelId}`, {
|
|
900
|
+
castTo: (r) => r
|
|
901
|
+
});
|
|
902
|
+
}
|
|
903
|
+
async search(q, options) {
|
|
904
|
+
return this._get(`/youtube/videos/search`, {
|
|
905
|
+
params: { q, count: options?.count }
|
|
906
|
+
});
|
|
907
|
+
}
|
|
908
|
+
async getVideoComments(videoId, options) {
|
|
909
|
+
return this._get(`/youtube/videos/${videoId}/comments`, {
|
|
910
|
+
params: { count: options?.count }
|
|
911
|
+
});
|
|
912
|
+
}
|
|
913
|
+
async getVideoTranscription(videoId, options) {
|
|
914
|
+
return this._get(`/youtube/videos/${videoId}/transcription`, {
|
|
915
|
+
params: { language: options?.language }
|
|
916
|
+
});
|
|
917
|
+
}
|
|
918
|
+
// -- Auto-pagination iterators --
|
|
919
|
+
iterSearch(q, options) {
|
|
920
|
+
return this._paginate(`/youtube/videos/search`, {
|
|
921
|
+
params: { q, count: options?.count },
|
|
922
|
+
itemsKey: "videos",
|
|
923
|
+
castTo: (r) => r
|
|
924
|
+
});
|
|
925
|
+
}
|
|
926
|
+
iterVideoComments(videoId, options) {
|
|
927
|
+
return this._paginate(`/youtube/videos/${videoId}/comments`, {
|
|
928
|
+
params: { count: options?.count },
|
|
929
|
+
itemsKey: "comments",
|
|
930
|
+
castTo: (r) => r
|
|
931
|
+
});
|
|
932
|
+
}
|
|
933
|
+
};
|
|
934
|
+
|
|
935
|
+
// src/client.ts
|
|
936
|
+
var ByCrawl = class {
|
|
937
|
+
threads;
|
|
938
|
+
facebook;
|
|
939
|
+
x;
|
|
940
|
+
instagram;
|
|
941
|
+
reddit;
|
|
942
|
+
linkedin;
|
|
943
|
+
tiktok;
|
|
944
|
+
youtube;
|
|
945
|
+
dcard;
|
|
946
|
+
gmaps;
|
|
947
|
+
job104;
|
|
948
|
+
web;
|
|
949
|
+
_transport;
|
|
950
|
+
constructor(options) {
|
|
951
|
+
const apiKey = options?.apiKey ?? process.env["BYCRAWL_API_KEY"] ?? "";
|
|
952
|
+
if (!apiKey) {
|
|
953
|
+
throw new Error(
|
|
954
|
+
"apiKey must be provided or set via the BYCRAWL_API_KEY environment variable"
|
|
955
|
+
);
|
|
956
|
+
}
|
|
957
|
+
this._transport = new Transport({
|
|
958
|
+
apiKey,
|
|
959
|
+
baseUrl: options?.baseUrl ?? DEFAULT_BASE_URL,
|
|
960
|
+
timeout: options?.timeout ?? DEFAULT_TIMEOUT,
|
|
961
|
+
maxRetries: options?.maxRetries ?? DEFAULT_MAX_RETRIES
|
|
962
|
+
});
|
|
963
|
+
this.threads = new Threads(this._transport);
|
|
964
|
+
this.facebook = new Facebook(this._transport);
|
|
965
|
+
this.x = new X(this._transport);
|
|
966
|
+
this.instagram = new Instagram(this._transport);
|
|
967
|
+
this.reddit = new Reddit(this._transport);
|
|
968
|
+
this.linkedin = new LinkedIn(this._transport);
|
|
969
|
+
this.tiktok = new TikTok(this._transport);
|
|
970
|
+
this.youtube = new YouTube(this._transport);
|
|
971
|
+
this.dcard = new Dcard(this._transport);
|
|
972
|
+
this.gmaps = new GMaps(this._transport);
|
|
973
|
+
this.job104 = new Job104(this._transport);
|
|
974
|
+
this.web = new WebFetch(this._transport);
|
|
975
|
+
}
|
|
976
|
+
};
|
|
977
|
+
export {
|
|
978
|
+
APIError,
|
|
979
|
+
AuthenticationError,
|
|
980
|
+
ByCrawl,
|
|
981
|
+
ByCrawlError,
|
|
982
|
+
ConnectionError,
|
|
983
|
+
NotFoundError,
|
|
984
|
+
PermissionError,
|
|
985
|
+
RateLimitError,
|
|
986
|
+
SDK_VERSION,
|
|
987
|
+
ServerError,
|
|
988
|
+
TimeoutError
|
|
989
|
+
};
|
|
990
|
+
//# sourceMappingURL=index.js.map
|