firecrawl 4.20.0 → 4.21.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.
@@ -8,7 +8,7 @@ var require_package = __commonJS({
8
8
  "package.json"(exports, module) {
9
9
  module.exports = {
10
10
  name: "@mendable/firecrawl-js",
11
- version: "4.20.0",
11
+ version: "4.21.0",
12
12
  description: "JavaScript SDK for Firecrawl API",
13
13
  main: "dist/index.js",
14
14
  types: "dist/index.d.ts",
package/dist/index.cjs CHANGED
@@ -35,7 +35,7 @@ var require_package = __commonJS({
35
35
  "package.json"(exports2, module2) {
36
36
  module2.exports = {
37
37
  name: "@mendable/firecrawl-js",
38
- version: "4.20.0",
38
+ version: "4.21.0",
39
39
  description: "JavaScript SDK for Firecrawl API",
40
40
  main: "dist/index.js",
41
41
  types: "dist/index.d.ts",
@@ -625,11 +625,17 @@ function prepareSearchPayload(req) {
625
625
  throw new Error("limit must be positive");
626
626
  if (req.timeout != null && req.timeout <= 0)
627
627
  throw new Error("timeout must be positive");
628
+ if (req.includeDomains?.length && req.excludeDomains?.length)
629
+ throw new Error(
630
+ "includeDomains and excludeDomains cannot both be specified"
631
+ );
628
632
  const payload = {
629
633
  query: req.query
630
634
  };
631
635
  if (req.sources) payload.sources = req.sources;
632
636
  if (req.categories) payload.categories = req.categories;
637
+ if (req.includeDomains) payload.includeDomains = req.includeDomains;
638
+ if (req.excludeDomains) payload.excludeDomains = req.excludeDomains;
633
639
  if (req.limit != null) payload.limit = req.limit;
634
640
  if (req.tbs != null) payload.tbs = req.tbs;
635
641
  if (req.location != null) payload.location = req.location;
@@ -1418,23 +1424,41 @@ var Watcher = class extends import_events.EventEmitter {
1418
1424
  return `${wsBase}${path}`;
1419
1425
  }
1420
1426
  async start() {
1421
- try {
1422
- const url = this.buildWsUrl();
1423
- const wsCtor = await getWebSocketCtor();
1424
- if (!wsCtor) {
1425
- this.pollLoop();
1426
- return;
1427
- }
1428
- this.ws = new wsCtor(url, this.http.getApiKey());
1429
- if (this.ws && "binaryType" in this.ws) {
1430
- this.ws.binaryType = "arraybuffer";
1431
- }
1432
- if (this.ws) {
1433
- this.attachWsHandlers(this.ws);
1434
- }
1435
- } catch (err) {
1436
- this.pollLoop();
1437
- }
1427
+ return new Promise((resolve, reject) => {
1428
+ const onDone = () => {
1429
+ cleanup();
1430
+ resolve();
1431
+ };
1432
+ const onError = (err) => {
1433
+ cleanup();
1434
+ resolve();
1435
+ };
1436
+ const cleanup = () => {
1437
+ this.removeListener("done", onDone);
1438
+ this.removeListener("error", onError);
1439
+ };
1440
+ this.on("done", onDone);
1441
+ this.on("error", onError);
1442
+ (async () => {
1443
+ try {
1444
+ const url = this.buildWsUrl();
1445
+ const wsCtor = await getWebSocketCtor();
1446
+ if (!wsCtor) {
1447
+ this.pollLoop();
1448
+ return;
1449
+ }
1450
+ this.ws = new wsCtor(url, this.http.getApiKey());
1451
+ if (this.ws && "binaryType" in this.ws) {
1452
+ this.ws.binaryType = "arraybuffer";
1453
+ }
1454
+ if (this.ws) {
1455
+ this.attachWsHandlers(this.ws);
1456
+ }
1457
+ } catch (err) {
1458
+ this.pollLoop();
1459
+ }
1460
+ })();
1461
+ });
1438
1462
  }
1439
1463
  attachWsHandlers(ws) {
1440
1464
  let startTs = Date.now();
@@ -1457,14 +1481,14 @@ var Watcher = class extends import_events.EventEmitter {
1457
1481
  }
1458
1482
  if (type === "document") {
1459
1483
  const doc = body.data;
1460
- if (doc) this.emit("document", doc);
1484
+ if (doc) this.emitDocuments([doc]);
1461
1485
  return;
1462
1486
  }
1463
1487
  if (type === "done") {
1464
1488
  const payload2 = body.data || body;
1465
1489
  const data = payload2.data || [];
1466
1490
  if (data.length) this.emitDocuments(data);
1467
- this.emit("done", { status: "completed", data, id: this.jobId });
1491
+ this.emit("done", { status: "completed", data, id: this.jobId, total: payload2.total, completed: payload2.completed, creditsUsed: payload2.creditsUsed });
1468
1492
  this.close();
1469
1493
  return;
1470
1494
  }
@@ -1472,7 +1496,10 @@ var Watcher = class extends import_events.EventEmitter {
1472
1496
  if (payload && payload.status) this.emitSnapshot(payload);
1473
1497
  } catch {
1474
1498
  }
1475
- if (timeoutMs && Date.now() - startTs > timeoutMs) this.close();
1499
+ if (timeoutMs && Date.now() - startTs > timeoutMs) {
1500
+ this.emit("error", { status: "failed", data: [], error: "Watcher timeout", id: this.jobId });
1501
+ this.close();
1502
+ }
1476
1503
  };
1477
1504
  ws.onerror = () => {
1478
1505
  this.emit("error", { status: "failed", data: [], error: "WebSocket error", id: this.jobId });
@@ -1528,7 +1555,7 @@ var Watcher = class extends import_events.EventEmitter {
1528
1555
  };
1529
1556
  this.emit("snapshot", snap);
1530
1557
  if (["completed", "failed", "cancelled"].includes(status)) {
1531
- this.emit("done", { status, data, id: this.jobId });
1558
+ this.emit("done", { status, data, id: this.jobId, total: payload.total ?? 0, completed: payload.completed ?? 0, creditsUsed: payload.creditsUsed });
1532
1559
  this.close();
1533
1560
  }
1534
1561
  }
@@ -1541,13 +1568,17 @@ var Watcher = class extends import_events.EventEmitter {
1541
1568
  this.emitDocuments(snap.data || []);
1542
1569
  this.emit("snapshot", snap);
1543
1570
  if (["completed", "failed", "cancelled"].includes(snap.status)) {
1544
- this.emit("done", { status: snap.status, data: snap.data, id: this.jobId });
1571
+ this.emit("done", { status: snap.status, data: snap.data, id: this.jobId, total: snap.total ?? 0, completed: snap.completed ?? 0, creditsUsed: snap.creditsUsed });
1545
1572
  this.close();
1546
1573
  break;
1547
1574
  }
1548
1575
  } catch {
1549
1576
  }
1550
- if (timeoutMs && Date.now() - startTs > timeoutMs) break;
1577
+ if (timeoutMs && Date.now() - startTs > timeoutMs) {
1578
+ this.emit("error", { status: "failed", data: [], error: "Watcher timeout", id: this.jobId });
1579
+ this.close();
1580
+ break;
1581
+ }
1551
1582
  await new Promise((r) => setTimeout(r, Math.max(1e3, this.pollInterval * 1e3)));
1552
1583
  }
1553
1584
  }
package/dist/index.d.cts CHANGED
@@ -395,6 +395,8 @@ interface SearchRequest {
395
395
  type: 'web' | 'news' | 'images';
396
396
  }>;
397
397
  categories?: Array<'github' | 'research' | 'pdf' | CategoryOption>;
398
+ includeDomains?: string[];
399
+ excludeDomains?: string[];
398
400
  limit?: number;
399
401
  tbs?: string;
400
402
  location?: string;
package/dist/index.d.ts CHANGED
@@ -395,6 +395,8 @@ interface SearchRequest {
395
395
  type: 'web' | 'news' | 'images';
396
396
  }>;
397
397
  categories?: Array<'github' | 'research' | 'pdf' | CategoryOption>;
398
+ includeDomains?: string[];
399
+ excludeDomains?: string[];
398
400
  limit?: number;
399
401
  tbs?: string;
400
402
  location?: string;
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  require_package
3
- } from "./chunk-UXVHRV2G.js";
3
+ } from "./chunk-R625SBJY.js";
4
4
 
5
5
  // src/v2/utils/httpClient.ts
6
6
  import axios from "axios";
@@ -501,11 +501,17 @@ function prepareSearchPayload(req) {
501
501
  throw new Error("limit must be positive");
502
502
  if (req.timeout != null && req.timeout <= 0)
503
503
  throw new Error("timeout must be positive");
504
+ if (req.includeDomains?.length && req.excludeDomains?.length)
505
+ throw new Error(
506
+ "includeDomains and excludeDomains cannot both be specified"
507
+ );
504
508
  const payload = {
505
509
  query: req.query
506
510
  };
507
511
  if (req.sources) payload.sources = req.sources;
508
512
  if (req.categories) payload.categories = req.categories;
513
+ if (req.includeDomains) payload.includeDomains = req.includeDomains;
514
+ if (req.excludeDomains) payload.excludeDomains = req.excludeDomains;
509
515
  if (req.limit != null) payload.limit = req.limit;
510
516
  if (req.tbs != null) payload.tbs = req.tbs;
511
517
  if (req.location != null) payload.location = req.location;
@@ -1294,23 +1300,41 @@ var Watcher = class extends EventEmitter {
1294
1300
  return `${wsBase}${path}`;
1295
1301
  }
1296
1302
  async start() {
1297
- try {
1298
- const url = this.buildWsUrl();
1299
- const wsCtor = await getWebSocketCtor();
1300
- if (!wsCtor) {
1301
- this.pollLoop();
1302
- return;
1303
- }
1304
- this.ws = new wsCtor(url, this.http.getApiKey());
1305
- if (this.ws && "binaryType" in this.ws) {
1306
- this.ws.binaryType = "arraybuffer";
1307
- }
1308
- if (this.ws) {
1309
- this.attachWsHandlers(this.ws);
1310
- }
1311
- } catch (err) {
1312
- this.pollLoop();
1313
- }
1303
+ return new Promise((resolve, reject) => {
1304
+ const onDone = () => {
1305
+ cleanup();
1306
+ resolve();
1307
+ };
1308
+ const onError = (err) => {
1309
+ cleanup();
1310
+ resolve();
1311
+ };
1312
+ const cleanup = () => {
1313
+ this.removeListener("done", onDone);
1314
+ this.removeListener("error", onError);
1315
+ };
1316
+ this.on("done", onDone);
1317
+ this.on("error", onError);
1318
+ (async () => {
1319
+ try {
1320
+ const url = this.buildWsUrl();
1321
+ const wsCtor = await getWebSocketCtor();
1322
+ if (!wsCtor) {
1323
+ this.pollLoop();
1324
+ return;
1325
+ }
1326
+ this.ws = new wsCtor(url, this.http.getApiKey());
1327
+ if (this.ws && "binaryType" in this.ws) {
1328
+ this.ws.binaryType = "arraybuffer";
1329
+ }
1330
+ if (this.ws) {
1331
+ this.attachWsHandlers(this.ws);
1332
+ }
1333
+ } catch (err) {
1334
+ this.pollLoop();
1335
+ }
1336
+ })();
1337
+ });
1314
1338
  }
1315
1339
  attachWsHandlers(ws) {
1316
1340
  let startTs = Date.now();
@@ -1333,14 +1357,14 @@ var Watcher = class extends EventEmitter {
1333
1357
  }
1334
1358
  if (type === "document") {
1335
1359
  const doc = body.data;
1336
- if (doc) this.emit("document", doc);
1360
+ if (doc) this.emitDocuments([doc]);
1337
1361
  return;
1338
1362
  }
1339
1363
  if (type === "done") {
1340
1364
  const payload2 = body.data || body;
1341
1365
  const data = payload2.data || [];
1342
1366
  if (data.length) this.emitDocuments(data);
1343
- this.emit("done", { status: "completed", data, id: this.jobId });
1367
+ this.emit("done", { status: "completed", data, id: this.jobId, total: payload2.total, completed: payload2.completed, creditsUsed: payload2.creditsUsed });
1344
1368
  this.close();
1345
1369
  return;
1346
1370
  }
@@ -1348,7 +1372,10 @@ var Watcher = class extends EventEmitter {
1348
1372
  if (payload && payload.status) this.emitSnapshot(payload);
1349
1373
  } catch {
1350
1374
  }
1351
- if (timeoutMs && Date.now() - startTs > timeoutMs) this.close();
1375
+ if (timeoutMs && Date.now() - startTs > timeoutMs) {
1376
+ this.emit("error", { status: "failed", data: [], error: "Watcher timeout", id: this.jobId });
1377
+ this.close();
1378
+ }
1352
1379
  };
1353
1380
  ws.onerror = () => {
1354
1381
  this.emit("error", { status: "failed", data: [], error: "WebSocket error", id: this.jobId });
@@ -1404,7 +1431,7 @@ var Watcher = class extends EventEmitter {
1404
1431
  };
1405
1432
  this.emit("snapshot", snap);
1406
1433
  if (["completed", "failed", "cancelled"].includes(status)) {
1407
- this.emit("done", { status, data, id: this.jobId });
1434
+ this.emit("done", { status, data, id: this.jobId, total: payload.total ?? 0, completed: payload.completed ?? 0, creditsUsed: payload.creditsUsed });
1408
1435
  this.close();
1409
1436
  }
1410
1437
  }
@@ -1417,13 +1444,17 @@ var Watcher = class extends EventEmitter {
1417
1444
  this.emitDocuments(snap.data || []);
1418
1445
  this.emit("snapshot", snap);
1419
1446
  if (["completed", "failed", "cancelled"].includes(snap.status)) {
1420
- this.emit("done", { status: snap.status, data: snap.data, id: this.jobId });
1447
+ this.emit("done", { status: snap.status, data: snap.data, id: this.jobId, total: snap.total ?? 0, completed: snap.completed ?? 0, creditsUsed: snap.creditsUsed });
1421
1448
  this.close();
1422
1449
  break;
1423
1450
  }
1424
1451
  } catch {
1425
1452
  }
1426
- if (timeoutMs && Date.now() - startTs > timeoutMs) break;
1453
+ if (timeoutMs && Date.now() - startTs > timeoutMs) {
1454
+ this.emit("error", { status: "failed", data: [], error: "Watcher timeout", id: this.jobId });
1455
+ this.close();
1456
+ break;
1457
+ }
1427
1458
  await new Promise((r) => setTimeout(r, Math.max(1e3, this.pollInterval * 1e3)));
1428
1459
  }
1429
1460
  }
@@ -1778,7 +1809,7 @@ var FirecrawlApp = class {
1778
1809
  if (typeof process !== "undefined" && process.env && process.env.npm_package_version) {
1779
1810
  return process.env.npm_package_version;
1780
1811
  }
1781
- const packageJson = await import("./package-ELM7Z5VP.js");
1812
+ const packageJson = await import("./package-MRLSD24T.js");
1782
1813
  return packageJson.default.version;
1783
1814
  } catch (error) {
1784
1815
  const isTest = typeof process !== "undefined" && (process.env.JEST_WORKER_ID != null || false);
@@ -1,4 +1,4 @@
1
1
  import {
2
2
  require_package
3
- } from "./chunk-UXVHRV2G.js";
3
+ } from "./chunk-R625SBJY.js";
4
4
  export default require_package();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "firecrawl",
3
- "version": "4.20.0",
3
+ "version": "4.21.0",
4
4
  "description": "JavaScript SDK for Firecrawl API",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -20,11 +20,17 @@ function prepareSearchPayload(req: SearchRequest): Record<string, unknown> {
20
20
  throw new Error("limit must be positive");
21
21
  if (req.timeout != null && req.timeout <= 0)
22
22
  throw new Error("timeout must be positive");
23
+ if (req.includeDomains?.length && req.excludeDomains?.length)
24
+ throw new Error(
25
+ "includeDomains and excludeDomains cannot both be specified",
26
+ );
23
27
  const payload: Record<string, unknown> = {
24
28
  query: req.query,
25
29
  };
26
30
  if (req.sources) payload.sources = req.sources;
27
31
  if (req.categories) payload.categories = req.categories;
32
+ if (req.includeDomains) payload.includeDomains = req.includeDomains;
33
+ if (req.excludeDomains) payload.excludeDomains = req.excludeDomains;
28
34
  if (req.limit != null) payload.limit = req.limit;
29
35
  if (req.tbs != null) payload.tbs = req.tbs;
30
36
  if (req.location != null) payload.location = req.location;
package/src/v2/types.ts CHANGED
@@ -508,6 +508,8 @@ export interface SearchRequest {
508
508
  'web' | 'news' | 'images' | { type: 'web' | 'news' | 'images' }
509
509
  >;
510
510
  categories?: Array<'github' | 'research' | 'pdf' | CategoryOption>;
511
+ includeDomains?: string[];
512
+ excludeDomains?: string[];
511
513
  limit?: number;
512
514
  tbs?: string;
513
515
  location?: string;
package/src/v2/watcher.ts CHANGED
@@ -109,24 +109,37 @@ export class Watcher extends EventEmitter {
109
109
  }
110
110
 
111
111
  async start(): Promise<void> {
112
- try {
113
- const url = this.buildWsUrl();
114
- const wsCtor = await getWebSocketCtor();
115
- if (!wsCtor) {
116
- this.pollLoop();
117
- return;
118
- }
119
- this.ws = new wsCtor(url, this.http.getApiKey()) as any;
120
- if (this.ws && "binaryType" in this.ws) {
121
- (this.ws as any).binaryType = "arraybuffer";
122
- }
123
-
124
- if (this.ws) {
125
- this.attachWsHandlers(this.ws);
126
- }
127
- } catch (err) {
128
- this.pollLoop();
129
- }
112
+ return new Promise<void>((resolve, reject) => {
113
+ const onDone = () => { cleanup(); resolve(); };
114
+ const onError = (err: any) => { cleanup(); resolve(); };
115
+ const cleanup = () => {
116
+ this.removeListener("done", onDone);
117
+ this.removeListener("error", onError);
118
+ };
119
+ this.on("done", onDone);
120
+ this.on("error", onError);
121
+
122
+ (async () => {
123
+ try {
124
+ const url = this.buildWsUrl();
125
+ const wsCtor = await getWebSocketCtor();
126
+ if (!wsCtor) {
127
+ this.pollLoop();
128
+ return;
129
+ }
130
+ this.ws = new wsCtor(url, this.http.getApiKey()) as any;
131
+ if (this.ws && "binaryType" in this.ws) {
132
+ (this.ws as any).binaryType = "arraybuffer";
133
+ }
134
+
135
+ if (this.ws) {
136
+ this.attachWsHandlers(this.ws);
137
+ }
138
+ } catch (err) {
139
+ this.pollLoop();
140
+ }
141
+ })();
142
+ });
130
143
  }
131
144
 
132
145
  private attachWsHandlers(ws: WebSocket) {
@@ -150,14 +163,14 @@ export class Watcher extends EventEmitter {
150
163
  }
151
164
  if (type === "document") {
152
165
  const doc = body.data;
153
- if (doc) this.emit("document", doc as Document & { id: string });
166
+ if (doc) this.emitDocuments([doc]);
154
167
  return;
155
168
  }
156
169
  if (type === "done") {
157
170
  const payload = body.data || body;
158
171
  const data = (payload.data || []) as Document[];
159
172
  if (data.length) this.emitDocuments(data);
160
- this.emit("done", { status: "completed", data, id: this.jobId });
173
+ this.emit("done", { status: "completed", data, id: this.jobId, total: payload.total, completed: payload.completed, creditsUsed: payload.creditsUsed });
161
174
  this.close();
162
175
  return;
163
176
  }
@@ -166,7 +179,10 @@ export class Watcher extends EventEmitter {
166
179
  } catch {
167
180
  // ignore
168
181
  }
169
- if (timeoutMs && Date.now() - startTs > timeoutMs) this.close();
182
+ if (timeoutMs && Date.now() - startTs > timeoutMs) {
183
+ this.emit("error", { status: "failed", data: [], error: "Watcher timeout", id: this.jobId });
184
+ this.close();
185
+ }
170
186
  };
171
187
  ws.onerror = () => {
172
188
  this.emit("error", { status: "failed", data: [], error: "WebSocket error", id: this.jobId });
@@ -227,7 +243,7 @@ export class Watcher extends EventEmitter {
227
243
  };
228
244
  this.emit("snapshot", snap);
229
245
  if (["completed", "failed", "cancelled"].includes(status)) {
230
- this.emit("done", { status, data, id: this.jobId });
246
+ this.emit("done", { status, data, id: this.jobId, total: payload.total ?? 0, completed: payload.completed ?? 0, creditsUsed: payload.creditsUsed });
231
247
  this.close();
232
248
  }
233
249
  }
@@ -243,14 +259,18 @@ export class Watcher extends EventEmitter {
243
259
  this.emitDocuments((snap.data || []) as Document[]);
244
260
  this.emit("snapshot", snap);
245
261
  if (["completed", "failed", "cancelled"].includes(snap.status)) {
246
- this.emit("done", { status: snap.status, data: snap.data, id: this.jobId });
262
+ this.emit("done", { status: snap.status, data: snap.data, id: this.jobId, total: (snap as any).total ?? 0, completed: (snap as any).completed ?? 0, creditsUsed: (snap as any).creditsUsed });
247
263
  this.close();
248
264
  break;
249
265
  }
250
266
  } catch {
251
267
  // ignore polling errors
252
268
  }
253
- if (timeoutMs && Date.now() - startTs > timeoutMs) break;
269
+ if (timeoutMs && Date.now() - startTs > timeoutMs) {
270
+ this.emit("error", { status: "failed", data: [], error: "Watcher timeout", id: this.jobId });
271
+ this.close();
272
+ break;
273
+ }
254
274
  await new Promise((r) => setTimeout(r, Math.max(1000, this.pollInterval * 1000)));
255
275
  }
256
276
  }