@graphql-mesh/plugin-rate-limit
Version:
47 lines (46 loc) • 1.96 kB
JavaScript
import { Store, useRateLimiter } from '@envelop/rate-limiter';
import { process } from '@graphql-mesh/cross-helpers';
import { stringInterpolator } from '@graphql-mesh/string-interpolation';
import { handleMaybePromise } from '@whatwg-node/promise-helpers';
class RateLimitMeshStore extends Store {
constructor(cache) {
super();
this.cache = cache;
}
getForIdentity(identity) {
return handleMaybePromise(() => this.cache.get(`rate-limit:${identity.contextIdentity}:${identity.fieldIdentity}`), value => value || []);
}
setForIdentity(identity, timestamps, windowMs) {
return this.cache.set(`rate-limit:${identity.contextIdentity}:${identity.fieldIdentity}`, timestamps, { ttl: windowMs / 1000 });
}
}
export default function useMeshRateLimit({ config, cache, }) {
return useRateLimiter({
identifyFn: (context) => context.headers?.authorization ||
context.req?.socket?.remoteAddress ||
context.req?.connection?.remoteAddress ||
context.req?.ip ||
context.headers?.['x-forwarded-for'] ||
context.headers?.host ||
'unknown',
store: new RateLimitMeshStore(cache),
interpolateMessage: (message, identifier, params) => stringInterpolator.parse(message, {
...params,
id: identifier,
identifier,
}),
configByField: config.map(origConfig => ({
type: origConfig.type,
field: origConfig.field,
max: origConfig.max,
window: `${origConfig.ttl}ms`,
message: `Rate limit of "${origConfig.type}.${origConfig.field}" exceeded for "{id}"`,
identifyFn: origConfig.identifier
? (context) => stringInterpolator.parse(origConfig.identifier, {
context,
env: process.env,
})
: undefined,
})),
});
}