UNPKG

@envelop/rate-limiter

Version:
84 lines (83 loc) 3.94 kB
import type { GraphQLField, GraphQLNamedOutputType } from 'graphql'; import type { Plugin } from '@envelop/core'; import { getGraphQLRateLimiter } from './get-graphql-rate-limiter.cjs'; import type { FormatErrorInput, GraphQLRateLimitConfig, GraphQLRateLimitDirectiveArgs, Identity, Options } from './types.cjs'; export { type FormatErrorInput, type GraphQLRateLimitConfig, type GraphQLRateLimitDirectiveArgs, type Identity, type Options, }; /** * Returns a string that uniquely identifies the caller for rate limiting. * * Receives the execution context and the resolved field argument values. Note that `args` is * only populated when the function is invoked via `configByField`. When used as the plugin-level * `identifyFn` for directive-based rate limiting, `args` will be an empty object. */ export type IdentifyFn<ContextType = unknown> = (context: ContextType, args: Record<string, unknown>) => string; interface RateLimitExecutionParams<ContextType = unknown> { root: unknown; args: Record<string, unknown>; context: ContextType; type: GraphQLNamedOutputType; field: GraphQLField<any, any>; } export type MessageInterpolator<ContextType = unknown> = (message: string, identifier: string, params: RateLimitExecutionParams<ContextType>) => string; export declare const DIRECTIVE_SDL = "\n directive @rateLimit(\n max: Int\n window: String\n message: String\n identityArgs: [String]\n arrayLengthField: String\n readOnly: Boolean\n uncountRejected: Boolean\n ) on FIELD_DEFINITION\n"; export type RateLimitDirectiveArgs = { max?: number; window?: string; message?: string; /** * Field argument names whose values are included in the rate limit key, creating a separate * bucket per unique combination of values. Equivalent to `@rateLimit(identityArgs: [...])`. * * @example * identityArgs: ['id'] // one bucket per unique id argument value */ identityArgs?: string[]; arrayLengthField?: string; readOnly?: boolean; uncountRejected?: boolean; }; export type RateLimiterPluginOptions = { identifyFn: IdentifyFn; rateLimitDirectiveName?: 'rateLimit' | string; transformError?: (message: string) => Error; onRateLimitError?: (event: { error: string; identifier: string; } & RateLimitExecutionParams) => void; interpolateMessage?: MessageInterpolator; configByField?: ConfigByField[]; } & Omit<GraphQLRateLimitConfig, 'identifyContext'>; export interface ConfigByField extends RateLimitDirectiveArgs { type: string; field: string; /** * Override the identity function for this specific field. Takes precedence over the * plugin-level `identifyFn`. * * Unlike the plugin-level `identifyFn`, this is always called with the resolved field * argument values, making it suitable for unauthenticated rate limiting keyed on an argument. * * @example * identifyFn: (ctx, args) => String(args.id) */ identifyFn?: IdentifyFn; /** * A template string that builds the rate limit identity key using `{args.argName}` or * `{context.propName}` dot-path interpolation. Takes precedence over `identifyFn` when set. * * Use this as a concise alternative to `identifyFn` when the identity is a single path. * * @example * identifier: "{args.id}" // one bucket per argument value * identifier: "{context.ip}" // one bucket per ip, no auth required */ identifier?: string; } export declare const defaultInterpolateMessageFn: MessageInterpolator; interface RateLimiterContext { rateLimiterFn: ReturnType<typeof getGraphQLRateLimiter>; } export declare const useRateLimiter: (options: RateLimiterPluginOptions) => Plugin<RateLimiterContext>; export { InMemoryStore } from './in-memory-store.cjs'; export { RedisStore } from './redis-store.cjs'; export { Store } from './store.cjs';