Skip to content

Commit ee3822c

Browse files
authored
pass team instead of project to rateLimit (#6092)
1 parent 1cff849 commit ee3822c

File tree

5 files changed

+19
-62
lines changed

5 files changed

+19
-62
lines changed

.changeset/large-beds-move.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@thirdweb-dev/service-utils": minor
3+
---
4+
5+
pass `team` instead of `project` to `rateLimit`

packages/service-utils/src/core/api.ts

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -164,24 +164,3 @@ export async function fetchTeamAndProject(
164164
);
165165
}
166166
}
167-
168-
export async function updateRateLimitedAt(
169-
projectId: string,
170-
config: CoreServiceConfig,
171-
): Promise<void> {
172-
const { apiUrl, serviceScope: scope, serviceApiKey } = config;
173-
174-
const url = `${apiUrl}/usage/rateLimit`;
175-
176-
await fetch(url, {
177-
method: "PUT",
178-
headers: {
179-
"x-service-api-key": serviceApiKey,
180-
"content-type": "application/json",
181-
},
182-
body: JSON.stringify({
183-
apiKeyId: projectId, // projectId is the apiKeyId
184-
scope,
185-
}),
186-
});
187-
}

packages/service-utils/src/core/rateLimit/index.ts

Lines changed: 4 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
1-
import {
2-
type CoreServiceConfig,
3-
type ProjectResponse,
4-
updateRateLimitedAt,
5-
} from "../api.js";
1+
import type { CoreServiceConfig, TeamResponse } from "../api.js";
62
import type { RateLimitResult } from "./types.js";
73

84
const RATE_LIMIT_WINDOW_SECONDS = 10;
@@ -14,7 +10,7 @@ type IRedis = {
1410
};
1511

1612
export async function rateLimit(args: {
17-
project?: ProjectResponse;
13+
team: TeamResponse;
1814
limitPerSecond: number;
1915
serviceConfig: CoreServiceConfig;
2016
redis: IRedis;
@@ -25,13 +21,7 @@ export async function rateLimit(args: {
2521
*/
2622
sampleRate?: number;
2723
}): Promise<RateLimitResult> {
28-
const {
29-
project,
30-
limitPerSecond,
31-
serviceConfig,
32-
redis,
33-
sampleRate = 1.0,
34-
} = args;
24+
const { team, limitPerSecond, serviceConfig, redis, sampleRate = 1.0 } = args;
3525

3626
const shouldSampleRequest = Math.random() < sampleRate;
3727
if (!shouldSampleRequest) {
@@ -57,7 +47,7 @@ export async function rateLimit(args: {
5747
const timestampWindow =
5848
Math.floor(Date.now() / (1000 * RATE_LIMIT_WINDOW_SECONDS)) *
5949
RATE_LIMIT_WINDOW_SECONDS;
60-
const key = `rate-limit:${serviceScope}:${project?.id}:${timestampWindow}`;
50+
const key = `rate-limit:${serviceScope}:${team.id}:${timestampWindow}`;
6151

6252
// Increment and get the current request count in this window.
6353
const requestCount = await redis.incr(key);
@@ -71,17 +61,6 @@ export async function rateLimit(args: {
7161
limitPerSecond * sampleRate * RATE_LIMIT_WINDOW_SECONDS;
7262

7363
if (requestCount > limitPerWindow) {
74-
/**
75-
* Report rate limit hits.
76-
* Only track rate limit when its hit for the first time.
77-
* Not waiting for tracking to complete as user doesn't need to wait.
78-
*/
79-
if (requestCount === limitPerWindow + 1 && project?.id) {
80-
updateRateLimitedAt(project.id, serviceConfig).catch(() => {
81-
// no-op
82-
});
83-
}
84-
8564
return {
8665
rateLimited: true,
8766
requestCount,

packages/service-utils/src/core/rateLimit/rateLimit.test.ts

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,12 @@
11
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2-
import { validProjectResponse, validServiceConfig } from "../../mocks.js";
3-
import { updateRateLimitedAt } from "../api.js";
2+
import { validServiceConfig, validTeamResponse } from "../../mocks.js";
43
import { rateLimit } from "./index.js";
54

65
const mockRedis = {
76
incr: vi.fn(),
87
expire: vi.fn(),
98
};
109

11-
// Mocking the updateRateLimitedAt function
12-
vi.mock("../../../src/core/api", () => ({
13-
updateRateLimitedAt: vi.fn().mockResolvedValue({}),
14-
}));
15-
1610
describe("rateLimit", () => {
1711
beforeEach(() => {
1812
// Clear mock function calls and reset any necessary state.
@@ -27,7 +21,7 @@ describe("rateLimit", () => {
2721

2822
it("should not rate limit if service scope is not in rate limits", async () => {
2923
const result = await rateLimit({
30-
project: validProjectResponse,
24+
team: validTeamResponse,
3125
limitPerSecond: 0,
3226
serviceConfig: validServiceConfig,
3327
redis: mockRedis,
@@ -44,7 +38,7 @@ describe("rateLimit", () => {
4438
mockRedis.incr.mockResolvedValue(50); // Current count is 50 requests in 10 seconds.
4539

4640
const result = await rateLimit({
47-
project: validProjectResponse,
41+
team: validTeamResponse,
4842
limitPerSecond: 5,
4943
serviceConfig: validServiceConfig,
5044
redis: mockRedis,
@@ -55,15 +49,15 @@ describe("rateLimit", () => {
5549
requestCount: 50,
5650
rateLimit: 50,
5751
});
58-
expect(updateRateLimitedAt).not.toHaveBeenCalled();
52+
5953
expect(mockRedis.expire).not.toHaveBeenCalled();
6054
});
6155

6256
it("should rate limit if exceeded hard limit", async () => {
6357
mockRedis.incr.mockResolvedValue(51);
6458

6559
const result = await rateLimit({
66-
project: validProjectResponse,
60+
team: validTeamResponse,
6761
limitPerSecond: 5,
6862
serviceConfig: validServiceConfig,
6963
redis: mockRedis,
@@ -77,15 +71,15 @@ describe("rateLimit", () => {
7771
errorMessage: `You've exceeded your storage rate limit at 5 reqs/sec. To get higher rate limits, contact us at https://thirdweb.com/contact-us.`,
7872
errorCode: "RATE_LIMIT_EXCEEDED",
7973
});
80-
expect(updateRateLimitedAt).toHaveBeenCalled();
74+
8175
expect(mockRedis.expire).not.toHaveBeenCalled();
8276
});
8377

8478
it("expires on the first incr request only", async () => {
8579
mockRedis.incr.mockResolvedValue(1);
8680

8781
const result = await rateLimit({
88-
project: validProjectResponse,
82+
team: validTeamResponse,
8983
limitPerSecond: 5,
9084
serviceConfig: validServiceConfig,
9185
redis: mockRedis,
@@ -104,7 +98,7 @@ describe("rateLimit", () => {
10498
vi.spyOn(global.Math, "random").mockReturnValue(0.08);
10599

106100
const result = await rateLimit({
107-
project: validProjectResponse,
101+
team: validTeamResponse,
108102
limitPerSecond: 5,
109103
serviceConfig: validServiceConfig,
110104
redis: mockRedis,
@@ -127,7 +121,7 @@ describe("rateLimit", () => {
127121
vi.spyOn(global.Math, "random").mockReturnValue(0.15);
128122

129123
const result = await rateLimit({
130-
project: validProjectResponse,
124+
team: validTeamResponse,
131125
limitPerSecond: 5,
132126
serviceConfig: validServiceConfig,
133127
redis: mockRedis,

packages/service-utils/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export type {
1010
TeamResponse,
1111
} from "./core/api.js";
1212

13-
export { fetchTeamAndProject, updateRateLimitedAt } from "./core/api.js";
13+
export { fetchTeamAndProject } from "./core/api.js";
1414

1515
export {
1616
authorizeBundleId,

0 commit comments

Comments
 (0)