n8n-nodes-firecrawl-latest 1.0.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 (24) hide show
  1. package/LICENSE.md +19 -0
  2. package/README.md +232 -0
  3. package/dist/credentials/FirecrawlApi.credentials.js +22 -0
  4. package/dist/icons/flames-icon.svg +144 -0
  5. package/dist/nodes/Firecrawl/FireCrawlScraper.node.js +156 -0
  6. package/dist/nodes/Firecrawl/resources/batchScrape/batchScrape.methods.js +253 -0
  7. package/dist/nodes/Firecrawl/resources/batchScrape/batchScrape.properties.js +205 -0
  8. package/dist/nodes/Firecrawl/resources/crawler/crawler.methods.js +281 -0
  9. package/dist/nodes/Firecrawl/resources/crawler/crawler.properties.js +313 -0
  10. package/dist/nodes/Firecrawl/resources/deepResearch/deepResearch.methods.js +171 -0
  11. package/dist/nodes/Firecrawl/resources/deepResearch/deepResearch.properties.js +200 -0
  12. package/dist/nodes/Firecrawl/resources/extract/extract.methods.js +424 -0
  13. package/dist/nodes/Firecrawl/resources/extract/extract.properties.js +339 -0
  14. package/dist/nodes/Firecrawl/resources/llmsText/llmsText.methods.js +124 -0
  15. package/dist/nodes/Firecrawl/resources/llmsText/llmsText.properties.js +87 -0
  16. package/dist/nodes/Firecrawl/resources/map/map.methods.js +52 -0
  17. package/dist/nodes/Firecrawl/resources/map/map.properties.js +22 -0
  18. package/dist/nodes/Firecrawl/resources/scrape/scrape.methods.js +203 -0
  19. package/dist/nodes/Firecrawl/resources/scrape/scrape.properties.js +348 -0
  20. package/dist/nodes/HttpBin/HttpBin.node.js +59 -0
  21. package/dist/nodes/HttpBin/HttpVerbDescription.js +246 -0
  22. package/dist/nodes/HttpBin/httpbin.svg +18 -0
  23. package/index.js +7 -0
  24. package/package.json +58 -0
@@ -0,0 +1,203 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.scrapeMethods = void 0;
7
+ const firecrawl_js_1 = __importDefault(require("@mendable/firecrawl-js"));
8
+ const n8n_workflow_1 = require("n8n-workflow");
9
+ // Helper function to generate schema from JSON example
10
+ function generateSchemaFromExample(jsonExample) {
11
+ if (jsonExample === null) {
12
+ return { type: 'null' };
13
+ }
14
+ if (typeof jsonExample === 'string') {
15
+ return { type: 'string' };
16
+ }
17
+ if (typeof jsonExample === 'number') {
18
+ return { type: 'number' };
19
+ }
20
+ if (typeof jsonExample === 'boolean') {
21
+ return { type: 'boolean' };
22
+ }
23
+ if (Array.isArray(jsonExample)) {
24
+ if (jsonExample.length === 0) {
25
+ return {
26
+ type: 'array',
27
+ items: { type: 'string' }, // Default to string items for empty arrays
28
+ };
29
+ }
30
+ // Use the first item as a sample for the items schema
31
+ const itemSchema = generateSchemaFromExample(jsonExample[0]);
32
+ return {
33
+ type: 'array',
34
+ items: itemSchema,
35
+ };
36
+ }
37
+ if (typeof jsonExample === 'object') {
38
+ const properties = {};
39
+ for (const [key, value] of Object.entries(jsonExample)) {
40
+ properties[key] = generateSchemaFromExample(value);
41
+ }
42
+ return {
43
+ type: 'object',
44
+ properties,
45
+ required: Object.keys(properties),
46
+ };
47
+ }
48
+ // Default fallback
49
+ return { type: 'string' };
50
+ }
51
+ exports.scrapeMethods = {
52
+ async execute() {
53
+ const items = this.getInputData();
54
+ const returnData = [];
55
+ // Get credentials
56
+ const credentials = await this.getCredentials('firecrawlApi');
57
+ const apiKey = credentials.apiKey;
58
+ // Initialize Firecrawl app
59
+ const firecrawl = new firecrawl_js_1.default({ apiKey });
60
+ // Process each item
61
+ for (let i = 0; i < items.length; i++) {
62
+ try {
63
+ // Get parameters
64
+ const url = this.getNodeParameter('url', i);
65
+ const outputFormats = this.getNodeParameter('outputFormats', i, ['markdown']);
66
+ const enableDebugLogs = this.getNodeParameter('enableDebugLogs', i, false);
67
+ const includeExtract = this.getNodeParameter('includeExtract', i, false);
68
+ const includeActions = this.getNodeParameter('includeActions', i, false);
69
+ const includeLocation = this.getNodeParameter('includeLocation', i, false);
70
+ const trackChanges = this.getNodeParameter('trackChanges', i, false);
71
+ const useFire1Agent = this.getNodeParameter('useFire1Agent', i, false);
72
+ // Create scrape options
73
+ const scrapeOptions = {
74
+ formats: outputFormats,
75
+ };
76
+ // Add change tracking if enabled
77
+ if (trackChanges) {
78
+ const changeTrackingModes = this.getNodeParameter('changeTrackingMode', i, ['git-diff']);
79
+ if (!scrapeOptions.formats.includes('changeTracking')) {
80
+ scrapeOptions.formats.push('changeTracking');
81
+ }
82
+ scrapeOptions.changeTrackingOptions = {
83
+ modes: changeTrackingModes,
84
+ };
85
+ // Add JSON schema for change tracking if JSON mode is selected
86
+ if (changeTrackingModes.includes('json')) {
87
+ const changeTrackingSchema = JSON.parse(this.getNodeParameter('changeTrackingSchema', i, '{}'));
88
+ scrapeOptions.changeTrackingOptions.schema = changeTrackingSchema;
89
+ }
90
+ }
91
+ // Add extraction if needed
92
+ if (includeExtract) {
93
+ const extractionMethod = this.getNodeParameter('extractionMethod', i);
94
+ // We need to use 'json' as the format name for extraction
95
+ if (!scrapeOptions.formats.includes('json')) {
96
+ scrapeOptions.formats.push('json');
97
+ }
98
+ scrapeOptions.jsonOptions = {};
99
+ if (extractionMethod === 'simple') {
100
+ const extractionPrompt = this.getNodeParameter('extractionPrompt', i);
101
+ scrapeOptions.jsonOptions.prompt = extractionPrompt;
102
+ }
103
+ else {
104
+ // Schema-based extraction
105
+ const schemaDefinitionType = this.getNodeParameter('schemaDefinitionType', i);
106
+ let schema;
107
+ if (schemaDefinitionType === 'example') {
108
+ const jsonExample = JSON.parse(this.getNodeParameter('jsonExample', i));
109
+ schema = generateSchemaFromExample(jsonExample);
110
+ }
111
+ else {
112
+ // Manual schema definition
113
+ schema = JSON.parse(this.getNodeParameter('schemaDefinition', i));
114
+ }
115
+ scrapeOptions.jsonOptions.schema = schema;
116
+ }
117
+ // Add system prompt if provided
118
+ const systemPrompt = this.getNodeParameter('systemPrompt', i, '');
119
+ if (systemPrompt) {
120
+ scrapeOptions.jsonOptions.systemPrompt = systemPrompt;
121
+ }
122
+ }
123
+ // Add FIRE-1 agent if enabled
124
+ if (useFire1Agent) {
125
+ scrapeOptions.agent = {
126
+ model: 'FIRE-1',
127
+ };
128
+ }
129
+ // Add page actions if needed
130
+ if (includeActions) {
131
+ const pageActionsString = this.getNodeParameter('pageActions', i);
132
+ try {
133
+ const pageActions = JSON.parse(pageActionsString);
134
+ if (useFire1Agent) {
135
+ // If using FIRE-1, add actions to the agent config
136
+ scrapeOptions.agent.actions = pageActions;
137
+ }
138
+ else {
139
+ // Otherwise add them as regular actions
140
+ scrapeOptions.actions = pageActions;
141
+ }
142
+ }
143
+ catch (e) {
144
+ throw new Error(`Invalid page actions JSON: ${e instanceof Error ? e.message : String(e)}`);
145
+ }
146
+ }
147
+ // Add location settings if needed
148
+ if (includeLocation) {
149
+ const country = this.getNodeParameter('country', i, 'US');
150
+ const languagesString = this.getNodeParameter('languages', i, '');
151
+ scrapeOptions.location = {
152
+ country,
153
+ };
154
+ if (languagesString) {
155
+ const languages = languagesString.split(',').map(lang => lang.trim());
156
+ scrapeOptions.location.languages = languages;
157
+ }
158
+ }
159
+ // Log the scrape parameters if debug is enabled
160
+ if (enableDebugLogs) {
161
+ console.log('URL:', url);
162
+ console.log('Scrape options:', JSON.stringify(scrapeOptions, null, 2));
163
+ }
164
+ // Scrape URL
165
+ const scrapeResponse = await firecrawl.scrapeUrl(url, scrapeOptions);
166
+ // Log the result if debug is enabled
167
+ if (enableDebugLogs) {
168
+ console.log('Scrape result:', JSON.stringify(scrapeResponse, null, 2));
169
+ }
170
+ // Add result to return data
171
+ returnData.push({
172
+ json: {
173
+ success: true,
174
+ data: scrapeResponse,
175
+ debug: enableDebugLogs
176
+ ? {
177
+ url,
178
+ options: scrapeOptions,
179
+ }
180
+ : undefined,
181
+ },
182
+ });
183
+ }
184
+ catch (error) {
185
+ const errorMessage = error instanceof Error ? error.message : String(error);
186
+ console.error('Scrape error:', errorMessage);
187
+ if (this.continueOnFail()) {
188
+ returnData.push({
189
+ json: {
190
+ success: false,
191
+ error: errorMessage,
192
+ },
193
+ });
194
+ continue;
195
+ }
196
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), error, {
197
+ itemIndex: i,
198
+ });
199
+ }
200
+ }
201
+ return [returnData];
202
+ },
203
+ };
@@ -0,0 +1,348 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.scrapeProperties = void 0;
4
+ // Fields for the Scrape resource
5
+ const scrapeFields = [
6
+ {
7
+ displayName: 'URL',
8
+ name: 'url',
9
+ type: 'string',
10
+ displayOptions: {
11
+ show: {
12
+ resource: ['scrape'],
13
+ },
14
+ },
15
+ default: '',
16
+ required: true,
17
+ description: 'The URL to scrape',
18
+ placeholder: 'https://example.com',
19
+ },
20
+ {
21
+ displayName: 'Output Formats',
22
+ name: 'outputFormats',
23
+ type: 'multiOptions',
24
+ displayOptions: {
25
+ show: {
26
+ resource: ['scrape'],
27
+ },
28
+ },
29
+ options: [
30
+ {
31
+ name: 'Full Page Screenshot',
32
+ value: 'screenshot@fullPage',
33
+ description: 'Return a screenshot of the entire page',
34
+ },
35
+ {
36
+ name: 'HTML',
37
+ value: 'html',
38
+ description: 'Return the content in HTML format (with some cleaning)',
39
+ },
40
+ {
41
+ name: 'Links',
42
+ value: 'links',
43
+ description: 'Return a list of links found on the page',
44
+ },
45
+ {
46
+ name: 'Markdown',
47
+ value: 'markdown',
48
+ description: 'Return the content in Markdown format',
49
+ },
50
+ {
51
+ name: 'Raw HTML',
52
+ value: 'rawHtml',
53
+ description: 'Return the raw HTML content with no modifications',
54
+ },
55
+ {
56
+ name: 'Screenshot',
57
+ value: 'screenshot',
58
+ description: 'Return a screenshot of the visible part of the page',
59
+ },
60
+ ],
61
+ default: ['markdown'],
62
+ description: 'The formats in which to return the scraped content',
63
+ },
64
+ {
65
+ displayName: 'Track Changes',
66
+ name: 'trackChanges',
67
+ type: 'boolean',
68
+ displayOptions: {
69
+ show: {
70
+ resource: ['scrape'],
71
+ },
72
+ },
73
+ default: false,
74
+ description: 'Whether to track changes between the current and previous scrapes',
75
+ },
76
+ {
77
+ displayName: 'Change Tracking Mode',
78
+ name: 'changeTrackingMode',
79
+ type: 'multiOptions',
80
+ displayOptions: {
81
+ show: {
82
+ resource: ['scrape'],
83
+ trackChanges: [true],
84
+ },
85
+ },
86
+ options: [
87
+ {
88
+ name: 'Git-Diff',
89
+ value: 'git-diff',
90
+ description: 'Track changes using Git-style diff format',
91
+ },
92
+ {
93
+ name: 'JSON',
94
+ value: 'json',
95
+ description: 'Track changes in structured JSON format',
96
+ },
97
+ ],
98
+ default: ['git-diff'],
99
+ description: 'The modes to use for change tracking',
100
+ },
101
+ {
102
+ displayName: 'JSON Schema for Change Tracking',
103
+ name: 'changeTrackingSchema',
104
+ type: 'json',
105
+ typeOptions: {
106
+ alwaysOpenEditWindow: true,
107
+ rows: 8,
108
+ },
109
+ displayOptions: {
110
+ show: {
111
+ resource: ['scrape'],
112
+ trackChanges: [true],
113
+ changeTrackingMode: ['json'],
114
+ },
115
+ },
116
+ default: '{\n "type": "object",\n "properties": {\n "title": {\n "type": "string",\n "description": "The title of the page"\n },\n "content": {\n "type": "string",\n "description": "The main content of the page"\n }\n }\n}',
117
+ description: 'Schema for JSON-based change tracking',
118
+ },
119
+ {
120
+ displayName: 'Include Extract',
121
+ name: 'includeExtract',
122
+ type: 'boolean',
123
+ displayOptions: {
124
+ show: {
125
+ resource: ['scrape'],
126
+ },
127
+ },
128
+ default: false,
129
+ description: 'Whether to include structured data extraction with the scrape',
130
+ },
131
+ {
132
+ displayName: 'Extraction Method',
133
+ name: 'extractionMethod',
134
+ type: 'options',
135
+ displayOptions: {
136
+ show: {
137
+ resource: ['scrape'],
138
+ includeExtract: [true],
139
+ },
140
+ },
141
+ options: [
142
+ {
143
+ name: 'Simple Extraction',
144
+ value: 'simple',
145
+ description: 'Extract data using a prompt',
146
+ },
147
+ {
148
+ name: 'Schema Based Extraction',
149
+ value: 'schema',
150
+ description: 'Extract data using a defined schema',
151
+ },
152
+ ],
153
+ default: 'simple',
154
+ description: 'The method to use for extraction',
155
+ },
156
+ {
157
+ displayName: 'Extraction Prompt',
158
+ name: 'extractionPrompt',
159
+ type: 'string',
160
+ displayOptions: {
161
+ show: {
162
+ resource: ['scrape'],
163
+ includeExtract: [true],
164
+ extractionMethod: ['simple'],
165
+ },
166
+ },
167
+ default: '',
168
+ required: true,
169
+ description: 'The prompt to guide the extraction process',
170
+ placeholder: 'Extract the company mission from the page',
171
+ },
172
+ {
173
+ displayName: 'System Prompt',
174
+ name: 'systemPrompt',
175
+ type: 'string',
176
+ displayOptions: {
177
+ show: {
178
+ resource: ['scrape'],
179
+ includeExtract: [true],
180
+ },
181
+ },
182
+ default: '',
183
+ description: 'Optional system prompt to provide additional context for the extraction',
184
+ placeholder: 'You are a data extraction assistant that extracts specific information from web content.',
185
+ },
186
+ {
187
+ displayName: 'Schema Definition Type',
188
+ name: 'schemaDefinitionType',
189
+ type: 'options',
190
+ displayOptions: {
191
+ show: {
192
+ resource: ['scrape'],
193
+ includeExtract: [true],
194
+ extractionMethod: ['schema'],
195
+ },
196
+ },
197
+ options: [
198
+ {
199
+ name: 'Generate From JSON Example',
200
+ value: 'example',
201
+ description: 'Generate schema from a JSON example',
202
+ },
203
+ {
204
+ name: 'Define Below',
205
+ value: 'manual',
206
+ description: 'Define schema manually in JSON Schema format',
207
+ },
208
+ ],
209
+ default: 'manual',
210
+ description: 'How to define the schema for extraction',
211
+ },
212
+ {
213
+ displayName: 'JSON Example',
214
+ name: 'jsonExample',
215
+ type: 'json',
216
+ typeOptions: {
217
+ alwaysOpenEditWindow: true,
218
+ rows: 8,
219
+ },
220
+ displayOptions: {
221
+ show: {
222
+ resource: ['scrape'],
223
+ includeExtract: [true],
224
+ extractionMethod: ['schema'],
225
+ schemaDefinitionType: ['example'],
226
+ },
227
+ },
228
+ default: '{\n "company_mission": "Our mission is to...",\n "supports_sso": true,\n "is_open_source": false\n}',
229
+ description: 'A JSON example that represents the data structure you want to extract',
230
+ hint: 'Provide a JSON object that represents the structure you want to extract',
231
+ },
232
+ {
233
+ displayName: 'Schema Definition',
234
+ name: 'schemaDefinition',
235
+ type: 'json',
236
+ typeOptions: {
237
+ alwaysOpenEditWindow: true,
238
+ rows: 12,
239
+ },
240
+ displayOptions: {
241
+ show: {
242
+ resource: ['scrape'],
243
+ includeExtract: [true],
244
+ extractionMethod: ['schema'],
245
+ schemaDefinitionType: ['manual'],
246
+ },
247
+ },
248
+ default: '{\n "type": "object",\n "properties": {\n "company_mission": {\n "type": "string",\n "description": "The mission statement of the company"\n },\n "supports_sso": {\n "type": "boolean",\n "description": "Whether the product supports Single Sign-On"\n },\n "is_open_source": {\n "type": "boolean",\n "description": "Whether the product is open source"\n }\n },\n "required": ["company_mission"]\n}',
249
+ description: 'The schema definition in standard JSON Schema format. Define the structure you want to extract.',
250
+ hint: 'Use standard JSON Schema format with "type", "properties", and optional "required" fields',
251
+ },
252
+ {
253
+ displayName: 'Include Page Actions',
254
+ name: 'includeActions',
255
+ type: 'boolean',
256
+ displayOptions: {
257
+ show: {
258
+ resource: ['scrape'],
259
+ },
260
+ },
261
+ default: false,
262
+ description: 'Whether to perform actions on the page before scraping (for dynamic content)',
263
+ },
264
+ {
265
+ displayName: 'Page Actions',
266
+ name: 'pageActions',
267
+ type: 'json',
268
+ typeOptions: {
269
+ alwaysOpenEditWindow: true,
270
+ rows: 12,
271
+ },
272
+ displayOptions: {
273
+ show: {
274
+ resource: ['scrape'],
275
+ includeActions: [true],
276
+ },
277
+ },
278
+ default: '[\n { "type": "wait", "milliseconds": 2000 },\n { "type": "click", "selector": "button.accept-cookies" },\n { "type": "wait", "milliseconds": 1000 },\n { "type": "scrape" }\n]',
279
+ description: 'Actions to perform on the page before scraping (JSON array of action objects)',
280
+ hint: 'Common actions: wait, click, write, press, scrape, screenshot. See docs for full list.',
281
+ },
282
+ {
283
+ displayName: 'Use FIRE-1 Agent',
284
+ name: 'useFire1Agent',
285
+ type: 'boolean',
286
+ displayOptions: {
287
+ show: {
288
+ resource: ['scrape'],
289
+ },
290
+ },
291
+ default: false,
292
+ description: 'Whether to use the FIRE-1 agent for advanced scraping capabilities',
293
+ },
294
+ {
295
+ displayName: 'Location Settings',
296
+ name: 'includeLocation',
297
+ type: 'boolean',
298
+ displayOptions: {
299
+ show: {
300
+ resource: ['scrape'],
301
+ },
302
+ },
303
+ default: false,
304
+ description: 'Whether to specify location and language settings for the request',
305
+ },
306
+ {
307
+ displayName: 'Country Code',
308
+ name: 'country',
309
+ type: 'string',
310
+ displayOptions: {
311
+ show: {
312
+ resource: ['scrape'],
313
+ includeLocation: [true],
314
+ },
315
+ },
316
+ default: 'US',
317
+ description: 'ISO 3166-1 alpha-2 country code (e.g., US, DE, JP, BR)',
318
+ placeholder: 'US',
319
+ },
320
+ {
321
+ displayName: 'Languages',
322
+ name: 'languages',
323
+ type: 'string',
324
+ displayOptions: {
325
+ show: {
326
+ resource: ['scrape'],
327
+ includeLocation: [true],
328
+ },
329
+ },
330
+ default: '',
331
+ description: 'Comma-separated list of preferred languages (e.g., en-US,en,fr)',
332
+ placeholder: 'en-US,en',
333
+ },
334
+ {
335
+ displayName: 'Enable Debug Logs',
336
+ name: 'enableDebugLogs',
337
+ type: 'boolean',
338
+ displayOptions: {
339
+ show: {
340
+ resource: ['scrape'],
341
+ },
342
+ },
343
+ default: false,
344
+ description: 'Whether to enable debug logs in the output',
345
+ },
346
+ ];
347
+ // Export all properties for the Scrape resource
348
+ exports.scrapeProperties = [...scrapeFields];
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HttpBin = void 0;
4
+ const HttpVerbDescription_1 = require("./HttpVerbDescription");
5
+ class HttpBin {
6
+ constructor() {
7
+ this.description = {
8
+ displayName: 'HttpBin',
9
+ name: 'httpBin',
10
+ icon: 'file:httpbin.svg',
11
+ group: ['transform'],
12
+ version: 1,
13
+ subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
14
+ description: 'Interact with HttpBin API',
15
+ defaults: {
16
+ name: 'HttpBin',
17
+ },
18
+ inputs: ['main'],
19
+ outputs: ['main'],
20
+ requestDefaults: {
21
+ baseURL: 'https://httpbin.org',
22
+ url: '',
23
+ headers: {
24
+ Accept: 'application/json',
25
+ 'Content-Type': 'application/json',
26
+ },
27
+ },
28
+ /**
29
+ * In the properties array we have two mandatory options objects required
30
+ *
31
+ * [Resource & Operation]
32
+ *
33
+ * https://docs.n8n.io/integrations/creating-nodes/code/create-first-node/#resources-and-operations
34
+ *
35
+ * In our example, the operations are separated into their own file (HTTPVerbDescription.ts)
36
+ * to keep this class easy to read.
37
+ *
38
+ */
39
+ properties: [
40
+ {
41
+ displayName: 'Resource',
42
+ name: 'resource',
43
+ type: 'options',
44
+ noDataExpression: true,
45
+ options: [
46
+ {
47
+ name: 'HTTP Verb',
48
+ value: 'httpVerb',
49
+ },
50
+ ],
51
+ default: 'httpVerb',
52
+ },
53
+ ...HttpVerbDescription_1.httpVerbOperations,
54
+ ...HttpVerbDescription_1.httpVerbFields,
55
+ ],
56
+ };
57
+ }
58
+ }
59
+ exports.HttpBin = HttpBin;