@nest-boot/graphql-rate-limit 7.0.3 → 7.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/complexities/connection.complexity.d.ts +10 -0
- package/dist/complexities/connection.complexity.js +10 -0
- package/dist/complexities/connection.complexity.js.map +1 -1
- package/dist/decorators/complexity.decorator.d.ts +8 -0
- package/dist/decorators/complexity.decorator.js +5 -0
- package/dist/decorators/complexity.decorator.js.map +1 -1
- package/dist/graphql-rate-limit.module-definition.d.ts +15 -1
- package/dist/graphql-rate-limit.module-definition.js +15 -1
- package/dist/graphql-rate-limit.module-definition.js.map +1 -1
- package/dist/graphql-rate-limit.module.d.ts +41 -2
- package/dist/graphql-rate-limit.module.js +64 -8
- package/dist/graphql-rate-limit.module.js.map +1 -1
- package/dist/graphql-rate-limit.plugin.js +5 -5
- package/dist/graphql-rate-limit.plugin.js.map +1 -1
- package/dist/graphql-rate-limit.storage.js +9 -9
- package/dist/interfaces/cost-response.interface.d.ts +9 -0
- package/dist/interfaces/graphql-rate-limit-module-options.interface.d.ts +1 -0
- package/dist/interfaces/graphql-rate-limit-options.interface.d.ts +8 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/utils/load-config-from-env.util.d.ts +16 -0
- package/dist/utils/load-config-from-env.util.js +47 -0
- package/dist/utils/load-config-from-env.util.js.map +1 -0
- package/package.json +20 -13
|
@@ -1,2 +1,12 @@
|
|
|
1
1
|
import { type Complexity } from "@nest-boot/graphql";
|
|
2
|
+
/**
|
|
3
|
+
* Complexity estimator for connection fields (Relay-style pagination).
|
|
4
|
+
*
|
|
5
|
+
* @remarks
|
|
6
|
+
* Multiplies `childComplexity` by the page size (`first` or `last` argument),
|
|
7
|
+
* defaulting to 1 if neither is specified.
|
|
8
|
+
*
|
|
9
|
+
* @param options - The complexity estimator arguments
|
|
10
|
+
* @returns The calculated complexity value
|
|
11
|
+
*/
|
|
2
12
|
export declare const connectionComplexity: Complexity;
|
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.connectionComplexity = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Complexity estimator for connection fields (Relay-style pagination).
|
|
6
|
+
*
|
|
7
|
+
* @remarks
|
|
8
|
+
* Multiplies `childComplexity` by the page size (`first` or `last` argument),
|
|
9
|
+
* defaulting to 1 if neither is specified.
|
|
10
|
+
*
|
|
11
|
+
* @param options - The complexity estimator arguments
|
|
12
|
+
* @returns The calculated complexity value
|
|
13
|
+
*/
|
|
4
14
|
const connectionComplexity = (options) => {
|
|
5
15
|
return (Number(options.args.first ?? options.args.last ?? 1) *
|
|
6
16
|
options.childComplexity);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connection.complexity.js","sourceRoot":"","sources":["../../src/complexities/connection.complexity.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"connection.complexity.js","sourceRoot":"","sources":["../../src/complexities/connection.complexity.ts"],"names":[],"mappings":";;;AAKA;;;;;;;;;GASG;AACI,MAAM,oBAAoB,GAAe,CAC9C,OAAgC,EAChC,EAAE;IACF,OAAO,CACL,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC;QACpD,OAAO,CAAC,eAAe,CACxB,CAAC;AACJ,CAAC,CAAC;AAPW,QAAA,oBAAoB,wBAO/B"}
|
|
@@ -1,5 +1,13 @@
|
|
|
1
|
+
/** Options for the `@Complexity` decorator. */
|
|
1
2
|
export interface ComplexityOptions {
|
|
3
|
+
/** Base complexity value for the field or resolver. */
|
|
2
4
|
value?: number;
|
|
5
|
+
/** Argument names whose values multiply the complexity (e.g. `["first"]`). */
|
|
3
6
|
multipliers?: string[];
|
|
4
7
|
}
|
|
8
|
+
/**
|
|
9
|
+
* Decorator that applies a `@complexity` directive to a GraphQL field or type.
|
|
10
|
+
* @param options - Complexity configuration options
|
|
11
|
+
* @returns A combined method, property, and class decorator
|
|
12
|
+
*/
|
|
5
13
|
export declare function Complexity(options: ComplexityOptions): MethodDecorator & PropertyDecorator & ClassDecorator;
|
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Complexity = Complexity;
|
|
4
4
|
const graphql_1 = require("@nest-boot/graphql");
|
|
5
|
+
/**
|
|
6
|
+
* Decorator that applies a `@complexity` directive to a GraphQL field or type.
|
|
7
|
+
* @param options - Complexity configuration options
|
|
8
|
+
* @returns A combined method, property, and class decorator
|
|
9
|
+
*/
|
|
5
10
|
function Complexity(options) {
|
|
6
11
|
return (0, graphql_1.Directive)(`@complexity(value: ${String(options.value ?? 1)}, multipliers: ${JSON.stringify(options.multipliers ?? [])})`);
|
|
7
12
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"complexity.decorator.js","sourceRoot":"","sources":["../../src/decorators/complexity.decorator.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"complexity.decorator.js","sourceRoot":"","sources":["../../src/decorators/complexity.decorator.ts"],"names":[],"mappings":";;AAeA,gCAQC;AAvBD,gDAA+C;AAU/C;;;;GAIG;AACH,SAAgB,UAAU,CACxB,OAA0B;IAE1B,OAAO,IAAA,mBAAS,EACd,sBAAsB,MAAM,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC,CAAC,kBAAkB,IAAI,CAAC,SAAS,CAC9E,OAAO,CAAC,WAAW,IAAI,EAAE,CAC1B,GAAG,CACL,CAAC;AACJ,CAAC"}
|
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
/** Redis command name used by the rate limiter. */
|
|
1
2
|
export declare const REDIS_COMMAND = "GRAPHQL_RATE_LIMIT";
|
|
3
|
+
/** Injection token for the resolved GraphQL rate limit options. */
|
|
2
4
|
export declare const OPTIONS_TOKEN: unique symbol;
|
|
3
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Module definition for the GraphQL rate limit module.
|
|
7
|
+
* @internal
|
|
8
|
+
*/
|
|
9
|
+
export declare const
|
|
10
|
+
/** @internal Base configurable module class. */
|
|
11
|
+
ConfigurableModuleClass: import("@nestjs/common").ConfigurableModuleCls<Partial<import("./interfaces").GraphQLRateLimitOptions>, "forRoot", "create", {}>,
|
|
12
|
+
/** @internal Module options injection token. */
|
|
13
|
+
MODULE_OPTIONS_TOKEN: string | symbol,
|
|
14
|
+
/** @internal Synchronous options type. */
|
|
15
|
+
OPTIONS_TYPE: Partial<import("./interfaces").GraphQLRateLimitOptions> & Partial<{}>,
|
|
16
|
+
/** @internal Asynchronous options type. */
|
|
17
|
+
ASYNC_OPTIONS_TYPE: import("@nestjs/common").ConfigurableModuleAsyncOptions<Partial<import("./interfaces").GraphQLRateLimitOptions>, "create"> & Partial<{}>;
|
|
@@ -3,9 +3,23 @@ var _a;
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
4
|
exports.ASYNC_OPTIONS_TYPE = exports.OPTIONS_TYPE = exports.MODULE_OPTIONS_TOKEN = exports.ConfigurableModuleClass = exports.OPTIONS_TOKEN = exports.REDIS_COMMAND = void 0;
|
|
5
5
|
const common_1 = require("@nestjs/common");
|
|
6
|
+
/** Redis command name used by the rate limiter. */
|
|
6
7
|
exports.REDIS_COMMAND = "GRAPHQL_RATE_LIMIT";
|
|
8
|
+
/** Injection token for the resolved GraphQL rate limit options. */
|
|
7
9
|
exports.OPTIONS_TOKEN = Symbol("GraphQLRateLimitOptions");
|
|
10
|
+
/**
|
|
11
|
+
* Module definition for the GraphQL rate limit module.
|
|
12
|
+
* @internal
|
|
13
|
+
*/
|
|
8
14
|
_a = new common_1.ConfigurableModuleBuilder()
|
|
9
15
|
.setClassMethodName("forRoot")
|
|
10
|
-
.build(),
|
|
16
|
+
.build(),
|
|
17
|
+
/** @internal Base configurable module class. */
|
|
18
|
+
exports.ConfigurableModuleClass = _a.ConfigurableModuleClass,
|
|
19
|
+
/** @internal Module options injection token. */
|
|
20
|
+
exports.MODULE_OPTIONS_TOKEN = _a.MODULE_OPTIONS_TOKEN,
|
|
21
|
+
/** @internal Synchronous options type. */
|
|
22
|
+
exports.OPTIONS_TYPE = _a.OPTIONS_TYPE,
|
|
23
|
+
/** @internal Asynchronous options type. */
|
|
24
|
+
exports.ASYNC_OPTIONS_TYPE = _a.ASYNC_OPTIONS_TYPE;
|
|
11
25
|
//# sourceMappingURL=graphql-rate-limit.module-definition.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graphql-rate-limit.module-definition.js","sourceRoot":"","sources":["../src/graphql-rate-limit.module-definition.ts"],"names":[],"mappings":";;;;AAAA,2CAA2D;
|
|
1
|
+
{"version":3,"file":"graphql-rate-limit.module-definition.js","sourceRoot":"","sources":["../src/graphql-rate-limit.module-definition.ts"],"names":[],"mappings":";;;;AAAA,2CAA2D;AAI3D,mDAAmD;AACtC,QAAA,aAAa,GAAG,oBAAoB,CAAC;AAElD,mEAAmE;AACtD,QAAA,aAAa,GAAG,MAAM,CAAC,yBAAyB,CAAC,CAAC;AAE/D;;;GAGG;AACU,KAST,IAAI,kCAAyB,EAAiC;KAC/D,kBAAkB,CAAC,SAAS,CAAC;KAC7B,KAAK,EAAE;AAVR,gDAAgD;AAChD,+BAAuB;AACvB,gDAAgD;AAChD,4BAAoB;AACpB,0CAA0C;AAC1C,oBAAY;AACZ,2CAA2C;AAC3C,0BAAkB,yBAGT"}
|
|
@@ -1,3 +1,42 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { type DynamicModule, type OnApplicationShutdown } from "@nestjs/common";
|
|
2
|
+
import Redis from "ioredis";
|
|
3
|
+
import { ASYNC_OPTIONS_TYPE, ConfigurableModuleClass, OPTIONS_TYPE } from "./graphql-rate-limit.module-definition";
|
|
4
|
+
/**
|
|
5
|
+
* GraphQL rate limiting module using Redis-backed leaky bucket algorithm.
|
|
6
|
+
*
|
|
7
|
+
* @remarks
|
|
8
|
+
* Provides query complexity analysis and rate limiting for GraphQL operations.
|
|
9
|
+
* Uses Redis for distributed rate limit state and supports custom ID extraction.
|
|
10
|
+
*
|
|
11
|
+
* The module automatically loads Redis connection from environment variables if not provided:
|
|
12
|
+
* - `REDIS_URL`: Full Redis connection URL (e.g., `redis://user:pass@host:6379/0`)
|
|
13
|
+
* - `REDIS_HOST`: Redis server hostname
|
|
14
|
+
* - `REDIS_PORT`: Redis server port
|
|
15
|
+
* - `REDIS_DB` or `REDIS_DATABASE`: Redis database number
|
|
16
|
+
* - `REDIS_USER` or `REDIS_USERNAME`: Redis username
|
|
17
|
+
* - `REDIS_PASS` or `REDIS_PASSWORD`: Redis password
|
|
18
|
+
* - `REDIS_TLS`: Enable TLS connection
|
|
19
|
+
*/
|
|
20
|
+
export declare class GraphQLRateLimitModule extends ConfigurableModuleClass implements OnApplicationShutdown {
|
|
21
|
+
private readonly redis;
|
|
22
|
+
/**
|
|
23
|
+
* Registers the GraphQLRateLimitModule with the given options.
|
|
24
|
+
* @param options - Configuration options including rate limit thresholds and Redis connection
|
|
25
|
+
* @returns Dynamic module configuration
|
|
26
|
+
*/
|
|
27
|
+
static forRoot(options: typeof OPTIONS_TYPE): DynamicModule;
|
|
28
|
+
/**
|
|
29
|
+
* Registers the GraphQLRateLimitModule asynchronously with factory functions.
|
|
30
|
+
* @param options - Async configuration options
|
|
31
|
+
* @returns Dynamic module configuration
|
|
32
|
+
*/
|
|
33
|
+
static forRootAsync(options: typeof ASYNC_OPTIONS_TYPE): DynamicModule;
|
|
34
|
+
/** Creates a new GraphQLRateLimitModule instance.
|
|
35
|
+
* @param redis - The ioredis client instance
|
|
36
|
+
*/
|
|
37
|
+
constructor(redis: Redis);
|
|
38
|
+
/**
|
|
39
|
+
* Gracefully closes the Redis connection when the application shuts down.
|
|
40
|
+
*/
|
|
41
|
+
onApplicationShutdown(): Promise<void>;
|
|
3
42
|
}
|
|
@@ -5,33 +5,88 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
5
5
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
6
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
7
|
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
8
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
15
|
exports.GraphQLRateLimitModule = void 0;
|
|
10
|
-
const redis_1 = require("@nest-boot/redis");
|
|
11
16
|
const common_1 = require("@nestjs/common");
|
|
17
|
+
const ioredis_1 = __importDefault(require("ioredis"));
|
|
12
18
|
const graphql_rate_limit_module_definition_1 = require("./graphql-rate-limit.module-definition");
|
|
13
19
|
const graphql_rate_limit_plugin_1 = require("./graphql-rate-limit.plugin");
|
|
14
20
|
const graphql_rate_limit_storage_1 = require("./graphql-rate-limit.storage");
|
|
21
|
+
const load_config_from_env_util_1 = require("./utils/load-config-from-env.util");
|
|
22
|
+
/**
|
|
23
|
+
* GraphQL rate limiting module using Redis-backed leaky bucket algorithm.
|
|
24
|
+
*
|
|
25
|
+
* @remarks
|
|
26
|
+
* Provides query complexity analysis and rate limiting for GraphQL operations.
|
|
27
|
+
* Uses Redis for distributed rate limit state and supports custom ID extraction.
|
|
28
|
+
*
|
|
29
|
+
* The module automatically loads Redis connection from environment variables if not provided:
|
|
30
|
+
* - `REDIS_URL`: Full Redis connection URL (e.g., `redis://user:pass@host:6379/0`)
|
|
31
|
+
* - `REDIS_HOST`: Redis server hostname
|
|
32
|
+
* - `REDIS_PORT`: Redis server port
|
|
33
|
+
* - `REDIS_DB` or `REDIS_DATABASE`: Redis database number
|
|
34
|
+
* - `REDIS_USER` or `REDIS_USERNAME`: Redis username
|
|
35
|
+
* - `REDIS_PASS` or `REDIS_PASSWORD`: Redis password
|
|
36
|
+
* - `REDIS_TLS`: Enable TLS connection
|
|
37
|
+
*/
|
|
15
38
|
let GraphQLRateLimitModule = class GraphQLRateLimitModule extends graphql_rate_limit_module_definition_1.ConfigurableModuleClass {
|
|
39
|
+
/**
|
|
40
|
+
* Registers the GraphQLRateLimitModule with the given options.
|
|
41
|
+
* @param options - Configuration options including rate limit thresholds and Redis connection
|
|
42
|
+
* @returns Dynamic module configuration
|
|
43
|
+
*/
|
|
44
|
+
static forRoot(options) {
|
|
45
|
+
return super.forRoot(options);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Registers the GraphQLRateLimitModule asynchronously with factory functions.
|
|
49
|
+
* @param options - Async configuration options
|
|
50
|
+
* @returns Dynamic module configuration
|
|
51
|
+
*/
|
|
52
|
+
static forRootAsync(options) {
|
|
53
|
+
return super.forRootAsync(options);
|
|
54
|
+
}
|
|
55
|
+
/** Creates a new GraphQLRateLimitModule instance.
|
|
56
|
+
* @param redis - The ioredis client instance
|
|
57
|
+
*/
|
|
58
|
+
constructor(redis) {
|
|
59
|
+
super();
|
|
60
|
+
this.redis = redis;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Gracefully closes the Redis connection when the application shuts down.
|
|
64
|
+
*/
|
|
65
|
+
async onApplicationShutdown() {
|
|
66
|
+
await this.redis.quit();
|
|
67
|
+
}
|
|
16
68
|
};
|
|
17
69
|
exports.GraphQLRateLimitModule = GraphQLRateLimitModule;
|
|
18
70
|
exports.GraphQLRateLimitModule = GraphQLRateLimitModule = __decorate([
|
|
19
71
|
(0, common_1.Global)(),
|
|
20
72
|
(0, common_1.Module)({
|
|
21
|
-
imports: [
|
|
22
|
-
redis_1.RedisModule.registerAsync({
|
|
23
|
-
inject: [graphql_rate_limit_module_definition_1.OPTIONS_TOKEN],
|
|
24
|
-
useFactory: (options) => options.connection ?? {},
|
|
25
|
-
}),
|
|
26
|
-
],
|
|
27
73
|
providers: [
|
|
28
74
|
graphql_rate_limit_plugin_1.GraphQLRateLimitPlugin,
|
|
29
75
|
graphql_rate_limit_storage_1.GraphQLRateLimitStorage,
|
|
76
|
+
{
|
|
77
|
+
provide: ioredis_1.default,
|
|
78
|
+
inject: [graphql_rate_limit_module_definition_1.OPTIONS_TOKEN],
|
|
79
|
+
useFactory: (options) => new ioredis_1.default({
|
|
80
|
+
...(0, load_config_from_env_util_1.loadConfigFromEnv)(),
|
|
81
|
+
...options.connection,
|
|
82
|
+
}),
|
|
83
|
+
},
|
|
30
84
|
{
|
|
31
85
|
provide: graphql_rate_limit_module_definition_1.OPTIONS_TOKEN,
|
|
32
86
|
inject: [{ token: graphql_rate_limit_module_definition_1.MODULE_OPTIONS_TOKEN, optional: true }],
|
|
33
87
|
useFactory: (options) => {
|
|
34
88
|
return {
|
|
89
|
+
connection: options?.connection,
|
|
35
90
|
maxComplexity: options?.maxComplexity ?? 1000,
|
|
36
91
|
defaultComplexity: options?.defaultComplexity ?? 0,
|
|
37
92
|
keyPrefix: options?.keyPrefix ?? "graphql-rate-limit",
|
|
@@ -51,6 +106,7 @@ exports.GraphQLRateLimitModule = GraphQLRateLimitModule = __decorate([
|
|
|
51
106
|
},
|
|
52
107
|
],
|
|
53
108
|
exports: [graphql_rate_limit_module_definition_1.OPTIONS_TOKEN],
|
|
54
|
-
})
|
|
109
|
+
}),
|
|
110
|
+
__metadata("design:paramtypes", [ioredis_1.default])
|
|
55
111
|
], GraphQLRateLimitModule);
|
|
56
112
|
//# sourceMappingURL=graphql-rate-limit.module.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graphql-rate-limit.module.js","sourceRoot":"","sources":["../src/graphql-rate-limit.module.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"graphql-rate-limit.module.js","sourceRoot":"","sources":["../src/graphql-rate-limit.module.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AACA,2CAKwB;AAExB,sDAA4B;AAE5B,iGAMgD;AAChD,2EAAqE;AACrE,6EAAuE;AAKvE,iFAAsE;AAEtE;;;;;;;;;;;;;;;GAeG;AAgDI,IAAM,sBAAsB,GAA5B,MAAM,sBACX,SAAQ,8DAAuB;IAG/B;;;;OAIG;IACH,MAAM,CAAU,OAAO,CAAC,OAA4B;QAClD,OAAO,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAChC,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAU,YAAY,CAC1B,OAAkC;QAElC,OAAO,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;IACrC,CAAC;IAED;;OAEG;IACH,YAA6B,KAAY;QACvC,KAAK,EAAE,CAAC;QADmB,UAAK,GAAL,KAAK,CAAO;IAEzC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,qBAAqB;QACzB,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;IAC1B,CAAC;CACF,CAAA;AArCY,wDAAsB;iCAAtB,sBAAsB;IA/ClC,IAAA,eAAM,GAAE;IACR,IAAA,eAAM,EAAC;QACN,SAAS,EAAE;YACT,kDAAsB;YACtB,oDAAuB;YACvB;gBACE,OAAO,EAAE,iBAAK;gBACd,MAAM,EAAE,CAAC,oDAAa,CAAC;gBACvB,UAAU,EAAE,CAAC,OAAgC,EAAE,EAAE,CAC/C,IAAI,iBAAK,CAAC;oBACR,GAAG,IAAA,6CAAiB,GAAE;oBACtB,GAAG,OAAO,CAAC,UAAU;iBACtB,CAAC;aACL;YACD;gBACE,OAAO,EAAE,oDAAa;gBACtB,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,2DAAoB,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;gBACzD,UAAU,EAAE,CACV,OAAuC,EACd,EAAE;oBAC3B,OAAO;wBACL,UAAU,EAAE,OAAO,EAAE,UAAU;wBAC/B,aAAa,EAAE,OAAO,EAAE,aAAa,IAAI,IAAI;wBAC7C,iBAAiB,EAAE,OAAO,EAAE,iBAAiB,IAAI,CAAC;wBAClD,SAAS,EAAE,OAAO,EAAE,SAAS,IAAI,oBAAoB;wBACrD,WAAW,EAAE,OAAO,EAAE,WAAW,IAAI,EAAE;wBACvC,gBAAgB,EAAE,OAAO,EAAE,gBAAgB,IAAI,IAAI;wBACnD,KAAK,EACH,OAAO,EAAE,KAAK;4BACd,CAAC,CAAC,IAAwC,EAAE,EAAE;gCAC5C,MAAM,GAAG,GAAI,IAAI,CAAC,YAAiC,CAAC,GAAG,CAAC;gCACxD,MAAM,EAAE,GAAG,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;gCAEhD,IAAI,OAAO,EAAE,KAAK,WAAW,EAAE,CAAC;oCAC9B,MAAM,IAAI,KAAK,CACb,8LAA8L,CAC/L,CAAC;gCACJ,CAAC;gCAED,OAAO,EAAE,CAAC;4BACZ,CAAC,CAAC;qBACL,CAAC;gBACJ,CAAC;aACF;SACF;QACD,OAAO,EAAE,CAAC,oDAAa,CAAC;KACzB,CAAC;qCA4BoC,iBAAK;GA3B9B,sBAAsB,CAqClC"}
|
|
@@ -23,19 +23,19 @@ function shopifyEstimator(args, type) {
|
|
|
23
23
|
if (type instanceof graphql_2.GraphQLNonNull || type instanceof graphql_2.GraphQLList) {
|
|
24
24
|
return shopifyEstimator(args, type.ofType);
|
|
25
25
|
}
|
|
26
|
-
// GraphQL
|
|
26
|
+
// A GraphQL Connection represents a one-to-many relationship. The cost is two points plus the number of objects to return.
|
|
27
27
|
if (type instanceof graphql_2.GraphQLObjectType && type.name.endsWith("Connection")) {
|
|
28
28
|
return 2 + args.childComplexity * (args.args.first ?? args.args.last ?? 0);
|
|
29
29
|
}
|
|
30
|
-
// Object
|
|
31
|
-
// Interface
|
|
30
|
+
// An Object is the basic unit of a query, generally representing a single server-side operation such as a database query or an internal service call.
|
|
31
|
+
// Interface and Union are similar to Object but can return different types of objects, so they cost one point.
|
|
32
32
|
if (type instanceof graphql_2.GraphQLObjectType ||
|
|
33
33
|
type instanceof graphql_2.GraphQLInterfaceType ||
|
|
34
34
|
type instanceof graphql_2.GraphQLUnionType) {
|
|
35
35
|
return 1 + args.childComplexity;
|
|
36
36
|
}
|
|
37
|
-
// Scalar
|
|
38
|
-
//
|
|
37
|
+
// Scalar and Enum are part of the Object itself; we've already counted their cost in the Object.
|
|
38
|
+
// They are just fields on an Object, and returning a few extra fields costs relatively little.
|
|
39
39
|
if (type instanceof graphql_2.GraphQLScalarType || type instanceof graphql_2.GraphQLEnumType) {
|
|
40
40
|
return 0;
|
|
41
41
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graphql-rate-limit.plugin.js","sourceRoot":"","sources":["../src/graphql-rate-limit.plugin.ts"],"names":[],"mappings":";AAAA,qDAAqD;;;;;;;;;;;;AAQrD,gDAAuD;AACvD,2CAAwC;AACxC,2CAA+C;AAE/C,qCASiB;AACjB,uEAOkC;AAElC,6EAAuE;AAGvE,sFAAsF;AACtF,SAAS,gBAAgB,CACvB,IAA6B,EAC7B,IAAkB;IAElB,IAAI,GAAG,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;IAE/B,IAAI,IAAI,YAAY,wBAAc,IAAI,IAAI,YAAY,qBAAW,EAAE,CAAC;QAClE,OAAO,gBAAgB,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IAC7C,CAAC;IAED
|
|
1
|
+
{"version":3,"file":"graphql-rate-limit.plugin.js","sourceRoot":"","sources":["../src/graphql-rate-limit.plugin.ts"],"names":[],"mappings":"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"}
|
|
@@ -26,47 +26,47 @@ let GraphQLRateLimitStorage = class GraphQLRateLimitStorage {
|
|
|
26
26
|
this.redis.defineCommand(graphql_rate_limit_module_definition_1.REDIS_COMMAND, {
|
|
27
27
|
numberOfKeys: 5,
|
|
28
28
|
lua: /* lua */ `
|
|
29
|
-
--
|
|
29
|
+
-- Get current timestamp
|
|
30
30
|
local currentTimestamp = redis.call("TIME")[1]
|
|
31
31
|
|
|
32
|
-
--
|
|
32
|
+
-- Get arguments
|
|
33
33
|
local bucketKeyPrefix = KEYS[1]
|
|
34
34
|
local maximumAvailable = tonumber(KEYS[2])
|
|
35
35
|
local restoreRate = tonumber(KEYS[3])
|
|
36
36
|
local id = KEYS[4]
|
|
37
37
|
local complexity = tonumber(KEYS[5])
|
|
38
38
|
|
|
39
|
-
--
|
|
39
|
+
-- Define the bucket key
|
|
40
40
|
local bucketKey = bucketKeyPrefix .. ":" .. id
|
|
41
41
|
|
|
42
42
|
local keyExpireSeconds = math.ceil(maximumAvailable / restoreRate)
|
|
43
43
|
|
|
44
|
-
--
|
|
44
|
+
-- Get the current number of tokens in the bucket; if it doesn't exist, set to max available
|
|
45
45
|
local currentlyAvailable = redis.call("HGET", bucketKey, "currentlyAvailable")
|
|
46
46
|
if not currentlyAvailable then
|
|
47
47
|
currentlyAvailable = maximumAvailable
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
-
--
|
|
50
|
+
-- If the bucket is empty, set the last updated timestamp to the current timestamp
|
|
51
51
|
local updatedTimestamp = redis.call("HGET", bucketKey, "updatedTimestamp")
|
|
52
52
|
if not updatedTimestamp then
|
|
53
53
|
updatedTimestamp = currentTimestamp
|
|
54
54
|
end
|
|
55
55
|
|
|
56
|
-
--
|
|
56
|
+
-- Update the last updated timestamp
|
|
57
57
|
redis.call("HSET", bucketKey, "updatedTimestamp", currentTimestamp)
|
|
58
58
|
|
|
59
|
-
--
|
|
59
|
+
-- Update the bucket's expiration time
|
|
60
60
|
redis.call("EXPIRE", bucketKey, keyExpireSeconds)
|
|
61
61
|
|
|
62
|
-
--
|
|
62
|
+
-- Calculate the number of tokens to restore since the last update, and restore tokens in the bucket
|
|
63
63
|
local intervalSeconds = currentTimestamp - updatedTimestamp;
|
|
64
64
|
if intervalSeconds > 0 then
|
|
65
65
|
currentlyAvailable = math.min((restoreRate * intervalSeconds) + currentlyAvailable, maximumAvailable);
|
|
66
66
|
redis.call("HSET", bucketKey, "currentlyAvailable", currentlyAvailable)
|
|
67
67
|
end
|
|
68
68
|
|
|
69
|
-
--
|
|
69
|
+
-- Check if there are enough tokens to deduct; if so, deduct and return the remaining tokens
|
|
70
70
|
local newCurrentlyAvailable = currentlyAvailable - complexity
|
|
71
71
|
if newCurrentlyAvailable >= 0 then
|
|
72
72
|
currentlyAvailable = newCurrentlyAvailable
|
|
@@ -1,11 +1,20 @@
|
|
|
1
|
+
/** Throttle status information for rate-limited queries. */
|
|
1
2
|
export interface CostThrottleStatus {
|
|
3
|
+
/** Whether the request is currently blocked due to rate limiting. */
|
|
2
4
|
blocked: boolean;
|
|
5
|
+
/** Maximum cost budget available. */
|
|
3
6
|
maximumAvailable: number;
|
|
7
|
+
/** Remaining cost budget currently available. */
|
|
4
8
|
currentlyAvailable: number;
|
|
9
|
+
/** Rate at which cost budget restores (points per second). */
|
|
5
10
|
restoreRate: number;
|
|
6
11
|
}
|
|
12
|
+
/** Response containing query cost and throttle status information. */
|
|
7
13
|
export interface CostResponse {
|
|
14
|
+
/** The estimated cost of the query before execution. */
|
|
8
15
|
requestedQueryCost: number;
|
|
16
|
+
/** The actual cost of the query after execution. */
|
|
9
17
|
actualQueryCost: number;
|
|
18
|
+
/** Current throttle status, if rate limiting is active. */
|
|
10
19
|
throttleStatus?: CostThrottleStatus;
|
|
11
20
|
}
|
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
import { BaseContext, GraphQLRequestContext } from "@apollo/server";
|
|
2
2
|
import { RedisOptions } from "ioredis";
|
|
3
|
+
/** Configuration options for GraphQL rate limiting. */
|
|
3
4
|
export interface GraphQLRateLimitOptions {
|
|
5
|
+
/** Redis connection options for rate limit state storage. */
|
|
4
6
|
connection?: RedisOptions;
|
|
7
|
+
/** Maximum allowed query complexity per request. */
|
|
5
8
|
maxComplexity: number;
|
|
9
|
+
/** Default complexity assigned to fields without explicit `@complexity` directives. */
|
|
6
10
|
defaultComplexity: number;
|
|
11
|
+
/** Redis key prefix for rate limit state. */
|
|
7
12
|
keyPrefix: string;
|
|
13
|
+
/** Rate at which cost budget restores (points per second). */
|
|
8
14
|
restoreRate: number;
|
|
15
|
+
/** Maximum cost budget available per client. */
|
|
9
16
|
maximumAvailable: number;
|
|
17
|
+
/** Function to extract a unique client identifier from the request context. */
|
|
10
18
|
getId: (args: GraphQLRequestContext<BaseContext>) => string;
|
|
11
19
|
}
|