2024-08-15 23:30:33 +02:00
import express , { NextFunction , Request , Response } from "express" ;
2024-08-27 09:42:55 -03:00
import { crawlController } from "../controllers/v1/crawl" ;
2024-08-06 15:24:45 -03:00
// import { crawlStatusController } from "../../src/controllers/v1/crawl-status";
import { scrapeController } from "../../src/controllers/v1/scrape" ;
2024-08-27 09:42:55 -03:00
import { crawlStatusController } from "../controllers/v1/crawl-status" ;
import { mapController } from "../controllers/v1/map" ;
2024-08-15 23:30:33 +02:00
import { ErrorResponse , RequestWithAuth , RequestWithMaybeAuth } from "../controllers/v1/types" ;
import { RateLimiterMode } from "../types" ;
2024-08-26 18:48:00 -03:00
import { authenticateUser } from "../controllers/auth" ;
2024-08-15 23:30:33 +02:00
import { createIdempotencyKey } from "../services/idempotency/create" ;
import { validateIdempotencyKey } from "../services/idempotency/validate" ;
import { checkTeamCredits } from "../services/billing/credit_billing" ;
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-27 09:42:55 -03:00
import { crawlCancelController } from "../controllers/v1/crawl-cancel" ;
2024-08-27 11:58:42 -03:00
import { Logger } from "../lib/logger" ;
2024-08-31 14:23:55 -03:00
import { scrapeStatusController } from "../controllers/v1/scrape-status" ;
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-20 14:39:52 -03:00
function checkCreditsMiddleware ( minimum? : number ) : ( req : RequestWithAuth , res : Response , next : NextFunction ) = > void {
2024-08-15 23:30:33 +02:00
return ( req , res , next ) = > {
( async ( ) = > {
2024-08-20 14:39:52 -03:00
if ( ! minimum && req . body ) {
minimum = ( req . body as any ) ? . limit ? ? 1 ;
}
const { success , message , remainingCredits } = await checkTeamCredits ( req . auth . team_id , minimum ) ;
if ( ! success ) {
2024-08-27 11:58:42 -03:00
Logger . error ( ` Insufficient credits: ${ JSON . stringify ( { team_id : req.auth.team_id , minimum , remainingCredits } )} ` ) ;
2024-09-04 11:29:32 -03:00
if ( ! res . headersSent ) {
return res . status ( 402 ) . json ( { success : false , error : "Insufficient credits" } ) ;
}
2024-08-15 23:30:33 +02:00
}
2024-08-20 14:39:52 -03:00
req . account = { remainingCredits }
2024-08-15 23:30:33 +02:00
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 ) {
2024-09-04 11:29:32 -03:00
if ( ! res . headersSent ) {
return res . status ( status ) . json ( { success : false , error } ) ;
}
2024-08-15 23:30:33 +02:00
}
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 ) {
2024-09-04 11:29:32 -03:00
if ( ! res . headersSent ) {
return res . status ( 409 ) . json ( { success : false , error : "Idempotency key already used" } ) ;
}
2024-08-15 23:30:33 +02:00
}
createIdempotencyKey ( req ) ;
}
next ( ) ;
} ) ( )
. catch ( err = > next ( err ) ) ;
}
2024-08-19 13:28:54 -03:00
function blocklistMiddleware ( req : Request , res : Response , next : NextFunction ) {
2024-09-10 10:25:14 +02:00
if ( typeof req . body . url === "string" && isUrlBlocked ( req . body . url ) ) {
2024-09-04 11:29:32 -03:00
if ( ! res . headersSent ) {
return res . status ( 403 ) . json ( { success : false , error : "URL is blocked. Firecrawl currently does not support social media scraping due to policy restrictions." } ) ;
}
2024-08-19 13:28:54 -03:00
}
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-15 23:30:33 +02:00
authMiddleware ( RateLimiterMode . Scrape ) ,
checkCreditsMiddleware ( 1 ) ,
2024-09-04 11:29:32 -03:00
blocklistMiddleware ,
2024-08-15 23:30:33 +02:00
wrap ( scrapeController )
) ;
v1Router . post (
2024-08-16 23:48:50 +02:00
"/crawl" ,
2024-08-15 23:30:33 +02:00
authMiddleware ( RateLimiterMode . Crawl ) ,
2024-08-20 14:39:52 -03:00
checkCreditsMiddleware ( ) ,
2024-09-04 11:29:32 -03:00
blocklistMiddleware ,
idempotencyMiddleware ,
2024-08-15 23:30:33 +02:00
wrap ( crawlController )
) ;
v1Router . post (
2024-08-16 23:48:50 +02:00
"/map" ,
2024-08-20 12:04:08 -03:00
authMiddleware ( RateLimiterMode . Map ) ,
2024-08-15 23:30:33 +02:00
checkCreditsMiddleware ( 1 ) ,
2024-09-04 11:29:32 -03:00
blocklistMiddleware ,
2024-08-15 23:30:33 +02:00
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-31 14:23:55 -03:00
v1Router . get (
"/scrape/:jobId" ,
wrap ( scrapeStatusController )
) ;
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);
2024-08-27 09:42:55 -03:00
v1Router . delete (
"/crawl/:jobId" ,
2024-09-24 18:28:46 +02:00
authMiddleware ( RateLimiterMode . CrawlStatus ) ,
2024-08-27 09:42:55 -03:00
crawlCancelController
) ;
2024-08-16 23:48:50 +02:00
// 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);