mcpscraper-sdk 0.51.0 → 0.53.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -6
- package/dist/index.cjs +119 -24
- package/dist/index.d.cts +875 -166
- package/dist/index.d.ts +875 -166
- package/dist/index.js +123 -25
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -40,7 +40,29 @@ var PUBLIC_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
|
40
40
|
"site_export_not_found",
|
|
41
41
|
"site_export_format_unavailable",
|
|
42
42
|
"site_export_read_failed",
|
|
43
|
-
"site_export_image_not_found"
|
|
43
|
+
"site_export_image_not_found",
|
|
44
|
+
"directory_job_not_found",
|
|
45
|
+
"idempotency_in_progress",
|
|
46
|
+
"idempotency_conflict",
|
|
47
|
+
"image_url_invalid",
|
|
48
|
+
"image_url_not_https",
|
|
49
|
+
"image_host_unresolvable",
|
|
50
|
+
"image_host_blocked",
|
|
51
|
+
"image_redirect_invalid",
|
|
52
|
+
"image_source_unavailable",
|
|
53
|
+
"image_too_large",
|
|
54
|
+
"image_redirect_limit",
|
|
55
|
+
"image_base64_invalid",
|
|
56
|
+
"image_source_missing",
|
|
57
|
+
"image_source_ambiguous",
|
|
58
|
+
"image_source_type_invalid",
|
|
59
|
+
"image_artifact_not_found",
|
|
60
|
+
"image_page_too_large",
|
|
61
|
+
"page_image_not_found",
|
|
62
|
+
"page_image_candidates_unusable",
|
|
63
|
+
"image_format_unsupported",
|
|
64
|
+
"image_storage_unconfigured",
|
|
65
|
+
"featured_image_unhostable"
|
|
44
66
|
]);
|
|
45
67
|
var PUBLIC_ERROR_FIELDS = /* @__PURE__ */ new Set([
|
|
46
68
|
"error",
|
|
@@ -71,13 +93,51 @@ var PUBLIC_DETAIL_FIELDS = /* @__PURE__ */ new Set([
|
|
|
71
93
|
"slots_per_pack",
|
|
72
94
|
"pack_price_usd",
|
|
73
95
|
"balance_credits",
|
|
74
|
-
"required_credits"
|
|
96
|
+
"required_credits",
|
|
97
|
+
"retry_guidance",
|
|
98
|
+
"http_status",
|
|
99
|
+
"job_id"
|
|
75
100
|
]);
|
|
101
|
+
function boundedString(value, limit) {
|
|
102
|
+
return typeof value === "string" && value.length > 0 && value.length <= limit;
|
|
103
|
+
}
|
|
104
|
+
function publicRecoveryFields(body) {
|
|
105
|
+
if (!body || typeof body !== "object" || Array.isArray(body)) return {};
|
|
106
|
+
const row = body;
|
|
107
|
+
const safe = {};
|
|
108
|
+
if (boundedString(row.idempotencyKey, 512)) safe.idempotencyKey = row.idempotencyKey;
|
|
109
|
+
if (typeof row.idempotencyFingerprint === "string" && /^[a-f0-9]{16}$/.test(row.idempotencyFingerprint)) safe.idempotencyFingerprint = row.idempotencyFingerprint;
|
|
110
|
+
const operation = row.operation;
|
|
111
|
+
if (operation && typeof operation === "object" && !Array.isArray(operation)) {
|
|
112
|
+
const op = operation;
|
|
113
|
+
if ((op.runId === null || boundedString(op.runId, 200)) && boundedString(op.idempotencyKey, 512) && boundedString(op.state, 100)) {
|
|
114
|
+
safe.operation = { runId: op.runId, idempotencyKey: op.idempotencyKey, state: op.state };
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
const recovery = row.recovery;
|
|
118
|
+
if (recovery && typeof recovery === "object" && !Array.isArray(recovery)) {
|
|
119
|
+
const receipt = recovery;
|
|
120
|
+
if (typeof receipt.jobId === "string" && /^[a-zA-Z0-9-]{1,100}$/.test(receipt.jobId) && typeof receipt.statusTool === "string" && /^[a-z][a-z0-9_]{0,99}$/.test(receipt.statusTool) && receipt.executionState === "unknown" && ["held", "unconfirmed"].includes(String(receipt.holdState))) {
|
|
121
|
+
safe.recovery = { jobId: receipt.jobId, statusTool: receipt.statusTool, executionState: receipt.executionState, holdState: receipt.holdState };
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
if (typeof row.job_id === "string" && /^[a-zA-Z0-9-]{1,100}$/.test(row.job_id)) safe.job_id = row.job_id;
|
|
125
|
+
if (typeof row.status_tool === "string" && /^[a-z][a-z0-9_]{0,99}$/.test(row.status_tool)) safe.status_tool = row.status_tool;
|
|
126
|
+
if (row.executionState === "unknown") safe.executionState = row.executionState;
|
|
127
|
+
if (row.hold_state === "held" || row.hold_state === "unconfirmed") safe.hold_state = row.hold_state;
|
|
128
|
+
if (typeof row.runId === "string" && /^[a-zA-Z0-9_-]{1,200}$/.test(row.runId)) {
|
|
129
|
+
safe.runId = row.runId;
|
|
130
|
+
if (["queued", "running", "interrupted", "complete", "partial", "failed", "cancelled"].includes(String(row.runStatus))) safe.runStatus = row.runStatus;
|
|
131
|
+
if (["unreserved", "held", "settling", "settled", "refunded", "pending_reconciliation"].includes(String(row.billingState))) safe.billingState = row.billingState;
|
|
132
|
+
if (row.statusPath === `/maps/place/runs/${row.runId}`) safe.statusPath = row.statusPath;
|
|
133
|
+
}
|
|
134
|
+
return safe;
|
|
135
|
+
}
|
|
76
136
|
function recognizedPublicDetails(value) {
|
|
77
137
|
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
78
138
|
const details = Object.fromEntries(
|
|
79
139
|
Object.entries(value).filter(
|
|
80
|
-
([key, child]) => PUBLIC_DETAIL_FIELDS.has(key) && (child === null ||
|
|
140
|
+
([key, child]) => PUBLIC_DETAIL_FIELDS.has(key) && (child === null || typeof child === "boolean" || typeof child === "number" && Number.isFinite(child) || typeof child === "string" && child.length <= (key === "job_id" ? 200 : 500))
|
|
81
141
|
)
|
|
82
142
|
);
|
|
83
143
|
return Object.keys(details).length > 0 ? details : void 0;
|
|
@@ -87,10 +147,13 @@ function recognizedPublicErrorBody(body) {
|
|
|
87
147
|
const record = body;
|
|
88
148
|
const code = readString(record, "error_code");
|
|
89
149
|
if (!code || !PUBLIC_ERROR_CODES.has(code)) return void 0;
|
|
90
|
-
const safe = Object.fromEntries(Object.entries(record).filter(([key]) => PUBLIC_ERROR_FIELDS.has(key)));
|
|
150
|
+
const safe = Object.fromEntries(Object.entries(record).filter(([key, value]) => PUBLIC_ERROR_FIELDS.has(key) && (value === null || typeof value === "boolean" || typeof value === "number" && Number.isFinite(value) || typeof value === "string" && value.length <= 1e3)));
|
|
151
|
+
Object.assign(safe, publicRecoveryFields(record));
|
|
91
152
|
const details = recognizedPublicDetails(record.details);
|
|
92
153
|
if (details) safe.details = details;
|
|
93
154
|
else delete safe.details;
|
|
155
|
+
const upgrade = recognizedPublicDetails(record.upgrade);
|
|
156
|
+
if (upgrade) safe.upgrade = upgrade;
|
|
94
157
|
return safe;
|
|
95
158
|
}
|
|
96
159
|
function publicErrorBody(status, body) {
|
|
@@ -103,20 +166,23 @@ function publicErrorBody(status, body) {
|
|
|
103
166
|
error_type: "service_unavailable",
|
|
104
167
|
retryable: true,
|
|
105
168
|
status,
|
|
106
|
-
message: PUBLIC_SERVICE_UNAVAILABLE_MESSAGE
|
|
169
|
+
message: PUBLIC_SERVICE_UNAVAILABLE_MESSAGE,
|
|
170
|
+
...publicRecoveryFields(body)
|
|
107
171
|
};
|
|
108
172
|
}
|
|
109
173
|
var ScraperApiError = class extends Error {
|
|
110
174
|
status;
|
|
111
175
|
code;
|
|
112
176
|
body;
|
|
113
|
-
|
|
177
|
+
requestId;
|
|
178
|
+
constructor(status, body, details = {}) {
|
|
114
179
|
const safeBody = publicErrorBody(status, body);
|
|
115
180
|
super(readString(safeBody, "message") ?? `mcpscraper.dev API request failed with status ${status}`);
|
|
116
181
|
this.name = "ScraperApiError";
|
|
117
182
|
this.status = status;
|
|
118
183
|
this.code = readString(safeBody, "error_code") ?? readString(safeBody, "error");
|
|
119
184
|
this.body = safeBody;
|
|
185
|
+
this.requestId = details.requestId;
|
|
120
186
|
}
|
|
121
187
|
isInsufficientBalance() {
|
|
122
188
|
return this.code === "insufficient_balance";
|
|
@@ -153,22 +219,35 @@ import {
|
|
|
153
219
|
VaultsNamespace,
|
|
154
220
|
VideoNamespace as MemoryVideoNamespace,
|
|
155
221
|
WebhooksNamespace,
|
|
156
|
-
McpToolsClient
|
|
222
|
+
McpToolsClient,
|
|
223
|
+
clientAttributionHeaders,
|
|
224
|
+
notifyResponse,
|
|
225
|
+
responseMetadata
|
|
157
226
|
} from "mcpscraper-memory-sdk";
|
|
158
227
|
var Requester = class {
|
|
159
|
-
constructor(apiKey, baseUrl, fetchImpl, timeoutMs) {
|
|
228
|
+
constructor(apiKey, baseUrl, fetchImpl, timeoutMs, metadataOptions = {}) {
|
|
160
229
|
this.apiKey = apiKey;
|
|
161
230
|
this.baseUrl = baseUrl;
|
|
162
231
|
this.fetchImpl = fetchImpl;
|
|
163
232
|
this.timeoutMs = timeoutMs;
|
|
233
|
+
this.metadataOptions = metadataOptions;
|
|
164
234
|
}
|
|
165
235
|
apiKey;
|
|
166
236
|
baseUrl;
|
|
167
237
|
fetchImpl;
|
|
168
238
|
timeoutMs;
|
|
239
|
+
metadataOptions;
|
|
240
|
+
headers(extra = {}) {
|
|
241
|
+
return { ...clientAttributionHeaders(this.metadataOptions.clientAttribution), ...extra, "x-api-key": this.apiKey };
|
|
242
|
+
}
|
|
243
|
+
received(res) {
|
|
244
|
+
notifyResponse(this.metadataOptions.onResponse, responseMetadata(res));
|
|
245
|
+
}
|
|
169
246
|
async request(url, init) {
|
|
170
247
|
try {
|
|
171
|
-
|
|
248
|
+
const response = await this.fetchImpl(url, { ...init, signal: AbortSignal.timeout(this.timeoutMs) });
|
|
249
|
+
this.received(response);
|
|
250
|
+
return response;
|
|
172
251
|
} catch (error) {
|
|
173
252
|
if (error instanceof DOMException && (error.name === "TimeoutError" || error.name === "AbortError")) {
|
|
174
253
|
throw new ScraperApiError(408, {
|
|
@@ -193,14 +272,14 @@ var Requester = class {
|
|
|
193
272
|
try {
|
|
194
273
|
res = await this.fetchImpl(`${this.baseUrl}${path}`, {
|
|
195
274
|
method,
|
|
196
|
-
headers: {
|
|
197
|
-
"x-api-key": this.apiKey,
|
|
275
|
+
headers: this.headers({
|
|
198
276
|
...body !== void 0 ? { "content-type": "application/json" } : {},
|
|
199
277
|
...extraHeaders
|
|
200
|
-
},
|
|
278
|
+
}),
|
|
201
279
|
body: body !== void 0 ? JSON.stringify(body) : void 0,
|
|
202
280
|
signal
|
|
203
281
|
});
|
|
282
|
+
this.received(res);
|
|
204
283
|
} catch (error) {
|
|
205
284
|
if (error instanceof DOMException && (error.name === "TimeoutError" || error.name === "AbortError")) {
|
|
206
285
|
if (options.signal?.aborted && !timeoutSignal.aborted) throw error;
|
|
@@ -215,14 +294,14 @@ var Requester = class {
|
|
|
215
294
|
throw error;
|
|
216
295
|
}
|
|
217
296
|
const data = await res.json().catch(() => void 0);
|
|
218
|
-
if (!res.ok) throw new ScraperApiError(res.status, data);
|
|
297
|
+
if (!res.ok) throw new ScraperApiError(res.status, data, { requestId: responseMetadata(res).requestId });
|
|
219
298
|
return { data, headers: res.headers };
|
|
220
299
|
}
|
|
221
300
|
async callRaw(method, path) {
|
|
222
|
-
const res = await this.request(`${this.baseUrl}${path}`, { method, headers:
|
|
301
|
+
const res = await this.request(`${this.baseUrl}${path}`, { method, headers: this.headers() });
|
|
223
302
|
if (!res.ok) {
|
|
224
303
|
const data = await res.json().catch(() => void 0);
|
|
225
|
-
throw new ScraperApiError(res.status, data);
|
|
304
|
+
throw new ScraperApiError(res.status, data, { requestId: responseMetadata(res).requestId });
|
|
226
305
|
}
|
|
227
306
|
return res.arrayBuffer();
|
|
228
307
|
}
|
|
@@ -304,8 +383,14 @@ var RedditNamespace = class {
|
|
|
304
383
|
this.r = r;
|
|
305
384
|
}
|
|
306
385
|
r;
|
|
307
|
-
thread(params) {
|
|
308
|
-
return this.r.call(
|
|
386
|
+
thread(params, options = {}) {
|
|
387
|
+
return this.r.call(
|
|
388
|
+
"POST",
|
|
389
|
+
"/reddit/thread",
|
|
390
|
+
params,
|
|
391
|
+
options.idempotencyKey === void 0 ? {} : { "Idempotency-Key": options.idempotencyKey },
|
|
392
|
+
options
|
|
393
|
+
);
|
|
309
394
|
}
|
|
310
395
|
};
|
|
311
396
|
var VideoNamespace = class {
|
|
@@ -326,7 +411,8 @@ var MapsNamespace = class {
|
|
|
326
411
|
}
|
|
327
412
|
r;
|
|
328
413
|
search(params, options = {}) {
|
|
329
|
-
|
|
414
|
+
const headers = options.idempotencyKey ? { "Idempotency-Key": options.idempotencyKey } : {};
|
|
415
|
+
return this.r.call("POST", "/maps/search", params, headers, options);
|
|
330
416
|
}
|
|
331
417
|
place(params, options = {}) {
|
|
332
418
|
const headers = {
|
|
@@ -372,8 +458,17 @@ var DirectoryNamespace = class {
|
|
|
372
458
|
this.r = r;
|
|
373
459
|
}
|
|
374
460
|
r;
|
|
375
|
-
run(params) {
|
|
376
|
-
return this.r.call(
|
|
461
|
+
run(params, options = {}) {
|
|
462
|
+
return this.r.call(
|
|
463
|
+
"POST",
|
|
464
|
+
"/directory/run",
|
|
465
|
+
params,
|
|
466
|
+
options.idempotencyKey ? { "Idempotency-Key": options.idempotencyKey } : {},
|
|
467
|
+
options
|
|
468
|
+
);
|
|
469
|
+
}
|
|
470
|
+
status(jobId, options = {}) {
|
|
471
|
+
return this.r.call("GET", `/directory/jobs/${encodeURIComponent(jobId)}`, void 0, {}, options);
|
|
377
472
|
}
|
|
378
473
|
};
|
|
379
474
|
var SerpIntelligenceNamespace = class {
|
|
@@ -398,7 +493,8 @@ var SerpIntelligenceNamespace = class {
|
|
|
398
493
|
);
|
|
399
494
|
return {
|
|
400
495
|
data: result.data,
|
|
401
|
-
idempotencyKey: result.headers.get("Idempotency-Key")
|
|
496
|
+
idempotencyKey: result.headers.get("Idempotency-Key"),
|
|
497
|
+
...result.headers.get("x-mcp-request-id") ? { requestId: result.headers.get("x-mcp-request-id") } : {}
|
|
402
498
|
};
|
|
403
499
|
}
|
|
404
500
|
pageSnapshots(params) {
|
|
@@ -538,7 +634,7 @@ var ScraperClient = class {
|
|
|
538
634
|
constructor(options) {
|
|
539
635
|
const requestTimeoutMs = options.requestTimeoutMs ?? 59e4;
|
|
540
636
|
if (!Number.isFinite(requestTimeoutMs) || requestTimeoutMs <= 0) throw new TypeError("requestTimeoutMs must be a positive number");
|
|
541
|
-
this.r = new Requester(options.apiKey, options.baseUrl ?? "https://mcpscraper.dev", options.fetch ?? globalThis.fetch, requestTimeoutMs);
|
|
637
|
+
this.r = new Requester(options.apiKey, options.baseUrl ?? "https://mcpscraper.dev", options.fetch ?? globalThis.fetch, requestTimeoutMs, options);
|
|
542
638
|
this.youtube = new YoutubeNamespace(this.r);
|
|
543
639
|
this.screenshot = new ScreenshotNamespace(this.r);
|
|
544
640
|
this.facebook = new FacebookNamespace(this.r);
|
|
@@ -556,17 +652,19 @@ var ScraperClient = class {
|
|
|
556
652
|
apiKey: options.apiKey,
|
|
557
653
|
baseUrl: options.baseUrl ?? "https://mcpscraper.dev",
|
|
558
654
|
fetch: options.fetch,
|
|
559
|
-
requestTimeoutMs
|
|
655
|
+
requestTimeoutMs,
|
|
656
|
+
clientAttribution: options.clientAttribution,
|
|
657
|
+
onResponse: options.onResponse
|
|
560
658
|
});
|
|
561
659
|
}
|
|
562
660
|
async callMemoryTool(toolName, args) {
|
|
563
|
-
const result = await this.r.
|
|
661
|
+
const { data: result, headers } = await this.r.callWithReceipt("POST", "/memory/mcp-call", {
|
|
564
662
|
toolName,
|
|
565
663
|
args: args ?? {}
|
|
566
664
|
});
|
|
567
665
|
if (result && typeof result === "object" && result.ok === false) {
|
|
568
666
|
const failure = result;
|
|
569
|
-
throw new ScraperApiError(200, { message: failure.error, ...failure });
|
|
667
|
+
throw new ScraperApiError(200, { message: failure.error, ...failure }, { requestId: headers.get("x-mcp-request-id") ?? void 0 });
|
|
570
668
|
}
|
|
571
669
|
return result;
|
|
572
670
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcpscraper-sdk",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Official Node.js client for all
|
|
3
|
+
"version": "0.53.0",
|
|
4
|
+
"description": "Official Node.js client for all 367 mcpscraper.dev MCP tools and the REST API",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "./dist/index.cjs",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"README.md"
|
|
20
20
|
],
|
|
21
21
|
"scripts": {
|
|
22
|
-
"generate": "openapi-typescript ../../contracts/scraper.openapi.
|
|
22
|
+
"generate": "openapi-typescript ../../contracts/scraper.openapi.generated.json -o src/schema.ts",
|
|
23
23
|
"prepack": "npm run build",
|
|
24
24
|
"build": "tsup src/index.ts --format esm,cjs --dts",
|
|
25
25
|
"typecheck": "tsc --noEmit",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"seo-api"
|
|
33
33
|
],
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"mcpscraper-memory-sdk": "^0.
|
|
35
|
+
"mcpscraper-memory-sdk": "^0.52.0"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"openapi-typescript": "^7.13.0"
|