feat(v1/map): timeout

This commit is contained in:
Gergő Móricz 2025-01-28 16:44:44 +01:00
parent 173028295b
commit 57e98e83d7
4 changed files with 73 additions and 11 deletions

View File

@ -0,0 +1,42 @@
import request from "supertest";
import { configDotenv } from "dotenv";
import { MapRequestInput } from "../../controllers/v1/types";
configDotenv();
const TEST_URL = "http://127.0.0.1:3002";
async function map(body: MapRequestInput) {
return await request(TEST_URL)
.post("/v1/map")
.set("Authorization", `Bearer ${process.env.TEST_API_KEY}`)
.set("Content-Type", "application/json")
.send(body);
}
function expectMapToSucceed(response: Awaited<ReturnType<typeof map>>) {
expect(response.statusCode).toBe(200);
expect(response.body.success).toBe(true);
expect(Array.isArray(response.body.links)).toBe(true);
expect(response.body.links.length).toBeGreaterThan(0);
}
describe("Map tests", () => {
it("basic map succeeds", async () => {
const response = await map({
url: "http://firecrawl.dev",
});
expectMapToSucceed(response);
});
it("times out properly", async () => {
const response = await map({
url: "http://firecrawl.dev",
timeout: 1
});
expect(response.statusCode).toBe(408);
expect(response.body.success).toBe(false);
expect(response.body.error).toBe("Request timed out");
});
});

View File

@ -276,17 +276,34 @@ export async function mapController(
) {
req.body = mapRequestSchema.parse(req.body);
const result = await getMapResults({
url: req.body.url,
search: req.body.search,
limit: req.body.limit,
ignoreSitemap: req.body.ignoreSitemap,
includeSubdomains: req.body.includeSubdomains,
crawlerOptions: req.body,
origin: req.body.origin,
teamId: req.auth.team_id,
plan: req.auth.plan,
});
let result: Awaited<ReturnType<typeof getMapResults>>;
try {
result = await Promise.race([
getMapResults({
url: req.body.url,
search: req.body.search,
limit: req.body.limit,
ignoreSitemap: req.body.ignoreSitemap,
includeSubdomains: req.body.includeSubdomains,
crawlerOptions: req.body,
origin: req.body.origin,
teamId: req.auth.team_id,
plan: req.auth.plan,
}),
...(req.body.timeout !== undefined ? [
new Promise((resolve, reject) => setTimeout(() => reject("timeout"), req.body.timeout))
] : []),
]) as any;
} catch (error) {
if (error === "timeout") {
return res.status(408).json({
success: false,
error: "Request timed out",
});
} else {
throw error;
}
}
// Bill the team
billTeam(req.auth.team_id, req.acuc?.sub_id, 1).catch((error) => {

View File

@ -429,6 +429,7 @@ export const mapRequestSchema = crawlerOptions
ignoreSitemap: z.boolean().default(false),
sitemapOnly: z.boolean().default(false),
limit: z.number().min(1).max(5000).default(5000),
timeout: z.number().positive().finite().optional(),
})
.strict(strictMessage);
@ -438,6 +439,7 @@ export const mapRequestSchema = crawlerOptions
// };
export type MapRequest = z.infer<typeof mapRequestSchema>;
export type MapRequestInput = z.input<typeof mapRequestSchema>;
export type Document = {
title?: string;

View File

@ -235,6 +235,7 @@ export interface MapParams {
includeSubdomains?: boolean;
sitemapOnly?: boolean;
limit?: number;
timeout?: number;
}
/**