UNPKG

@graphql-mesh/plugin-rate-limit

Version:
47 lines (46 loc) 1.96 kB
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, })), }); }