mcpscraper-sdk 0.52.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 +9 -3
- package/dist/index.cjs +106 -21
- package/dist/index.d.cts +390 -98
- package/dist/index.d.ts +390 -98
- package/dist/index.js +110 -22
- package/package.json +3 -3
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 {
|
|
@@ -408,7 +493,8 @@ var SerpIntelligenceNamespace = class {
|
|
|
408
493
|
);
|
|
409
494
|
return {
|
|
410
495
|
data: result.data,
|
|
411
|
-
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") } : {}
|
|
412
498
|
};
|
|
413
499
|
}
|
|
414
500
|
pageSnapshots(params) {
|
|
@@ -548,7 +634,7 @@ var ScraperClient = class {
|
|
|
548
634
|
constructor(options) {
|
|
549
635
|
const requestTimeoutMs = options.requestTimeoutMs ?? 59e4;
|
|
550
636
|
if (!Number.isFinite(requestTimeoutMs) || requestTimeoutMs <= 0) throw new TypeError("requestTimeoutMs must be a positive number");
|
|
551
|
-
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);
|
|
552
638
|
this.youtube = new YoutubeNamespace(this.r);
|
|
553
639
|
this.screenshot = new ScreenshotNamespace(this.r);
|
|
554
640
|
this.facebook = new FacebookNamespace(this.r);
|
|
@@ -566,17 +652,19 @@ var ScraperClient = class {
|
|
|
566
652
|
apiKey: options.apiKey,
|
|
567
653
|
baseUrl: options.baseUrl ?? "https://mcpscraper.dev",
|
|
568
654
|
fetch: options.fetch,
|
|
569
|
-
requestTimeoutMs
|
|
655
|
+
requestTimeoutMs,
|
|
656
|
+
clientAttribution: options.clientAttribution,
|
|
657
|
+
onResponse: options.onResponse
|
|
570
658
|
});
|
|
571
659
|
}
|
|
572
660
|
async callMemoryTool(toolName, args) {
|
|
573
|
-
const result = await this.r.
|
|
661
|
+
const { data: result, headers } = await this.r.callWithReceipt("POST", "/memory/mcp-call", {
|
|
574
662
|
toolName,
|
|
575
663
|
args: args ?? {}
|
|
576
664
|
});
|
|
577
665
|
if (result && typeof result === "object" && result.ok === false) {
|
|
578
666
|
const failure = result;
|
|
579
|
-
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 });
|
|
580
668
|
}
|
|
581
669
|
return result;
|
|
582
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",
|
|
@@ -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"
|