@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
JavaScript
;
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()]);
}