mcpscraper-sdk 0.26.2 → 0.27.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 CHANGED
@@ -38,11 +38,14 @@ try {
38
38
  Every non-2xx response throws a `ScraperApiError` with `status`, `code`, and the raw response `body`. Two cases have typed narrowing helpers:
39
39
 
40
40
  - `err.isInsufficientBalance()` — narrows `err.body` to `{ balance_credits, required_credits, topup_url, ... }`.
41
- - `err.isConcurrencyLimitExceeded()` — narrows `err.body` to `{ active, limit, retryable, ... }`.
41
+ - `err.isConcurrencyLimitExceeded()` — narrows `err.body` to `{ active, limit, retryable, upgrade, ... }`.
42
+ - `err.isVerificationChallenge()` / `err.isTimeout()` — preserve actionable, vendor-neutral retry and charge details returned by the service.
43
+
44
+ Current Google search pricing is 60 Credits per SERP search and 400 Credits plus 10 Credits per returned question for PAA. One optional concurrency pack adds two browser slots for $5/month; quantity `n` adds `2n` slots for `$5n` without changing the base plan.
42
45
 
43
46
  ## API surface
44
47
 
45
- `client.tools` is the generated, typed 246-tool MCP surface. It includes 145 MCP Scraper tools and all 101 mirrored Memory tools from `contracts/mcp.tools.json`.
48
+ `client.tools` is the generated, typed 249-tool MCP surface. It includes 148 MCP Scraper tools and all 101 mirrored Memory tools from `contracts/mcp.tools.json`.
46
49
 
47
50
  For multimodal results such as `meta_ad_creative_media`, call `client.tools.callToolResult(...)` to preserve native MCP image/audio/resource blocks. `callTool(...)` remains backward-compatible and returns the parsed structured or text value.
48
51
 
package/dist/index.cjs CHANGED
@@ -39,7 +39,78 @@ function readString(body, key) {
39
39
  return void 0;
40
40
  }
41
41
  var PUBLIC_SERVICE_UNAVAILABLE_MESSAGE = "This operation is temporarily unavailable. Please retry later.";
42
+ var PUBLIC_ERROR_CODES = /* @__PURE__ */ new Set([
43
+ "request_aborted",
44
+ "captcha_exhausted",
45
+ "captcha_or_blocked",
46
+ "location_mismatch",
47
+ "proxy_tunnel_failed",
48
+ "proxy_unavailable",
49
+ "harvest_timeout",
50
+ "mcp_request_timeout",
51
+ "extraction_failed",
52
+ "concurrency_limit_exceeded",
53
+ "unauthorized",
54
+ "forbidden",
55
+ "invalid_request",
56
+ "rate_limited",
57
+ "insufficient_balance",
58
+ "service_unavailable"
59
+ ]);
60
+ var PUBLIC_ERROR_FIELDS = /* @__PURE__ */ new Set([
61
+ "error",
62
+ "error_code",
63
+ "error_type",
64
+ "message",
65
+ "retryable",
66
+ "retry_after_seconds",
67
+ "charge_status",
68
+ "details",
69
+ "active",
70
+ "limit",
71
+ "operation",
72
+ "upgrade",
73
+ "upgrade_url",
74
+ "upgrade_command",
75
+ "balance_credits",
76
+ "required_credits",
77
+ "topup_url"
78
+ ]);
79
+ var PUBLIC_DETAIL_FIELDS = /* @__PURE__ */ new Set([
80
+ "active",
81
+ "limit",
82
+ "operation",
83
+ "upgrade_url",
84
+ "topup_url",
85
+ "upgrade_command",
86
+ "slots_per_pack",
87
+ "pack_price_usd",
88
+ "balance_credits",
89
+ "required_credits"
90
+ ]);
91
+ function recognizedPublicDetails(value) {
92
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
93
+ const details = Object.fromEntries(
94
+ Object.entries(value).filter(
95
+ ([key, child]) => PUBLIC_DETAIL_FIELDS.has(key) && (child === null || ["string", "number", "boolean"].includes(typeof child))
96
+ )
97
+ );
98
+ return Object.keys(details).length > 0 ? details : void 0;
99
+ }
100
+ function recognizedPublicErrorBody(body) {
101
+ if (!body || typeof body !== "object" || Array.isArray(body)) return void 0;
102
+ const record = body;
103
+ const code = readString(record, "error_code");
104
+ if (!code || !PUBLIC_ERROR_CODES.has(code)) return void 0;
105
+ const safe = Object.fromEntries(Object.entries(record).filter(([key]) => PUBLIC_ERROR_FIELDS.has(key)));
106
+ const details = recognizedPublicDetails(record.details);
107
+ if (details) safe.details = details;
108
+ else delete safe.details;
109
+ return safe;
110
+ }
42
111
  function publicErrorBody(status, body) {
112
+ const recognized = recognizedPublicErrorBody(body);
113
+ if (recognized) return recognized;
43
114
  if (status < 500) return body;
44
115
  return {
45
116
  error: "service_unavailable",
@@ -71,6 +142,12 @@ var ScraperApiError = class extends Error {
71
142
  isStructuredError() {
72
143
  return typeof readString(this.body, "error_type") === "string";
73
144
  }
145
+ isVerificationChallenge() {
146
+ return this.code === "captcha_exhausted" || this.code === "captcha_or_blocked";
147
+ }
148
+ isTimeout() {
149
+ return this.code === "harvest_timeout" || this.code === "mcp_request_timeout";
150
+ }
74
151
  };
75
152
 
76
153
  // src/client.ts
package/dist/index.d.cts CHANGED
@@ -17,10 +17,9 @@ interface paths {
17
17
  put?: never;
18
18
  /**
19
19
  * Run a Google SERP search, or a full People-Also-Ask harvest
20
- * @description Set `serpOnly: true` for a pure organic-results/SERP call (14 credits; runs headful so
21
- * Google serves a complete page).
20
+ * @description Set `serpOnly: true` for a pure organic-results/SERP call (60 Credits).
22
21
  * Omit or set `false` for a full People-Also-Ask harvest, which also returns SERP data
23
- * (55 credit base + 3 credits per question actually returned; unused estimate is
22
+ * (400 Credit base + 10 Credits per question actually returned; unused estimate is
24
23
  * refunded). Runs synchronously and returns the result inline.
25
24
  */
26
25
  post: operations["harvestSync"];
@@ -618,8 +617,7 @@ interface paths {
618
617
  put?: never;
619
618
  /**
620
619
  * Structured SERP capture with AI Overview/AI Mode detection, entity IDs, and location-match evidence
621
- * @description Holds 14 credits for the SERP and settles to 4 credits when the capture is served
622
- * headless, or retains 14 credits when it runs headful.
620
+ * @description Costs 60 Credits for the base SERP capture.
623
621
  * When `includePageSnapshots` is true, also holds 1 credit per requested
624
622
  * `pageSnapshotLimit` slot and settles to 1 credit per URL actually attempted.
625
623
  * Rate-limited to 60 requests/minute per account.
@@ -838,15 +836,33 @@ interface components {
838
836
  Error: {
839
837
  error: string;
840
838
  error_code?: string;
839
+ error_type?: string;
841
840
  message?: string;
842
- };
843
- /** @description Shared structured error shape used by SERP Intelligence endpoints. */
844
- StructuredError: {
845
- error_code: string;
846
- error_type: string;
841
+ retryable?: boolean;
842
+ retry_after_seconds?: number;
843
+ charge_status?: components["schemas"]["PublicChargeStatus"];
844
+ details?: components["schemas"]["PublicErrorDetails"];
845
+ };
846
+ /** @enum {string} */
847
+ PublicChargeStatus: "not_charged" | "refunded" | "charged";
848
+ /** @description Bounded, vendor-neutral recovery and account details safe for public clients. */
849
+ PublicErrorDetails: {
850
+ [key: string]: string | number | boolean | (string | null);
851
+ };
852
+ /** @description Stable public failure envelope shared across REST and MCP operations. */
853
+ PublicErrorEnvelope: {
854
+ /** @enum {string} */
855
+ error_code: "request_aborted" | "captcha_exhausted" | "captcha_or_blocked" | "location_mismatch" | "proxy_tunnel_failed" | "proxy_unavailable" | "harvest_timeout" | "mcp_request_timeout" | "extraction_failed" | "concurrency_limit_exceeded" | "unauthorized" | "forbidden" | "invalid_request" | "rate_limited" | "insufficient_balance" | "service_unavailable";
856
+ /** @enum {string} */
857
+ error_type: "request_aborted" | "captcha" | "location_mismatch" | "connection" | "timeout" | "extraction" | "concurrency_limit" | "unauthorized" | "forbidden" | "invalid_request" | "rate_limit" | "billing" | "service_unavailable";
847
858
  message: string;
848
859
  retryable: boolean;
860
+ retry_after_seconds?: number;
861
+ charge_status?: components["schemas"]["PublicChargeStatus"];
862
+ details?: components["schemas"]["PublicErrorDetails"];
849
863
  };
864
+ /** @description Shared structured error shape used by SERP Intelligence endpoints. */
865
+ StructuredError: components["schemas"]["PublicErrorEnvelope"];
850
866
  InsufficientBalanceError: {
851
867
  /** @enum {string} */
852
868
  error: "insufficient_balance";
@@ -858,22 +874,53 @@ interface components {
858
874
  /** Format: uri */
859
875
  topup_url: string;
860
876
  };
861
- ConcurrencyLimitError: {
877
+ ConcurrencyLimitError: components["schemas"]["PublicErrorEnvelope"] & {
862
878
  error?: string;
863
- message: string;
864
879
  /** @enum {string} */
865
880
  error_code: "concurrency_limit_exceeded";
866
881
  /** @enum {string} */
867
- error_type?: "concurrency_limit";
868
- retryable?: boolean;
882
+ error_type: "concurrency_limit";
869
883
  active: number;
870
884
  limit: number;
871
885
  operation: string;
886
+ upgrade: components["schemas"]["ConcurrencyPack"];
872
887
  /** Format: uri */
873
888
  upgrade_url?: string;
874
- /** @description CLI command to buy an extra concurrency slot. */
889
+ /** @description CLI command to buy or update two-browser concurrency packs. */
875
890
  upgrade_command?: string;
876
891
  };
892
+ /** @description One $5 monthly pack adds exactly two concurrent browser slots. Quantity n adds 2n slots for $5n per month. */
893
+ ConcurrencyPack: {
894
+ product: string;
895
+ rate_policy_version: string;
896
+ price_label: string;
897
+ /** @enum {number} */
898
+ unit_amount_usd: 5;
899
+ /** @enum {string} */
900
+ currency: "usd";
901
+ /** @enum {string} */
902
+ interval: "month";
903
+ /** @enum {string} */
904
+ billing_unit: "pack";
905
+ pack_quantity: number;
906
+ /** @enum {integer} */
907
+ slots_per_pack: 2;
908
+ extra_slots: number;
909
+ /** Format: uri */
910
+ billing_url: string;
911
+ terminal_command: string;
912
+ terminal_command_with_api_key_env: string;
913
+ };
914
+ /** @description Quantity-based add-on entitlement projected by account and billing endpoints. */
915
+ ConcurrencyAccountView: {
916
+ pack_quantity: number;
917
+ /** @enum {integer} */
918
+ slots_per_pack: 2;
919
+ extra_concurrency_slots: number;
920
+ effective_limit: number;
921
+ monthly_amount_usd: number;
922
+ has_subscription?: boolean;
923
+ };
877
924
  HarvestSyncRequest: {
878
925
  /** @description Search query. */
879
926
  query: string;
@@ -3866,6 +3913,9 @@ declare class ScraperClient {
3866
3913
  type InsufficientBalanceBody = components['schemas']['InsufficientBalanceError'];
3867
3914
  type ConcurrencyLimitBody = components['schemas']['ConcurrencyLimitError'];
3868
3915
  type StructuredErrorBody = components['schemas']['StructuredError'];
3916
+ type PublicErrorEnvelopeBody = components['schemas']['PublicErrorEnvelope'];
3917
+ type ConcurrencyPackBody = components['schemas']['ConcurrencyPack'];
3918
+ type ConcurrencyAccountViewBody = components['schemas']['ConcurrencyAccountView'];
3869
3919
  declare class ScraperApiError extends Error {
3870
3920
  readonly status: number;
3871
3921
  readonly code?: string;
@@ -3880,6 +3930,12 @@ declare class ScraperApiError extends Error {
3880
3930
  isStructuredError(): this is ScraperApiError & {
3881
3931
  body: StructuredErrorBody;
3882
3932
  };
3933
+ isVerificationChallenge(): this is ScraperApiError & {
3934
+ body: PublicErrorEnvelopeBody;
3935
+ };
3936
+ isTimeout(): this is ScraperApiError & {
3937
+ body: PublicErrorEnvelopeBody;
3938
+ };
3883
3939
  }
3884
3940
 
3885
- export { type ConcurrencyLimitBody, type InsufficientBalanceBody, ScraperApiError, ScraperClient, type ScraperClientOptions, type SerpIntelligenceCaptureOptions, type SerpIntelligenceCaptureParams, type SerpIntelligenceCaptureReceipt, type StructuredErrorBody, type components, type operations, type paths };
3941
+ export { type ConcurrencyAccountViewBody, type ConcurrencyLimitBody, type ConcurrencyPackBody, type InsufficientBalanceBody, type PublicErrorEnvelopeBody, ScraperApiError, ScraperClient, type ScraperClientOptions, type SerpIntelligenceCaptureOptions, type SerpIntelligenceCaptureParams, type SerpIntelligenceCaptureReceipt, type StructuredErrorBody, type components, type operations, type paths };
package/dist/index.d.ts CHANGED
@@ -17,10 +17,9 @@ interface paths {
17
17
  put?: never;
18
18
  /**
19
19
  * Run a Google SERP search, or a full People-Also-Ask harvest
20
- * @description Set `serpOnly: true` for a pure organic-results/SERP call (14 credits; runs headful so
21
- * Google serves a complete page).
20
+ * @description Set `serpOnly: true` for a pure organic-results/SERP call (60 Credits).
22
21
  * Omit or set `false` for a full People-Also-Ask harvest, which also returns SERP data
23
- * (55 credit base + 3 credits per question actually returned; unused estimate is
22
+ * (400 Credit base + 10 Credits per question actually returned; unused estimate is
24
23
  * refunded). Runs synchronously and returns the result inline.
25
24
  */
26
25
  post: operations["harvestSync"];
@@ -618,8 +617,7 @@ interface paths {
618
617
  put?: never;
619
618
  /**
620
619
  * Structured SERP capture with AI Overview/AI Mode detection, entity IDs, and location-match evidence
621
- * @description Holds 14 credits for the SERP and settles to 4 credits when the capture is served
622
- * headless, or retains 14 credits when it runs headful.
620
+ * @description Costs 60 Credits for the base SERP capture.
623
621
  * When `includePageSnapshots` is true, also holds 1 credit per requested
624
622
  * `pageSnapshotLimit` slot and settles to 1 credit per URL actually attempted.
625
623
  * Rate-limited to 60 requests/minute per account.
@@ -838,15 +836,33 @@ interface components {
838
836
  Error: {
839
837
  error: string;
840
838
  error_code?: string;
839
+ error_type?: string;
841
840
  message?: string;
842
- };
843
- /** @description Shared structured error shape used by SERP Intelligence endpoints. */
844
- StructuredError: {
845
- error_code: string;
846
- error_type: string;
841
+ retryable?: boolean;
842
+ retry_after_seconds?: number;
843
+ charge_status?: components["schemas"]["PublicChargeStatus"];
844
+ details?: components["schemas"]["PublicErrorDetails"];
845
+ };
846
+ /** @enum {string} */
847
+ PublicChargeStatus: "not_charged" | "refunded" | "charged";
848
+ /** @description Bounded, vendor-neutral recovery and account details safe for public clients. */
849
+ PublicErrorDetails: {
850
+ [key: string]: string | number | boolean | (string | null);
851
+ };
852
+ /** @description Stable public failure envelope shared across REST and MCP operations. */
853
+ PublicErrorEnvelope: {
854
+ /** @enum {string} */
855
+ error_code: "request_aborted" | "captcha_exhausted" | "captcha_or_blocked" | "location_mismatch" | "proxy_tunnel_failed" | "proxy_unavailable" | "harvest_timeout" | "mcp_request_timeout" | "extraction_failed" | "concurrency_limit_exceeded" | "unauthorized" | "forbidden" | "invalid_request" | "rate_limited" | "insufficient_balance" | "service_unavailable";
856
+ /** @enum {string} */
857
+ error_type: "request_aborted" | "captcha" | "location_mismatch" | "connection" | "timeout" | "extraction" | "concurrency_limit" | "unauthorized" | "forbidden" | "invalid_request" | "rate_limit" | "billing" | "service_unavailable";
847
858
  message: string;
848
859
  retryable: boolean;
860
+ retry_after_seconds?: number;
861
+ charge_status?: components["schemas"]["PublicChargeStatus"];
862
+ details?: components["schemas"]["PublicErrorDetails"];
849
863
  };
864
+ /** @description Shared structured error shape used by SERP Intelligence endpoints. */
865
+ StructuredError: components["schemas"]["PublicErrorEnvelope"];
850
866
  InsufficientBalanceError: {
851
867
  /** @enum {string} */
852
868
  error: "insufficient_balance";
@@ -858,22 +874,53 @@ interface components {
858
874
  /** Format: uri */
859
875
  topup_url: string;
860
876
  };
861
- ConcurrencyLimitError: {
877
+ ConcurrencyLimitError: components["schemas"]["PublicErrorEnvelope"] & {
862
878
  error?: string;
863
- message: string;
864
879
  /** @enum {string} */
865
880
  error_code: "concurrency_limit_exceeded";
866
881
  /** @enum {string} */
867
- error_type?: "concurrency_limit";
868
- retryable?: boolean;
882
+ error_type: "concurrency_limit";
869
883
  active: number;
870
884
  limit: number;
871
885
  operation: string;
886
+ upgrade: components["schemas"]["ConcurrencyPack"];
872
887
  /** Format: uri */
873
888
  upgrade_url?: string;
874
- /** @description CLI command to buy an extra concurrency slot. */
889
+ /** @description CLI command to buy or update two-browser concurrency packs. */
875
890
  upgrade_command?: string;
876
891
  };
892
+ /** @description One $5 monthly pack adds exactly two concurrent browser slots. Quantity n adds 2n slots for $5n per month. */
893
+ ConcurrencyPack: {
894
+ product: string;
895
+ rate_policy_version: string;
896
+ price_label: string;
897
+ /** @enum {number} */
898
+ unit_amount_usd: 5;
899
+ /** @enum {string} */
900
+ currency: "usd";
901
+ /** @enum {string} */
902
+ interval: "month";
903
+ /** @enum {string} */
904
+ billing_unit: "pack";
905
+ pack_quantity: number;
906
+ /** @enum {integer} */
907
+ slots_per_pack: 2;
908
+ extra_slots: number;
909
+ /** Format: uri */
910
+ billing_url: string;
911
+ terminal_command: string;
912
+ terminal_command_with_api_key_env: string;
913
+ };
914
+ /** @description Quantity-based add-on entitlement projected by account and billing endpoints. */
915
+ ConcurrencyAccountView: {
916
+ pack_quantity: number;
917
+ /** @enum {integer} */
918
+ slots_per_pack: 2;
919
+ extra_concurrency_slots: number;
920
+ effective_limit: number;
921
+ monthly_amount_usd: number;
922
+ has_subscription?: boolean;
923
+ };
877
924
  HarvestSyncRequest: {
878
925
  /** @description Search query. */
879
926
  query: string;
@@ -3866,6 +3913,9 @@ declare class ScraperClient {
3866
3913
  type InsufficientBalanceBody = components['schemas']['InsufficientBalanceError'];
3867
3914
  type ConcurrencyLimitBody = components['schemas']['ConcurrencyLimitError'];
3868
3915
  type StructuredErrorBody = components['schemas']['StructuredError'];
3916
+ type PublicErrorEnvelopeBody = components['schemas']['PublicErrorEnvelope'];
3917
+ type ConcurrencyPackBody = components['schemas']['ConcurrencyPack'];
3918
+ type ConcurrencyAccountViewBody = components['schemas']['ConcurrencyAccountView'];
3869
3919
  declare class ScraperApiError extends Error {
3870
3920
  readonly status: number;
3871
3921
  readonly code?: string;
@@ -3880,6 +3930,12 @@ declare class ScraperApiError extends Error {
3880
3930
  isStructuredError(): this is ScraperApiError & {
3881
3931
  body: StructuredErrorBody;
3882
3932
  };
3933
+ isVerificationChallenge(): this is ScraperApiError & {
3934
+ body: PublicErrorEnvelopeBody;
3935
+ };
3936
+ isTimeout(): this is ScraperApiError & {
3937
+ body: PublicErrorEnvelopeBody;
3938
+ };
3883
3939
  }
3884
3940
 
3885
- export { type ConcurrencyLimitBody, type InsufficientBalanceBody, ScraperApiError, ScraperClient, type ScraperClientOptions, type SerpIntelligenceCaptureOptions, type SerpIntelligenceCaptureParams, type SerpIntelligenceCaptureReceipt, type StructuredErrorBody, type components, type operations, type paths };
3941
+ export { type ConcurrencyAccountViewBody, type ConcurrencyLimitBody, type ConcurrencyPackBody, type InsufficientBalanceBody, type PublicErrorEnvelopeBody, ScraperApiError, ScraperClient, type ScraperClientOptions, type SerpIntelligenceCaptureOptions, type SerpIntelligenceCaptureParams, type SerpIntelligenceCaptureReceipt, type StructuredErrorBody, type components, type operations, type paths };
package/dist/index.js CHANGED
@@ -7,7 +7,78 @@ function readString(body, key) {
7
7
  return void 0;
8
8
  }
9
9
  var PUBLIC_SERVICE_UNAVAILABLE_MESSAGE = "This operation is temporarily unavailable. Please retry later.";
10
+ var PUBLIC_ERROR_CODES = /* @__PURE__ */ new Set([
11
+ "request_aborted",
12
+ "captcha_exhausted",
13
+ "captcha_or_blocked",
14
+ "location_mismatch",
15
+ "proxy_tunnel_failed",
16
+ "proxy_unavailable",
17
+ "harvest_timeout",
18
+ "mcp_request_timeout",
19
+ "extraction_failed",
20
+ "concurrency_limit_exceeded",
21
+ "unauthorized",
22
+ "forbidden",
23
+ "invalid_request",
24
+ "rate_limited",
25
+ "insufficient_balance",
26
+ "service_unavailable"
27
+ ]);
28
+ var PUBLIC_ERROR_FIELDS = /* @__PURE__ */ new Set([
29
+ "error",
30
+ "error_code",
31
+ "error_type",
32
+ "message",
33
+ "retryable",
34
+ "retry_after_seconds",
35
+ "charge_status",
36
+ "details",
37
+ "active",
38
+ "limit",
39
+ "operation",
40
+ "upgrade",
41
+ "upgrade_url",
42
+ "upgrade_command",
43
+ "balance_credits",
44
+ "required_credits",
45
+ "topup_url"
46
+ ]);
47
+ var PUBLIC_DETAIL_FIELDS = /* @__PURE__ */ new Set([
48
+ "active",
49
+ "limit",
50
+ "operation",
51
+ "upgrade_url",
52
+ "topup_url",
53
+ "upgrade_command",
54
+ "slots_per_pack",
55
+ "pack_price_usd",
56
+ "balance_credits",
57
+ "required_credits"
58
+ ]);
59
+ function recognizedPublicDetails(value) {
60
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
61
+ const details = Object.fromEntries(
62
+ Object.entries(value).filter(
63
+ ([key, child]) => PUBLIC_DETAIL_FIELDS.has(key) && (child === null || ["string", "number", "boolean"].includes(typeof child))
64
+ )
65
+ );
66
+ return Object.keys(details).length > 0 ? details : void 0;
67
+ }
68
+ function recognizedPublicErrorBody(body) {
69
+ if (!body || typeof body !== "object" || Array.isArray(body)) return void 0;
70
+ const record = body;
71
+ const code = readString(record, "error_code");
72
+ if (!code || !PUBLIC_ERROR_CODES.has(code)) return void 0;
73
+ const safe = Object.fromEntries(Object.entries(record).filter(([key]) => PUBLIC_ERROR_FIELDS.has(key)));
74
+ const details = recognizedPublicDetails(record.details);
75
+ if (details) safe.details = details;
76
+ else delete safe.details;
77
+ return safe;
78
+ }
10
79
  function publicErrorBody(status, body) {
80
+ const recognized = recognizedPublicErrorBody(body);
81
+ if (recognized) return recognized;
11
82
  if (status < 500) return body;
12
83
  return {
13
84
  error: "service_unavailable",
@@ -39,6 +110,12 @@ var ScraperApiError = class extends Error {
39
110
  isStructuredError() {
40
111
  return typeof readString(this.body, "error_type") === "string";
41
112
  }
113
+ isVerificationChallenge() {
114
+ return this.code === "captcha_exhausted" || this.code === "captcha_or_blocked";
115
+ }
116
+ isTimeout() {
117
+ return this.code === "harvest_timeout" || this.code === "mcp_request_timeout";
118
+ }
42
119
  };
43
120
 
44
121
  // src/client.ts
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mcpscraper-sdk",
3
- "version": "0.26.2",
4
- "description": "Official Node.js client for all 246 mcpscraper.dev MCP tools and the REST API",
3
+ "version": "0.27.0",
4
+ "description": "Official Node.js client for all 249 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.27.2"
35
+ "mcpscraper-memory-sdk": "^0.28.0"
36
36
  },
37
37
  "devDependencies": {
38
38
  "openapi-typescript": "^7.13.0"