UNPKG

@envelop/rate-limiter

Version:

This plugins uses [`graphql-rate-limit`](https://github.com/teamplanes/graphql-rate-limit#readme) in order to limit the rate of calling queries and mutations.

67 lines (66 loc) 3.07 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.useRateLimiter = exports.DIRECTIVE_SDL = exports.UnauthenticatedError = void 0; const tslib_1 = require("tslib"); const on_resolve_1 = require("@envelop/on-resolve"); const utils_js_1 = require("./utils.js"); const graphql_rate_limit_1 = require("graphql-rate-limit"); tslib_1.__exportStar(require("./utils.js"), exports); class UnauthenticatedError extends Error { } exports.UnauthenticatedError = UnauthenticatedError; exports.DIRECTIVE_SDL = ` directive @rateLimit(max: Int, window: String, message: String) on FIELD_DEFINITION `; const useRateLimiter = (options) => { const rateLimiterFn = (0, graphql_rate_limit_1.getGraphQLRateLimiter)({ identifyContext: options.identifyFn }); return { onPluginInit({ addPlugin }) { addPlugin((0, on_resolve_1.useOnResolve)(async ({ args, root, context, info }) => { const rateLimitDirectiveNode = (0, utils_js_1.getDirective)(info, options.rateLimitDirectiveName || 'rateLimit'); if (rateLimitDirectiveNode && rateLimitDirectiveNode.arguments) { const maxNode = rateLimitDirectiveNode.arguments.find(arg => arg.name.value === 'max') ?.value; const windowNode = rateLimitDirectiveNode.arguments.find(arg => arg.name.value === 'window') ?.value; const messageNode = rateLimitDirectiveNode.arguments.find(arg => arg.name.value === 'message') ?.value; const message = messageNode.value; const max = parseInt(maxNode.value); const window = windowNode.value; const id = options.identifyFn(context); const errorMessage = await context.rateLimiterFn({ parent: root, args, context, info }, { max, window, message: interpolate(message, { id, }), }); if (errorMessage) { if (options.onRateLimitError) { options.onRateLimitError({ error: errorMessage, identifier: id, context, info, }); } if (options.transformError) { throw options.transformError(errorMessage); } throw new Error(errorMessage); } } })); }, async onContextBuilding({ extendContext }) { extendContext({ rateLimiterFn, }); }, }; }; exports.useRateLimiter = useRateLimiter; function interpolate(message, args) { return message.replace(/\{{([^)]*)\}}/g, (_, key) => args[key.trim()]); }