From b0f9ea6f7af933f7d0a3cf589018407786db4e24 Mon Sep 17 00:00:00 2001 From: Developers Digest <124798203+developersdigest@users.noreply.github.com> Date: Fri, 22 May 2026 12:19:37 -0400 Subject: [PATCH 1/2] send session_id header on api requests --- src/commands/monitor.ts | 2 ++ src/commands/parse.ts | 6 +++++- src/utils/client.ts | 34 ++++++++++++++++++++++++++++++++-- src/utils/session-tracking.ts | 17 +++++++++++++++++ 4 files changed, 56 insertions(+), 3 deletions(-) create mode 100644 src/utils/session-tracking.ts diff --git a/src/commands/monitor.ts b/src/commands/monitor.ts index f042ec922..e2158c253 100644 --- a/src/commands/monitor.ts +++ b/src/commands/monitor.ts @@ -20,6 +20,7 @@ import * as fs from 'fs'; import { Command } from 'commander'; import { getConfig, validateConfig } from '../utils/config'; import { writeOutput } from '../utils/output'; +import { getSessionHeaders } from '../utils/session-tracking'; const DEFAULT_API_URL = 'https://api.firecrawl.dev'; @@ -63,6 +64,7 @@ async function monitorRequest( const headers: Record = { Authorization: `Bearer ${apiKey}`, 'X-Origin': 'cli', + ...getSessionHeaders(), }; if (init.body !== undefined) headers['Content-Type'] = 'application/json'; diff --git a/src/commands/parse.ts b/src/commands/parse.ts index 1fd481fc9..adfb0e4ea 100644 --- a/src/commands/parse.ts +++ b/src/commands/parse.ts @@ -14,6 +14,7 @@ import type { ScrapeFormat } from '../types/scrape'; import { getClient } from '../utils/client'; import { getConfig, validateConfig } from '../utils/config'; import { handleScrapeOutput } from '../utils/output'; +import { getSessionHeaders } from '../utils/session-tracking'; const DEFAULT_API_URL = 'https://api.firecrawl.dev'; @@ -181,7 +182,10 @@ export async function executeParse( try { const response = await fetch(`${apiUrl}/v2/parse`, { method: 'POST', - headers: apiKey ? { Authorization: `Bearer ${apiKey}` } : undefined, + headers: { + ...(apiKey ? { Authorization: `Bearer ${apiKey}` } : {}), + ...getSessionHeaders(), + }, body: form, }); diff --git a/src/utils/client.ts b/src/utils/client.ts index 317e093ef..6e901d20c 100644 --- a/src/utils/client.ts +++ b/src/utils/client.ts @@ -11,9 +11,39 @@ import { updateConfig, type GlobalConfig, } from './config'; +import { getSessionHeaders } from './session-tracking'; let clientInstance: Firecrawl | null = null; +function attachSessionHeaders(client: Firecrawl): Firecrawl { + const headers = getSessionHeaders(); + if (Object.keys(headers).length === 0) return client; + + const httpClient = ( + client as unknown as { + http?: { + instance?: { + defaults?: { + headers?: Record & { + common?: Record; + }; + }; + }; + }; + } + ).http; + const defaultHeaders = httpClient?.instance?.defaults?.headers; + if (!defaultHeaders) return client; + + if (!defaultHeaders.common) { + defaultHeaders.common = {}; + } + for (const [key, value] of Object.entries(headers)) { + (defaultHeaders.common as Record)[key] = value; + } + return client; +} + /** * Get or create the Firecrawl client instance * Uses global configuration if available, otherwise creates with provided options @@ -68,7 +98,7 @@ export function getClient( backoffFactor: options.backoffFactor ?? config.backoffFactor, }; - return new Firecrawl(clientOptions); + return attachSessionHeaders(new Firecrawl(clientOptions)); } // Return singleton instance or create one @@ -84,7 +114,7 @@ export function getClient( backoffFactor: config.backoffFactor, }; - clientInstance = new Firecrawl(clientOptions); + clientInstance = attachSessionHeaders(new Firecrawl(clientOptions)); } return clientInstance; diff --git a/src/utils/session-tracking.ts b/src/utils/session-tracking.ts new file mode 100644 index 000000000..bb931d231 --- /dev/null +++ b/src/utils/session-tracking.ts @@ -0,0 +1,17 @@ +import { randomUUID } from 'crypto'; + +let cachedSessionId: string | null = null; +export function getSessionId(): string { + if (!cachedSessionId) { + cachedSessionId = randomUUID(); + } + return cachedSessionId; +} + +export type SessionHeaders = Record; + +export function getSessionHeaders(): SessionHeaders { + return { + 'x-firecrawl-session-id': getSessionId(), + }; +} From dbfb3b3b55d8941d5167e9c9a646c04a59820a9d Mon Sep 17 00:00:00 2001 From: Developers Digest <124798203+developersdigest@users.noreply.github.com> Date: Fri, 22 May 2026 13:55:32 -0400 Subject: [PATCH 2/2] Update session-tracking.ts --- src/utils/session-tracking.ts | 58 ++++++++++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 4 deletions(-) diff --git a/src/utils/session-tracking.ts b/src/utils/session-tracking.ts index bb931d231..a1269128a 100644 --- a/src/utils/session-tracking.ts +++ b/src/utils/session-tracking.ts @@ -1,11 +1,61 @@ +import * as fs from 'fs'; +import * as path from 'path'; import { randomUUID } from 'crypto'; +import { getConfigDirectoryPath } from './credentials'; + +const SESSION_FILE = 'session.json'; +const SESSION_TTL_MS = 30 * 60 * 1000; + +type StoredSession = { id: string; last_active_at: number }; + +function sessionFilePath(): string { + return path.join(getConfigDirectoryPath(), SESSION_FILE); +} + +function readSession(): StoredSession | null { + try { + const raw = fs.readFileSync(sessionFilePath(), 'utf8'); + const parsed = JSON.parse(raw); + if ( + parsed && + typeof parsed.id === 'string' && + typeof parsed.last_active_at === 'number' + ) { + return parsed as StoredSession; + } + } catch { + // ignore + } + return null; +} + +function writeSession(session: StoredSession): void { + try { + const dir = path.dirname(sessionFilePath()); + if (!fs.existsSync(dir)) { + fs.mkdirSync(dir, { recursive: true }); + } + fs.writeFileSync(sessionFilePath(), JSON.stringify(session)); + } catch { + // best-effort + } +} let cachedSessionId: string | null = null; + export function getSessionId(): string { - if (!cachedSessionId) { - cachedSessionId = randomUUID(); - } - return cachedSessionId; + if (cachedSessionId) return cachedSessionId; + + const now = Date.now(); + const existing = readSession(); + const id = + existing && now - existing.last_active_at < SESSION_TTL_MS + ? existing.id + : randomUUID(); + + writeSession({ id, last_active_at: now }); + cachedSessionId = id; + return id; } export type SessionHeaders = Record;