Remove unused GraphQL throttler plugin and graphql-rate-limit dependency (#17785)

## Summary

- Deletes `use-throttler.ts` — an envelop plugin that was never
registered in the GraphQL config plugin chain (dead code since
introduction)
- Removes the `graphql-rate-limit` dependency from `package.json` (only
consumer was the deleted file)

API rate limiting continues to work via `ThrottlerService` in the query
runner layer (for API key auth). Global coverage should be handled at
the infrastructure level (Cloudflare).

## Test plan

- [x] Confirmed no imports of `useThrottler`, `ThrottlerPluginOptions`,
or `UnauthenticatedError` from this file exist anywhere in the codebase
- [x] `graphql-rate-limit` has no other consumers

Made with [Cursor](https://cursor.com)

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Félix Malfait
2026-02-08 19:52:59 +01:00
committed by GitHub
parent d7132b35d3
commit 7402edb887
2 changed files with 0 additions and 91 deletions
-1
View File
@@ -108,7 +108,6 @@
"graphql": "16.8.1",
"graphql-fields": "2.0.3",
"graphql-middleware": "^6.1.35",
"graphql-rate-limit": "3.3.0",
"graphql-redis-subscriptions": "2.7.0",
"graphql-scalars": "1.23.0",
"graphql-subscriptions": "2.0.0",
@@ -1,90 +0,0 @@
import { type GraphQLResolveInfo } from 'graphql';
import { getGraphQLRateLimiter } from 'graphql-rate-limit';
import { type Plugin } from '@envelop/core';
import { useOnResolve } from '@envelop/on-resolve';
import { type GraphQLContext } from 'src/engine/api/graphql/graphql-config/graphql-config.service';
export class UnauthenticatedError extends Error {}
export type IdentifyFn<ContextType = ThrottlerContext> = (
context: ContextType,
) => string;
export type ThrottlerPluginOptions = {
identifyFn: IdentifyFn;
ttl?: number;
limit?: number;
transformError?: (message: string) => Error;
onThrottlerError?: (event: {
error: string;
identifier: string;
context: unknown;
info: GraphQLResolveInfo;
}) => void;
};
interface ThrottlerContext extends GraphQLContext {
rateLimiterFn: ReturnType<typeof getGraphQLRateLimiter>;
}
export const useThrottler = (
options: ThrottlerPluginOptions,
): Plugin<ThrottlerContext> => {
const rateLimiterFn = getGraphQLRateLimiter({
identifyContext: options.identifyFn,
});
return {
onPluginInit({ addPlugin }) {
addPlugin(
useOnResolve(async ({ args, root, context, info }) => {
if (options.limit && options.ttl) {
if (root !== undefined) {
return;
}
const id = options.identifyFn(context);
const errorMessage = await context.rateLimiterFn(
{ parent: root, args, context, info },
{
max: options?.limit,
window: `${options?.ttl}s`,
message: interpolate('Too many requests.', {
id,
}),
},
);
if (errorMessage) {
if (options.onThrottlerError) {
options.onThrottlerError({
error: errorMessage,
identifier: id,
context,
info,
});
}
if (options.transformError) {
throw options.transformError(errorMessage);
}
throw new Error(errorMessage);
}
}
}),
);
},
async onContextBuilding({ extendContext }) {
extendContext({
rateLimiterFn,
});
},
};
};
function interpolate(message: string, args: { [key: string]: string }) {
return message.replace(/\{{([^)]*)\}}/g, (_, key) => args[key.trim()]);
}