Merge pull request #727 from mendableai/nsc/error-js-sdk-improv

Improves error handler in Node SDK to return the status code
This commit is contained in:
Nicolas 2024-10-03 17:36:31 -03:00 committed by GitHub
commit 85e9f7b9b9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 36 additions and 20 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "@mendable/firecrawl-js", "name": "@mendable/firecrawl-js",
"version": "1.5.2", "version": "1.5.3",
"description": "JavaScript SDK for Firecrawl API", "description": "JavaScript SDK for Firecrawl API",
"main": "dist/index.js", "main": "dist/index.js",
"types": "dist/index.d.ts", "types": "dist/index.d.ts",

View File

@ -199,6 +199,19 @@ export interface ErrorResponse {
error: string; error: string;
} }
/**
* Custom error class for Firecrawl.
* Extends the built-in Error class to include a status code.
*/
export class FirecrawlError extends Error {
statusCode: number;
constructor(message: string, statusCode: number) {
super(message);
this.statusCode = statusCode;
}
}
/** /**
* Main class for interacting with the Firecrawl API. * Main class for interacting with the Firecrawl API.
* Provides methods for scraping, searching, crawling, and mapping web content. * Provides methods for scraping, searching, crawling, and mapping web content.
@ -213,7 +226,7 @@ export default class FirecrawlApp {
*/ */
constructor({ apiKey = null, apiUrl = null }: FirecrawlAppConfig) { constructor({ apiKey = null, apiUrl = null }: FirecrawlAppConfig) {
if (typeof apiKey !== "string") { if (typeof apiKey !== "string") {
throw new Error("No API key provided"); throw new FirecrawlError("No API key provided", 401);
} }
this.apiKey = apiKey; this.apiKey = apiKey;
@ -268,13 +281,13 @@ export default class FirecrawlApp {
...responseData.data ...responseData.data
}; };
} else { } else {
throw new Error(`Failed to scrape URL. Error: ${responseData.error}`); throw new FirecrawlError(`Failed to scrape URL. Error: ${responseData.error}`, response.status);
} }
} else { } else {
this.handleError(response, "scrape URL"); this.handleError(response, "scrape URL");
} }
} catch (error: any) { } catch (error: any) {
throw new Error(error.message); throw new FirecrawlError(error.message, 500);
} }
return { success: false, error: "Internal server error." }; return { success: false, error: "Internal server error." };
} }
@ -289,7 +302,7 @@ export default class FirecrawlApp {
query: string, query: string,
params?: any params?: any
): Promise<any> { ): Promise<any> {
throw new Error("Search is not supported in v1, please downgrade Firecrawl to 0.0.36."); throw new FirecrawlError("Search is not supported in v1, please downgrade Firecrawl to 0.0.36.", 400);
} }
/** /**
@ -322,9 +335,9 @@ export default class FirecrawlApp {
} }
} catch (error: any) { } catch (error: any) {
if (error.response?.data?.error) { if (error.response?.data?.error) {
throw new Error(`Request failed with status code ${error.response.status}. Error: ${error.response.data.error} ${error.response.data.details ? ` - ${JSON.stringify(error.response.data.details)}` : ''}`); throw new FirecrawlError(`Request failed with status code ${error.response.status}. Error: ${error.response.data.error} ${error.response.data.details ? ` - ${JSON.stringify(error.response.data.details)}` : ''}`, error.response.status);
} else { } else {
throw new Error(error.message); throw new FirecrawlError(error.message, 500);
} }
} }
return { success: false, error: "Internal server error." }; return { success: false, error: "Internal server error." };
@ -350,9 +363,9 @@ export default class FirecrawlApp {
} }
} catch (error: any) { } catch (error: any) {
if (error.response?.data?.error) { if (error.response?.data?.error) {
throw new Error(`Request failed with status code ${error.response.status}. Error: ${error.response.data.error} ${error.response.data.details ? ` - ${JSON.stringify(error.response.data.details)}` : ''}`); throw new FirecrawlError(`Request failed with status code ${error.response.status}. Error: ${error.response.data.error} ${error.response.data.details ? ` - ${JSON.stringify(error.response.data.details)}` : ''}`, error.response.status);
} else { } else {
throw new Error(error.message); throw new FirecrawlError(error.message, 500);
} }
} }
return { success: false, error: "Internal server error." }; return { success: false, error: "Internal server error." };
@ -366,7 +379,7 @@ export default class FirecrawlApp {
*/ */
async checkCrawlStatus(id?: string, getAllData = false): Promise<CrawlStatusResponse | ErrorResponse> { async checkCrawlStatus(id?: string, getAllData = false): Promise<CrawlStatusResponse | ErrorResponse> {
if (!id) { if (!id) {
throw new Error("No crawl ID provided"); throw new FirecrawlError("No crawl ID provided", 400);
} }
const headers: AxiosRequestHeaders = this.prepareHeaders(); const headers: AxiosRequestHeaders = this.prepareHeaders();
@ -403,7 +416,7 @@ export default class FirecrawlApp {
this.handleError(response, "check crawl status"); this.handleError(response, "check crawl status");
} }
} catch (error: any) { } catch (error: any) {
throw new Error(error.message); throw new FirecrawlError(error.message, 500);
} }
return { success: false, error: "Internal server error." }; return { success: false, error: "Internal server error." };
} }
@ -420,7 +433,7 @@ export default class FirecrawlApp {
return new CrawlWatcher(id, this); return new CrawlWatcher(id, this);
} }
throw new Error("Crawl job failed to start"); throw new FirecrawlError("Crawl job failed to start", 400);
} }
async mapUrl(url: string, params?: MapParams): Promise<MapResponse | ErrorResponse> { async mapUrl(url: string, params?: MapParams): Promise<MapResponse | ErrorResponse> {
@ -439,7 +452,7 @@ export default class FirecrawlApp {
this.handleError(response, "map"); this.handleError(response, "map");
} }
} catch (error: any) { } catch (error: any) {
throw new Error(error.message); throw new FirecrawlError(error.message, 500);
} }
return { success: false, error: "Internal server error." }; return { success: false, error: "Internal server error." };
} }
@ -524,7 +537,7 @@ export default class FirecrawlApp {
statusData.data = data; statusData.data = data;
return statusData; return statusData;
} else { } else {
throw new Error("Crawl job completed but no data was returned"); throw new FirecrawlError("Crawl job completed but no data was returned", 500);
} }
} else if ( } else if (
["active", "paused", "pending", "queued", "waiting", "scraping"].includes(statusData.status) ["active", "paused", "pending", "queued", "waiting", "scraping"].includes(statusData.status)
@ -534,8 +547,9 @@ export default class FirecrawlApp {
setTimeout(resolve, checkInterval * 1000) setTimeout(resolve, checkInterval * 1000)
); );
} else { } else {
throw new Error( throw new FirecrawlError(
`Crawl job failed or was stopped. Status: ${statusData.status}` `Crawl job failed or was stopped. Status: ${statusData.status}`,
500
); );
} }
} else { } else {
@ -553,12 +567,14 @@ export default class FirecrawlApp {
if ([402, 408, 409, 500].includes(response.status)) { if ([402, 408, 409, 500].includes(response.status)) {
const errorMessage: string = const errorMessage: string =
response.data.error || "Unknown error occurred"; response.data.error || "Unknown error occurred";
throw new Error( throw new FirecrawlError(
`Failed to ${action}. Status code: ${response.status}. Error: ${errorMessage}` `Failed to ${action}. Status code: ${response.status}. Error: ${errorMessage}`,
response.status
); );
} else { } else {
throw new Error( throw new FirecrawlError(
`Unexpected error occurred while trying to ${action}. Status code: ${response.status}` `Unexpected error occurred while trying to ${action}. Status code: ${response.status}`,
response.status
); );
} }
} }