From 6c574be0f29a309f205ecd7728bb358a8ccb74c2 Mon Sep 17 00:00:00 2001 From: Abimael Martell Date: Tue, 13 Jan 2026 09:55:39 -0800 Subject: [PATCH 1/2] Add timing information to scrape --- src/commands/scrape.ts | 117 +++++++++++++++++++++++++++-------------- src/index.ts | 5 ++ src/types/scrape.ts | 2 + src/utils/options.ts | 1 + 4 files changed, 86 insertions(+), 39 deletions(-) diff --git a/src/commands/scrape.ts b/src/commands/scrape.ts index 5bad3239f..dcf95e2c8 100644 --- a/src/commands/scrape.ts +++ b/src/commands/scrape.ts @@ -7,69 +7,108 @@ import type { ScrapeOptions, ScrapeResult } from '../types/scrape'; import { getClient } from '../utils/client'; import { handleScrapeOutput } from '../utils/output'; +/** + * Output timing information if requested + */ +function outputTiming( + options: ScrapeOptions, + requestStartTime: number, + requestEndTime: number, + error?: Error | unknown +): void { + if (!options.timing) return; + + const requestDuration = requestEndTime - requestStartTime; + const timingInfo: { + url: string; + requestTime: string; + duration: string; + status: 'success' | 'error'; + error?: string; + } = { + url: options.url, + requestTime: new Date(requestStartTime).toISOString(), + duration: `${requestDuration}ms`, + status: error ? 'error' : 'success', + }; + + if (error) { + timingInfo.error = error instanceof Error ? error.message : 'Unknown error'; + } + + console.error('Timing:', JSON.stringify(timingInfo, null, 2)); +} + /** * Execute the scrape command */ export async function executeScrape( options: ScrapeOptions ): Promise { - try { - // Get client instance (updates global config if apiKey provided) - const app = getClient({ apiKey: options.apiKey }); + // Get client instance (updates global config if apiKey provided) + const app = getClient({ apiKey: options.apiKey }); - // Build scrape options - const formats: FormatOption[] = []; + // Build scrape options + const formats: FormatOption[] = []; - if (options.format) { - formats.push(options.format); - } + if (options.format) { + formats.push(options.format); + } - if (options.screenshot) { - // Add screenshot format if not already included - if (!formats.includes('screenshot')) { - formats.push('screenshot'); - } + if (options.screenshot) { + // Add screenshot format if not already included + if (!formats.includes('screenshot')) { + formats.push('screenshot'); } + } - // If no formats specified, default to markdown - if (formats.length === 0) { - formats.push('markdown'); - } + // If no formats specified, default to markdown + if (formats.length === 0) { + formats.push('markdown'); + } - const scrapeParams: { - formats?: FormatOption[]; - onlyMainContent?: boolean; - waitFor?: number; - includeTags?: string[]; - excludeTags?: string[]; - } = { - formats, - }; + const scrapeParams: { + formats?: FormatOption[]; + onlyMainContent?: boolean; + waitFor?: number; + includeTags?: string[]; + excludeTags?: string[]; + } = { + formats, + }; - if (options.onlyMainContent !== undefined) { - scrapeParams.onlyMainContent = options.onlyMainContent; - } + if (options.onlyMainContent !== undefined) { + scrapeParams.onlyMainContent = options.onlyMainContent; + } - if (options.waitFor !== undefined) { - scrapeParams.waitFor = options.waitFor; - } + if (options.waitFor !== undefined) { + scrapeParams.waitFor = options.waitFor; + } - if (options.includeTags && options.includeTags.length > 0) { - scrapeParams.includeTags = options.includeTags; - } + if (options.includeTags && options.includeTags.length > 0) { + scrapeParams.includeTags = options.includeTags; + } - if (options.excludeTags && options.excludeTags.length > 0) { - scrapeParams.excludeTags = options.excludeTags; - } + if (options.excludeTags && options.excludeTags.length > 0) { + scrapeParams.excludeTags = options.excludeTags; + } - // Execute scrape + // Execute scrape with timing - only wrap the scrape call in try-catch + const requestStartTime = Date.now(); + + try { const result = await app.scrape(options.url, scrapeParams); + const requestEndTime = Date.now(); + outputTiming(options, requestStartTime, requestEndTime); return { success: true, data: result, }; } catch (error) { + const requestEndTime = Date.now(); + outputTiming(options, requestStartTime, requestEndTime, error); + return { success: false, error: error instanceof Error ? error.message : 'Unknown error occurred', diff --git a/src/index.ts b/src/index.ts index ba92997c6..fc00ffab8 100644 --- a/src/index.ts +++ b/src/index.ts @@ -73,6 +73,11 @@ function createScrapeCommand(): Command { ) .option('-o, --output ', 'Output file path (default: stdout)') .option('--pretty', 'Pretty print JSON output', false) + .option( + '--timing', + 'Show request timing and other useful information', + false + ) .action(async (positionalUrl, options) => { // Use positional URL if provided, otherwise use --url option const url = positionalUrl || options.url; diff --git a/src/types/scrape.ts b/src/types/scrape.ts index 508a25ef6..dca3a18ec 100644 --- a/src/types/scrape.ts +++ b/src/types/scrape.ts @@ -36,6 +36,8 @@ export interface ScrapeOptions { output?: string; /** Pretty print JSON output */ pretty?: boolean; + /** Show request timing and other useful information */ + timing?: boolean; } export interface ScrapeResult { diff --git a/src/utils/options.ts b/src/utils/options.ts index 2c3207070..dfd1f94df 100644 --- a/src/utils/options.ts +++ b/src/utils/options.ts @@ -23,5 +23,6 @@ export function parseScrapeOptions(options: any): ScrapeOptions { apiKey: options.apiKey, output: options.output, pretty: options.pretty, + timing: options.timing, }; } From 785cefc0ae490bc74a22dcfd39d3ed54fd3fa173 Mon Sep 17 00:00:00 2001 From: Abimael Martell Date: Tue, 13 Jan 2026 10:47:45 -0800 Subject: [PATCH 2/2] bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index dfa197408..7889d20f6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "firecrawl-cli", - "version": "0.0.4", + "version": "0.0.5", "description": "Command-line interface for Firecrawl. Scrape, crawl, and extract data from any website directly from your terminal.", "main": "dist/index.js", "bin": {