Files
firecrawl/apps/api/src/services/rate-limiter.ts
T

227 lines
4.5 KiB
TypeScript
Raw Normal View History

2024-04-15 17:01:47 -04:00
import { RateLimiterRedis } from "rate-limiter-flexible";
2024-04-20 14:02:22 -07:00
import { RateLimiterMode } from "../../src/types";
2024-07-16 22:41:13 -04:00
import Redis from "ioredis";
2024-04-15 17:01:47 -04:00
2024-05-30 14:31:36 -07:00
const RATE_LIMITS = {
crawl: {
2024-06-06 11:23:10 -07:00
default: 3,
2024-06-05 14:38:10 -07:00
free: 2,
2024-09-10 06:53:24 -03:00
starter: 10,
2024-05-30 14:31:36 -07:00
standard: 5,
2024-06-06 09:29:25 -07:00
standardOld: 40,
2024-07-24 16:56:19 -04:00
scale: 50,
2024-05-30 14:31:36 -07:00
hobby: 3,
standardNew: 10,
2024-06-23 18:59:08 -03:00
standardnew: 10,
2024-05-30 14:31:36 -07:00
growth: 50,
2024-08-15 18:37:19 -04:00
growthdouble: 50,
2024-10-29 21:01:43 -03:00
etier2c: 300,
2024-11-04 18:14:38 -05:00
etier1a: 1000,
2024-11-05 13:08:01 -05:00
etier2a: 300,
2024-12-11 19:46:11 -03:00
etierscale1: 150
2024-05-30 14:31:36 -07:00
},
scrape: {
2024-08-27 12:08:50 -03:00
default: 20,
free: 10,
2024-09-10 06:53:24 -03:00
starter: 100,
2024-08-27 12:08:50 -03:00
standard: 100,
2024-09-10 06:53:24 -03:00
standardOld: 100,
2024-08-27 12:08:50 -03:00
scale: 500,
hobby: 20,
standardNew: 100,
standardnew: 100,
growth: 1000,
growthdouble: 1000,
2024-10-29 21:01:43 -03:00
etier2c: 2500,
2024-11-04 18:14:38 -05:00
etier1a: 1000,
2024-11-05 13:08:01 -05:00
etier2a: 2500,
2024-12-11 19:46:11 -03:00
etierscale1: 1500
2024-08-27 12:08:50 -03:00
},
search: {
2024-06-06 11:23:10 -07:00
default: 20,
2024-05-30 14:31:36 -07:00
free: 5,
2024-09-10 06:53:24 -03:00
starter: 50,
standard: 50,
2024-05-30 14:31:36 -07:00
standardOld: 40,
2024-07-24 16:56:19 -04:00
scale: 500,
2024-05-30 14:31:36 -07:00
hobby: 10,
standardNew: 50,
2024-06-23 18:59:08 -03:00
standardnew: 50,
2024-05-30 14:31:36 -07:00
growth: 500,
2024-08-15 18:37:19 -04:00
growthdouble: 500,
2024-10-29 21:01:43 -03:00
etier2c: 2500,
2024-11-04 18:14:38 -05:00
etier1a: 1000,
2024-11-05 13:08:01 -05:00
etier2a: 2500,
2024-12-11 19:46:11 -03:00
etierscale1: 1500
2024-05-30 14:31:36 -07:00
},
2024-12-11 19:46:11 -03:00
map: {
2024-06-06 11:23:10 -07:00
default: 20,
2024-05-30 14:31:36 -07:00
free: 5,
2024-09-10 06:53:24 -03:00
starter: 50,
standard: 50,
standardOld: 50,
2024-07-24 16:56:19 -04:00
scale: 500,
2024-05-30 14:31:36 -07:00
hobby: 10,
standardNew: 50,
2024-06-23 18:59:08 -03:00
standardnew: 50,
2024-05-30 14:31:36 -07:00
growth: 500,
2024-08-15 18:37:19 -04:00
growthdouble: 500,
2024-10-29 21:01:43 -03:00
etier2c: 2500,
2024-11-04 18:14:38 -05:00
etier1a: 1000,
2024-11-05 13:08:01 -05:00
etier2a: 2500,
2024-12-11 19:46:11 -03:00
etierscale1: 1500
2024-05-30 14:31:36 -07:00
},
2024-06-06 11:23:10 -07:00
preview: {
2024-06-06 11:53:12 -07:00
free: 5,
2024-12-11 19:46:11 -03:00
default: 5
2024-06-06 11:23:10 -07:00
},
account: {
2024-06-14 12:13:02 -07:00
free: 100,
2024-12-11 19:46:11 -03:00
default: 100
2024-06-06 11:23:10 -07:00
},
crawlStatus: {
2024-11-27 12:47:11 -03:00
free: 300,
2024-12-11 19:46:11 -03:00
default: 500
2024-06-06 11:23:10 -07:00
},
testSuite: {
2024-06-06 11:53:12 -07:00
free: 10000,
2024-12-11 19:46:11 -03:00
default: 10000
}
2024-05-30 14:31:36 -07:00
};
2024-04-20 14:02:22 -07:00
2024-07-16 22:41:13 -04:00
export const redisRateLimitClient = new Redis(
2024-11-07 20:57:33 +01:00
process.env.REDIS_RATE_LIMIT_URL!
2024-12-11 19:46:11 -03:00
);
2024-04-15 17:01:47 -04:00
2024-06-06 11:23:10 -07:00
const createRateLimiter = (keyPrefix, points) =>
new RateLimiterRedis({
2024-07-16 22:41:13 -04:00
storeClient: redisRateLimitClient,
2024-06-06 11:23:10 -07:00
keyPrefix,
points,
2024-12-11 19:46:11 -03:00
duration: 60 // Duration in seconds
2024-06-06 11:23:10 -07:00
});
2024-04-15 17:01:47 -04:00
2024-06-06 11:23:10 -07:00
export const serverRateLimiter = createRateLimiter(
"server",
2024-06-06 11:56:00 -07:00
RATE_LIMITS.account.default
2024-06-06 11:23:10 -07:00
);
2024-06-06 12:05:20 -07:00
2024-05-08 15:14:39 -07:00
export const testSuiteRateLimiter = new RateLimiterRedis({
2024-07-16 22:41:13 -04:00
storeClient: redisRateLimitClient,
2024-05-14 14:26:42 -07:00
keyPrefix: "test-suite",
2024-05-19 12:23:34 -07:00
points: 10000,
2024-12-11 19:46:11 -03:00
duration: 60 // Duration in seconds
2024-05-08 15:14:39 -07:00
});
2024-04-15 17:01:47 -04:00
2024-08-26 16:05:11 -03:00
export const devBRateLimiter = new RateLimiterRedis({
storeClient: redisRateLimitClient,
keyPrefix: "dev-b",
points: 1200,
2024-12-11 19:46:11 -03:00
duration: 60 // Duration in seconds
2024-08-26 16:05:11 -03:00
});
2024-09-13 18:09:59 -04:00
export const manualRateLimiter = new RateLimiterRedis({
storeClient: redisRateLimitClient,
keyPrefix: "manual",
points: 2000,
2024-12-11 19:46:11 -03:00
duration: 60 // Duration in seconds
2024-09-13 18:09:59 -04:00
});
2024-08-31 14:23:55 -03:00
export const scrapeStatusRateLimiter = new RateLimiterRedis({
storeClient: redisRateLimitClient,
keyPrefix: "scrape-status",
2024-08-31 14:26:16 -03:00
points: 400,
2024-12-11 19:46:11 -03:00
duration: 60 // Duration in seconds
2024-08-31 14:23:55 -03:00
});
2024-11-04 18:14:38 -05:00
export const etier1aRateLimiter = new RateLimiterRedis({
storeClient: redisRateLimitClient,
keyPrefix: "etier1a",
points: 10000,
2024-12-11 19:46:11 -03:00
duration: 60 // Duration in seconds
2024-11-04 18:14:38 -05:00
});
2024-11-05 13:08:01 -05:00
export const etier2aRateLimiter = new RateLimiterRedis({
storeClient: redisRateLimitClient,
keyPrefix: "etier2a",
points: 2500,
2024-12-11 19:46:11 -03:00
duration: 60 // Duration in seconds
2024-11-05 13:08:01 -05:00
});
2024-10-08 15:11:08 -03:00
const testSuiteTokens = [
"a01ccae",
"6254cf9",
"0f96e673",
"23befa1b",
"69141c4",
"48f9a97",
"5dc70ad",
"e5e60e5",
"65181ba",
"77c85b7",
"8567275",
"6c46abb",
"cb0ff78",
"fd769b2",
2024-11-19 17:51:31 -08:00
"4c2638d",
2024-10-30 17:19:37 -03:00
"cbb3462", // don't remove (s-ai)
"824abcd" // don't remove (s-ai)
2024-10-08 15:11:08 -03:00
];
2024-09-11 14:03:34 -04:00
2024-09-13 18:09:59 -04:00
const manual = ["69be9e74-7624-4990-b20d-08e0acc70cf6"];
function makePlanKey(plan?: string) {
return plan ? plan.replace("-", "") : "default"; // "default"
}
export function getRateLimiterPoints(
2024-06-06 11:23:10 -07:00
mode: RateLimiterMode,
token?: string,
2024-08-26 16:05:11 -03:00
plan?: string,
teamId?: string
2024-12-11 19:46:11 -03:00
): number {
2024-10-01 16:04:39 -03:00
const rateLimitConfig = RATE_LIMITS[mode]; // {default : 5}
if (!rateLimitConfig) return RATE_LIMITS.account.default;
2024-12-11 19:46:11 -03:00
const points: number =
2024-10-01 16:04:39 -03:00
rateLimitConfig[makePlanKey(plan)] || rateLimitConfig.default; // 5
return points;
}
export function getRateLimiter(
mode: RateLimiterMode,
token?: string,
plan?: string,
teamId?: string
2024-12-11 19:46:11 -03:00
): RateLimiterRedis {
if (token && testSuiteTokens.some((testToken) => token.includes(testToken))) {
2024-05-30 14:31:36 -07:00
return testSuiteRateLimiter;
}
2024-04-20 14:02:22 -07:00
2024-12-11 19:46:11 -03:00
if (teamId && teamId === process.env.DEV_B_TEAM_ID) {
2024-08-26 16:05:11 -03:00
return devBRateLimiter;
}
2024-12-11 19:46:11 -03:00
if (teamId && teamId === process.env.ETIER1A_TEAM_ID) {
2024-11-04 18:14:38 -05:00
return etier1aRateLimiter;
}
2024-08-26 16:05:11 -03:00
2024-12-11 19:46:11 -03:00
if (teamId && teamId === process.env.ETIER2A_TEAM_ID) {
2024-11-05 13:08:01 -05:00
return etier2aRateLimiter;
}
2024-12-11 19:46:11 -03:00
if (teamId && teamId === process.env.ETIER2D_TEAM_ID) {
2024-11-21 13:45:30 -03:00
return etier2aRateLimiter;
}
2024-12-11 19:46:11 -03:00
if (teamId && manual.includes(teamId)) {
2024-09-13 18:09:59 -04:00
return manualRateLimiter;
}
2024-12-11 19:46:11 -03:00
return createRateLimiter(
`${mode}-${makePlanKey(plan)}`,
getRateLimiterPoints(mode, token, plan, teamId)
);
2024-04-15 17:01:47 -04:00
}