@mendable/firecrawl-js 4.38.0 → 4.40.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.
Files changed (37) hide show
  1. package/README.md +53 -2
  2. package/dist/{chunk-KSTNOGOD.js → chunk-OJ4YJQ4J.js} +1 -1
  3. package/dist/index.cjs +204 -17
  4. package/dist/index.d.cts +289 -7
  5. package/dist/index.d.ts +289 -7
  6. package/dist/index.js +203 -17
  7. package/dist/{package-OS7RONXY.js → package-F6O7J2XI.js} +1 -1
  8. package/package.json +1 -1
  9. package/pnpm-workspace.yaml +3 -2
  10. package/src/__tests__/e2e/v2/batch.test.ts +13 -11
  11. package/src/__tests__/e2e/v2/crawl.test.ts +24 -20
  12. package/src/__tests__/e2e/v2/extract.test.ts +32 -7
  13. package/src/__tests__/e2e/v2/map.test.ts +4 -3
  14. package/src/__tests__/e2e/v2/parse.test.ts +4 -3
  15. package/src/__tests__/e2e/v2/scrape.test.ts +10 -9
  16. package/src/__tests__/e2e/v2/search.test.ts +9 -8
  17. package/src/__tests__/e2e/v2/usage.test.ts +6 -5
  18. package/src/__tests__/e2e/v2/utils/rateLimit.ts +257 -0
  19. package/src/__tests__/e2e/v2/watcher.test.ts +4 -3
  20. package/src/__tests__/unit/v2/agent-effort-trace.unit.test.ts +1 -1
  21. package/src/__tests__/unit/v2/agent-thread.unit.test.ts +164 -0
  22. package/src/__tests__/unit/v2/e2eRateLimitRetry.test.ts +501 -0
  23. package/src/__tests__/unit/v2/extract.unit.test.ts +1 -1
  24. package/src/__tests__/unit/v2/scrapeAutoResume.test.ts +1 -1
  25. package/src/__tests__/unit/v2/search-country.unit.test.ts +32 -0
  26. package/src/__tests__/unit/v2/search-data-property.test.ts +1 -0
  27. package/src/__tests__/unit/v2/threat-protection.unit.test.ts +18 -1
  28. package/src/__tests__/unit/v2/tools.unit.test.ts +240 -0
  29. package/src/__tests__/unit/v2/v1-aliases.test.ts +1 -0
  30. package/src/v2/client.ts +52 -4
  31. package/src/v2/methods/agent.ts +23 -1
  32. package/src/v2/methods/research.ts +14 -8
  33. package/src/v2/methods/scrape.ts +3 -1
  34. package/src/v2/methods/search.ts +8 -1
  35. package/src/v2/methods/tools.ts +137 -0
  36. package/src/v2/types.ts +307 -35
  37. package/src/v2/utils/errorHandler.ts +19 -3
@@ -0,0 +1,137 @@
1
+ import type {
2
+ AlexandriaCall,
3
+ AlexandriaOptions,
4
+ AlexandriaScrapeData,
5
+ AlexandriaScrapeResult,
6
+ FindToolsData,
7
+ FindToolsOptions,
8
+ } from "../types";
9
+ import { SdkError } from "../types";
10
+ import { HttpClient } from "../utils/httpClient";
11
+ import {
12
+ normalizeAxiosError,
13
+ throwForBadResponse,
14
+ } from "../utils/errorHandler";
15
+
16
+ const ALEXANDRIA_MAX_CALLS = 10;
17
+
18
+ function prepareAlexandriaPayload(
19
+ calls: AlexandriaCall[],
20
+ opts: AlexandriaOptions,
21
+ ): Record<string, unknown> {
22
+ if (!Array.isArray(calls) || calls.length === 0) {
23
+ throw new Error("alexandria requires at least one call");
24
+ }
25
+ if (calls.length > ALEXANDRIA_MAX_CALLS) {
26
+ throw new Error(`alexandria accepts at most ${ALEXANDRIA_MAX_CALLS} calls`);
27
+ }
28
+ const alexandria = calls.map((call, index) => {
29
+ if (!call || typeof call.provider !== "string" || !call.provider.trim()) {
30
+ throw new Error(`alexandria[${index}].provider cannot be empty`);
31
+ }
32
+ if (typeof call.capability !== "string" || !call.capability.trim()) {
33
+ throw new Error(`alexandria[${index}].capability cannot be empty`);
34
+ }
35
+ if (
36
+ Object.keys(call).some(
37
+ (key) => !["provider", "capability", "options"].includes(key),
38
+ )
39
+ )
40
+ throw new Error("Unknown alexandria call option");
41
+ const item: Record<string, unknown> = {
42
+ provider: call.provider.trim(),
43
+ capability: call.capability.trim(),
44
+ };
45
+ if (call.options != null) {
46
+ if (typeof call.options !== "object" || Array.isArray(call.options)) {
47
+ throw new Error(`alexandria[${index}].options must be an object`);
48
+ }
49
+ item.options = call.options;
50
+ }
51
+ return item;
52
+ });
53
+ if (
54
+ opts.timeout != null &&
55
+ (!Number.isInteger(opts.timeout) || opts.timeout <= 0)
56
+ ) {
57
+ throw new Error("timeout must be a positive integer");
58
+ }
59
+ const payload: Record<string, unknown> = { alexandria };
60
+ if (opts.timeout != null) payload.timeout = opts.timeout;
61
+ if (opts.integration && opts.integration.trim())
62
+ payload.integration = opts.integration.trim();
63
+ if (opts.origin) payload.origin = opts.origin;
64
+ return payload;
65
+ }
66
+
67
+ export async function scrapeAlexandria(
68
+ http: HttpClient,
69
+ calls: AlexandriaCall[],
70
+ opts: AlexandriaOptions = {},
71
+ ): Promise<AlexandriaScrapeData> {
72
+ const payload = prepareAlexandriaPayload(calls, opts);
73
+ const requestId = opts.requestId ?? crypto.randomUUID();
74
+ if (!/^[A-Za-z0-9._:-]{1,128}$/.test(requestId))
75
+ throw new Error("Invalid requestId");
76
+ try {
77
+ const res = await http.post<{
78
+ success: boolean;
79
+ scrape_id?: string;
80
+ data?: { alexandria?: AlexandriaScrapeResult[]; creditsCost?: number };
81
+ error?: string;
82
+ }>("/v2/scrape", payload, {
83
+ headers: { "x-request-id": requestId },
84
+ // Allow response delivery after the API's capped execution deadline.
85
+ timeoutMs: Math.min(opts.timeout ?? 50000, 50000) + 30000,
86
+ });
87
+ if (res.status !== 200 || !res.data?.success) {
88
+ throwForBadResponse(res, "alexandria");
89
+ }
90
+ const data = res.data.data;
91
+ if (
92
+ !data ||
93
+ !Array.isArray(data.alexandria) ||
94
+ typeof data.creditsCost !== "number" ||
95
+ !Number.isInteger(data.creditsCost) ||
96
+ data.creditsCost < 0
97
+ ) {
98
+ throw new SdkError("Invalid alexandria response");
99
+ }
100
+ return {
101
+ scrapeId: res.data.scrape_id ?? "",
102
+ requestId,
103
+ alexandria: data.alexandria,
104
+ creditsCost: data.creditsCost,
105
+ };
106
+ } catch (err: any) {
107
+ try {
108
+ if (err?.isAxiosError) normalizeAxiosError(err, "alexandria");
109
+ throw err;
110
+ } catch (error) {
111
+ if (error && typeof error === "object")
112
+ Object.assign(error, { requestId });
113
+ throw error;
114
+ }
115
+ }
116
+ }
117
+
118
+ export async function findTools(
119
+ http: HttpClient,
120
+ options: FindToolsOptions = {},
121
+ ): Promise<FindToolsData> {
122
+ const result = await scrapeAlexandria(http, [
123
+ {
124
+ provider: "firecrawl",
125
+ capability: "find-tools",
126
+ options: { ...options },
127
+ },
128
+ ]);
129
+ const item = result.alexandria[0];
130
+ if (!item) throw new SdkError("Missing Find Tools result");
131
+ if (item.error)
132
+ throw Object.assign(
133
+ new SdkError(item.error.message, item.error.status, item.error.code),
134
+ { requestId: result.requestId },
135
+ );
136
+ return item.data as FindToolsData;
137
+ }
package/src/v2/types.ts CHANGED
@@ -275,15 +275,12 @@ export interface ScrapeOptions {
275
275
  };
276
276
  integration?: string;
277
277
  origin?: string;
278
+ /** Include domain-matched Alexandria contracts for this URL in `tools`. Default off. */
279
+ domainTools?: boolean;
278
280
  }
279
281
 
280
282
  export type RedactPIIEntity =
281
- | "PERSON"
282
- | "EMAIL"
283
- | "PHONE"
284
- | "LOCATION"
285
- | "FINANCIAL"
286
- | "SECRET";
283
+ "PERSON" | "EMAIL" | "PHONE" | "LOCATION" | "FINANCIAL" | "SECRET";
287
284
 
288
285
  export interface RedactPIIOptions {
289
286
  /**
@@ -324,12 +321,7 @@ export interface ThreatProtectionOptions {
324
321
  }
325
322
 
326
323
  export type ParseFileData =
327
- | Blob
328
- | File
329
- | Buffer
330
- | Uint8Array
331
- | ArrayBuffer
332
- | string;
324
+ Blob | File | Buffer | Uint8Array | ArrayBuffer | string;
333
325
 
334
326
  export interface ParseFile {
335
327
  data: ParseFileData;
@@ -364,11 +356,7 @@ export interface WebhookConfig {
364
356
 
365
357
  // Agent webhook events differ from crawl: has 'action' and 'cancelled', no 'page'
366
358
  export type AgentWebhookEvent =
367
- | "started"
368
- | "action"
369
- | "completed"
370
- | "failed"
371
- | "cancelled";
359
+ "started" | "action" | "completed" | "failed" | "cancelled";
372
360
 
373
361
  export interface AgentWebhookConfig {
374
362
  url: string;
@@ -489,10 +477,7 @@ export interface BrandingProfile {
489
477
  headerHeight?: string;
490
478
  footerHeight?: string;
491
479
  [key: string]:
492
- | number
493
- | string
494
- | Record<string, number | string | undefined>
495
- | undefined;
480
+ number | string | Record<string, number | string | undefined> | undefined;
496
481
  };
497
482
  tone?: {
498
483
  voice?: string;
@@ -702,6 +687,8 @@ export interface Document {
702
687
  pages?: PdfPage[];
703
688
  /** Typed PDF layout blocks, present only when `parsers[].blocks` is true. */
704
689
  blocks?: PdfPageBlocks[];
690
+ /** Present when `domainTools` discovered contracts matching this URL. */
691
+ tools?: DiscoveredTool[];
705
692
  }
706
693
 
707
694
  // Pagination configuration for auto-fetching pages from v2 endpoints that return a `next` URL
@@ -814,9 +801,129 @@ export interface SearchResultImages {
814
801
  }
815
802
 
816
803
  export interface SearchData {
804
+ warning?: string;
817
805
  web?: Array<SearchResultWeb | Document>;
818
806
  news?: Array<SearchResultNews | Document>;
819
807
  images?: Array<SearchResultImages | Document>;
808
+ tools?: DiscoveredTool[];
809
+ }
810
+
811
+ /** A complete tool contract returned by semantic or contextual discovery. */
812
+ export interface DiscoveredTool {
813
+ id?: string;
814
+ provider: string;
815
+ capability: string;
816
+ name: string;
817
+ description: string;
818
+ creditsCost: number;
819
+ perRecord: boolean;
820
+ options: Array<{
821
+ name: string;
822
+ type: string;
823
+ required?: boolean;
824
+ [key: string]: unknown;
825
+ }>;
826
+ requiresOneOf?: string[][];
827
+ response?: {
828
+ about?: string;
829
+ key?: string;
830
+ fields?: Array<{ name: string; type: string; [key: string]: unknown }>;
831
+ [key: string]: unknown;
832
+ };
833
+ examples?: Partial<Record<"javascript" | "python" | "curl", string>> &
834
+ Record<string, string>;
835
+ example?: {
836
+ recordedAt: string;
837
+ request: Record<string, unknown>;
838
+ response: unknown;
839
+ };
840
+ label?: string;
841
+ whenToUse?: string;
842
+ returns?: unknown;
843
+ discovery?: unknown;
844
+ attribution?: unknown;
845
+ matchedBy?: Array<"semantic" | "domain">;
846
+ matchedUrls?: string[];
847
+ concept?: string;
848
+ cohorts?: string[];
849
+ similarity?: number;
850
+ }
851
+
852
+ export interface FindToolsOptions {
853
+ urls?: string[];
854
+ providers?: string[];
855
+ categories?: string[];
856
+ groups?: string[];
857
+ capabilities?: string[];
858
+ level?: "providers" | "groups" | "tools";
859
+ expand?: Array<"options" | "response" | "examples">;
860
+ limit?: number;
861
+ offset?: number;
862
+ }
863
+
864
+ export interface FindToolsData {
865
+ level: "providers" | "groups" | "tools";
866
+ items: Array<{
867
+ id: string;
868
+ name: string;
869
+ next?: AlexandriaCall;
870
+ execute?: Pick<AlexandriaCall, "provider" | "capability">;
871
+ [key: string]: unknown;
872
+ }>;
873
+ total: number;
874
+ next: AlexandriaCall | null;
875
+ }
876
+
877
+ export interface AlexandriaScrapeRequest extends AlexandriaOptions {
878
+ alexandria: AlexandriaCall | AlexandriaCall[];
879
+ }
880
+
881
+ export interface AlexandriaCall {
882
+ provider: string;
883
+ capability: string;
884
+ options?: Record<string, unknown>;
885
+ }
886
+
887
+ export interface AlexandriaScrapeError {
888
+ code: string;
889
+ message: string;
890
+ status?: number;
891
+ /** Present when credits were captured before the failure. */
892
+ chargeId?: string;
893
+ }
894
+
895
+ export type AlexandriaScrapeResult =
896
+ | {
897
+ provider: string;
898
+ capability: string;
899
+ creditsCost: number;
900
+ data: unknown;
901
+ records?: number;
902
+ upstreamStatus?: number;
903
+ recordedAt?: string;
904
+ error?: undefined;
905
+ [key: string]: unknown;
906
+ }
907
+ | {
908
+ provider?: string;
909
+ capability?: string;
910
+ error: AlexandriaScrapeError;
911
+ [key: string]: unknown;
912
+ };
913
+
914
+ export interface AlexandriaScrapeData {
915
+ scrapeId: string;
916
+ requestId: string;
917
+ alexandria: AlexandriaScrapeResult[];
918
+ creditsCost: number;
919
+ }
920
+
921
+ export interface AlexandriaOptions {
922
+ /** Reuse this ID with the identical payload when retrying an execution. */
923
+ requestId?: string;
924
+ timeout?: number;
925
+ integration?: string;
926
+ origin?: string;
820
927
  }
821
928
 
822
929
  /**
@@ -847,8 +954,11 @@ export interface CategoryOption {
847
954
 
848
955
  export interface SearchRequest {
849
956
  query: string;
957
+ /** Include domain-matched contracts in tools alongside semantic matches. */
958
+ domainTools?: boolean;
850
959
  sources?: Array<
851
- "web" | "news" | "images" | { type: "web" | "news" | "images" }
960
+ "web" | "news" | "images" | "alexandria"
961
+ | { type: "web" | "news" | "images" | "alexandria" }
852
962
  >;
853
963
  /**
854
964
  * Narrow web search by category. See {@link CategoryOption}.
@@ -866,6 +976,8 @@ export interface SearchRequest {
866
976
  limit?: number;
867
977
  tbs?: string;
868
978
  location?: string;
979
+ /** ISO 3166-1 alpha-2 country code used to geo-target the search results. */
980
+ country?: string;
869
981
  ignoreInvalidURLs?: boolean;
870
982
  timeout?: number; // ms
871
983
  /** Generate query-relevant highlights for search results. Defaults to true. */
@@ -1095,9 +1207,7 @@ export interface MonitorSearchTarget {
1095
1207
  }
1096
1208
 
1097
1209
  export type MonitorTarget =
1098
- | MonitorScrapeTarget
1099
- | MonitorCrawlTarget
1100
- | MonitorSearchTarget;
1210
+ MonitorScrapeTarget | MonitorCrawlTarget | MonitorSearchTarget;
1101
1211
 
1102
1212
  export interface CreateMonitorRequest {
1103
1213
  name: string;
@@ -1220,11 +1330,7 @@ export interface MonitorCheck {
1220
1330
  reservedCredits?: number | null;
1221
1331
  actualCredits?: number | null;
1222
1332
  billingStatus:
1223
- | "not_applicable"
1224
- | "reserved"
1225
- | "confirmed"
1226
- | "released"
1227
- | "failed";
1333
+ "not_applicable" | "reserved" | "confirmed" | "released" | "failed";
1228
1334
  summary: MonitorSummary;
1229
1335
  targetResults?: MonitorTargetResult[];
1230
1336
  notificationStatus?: unknown;
@@ -1311,10 +1417,65 @@ export interface ExtractResponse {
1311
1417
  creditsUsed?: number;
1312
1418
  }
1313
1419
 
1420
+ /** Conversation mode for an agent run. Defaults to "extract" server-side. */
1421
+ export type AgentMode = "extract" | "chat";
1422
+
1423
+ /** Options forwarded verbatim to the agent; the server owns every default. */
1424
+ export interface AgentExchangeOptions {
1425
+ enabled?: boolean;
1426
+ /** At most 5. */
1427
+ toolkits?: string[];
1428
+ maxCalls?: number;
1429
+ requireApproval?: boolean;
1430
+ /** Answers a pendingApproval from the previous turn of the thread. */
1431
+ approve?: { approvalId: string; callIds?: string[]; always?: boolean };
1432
+ decline?: { approvalId: string };
1433
+ }
1434
+
1435
+ /** Per-run summary reported on a status response. */
1436
+ export interface AgentExchangeSummary {
1437
+ enabled: boolean;
1438
+ /** What the run resolved to after thread inheritance, not what it requested. */
1439
+ toolkits?: string[];
1440
+ requireApproval?: boolean;
1441
+ paidCalls: number;
1442
+ creditsUsed: number | null;
1443
+ }
1444
+
1445
+ /** A follow-up the agent offers for the next turn of the thread. */
1446
+ export interface AgentSuggestion {
1447
+ label: string;
1448
+ prompt: string;
1449
+ }
1450
+
1451
+ /** A turn that ended waiting for the caller to allow or refuse paid calls. */
1452
+ export interface PendingApproval {
1453
+ id: string;
1454
+ reason: string;
1455
+ calls: {
1456
+ id: string;
1457
+ provider: string;
1458
+ capability: string;
1459
+ input: Record<string, unknown>;
1460
+ more?: Record<string, unknown>[];
1461
+ creditsEstimate: number | null;
1462
+ }[];
1463
+ resolution: null | {
1464
+ approved: boolean;
1465
+ callIds: string[];
1466
+ always: boolean;
1467
+ byRunId: string;
1468
+ };
1469
+ }
1470
+
1314
1471
  export interface AgentResponse {
1315
1472
  success: boolean;
1316
1473
  id: string;
1317
1474
  error?: string;
1475
+ /** Thread this run belongs to; pass it back to continue the conversation. */
1476
+ threadId?: string;
1477
+ /** 1-based position of this run in its thread. */
1478
+ threadTurn?: number;
1318
1479
  }
1319
1480
 
1320
1481
  export interface AgentStatusResponse {
@@ -1335,6 +1496,55 @@ export interface AgentStatusResponse {
1335
1496
  effort?: "low" | "medium" | "high";
1336
1497
  expiresAt: string;
1337
1498
  creditsUsed?: number;
1499
+ threadId?: string;
1500
+ threadTurn?: number;
1501
+ mode?: AgentMode;
1502
+ /** Assistant text reply. Chat-mode runs answer here instead of in `data`. */
1503
+ message?: string;
1504
+ suggestions?: AgentSuggestion[];
1505
+ pendingApproval?: PendingApproval;
1506
+ exchange?: AgentExchangeSummary;
1507
+ }
1508
+
1509
+ /** A single run of a thread, as returned by getAgentThread. */
1510
+ export interface AgentThreadRun {
1511
+ id: string;
1512
+ turn: number;
1513
+ mode: AgentMode;
1514
+ prompt: string;
1515
+ urls?: string[];
1516
+ schema?: unknown;
1517
+ effort?: "low" | "medium" | "high";
1518
+ status:
1519
+ | "processing"
1520
+ | "succeeded"
1521
+ | "failed"
1522
+ | "cancelled"
1523
+ | "refused"
1524
+ | "credit_limit_reached";
1525
+ createdAt: string;
1526
+ finishedAt: string | null;
1527
+ creditsUsed: number | null;
1528
+ message: string | null;
1529
+ /** Only present when the request asked for includeData. */
1530
+ data?: unknown;
1531
+ suggestions?: AgentSuggestion[] | null;
1532
+ pendingApproval?: PendingApproval | null;
1533
+ exchange?: AgentExchangeSummary | null;
1534
+ }
1535
+
1536
+ export interface AgentThread {
1537
+ id: string;
1538
+ createdAt: string;
1539
+ updatedAt: string;
1540
+ status: "idle" | "running";
1541
+ runs: AgentThreadRun[];
1542
+ }
1543
+
1544
+ export interface AgentThreadResponse {
1545
+ success: boolean;
1546
+ thread?: AgentThread;
1547
+ error?: string;
1338
1548
  }
1339
1549
 
1340
1550
  /** Reasoning effort for agent jobs. Every level runs spark-2. */
@@ -1384,7 +1594,8 @@ export interface AgentListOptions {
1384
1594
  before?: number;
1385
1595
  }
1386
1596
 
1387
- export type AgentTraceAgentRole = "orchestrator" | "subagent" | "browser" | "system";
1597
+ export type AgentTraceAgentRole =
1598
+ "orchestrator" | "subagent" | "browser" | "system";
1388
1599
 
1389
1600
  export interface AgentTraceAgentIdentity {
1390
1601
  id: string;
@@ -1394,7 +1605,12 @@ export interface AgentTraceAgentIdentity {
1394
1605
  }
1395
1606
 
1396
1607
  export interface AgentTraceError {
1397
- code: "cancelled" | "credit_limit_reached" | "parent_finished" | "refused" | "internal";
1608
+ code:
1609
+ | "cancelled"
1610
+ | "credit_limit_reached"
1611
+ | "parent_finished"
1612
+ | "refused"
1613
+ | "internal";
1398
1614
  source: "agent" | "tool" | "billing" | "system";
1399
1615
  retryable: boolean;
1400
1616
  message: string;
@@ -1432,7 +1648,8 @@ export interface AgentTraceRunCancelRequestedEvent extends AgentTraceEventBase {
1432
1648
 
1433
1649
  export interface AgentTraceRunFinishedEvent extends AgentTraceEventBase {
1434
1650
  type: "run.finished";
1435
- outcome: "succeeded" | "failed" | "cancelled" | "refused" | "credit_limit_reached";
1651
+ outcome:
1652
+ "succeeded" | "failed" | "cancelled" | "refused" | "credit_limit_reached";
1436
1653
  /** The canonical schema always writes this key (nullable), but older rows may omit it. */
1437
1654
  error?: AgentTraceError | null;
1438
1655
  }
@@ -1617,17 +1834,43 @@ export interface ErrorDetails {
1617
1834
  status?: number;
1618
1835
  }
1619
1836
 
1837
+ /** An out-of-band step the API requires before the request can succeed. */
1838
+ export interface RequiresAction {
1839
+ type: "accept_terms" | (string & {});
1840
+ terms?: string;
1841
+ version?: string;
1842
+ url?: string;
1843
+ }
1844
+
1845
+ export function parseRequiresAction(value: unknown): RequiresAction | undefined {
1846
+ if (!value || typeof value !== "object") return undefined;
1847
+ const record = value as Record<string, unknown>;
1848
+ if (typeof record.type !== "string") return undefined;
1849
+ const action: RequiresAction = { type: record.type };
1850
+ if (typeof record.terms === "string") action.terms = record.terms;
1851
+ if (typeof record.version === "string") action.version = record.version;
1852
+ if (typeof record.url === "string") action.url = record.url;
1853
+ return action;
1854
+ }
1855
+
1620
1856
  export class SdkError extends Error {
1857
+ requestId?: string;
1621
1858
  status?: number;
1622
1859
  code?: string;
1623
1860
  details?: unknown;
1624
1861
  jobId?: string;
1862
+ /** Present on exchange-mediated scrape failures that already captured credits. */
1863
+ chargeId?: string;
1864
+ /** Present when the API needs an out-of-band step first, such as accepting provider terms. */
1865
+ requiresAction?: RequiresAction;
1625
1866
  constructor(
1626
1867
  message: string,
1627
1868
  status?: number,
1628
1869
  code?: string,
1629
1870
  details?: unknown,
1630
1871
  jobId?: string,
1872
+ chargeId?: string,
1873
+ requiresAction?: RequiresAction,
1631
1874
  ) {
1632
1875
  super(message);
1633
1876
  this.name = "FirecrawlSdkError";
@@ -1635,6 +1878,8 @@ export class SdkError extends Error {
1635
1878
  this.code = code;
1636
1879
  this.details = details;
1637
1880
  this.jobId = jobId;
1881
+ this.chargeId = chargeId;
1882
+ this.requiresAction = requiresAction;
1638
1883
  }
1639
1884
  }
1640
1885
 
@@ -1829,7 +2074,14 @@ export interface SimilarPapersResponse {
1829
2074
  note?: string | null;
1830
2075
  }
1831
2076
 
1832
- /** Component scores; each field is present only when that signal contributed. */
2077
+ /**
2078
+ * Component scores; each field is present only when that signal contributed.
2079
+ *
2080
+ * @deprecated Use the developer index instead. The research index GitHub
2081
+ * search stops responding after 2026-11-03. The developer index does not
2082
+ * expose a score breakdown. See
2083
+ * https://docs.firecrawl.dev/features/developer.
2084
+ */
1833
2085
  export interface GitHubScoreBreakdown {
1834
2086
  rrf?: number;
1835
2087
  semantic?: number;
@@ -1838,6 +2090,11 @@ export interface GitHubScoreBreakdown {
1838
2090
  rerank?: number;
1839
2091
  }
1840
2092
 
2093
+ /**
2094
+ * @deprecated Use the developer index instead. The research index GitHub
2095
+ * search stops responding after 2026-11-03. See
2096
+ * https://docs.firecrawl.dev/features/developer.
2097
+ */
1841
2098
  export interface GitHubSearchItem {
1842
2099
  resultType?: "github_history" | "repo_readme" | "web";
1843
2100
  /** `owner/name`; empty for web results whose URL is not a repo page. */
@@ -1860,9 +2117,18 @@ export interface GitHubSearchItem {
1860
2117
  scores: GitHubScoreBreakdown;
1861
2118
  }
1862
2119
 
2120
+ /**
2121
+ * @deprecated Use the developer index instead. The research index GitHub
2122
+ * search stops responding after 2026-11-03. See
2123
+ * https://docs.firecrawl.dev/features/developer.
2124
+ */
1863
2125
  export interface GitHubSearchResponse {
1864
2126
  success: boolean;
1865
2127
  results: GitHubSearchItem[];
2128
+ /** Deprecation notice while the sunset window is live. */
2129
+ warnings?: string[];
2130
+ /** Replacement endpoint path, while the sunset window is live. */
2131
+ replacement?: string;
1866
2132
  }
1867
2133
 
1868
2134
  /** Options for `research.searchPapers`. */
@@ -1901,7 +2167,13 @@ export interface SimilarPapersOptions {
1901
2167
  anchor?: string[];
1902
2168
  }
1903
2169
 
1904
- /** Options for `research.searchGithub`. */
2170
+ /**
2171
+ * Options for `research.searchGithub`.
2172
+ *
2173
+ * @deprecated Use the developer index instead. The research index GitHub
2174
+ * search stops responding after 2026-11-03. See
2175
+ * https://docs.firecrawl.dev/features/developer.
2176
+ */
1905
2177
  export interface SearchGithubOptions {
1906
2178
  /** Number of results to return (1–100, default 20). */
1907
2179
  k?: number;
@@ -1,11 +1,19 @@
1
1
  import { type AxiosError, type AxiosResponse } from "axios";
2
- import { SdkError, JobTimeoutError } from "../types";
2
+ import { SdkError, JobTimeoutError, parseRequiresAction } from "../types";
3
3
 
4
4
  export function throwForBadResponse(resp: AxiosResponse, action: string): never {
5
5
  const status = resp.status;
6
6
  const body = resp.data || {};
7
7
  const msg = body?.error || body?.message || `Request failed (${status}) while trying to ${action}`;
8
- throw new SdkError(msg, status, undefined, body?.details);
8
+ throw new SdkError(
9
+ msg,
10
+ status,
11
+ body?.code,
12
+ body?.details,
13
+ undefined,
14
+ body?.chargeId,
15
+ parseRequiresAction(body?.requiresAction),
16
+ );
9
17
  }
10
18
 
11
19
  export function normalizeAxiosError(err: AxiosError, action: string): never {
@@ -13,7 +21,15 @@ export function normalizeAxiosError(err: AxiosError, action: string): never {
13
21
  const body: any = err.response?.data;
14
22
  const message = body?.error || err.message || `Request failed${status ? ` (${status})` : ""} while trying to ${action}`;
15
23
  const code = (body?.code as string) || err.code;
16
- throw new SdkError(message, status, code, body?.details ?? body);
24
+ throw new SdkError(
25
+ message,
26
+ status,
27
+ code,
28
+ body?.details ?? body,
29
+ undefined,
30
+ body?.chargeId,
31
+ parseRequiresAction(body?.requiresAction),
32
+ );
17
33
  }
18
34
 
19
35
  export function isRetryableError(err: any): boolean {