2024-08-15 23:30:33 +02:00
import express , { NextFunction , Request , Response } from "express" ;
2024-08-06 15:24:45 -03:00
import { crawlController } from "../../src/controllers/v1/crawl" ;
// import { crawlStatusController } from "../../src/controllers/v1/crawl-status";
import { scrapeController } from "../../src/controllers/v1/scrape" ;
import { crawlStatusController } from "../../src/controllers/v1/crawl-status" ;
import { mapController } from "../../src/controllers/v1/map" ;
2024-08-15 23:30:33 +02:00
import { ErrorResponse , RequestWithAuth , RequestWithMaybeAuth } from "../controllers/v1/types" ;
import { RateLimiterMode } from "../types" ;
import { authenticateUser } from "../controllers/v1/auth" ;
import { Logger } from "../lib/logger" ;
import { createIdempotencyKey } from "../services/idempotency/create" ;
import { validateIdempotencyKey } from "../services/idempotency/validate" ;
import { ZodError } from "zod" ;
import { checkTeamCredits } from "../services/billing/credit_billing" ;
import { v4 as uuidv4 } from "uuid" ;
2024-08-17 01:04:14 +02:00
import expressWs from "express-ws" ;
import { crawlStatusWSController } from "../controllers/v1/crawl-status-ws" ;
2024-08-19 13:28:54 -03:00
import { isUrlBlocked } from "../scraper/WebScraper/utils/blocklist" ;
2024-08-06 15:24:45 -03:00
// import { crawlPreviewController } from "../../src/controllers/v1/crawlPreview";
// import { crawlJobStatusPreviewController } from "../../src/controllers/v1/status";
// import { searchController } from "../../src/controllers/v1/search";
// import { crawlCancelController } from "../../src/controllers/v1/crawl-cancel";
// import { keyAuthController } from "../../src/controllers/v1/keyAuth";
// import { livenessController } from "../controllers/v1/liveness";
// import { readinessController } from "../controllers/v1/readiness";
2024-08-15 23:30:33 +02:00
function checkCreditsMiddleware ( minimum : number ) : ( req : RequestWithAuth , res : Response , next : NextFunction ) = > void {
return ( req , res , next ) = > {
( async ( ) = > {
if ( ! ( await checkTeamCredits ( req . auth . team_id , minimum ) ) . success ) {
return res . status ( 402 ) . json ( { success : false , error : "Insufficient credits" } ) ;
}
next ( ) ;
} ) ( )
. catch ( err = > next ( err ) ) ;
} ;
}
2024-08-17 01:04:14 +02:00
export function authMiddleware ( rateLimiterMode : RateLimiterMode ) : ( req : RequestWithMaybeAuth , res : Response , next : NextFunction ) = > void {
2024-08-15 23:30:33 +02:00
return ( req , res , next ) = > {
( async ( ) = > {
const { success , team_id , error , status , plan } = await authenticateUser (
req ,
res ,
rateLimiterMode ,
) ;
if ( ! success ) {
return res . status ( status ) . json ( { success : false , error } ) ;
}
req . auth = { team_id , plan } ;
next ( ) ;
} ) ( )
. catch ( err = > next ( err ) ) ;
}
}
function idempotencyMiddleware ( req : Request , res : Response , next : NextFunction ) {
( async ( ) = > {
if ( req . headers [ "x-idempotency-key" ] ) {
const isIdempotencyValid = await validateIdempotencyKey ( req ) ;
if ( ! isIdempotencyValid ) {
return res . status ( 409 ) . json ( { success : false , error : "Idempotency key already used" } ) ;
}
createIdempotencyKey ( req ) ;
}
next ( ) ;
} ) ( )
. catch ( err = > next ( err ) ) ;
}
2024-08-19 13:28:54 -03:00
function blocklistMiddleware ( req : Request , res : Response , next : NextFunction ) {
2024-08-20 12:04:08 -03:00
if ( req . body . url && isUrlBlocked ( req . body . url ) ) {
2024-08-19 13:28:54 -03:00
return res . status ( 403 ) . json ( { success : false , error : "URL is blocked. Firecrawl currently does not support social media scraping due to policy restrictions." } ) ;
}
next ( ) ;
}
2024-08-15 23:30:33 +02:00
function wrap ( controller : ( req : Request , res : Response ) = > Promise < any > ) : ( req : Request , res : Response , next : NextFunction ) = > any {
return ( req , res , next ) = > {
controller ( req , res )
. catch ( err = > next ( err ) )
}
}
2024-08-17 01:04:14 +02:00
expressWs ( express ( ) ) ;
2024-08-06 15:24:45 -03:00
export const v1Router = express . Router ( ) ;
2024-08-15 23:30:33 +02:00
v1Router . post (
2024-08-16 23:48:50 +02:00
"/scrape" ,
2024-08-19 13:28:54 -03:00
blocklistMiddleware ,
2024-08-15 23:30:33 +02:00
authMiddleware ( RateLimiterMode . Scrape ) ,
checkCreditsMiddleware ( 1 ) ,
wrap ( scrapeController )
) ;
v1Router . post (
2024-08-16 23:48:50 +02:00
"/crawl" ,
2024-08-19 13:28:54 -03:00
blocklistMiddleware ,
2024-08-15 23:30:33 +02:00
authMiddleware ( RateLimiterMode . Crawl ) ,
idempotencyMiddleware ,
checkCreditsMiddleware ( 1 ) ,
wrap ( crawlController )
) ;
v1Router . post (
2024-08-16 23:48:50 +02:00
"/map" ,
2024-08-19 13:28:54 -03:00
blocklistMiddleware ,
2024-08-20 12:04:08 -03:00
authMiddleware ( RateLimiterMode . Map ) ,
2024-08-15 23:30:33 +02:00
checkCreditsMiddleware ( 1 ) ,
wrap ( mapController )
) ;
v1Router . get (
2024-08-16 23:48:50 +02:00
"/crawl/:jobId" ,
2024-08-15 23:30:33 +02:00
authMiddleware ( RateLimiterMode . CrawlStatus ) ,
wrap ( crawlStatusController )
) ;
2024-08-17 01:04:14 +02:00
v1Router . ws (
"/crawl/:jobId" ,
crawlStatusWSController
) ;
2024-08-16 23:48:50 +02:00
// v1Router.post("/crawlWebsitePreview", crawlPreviewController);
// v1Router.delete("/crawl/:jobId", crawlCancelController);
// v1Router.get("/checkJobStatus/:jobId", crawlJobStatusPreviewController);
2024-08-06 15:24:45 -03:00
// // Auth route for key based authentication
2024-08-16 23:48:50 +02:00
// v1Router.get("/keyAuth", keyAuthController);
2024-08-06 15:24:45 -03:00
// // Search routes
2024-08-16 23:48:50 +02:00
// v0Router.post("/search", searchController);
2024-08-06 15:24:45 -03:00
// Health/Probe routes
2024-08-16 23:48:50 +02:00
// v1Router.get("/health/liveness", livenessController);
// v1Router.get("/health/readiness", readinessController);
2024-08-06 15:24:45 -03:00
2024-08-15 23:30:33 +02:00
v1Router . use ( ( err : unknown , req : Request < { } , ErrorResponse , undefined > , res : Response < ErrorResponse > , next : NextFunction ) = > {
if ( err instanceof ZodError ) {
res . status ( 400 ) . json ( { success : false , error : "Bad Request" , details : err.errors } ) ;
} else {
const id = uuidv4 ( ) ;
2024-08-16 22:47:56 +02:00
let verbose = JSON . stringify ( err ) ;
if ( verbose === "{}" ) {
if ( err instanceof Error ) {
verbose = JSON . stringify ( {
message : err.message ,
name : err.name ,
stack : err.stack ,
} ) ;
}
}
Logger . error ( "Error occurred in request! (" + req . path + ") -- ID " + id + " -- " + verbose ) ;
2024-08-15 23:30:33 +02:00
res . status ( 500 ) . json ( { success : false , error : "An unexpected error occurred. Please contact hello@firecrawl.com for help. Your exception ID is " + id + "" } ) ;
}
} ) ;