limitly 1.0.1 → 2.0.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.
Files changed (79) hide show
  1. package/README.md +301 -22
  2. package/dist/algorithms/factory.d.ts +3 -2
  3. package/dist/algorithms/factory.d.ts.map +1 -1
  4. package/dist/algorithms/factory.js +3 -3
  5. package/dist/algorithms/factory.js.map +1 -1
  6. package/dist/algorithms/sliding-window.d.ts +4 -4
  7. package/dist/algorithms/sliding-window.d.ts.map +1 -1
  8. package/dist/algorithms/sliding-window.js +3 -23
  9. package/dist/algorithms/sliding-window.js.map +1 -1
  10. package/dist/algorithms/token-bucket.d.ts +4 -4
  11. package/dist/algorithms/token-bucket.d.ts.map +1 -1
  12. package/dist/algorithms/token-bucket.js +3 -20
  13. package/dist/algorithms/token-bucket.js.map +1 -1
  14. package/dist/index.d.ts +15 -1
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +32 -1
  17. package/dist/index.js.map +1 -1
  18. package/dist/limiter.d.ts +19 -7
  19. package/dist/limiter.d.ts.map +1 -1
  20. package/dist/limiter.js +66 -15
  21. package/dist/limiter.js.map +1 -1
  22. package/dist/middleware/bun.d.ts +9 -0
  23. package/dist/middleware/bun.d.ts.map +1 -0
  24. package/dist/middleware/bun.js +96 -0
  25. package/dist/middleware/bun.js.map +1 -0
  26. package/dist/middleware/express.d.ts.map +1 -1
  27. package/dist/middleware/express.js +11 -5
  28. package/dist/middleware/express.js.map +1 -1
  29. package/dist/middleware/fastify.d.ts +3 -3
  30. package/dist/middleware/fastify.d.ts.map +1 -1
  31. package/dist/middleware/fastify.js +19 -13
  32. package/dist/middleware/fastify.js.map +1 -1
  33. package/dist/middleware/hono.d.ts +5 -0
  34. package/dist/middleware/hono.d.ts.map +1 -0
  35. package/dist/middleware/hono.js +57 -0
  36. package/dist/middleware/hono.js.map +1 -0
  37. package/dist/middleware/koa.d.ts +5 -0
  38. package/dist/middleware/koa.d.ts.map +1 -0
  39. package/dist/middleware/koa.js +54 -0
  40. package/dist/middleware/koa.js.map +1 -0
  41. package/dist/middleware/nest.d.ts +14 -0
  42. package/dist/middleware/nest.d.ts.map +1 -0
  43. package/dist/middleware/nest.js +102 -0
  44. package/dist/middleware/nest.js.map +1 -0
  45. package/dist/stores/factory.d.ts +5 -0
  46. package/dist/stores/factory.d.ts.map +1 -0
  47. package/dist/stores/factory.js +36 -0
  48. package/dist/stores/factory.js.map +1 -0
  49. package/dist/stores/memcached-store.d.ts +13 -0
  50. package/dist/stores/memcached-store.d.ts.map +1 -0
  51. package/dist/stores/memcached-store.js +117 -0
  52. package/dist/stores/memcached-store.js.map +1 -0
  53. package/dist/stores/redis-store.d.ts +12 -0
  54. package/dist/stores/redis-store.d.ts.map +1 -0
  55. package/dist/stores/redis-store.js +54 -0
  56. package/dist/stores/redis-store.js.map +1 -0
  57. package/dist/stores/types.d.ts +8 -0
  58. package/dist/stores/types.d.ts.map +1 -0
  59. package/dist/stores/types.js +3 -0
  60. package/dist/stores/types.js.map +1 -0
  61. package/dist/types/index.d.ts +62 -1
  62. package/dist/types/index.d.ts.map +1 -1
  63. package/dist/utils/defaults.d.ts +6 -0
  64. package/dist/utils/defaults.d.ts.map +1 -0
  65. package/dist/utils/defaults.js +59 -0
  66. package/dist/utils/defaults.js.map +1 -0
  67. package/dist/utils/memcached.d.ts +11 -0
  68. package/dist/utils/memcached.d.ts.map +1 -0
  69. package/dist/utils/memcached.js +91 -0
  70. package/dist/utils/memcached.js.map +1 -0
  71. package/dist/utils/metrics.d.ts +21 -0
  72. package/dist/utils/metrics.d.ts.map +1 -0
  73. package/dist/utils/metrics.js +60 -0
  74. package/dist/utils/metrics.js.map +1 -0
  75. package/dist/utils/redis.d.ts +1 -0
  76. package/dist/utils/redis.d.ts.map +1 -1
  77. package/dist/utils/redis.js +2 -0
  78. package/dist/utils/redis.js.map +1 -1
  79. package/package.json +60 -3
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,qCAAsD;AAA7C,qGAAA,UAAU,OAAA;AAAE,wGAAA,aAAa,OAAA;AAClC,gDAA+D;AAAtD,kHAAA,uBAAuB,OAAA;AAChC,gDAA6E;AAApE,8GAAA,mBAAmB,OAAA;AAAE,2GAAA,gBAAgB,OAAA;AAC9C,8DAAoE;AAA3D,uHAAA,qBAAqB,OAAA;AAC9B,0DAAgE;AAAvD,mHAAA,mBAAmB,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,qCAAsD;AAA7C,qGAAA,UAAU,OAAA;AAAE,wGAAA,aAAa,OAAA;AAClC,gDAA+D;AAAtD,kHAAA,uBAAuB,OAAA;AAChC,gDAA6E;AAApE,8GAAA,mBAAmB,OAAA;AAAE,2GAAA,gBAAgB,OAAA;AAC9C,0CAAyD;AAAhD,4GAAA,oBAAoB,OAAA;AAC7B,wCAAuD;AAA9C,0GAAA,mBAAmB,OAAA;AAC5B,wCAK0B;AAJxB,4GAAA,qBAAqB,OAAA;AACrB,wGAAA,iBAAiB,OAAA;AACjB,0GAAA,mBAAmB,OAAA;AACnB,mGAAA,YAAY,OAAA;AAGd,0CAM2B;AALzB,uGAAA,eAAe,OAAA;AACf,yGAAA,iBAAiB,OAAA;AACjB,qGAAA,aAAa,OAAA;AACb,iGAAA,SAAS,OAAA;AACT,sGAAA,cAAc,OAAA;AAGhB,8DAAoE;AAA3D,uHAAA,qBAAqB,OAAA;AAC9B,0DAAgE;AAAvD,mHAAA,mBAAmB,OAAA;AAE5B,uCAAmD;AAA1C,2GAAA,kBAAkB,OAAA;AAC3B,6CAK0B;AAJxB,kHAAA,sBAAsB,OAAA;AACtB,gHAAA,oBAAoB,OAAA;AACpB,kHAAA,sBAAsB,OAAA;AACtB,oHAAA,wBAAwB,OAAA;AAE1B,2CAAmD;AAA1C,2GAAA,gBAAgB,OAAA;AAEzB,4CAAiE;AAAxD,sGAAA,WAAW,OAAA;AAAE,2GAAA,gBAAgB,OAAA;AACtC,oDAAkD;AAAzC,yGAAA,UAAU,OAAA;AACnB,4DAA0D;AAAjD,iHAAA,cAAc,OAAA"}
package/dist/limiter.d.ts CHANGED
@@ -1,19 +1,31 @@
1
+ import type { RateLimitStore } from "./stores/types";
1
2
  import type { FastifyPluginAsync } from "fastify";
2
- import type { AlgorithmConfig, MiddlewareOptions, RateLimitResult, RateLimitStrategy, RedisClient, RedisLimitOptions } from "./types";
3
+ import type { CanActivate, Type } from "@nestjs/common";
4
+ import type { AlgorithmConfig, MemcachedClient, MiddlewareOptions, MiddlewareOptionsInput, RateLimitResult, RateLimitStrategy, RedisClient, RedisLimitOptions } from "./types";
3
5
  export declare class RedisLimit {
4
- private readonly redis;
6
+ private readonly store;
5
7
  private readonly failOpen;
6
- private readonly keyPrefix;
8
+ private readonly defaultOptions;
7
9
  constructor(options: RedisLimitOptions);
10
+ getStore(): RateLimitStore;
11
+ getStoreType(): RateLimitStore["type"];
12
+ getDefaultOptions(): MiddlewareOptionsInput;
13
+ resolveOptions(options?: MiddlewareOptionsInput): MiddlewareOptions;
8
14
  getRedis(): RedisClient;
15
+ getMemcached(): MemcachedClient;
9
16
  createStrategy(config: AlgorithmConfig): RateLimitStrategy;
10
- check(key: string, config: AlgorithmConfig, options?: {
17
+ createStrategyFromOptions(options?: MiddlewareOptionsInput): RateLimitStrategy;
18
+ check(key: string, config?: MiddlewareOptionsInput, options?: {
11
19
  failOpen?: boolean;
12
20
  }): Promise<RateLimitResult>;
13
- middleware(options: MiddlewareOptions): (req: import("express").Request, res: import("express").Response, next: import("express").NextFunction) => Promise<void>;
14
- get fastifyPlugin(): FastifyPluginAsync<MiddlewareOptions>;
21
+ middleware(options?: MiddlewareOptionsInput): (req: import("express").Request, res: import("express").Response, next: import("express").NextFunction) => Promise<void>;
22
+ honoMiddleware(options?: MiddlewareOptionsInput): (c: import("hono").Context, next: import("hono").Next) => Promise<Response | void>;
23
+ koaMiddleware(options?: MiddlewareOptionsInput): (ctx: import("koa").Context, next: import("koa").Next) => Promise<void>;
24
+ bunMiddleware(options?: MiddlewareOptionsInput): import("./middleware/bun").BunMiddleware;
25
+ get fastifyPlugin(): FastifyPluginAsync<MiddlewareOptionsInput>;
26
+ nestGuard(defaultOptions?: MiddlewareOptionsInput): Type<CanActivate>;
15
27
  private createFailOpenResult;
16
28
  }
17
29
  export declare function createLimiter(options: RedisLimitOptions): RedisLimit;
18
- export type { MiddlewareOptions };
30
+ export type { MiddlewareOptions, MiddlewareOptionsInput };
19
31
  //# sourceMappingURL=limiter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"limiter.d.ts","sourceRoot":"","sources":["../src/limiter.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,KAAK,EACV,eAAe,EACf,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,WAAW,EACX,iBAAiB,EAClB,MAAM,SAAS,CAAC;AAGjB,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAc;IACpC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAU;IACnC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;gBAEvB,OAAO,EAAE,iBAAiB;IAMtC,QAAQ,IAAI,WAAW;IAIvB,cAAc,CAAC,MAAM,EAAE,eAAe,GAAG,iBAAiB;IAIpD,KAAK,CACT,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,eAAe,EACvB,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,GAC/B,OAAO,CAAC,eAAe,CAAC;IAc3B,UAAU,CAAC,OAAO,EAAE,iBAAiB;IAIrC,IAAI,aAAa,IAAI,kBAAkB,CAAC,iBAAiB,CAAC,CAEzD;IAED,OAAO,CAAC,oBAAoB;CAW7B;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,iBAAiB,GAAG,UAAU,CAEpE;AAED,YAAY,EAAE,iBAAiB,EAAE,CAAC"}
1
+ {"version":3,"file":"limiter.d.ts","sourceRoot":"","sources":["../src/limiter.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAQrD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,KAAK,EACV,eAAe,EACf,eAAe,EACf,iBAAiB,EACjB,sBAAsB,EACtB,eAAe,EACf,iBAAiB,EACjB,WAAW,EACX,iBAAiB,EAClB,MAAM,SAAS,CAAC;AAEjB,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiB;IACvC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAU;IACnC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAyB;gBAE5C,OAAO,EAAE,iBAAiB;IAStC,QAAQ,IAAI,cAAc;IAI1B,YAAY,IAAI,cAAc,CAAC,MAAM,CAAC;IAItC,iBAAiB,IAAI,sBAAsB;IAI3C,cAAc,CAAC,OAAO,GAAE,sBAA2B,GAAG,iBAAiB;IAIvE,QAAQ,IAAI,WAAW;IASvB,YAAY,IAAI,eAAe;IAS/B,cAAc,CAAC,MAAM,EAAE,eAAe,GAAG,iBAAiB;IAI1D,yBAAyB,CACvB,OAAO,GAAE,sBAA2B,GACnC,iBAAiB;IAOd,KAAK,CACT,GAAG,EAAE,MAAM,EACX,MAAM,GAAE,sBAA2B,EACnC,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,GAC/B,OAAO,CAAC,eAAe,CAAC;IAsB3B,UAAU,CAAC,OAAO,GAAE,sBAA2B;IAI/C,cAAc,CAAC,OAAO,GAAE,sBAA2B;IAInD,aAAa,CAAC,OAAO,GAAE,sBAA2B;IAIlD,aAAa,CAAC,OAAO,GAAE,sBAA2B;IAIlD,IAAI,aAAa,IAAI,kBAAkB,CAAC,sBAAsB,CAAC,CAE9D;IAED,SAAS,CAAC,cAAc,GAAE,sBAA2B,GAAG,IAAI,CAAC,WAAW,CAAC;IAIzE,OAAO,CAAC,oBAAoB;CAW7B;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,iBAAiB,GAAG,UAAU,CAEpE;AAED,YAAY,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,CAAC"}
package/dist/limiter.js CHANGED
@@ -5,38 +5,89 @@ exports.createLimiter = createLimiter;
5
5
  const factory_1 = require("./algorithms/factory");
6
6
  const express_1 = require("./middleware/express");
7
7
  const fastify_1 = require("./middleware/fastify");
8
- const redis_1 = require("./utils/redis");
8
+ const hono_1 = require("./middleware/hono");
9
+ const bun_1 = require("./middleware/bun");
10
+ const koa_1 = require("./middleware/koa");
11
+ const nest_1 = require("./middleware/nest");
12
+ const factory_2 = require("./stores/factory");
13
+ const defaults_1 = require("./utils/defaults");
14
+ const metrics_1 = require("./utils/metrics");
9
15
  class RedisLimit {
10
16
  constructor(options) {
11
- this.redis = (0, redis_1.createRedisClient)(options.redis);
17
+ this.store = (0, factory_2.createStore)(options);
12
18
  this.failOpen = options.failOpen ?? true;
13
- this.keyPrefix = options.keyPrefix ?? "redislimit";
19
+ this.defaultOptions = {
20
+ onMetrics: options.onMetrics,
21
+ ...options.default,
22
+ };
23
+ }
24
+ getStore() {
25
+ return this.store;
26
+ }
27
+ getStoreType() {
28
+ return this.store.type;
29
+ }
30
+ getDefaultOptions() {
31
+ return this.defaultOptions;
32
+ }
33
+ resolveOptions(options = {}) {
34
+ return (0, defaults_1.resolveMiddlewareOptions)(options, this.defaultOptions);
14
35
  }
15
36
  getRedis() {
16
- return this.redis;
37
+ if (this.store.type === "memcached") {
38
+ throw new Error(`getRedis() is not available when using the "${this.store.type}" store`);
39
+ }
40
+ return this.store.getClient();
41
+ }
42
+ getMemcached() {
43
+ if (this.store.type !== "memcached") {
44
+ throw new Error(`getMemcached() is only available when using the "memcached" store`);
45
+ }
46
+ return this.store.getClient();
17
47
  }
18
48
  createStrategy(config) {
19
- return (0, factory_1.createStrategy)(this.redis, config, this.keyPrefix);
49
+ return (0, factory_1.createStrategy)(this.store, config);
50
+ }
51
+ createStrategyFromOptions(options = {}) {
52
+ return (0, factory_1.createStrategy)(this.store, (0, defaults_1.resolveAlgorithmConfig)(options, this.defaultOptions));
20
53
  }
21
- async check(key, config, options) {
22
- const strategy = this.createStrategy(config);
54
+ async check(key, config = {}, options) {
55
+ const resolved = this.resolveOptions(config);
56
+ const strategy = this.createStrategy(resolved);
23
57
  const shouldFailOpen = options?.failOpen ?? this.failOpen;
24
- try {
25
- return await strategy.consume(key);
26
- }
27
- catch (error) {
58
+ const outcome = await (0, metrics_1.consumeRateLimit)({
59
+ strategy,
60
+ key,
61
+ options: resolved,
62
+ failOpen: shouldFailOpen,
63
+ storeType: this.store.type,
64
+ });
65
+ if (outcome.status === "error") {
28
66
  if (shouldFailOpen) {
29
- return this.createFailOpenResult(config);
67
+ return this.createFailOpenResult(resolved);
30
68
  }
31
- throw error;
69
+ throw outcome.error;
32
70
  }
71
+ return outcome.result;
72
+ }
73
+ middleware(options = {}) {
74
+ return (0, express_1.createExpressMiddleware)(this)(this.resolveOptions(options));
33
75
  }
34
- middleware(options) {
35
- return (0, express_1.createExpressMiddleware)(this)(options);
76
+ honoMiddleware(options = {}) {
77
+ return (0, hono_1.createHonoMiddleware)(this)(this.resolveOptions(options));
78
+ }
79
+ koaMiddleware(options = {}) {
80
+ return (0, koa_1.createKoaMiddleware)(this)(this.resolveOptions(options));
81
+ }
82
+ bunMiddleware(options = {}) {
83
+ return (0, bun_1.createBunMiddleware)(this)(this.resolveOptions(options));
36
84
  }
37
85
  get fastifyPlugin() {
38
86
  return (0, fastify_1.createFastifyPlugin)(this);
39
87
  }
88
+ nestGuard(defaultOptions = {}) {
89
+ return (0, nest_1.createNestGuard)(this)(defaultOptions);
90
+ }
40
91
  createFailOpenResult(config) {
41
92
  const limit = config.algorithm === "sliding-window" ? config.limit : config.capacity;
42
93
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"limiter.js","sourceRoot":"","sources":["../src/limiter.ts"],"names":[],"mappings":";;;AAwEA,sCAEC;AA1ED,kDAAsD;AACtD,kDAA+D;AAC/D,kDAA2D;AAU3D,yCAAkD;AAElD,MAAa,UAAU;IAKrB,YAAY,OAA0B;QACpC,IAAI,CAAC,KAAK,GAAG,IAAA,yBAAiB,EAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAC9C,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,IAAI,CAAC;QACzC,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,YAAY,CAAC;IACrD,CAAC;IAED,QAAQ;QACN,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED,cAAc,CAAC,MAAuB;QACpC,OAAO,IAAA,wBAAc,EAAC,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;IAC5D,CAAC;IAED,KAAK,CAAC,KAAK,CACT,GAAW,EACX,MAAuB,EACvB,OAAgC;QAEhC,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;QAC7C,MAAM,cAAc,GAAG,OAAO,EAAE,QAAQ,IAAI,IAAI,CAAC,QAAQ,CAAC;QAE1D,IAAI,CAAC;YACH,OAAO,MAAM,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACrC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,cAAc,EAAE,CAAC;gBACnB,OAAO,IAAI,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC;YAC3C,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED,UAAU,CAAC,OAA0B;QACnC,OAAO,IAAA,iCAAuB,EAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC;IAChD,CAAC;IAED,IAAI,aAAa;QACf,OAAO,IAAA,6BAAmB,EAAC,IAAI,CAAC,CAAC;IACnC,CAAC;IAEO,oBAAoB,CAAC,MAAuB;QAClD,MAAM,KAAK,GACT,MAAM,CAAC,SAAS,KAAK,gBAAgB,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC;QAEzE,OAAO;YACL,OAAO,EAAE,IAAI;YACb,KAAK;YACL,SAAS,EAAE,KAAK;YAChB,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE;SACzC,CAAC;IACJ,CAAC;CACF;AAxDD,gCAwDC;AAED,SAAgB,aAAa,CAAC,OAA0B;IACtD,OAAO,IAAI,UAAU,CAAC,OAAO,CAAC,CAAC;AACjC,CAAC"}
1
+ {"version":3,"file":"limiter.js","sourceRoot":"","sources":["../src/limiter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { RedisLimit } from "../limiter";
2
+ import type { MiddlewareOptions, RateLimitHeaders } from "../types";
3
+ export type BunNext = () => Promise<Response>;
4
+ export type BunMiddleware = (req: Request, next: BunNext) => Promise<Response>;
5
+ export declare function applyRateLimitHeaders(response: Response, headers: RateLimitHeaders): Response;
6
+ export declare function jsonResponse(body: unknown, status: number, headers?: RateLimitHeaders): Response;
7
+ export declare function createBunMiddleware(limiter: RedisLimit): (options: MiddlewareOptions) => BunMiddleware;
8
+ export declare function composeBunHandler(middlewares: BunMiddleware[], handler: (req: Request) => Response | Promise<Response>): (req: Request) => Promise<Response>;
9
+ //# sourceMappingURL=bun.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bun.d.ts","sourceRoot":"","sources":["../../src/middleware/bun.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAIpE,MAAM,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,CAAC;AAE9C,MAAM,MAAM,aAAa,GAAG,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;AAoB/E,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,gBAAgB,GACxB,QAAQ,CAaV;AAED,wBAAgB,YAAY,CAC1B,IAAI,EAAE,OAAO,EACb,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,gBAAgB,GACzB,QAAQ,CAKV;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,UAAU,IAC1B,SAAS,iBAAiB,KAAG,aAAa,CAsDtE;AAED,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,aAAa,EAAE,EAC5B,OAAO,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,GACtD,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAcrC"}
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.applyRateLimitHeaders = applyRateLimitHeaders;
4
+ exports.jsonResponse = jsonResponse;
5
+ exports.createBunMiddleware = createBunMiddleware;
6
+ exports.composeBunHandler = composeBunHandler;
7
+ const headers_1 = require("../utils/headers");
8
+ const metrics_1 = require("../utils/metrics");
9
+ const DEFAULT_KEY = (req) => {
10
+ const forwarded = req.headers.get("x-forwarded-for");
11
+ if (forwarded) {
12
+ return forwarded.split(",")[0].trim();
13
+ }
14
+ return req.headers.get("x-real-ip") ?? "unknown";
15
+ };
16
+ function toHeaderRecord(headers) {
17
+ const record = {};
18
+ for (const [name, value] of Object.entries(headers)) {
19
+ if (value !== undefined) {
20
+ record[name] = value;
21
+ }
22
+ }
23
+ return record;
24
+ }
25
+ function applyRateLimitHeaders(response, headers) {
26
+ const nextHeaders = new Headers(response.headers);
27
+ for (const [name, value] of Object.entries(headers)) {
28
+ if (value !== undefined) {
29
+ nextHeaders.set(name, value);
30
+ }
31
+ }
32
+ return new Response(response.body, {
33
+ status: response.status,
34
+ statusText: response.statusText,
35
+ headers: nextHeaders,
36
+ });
37
+ }
38
+ function jsonResponse(body, status, headers) {
39
+ return Response.json(body, headers ? { status, headers: toHeaderRecord(headers) } : { status });
40
+ }
41
+ function createBunMiddleware(limiter) {
42
+ return function middleware(options) {
43
+ const strategy = limiter.createStrategy(options);
44
+ const keyExtractor = (options.key ?? DEFAULT_KEY);
45
+ const sendHeaders = options.headers !== false;
46
+ const failOpen = options.failOpen ?? true;
47
+ return async (req, next) => {
48
+ const key = keyExtractor(req) ?? "unknown";
49
+ const outcome = await (0, metrics_1.consumeRateLimit)({
50
+ strategy,
51
+ key,
52
+ options,
53
+ failOpen,
54
+ storeType: limiter.getStoreType(),
55
+ context: req,
56
+ });
57
+ if (outcome.status === "error") {
58
+ if (failOpen) {
59
+ return next();
60
+ }
61
+ return jsonResponse({ error: "Service Unavailable" }, 503);
62
+ }
63
+ const result = outcome.result;
64
+ const rateLimitHeaders = (0, headers_1.buildRateLimitHeaders)(result);
65
+ if (!result.allowed) {
66
+ if (options.onLimitReached) {
67
+ await options.onLimitReached(req, { headers: rateLimitHeaders });
68
+ return new Response(null, {
69
+ status: 429,
70
+ headers: sendHeaders ? toHeaderRecord(rateLimitHeaders) : undefined,
71
+ });
72
+ }
73
+ return jsonResponse({ error: "Too Many Requests" }, 429, sendHeaders ? rateLimitHeaders : undefined);
74
+ }
75
+ const response = await next();
76
+ if (sendHeaders) {
77
+ return applyRateLimitHeaders(response, rateLimitHeaders);
78
+ }
79
+ return response;
80
+ };
81
+ };
82
+ }
83
+ function composeBunHandler(middlewares, handler) {
84
+ return async (req) => {
85
+ let index = 0;
86
+ const dispatch = async () => {
87
+ if (index < middlewares.length) {
88
+ const middleware = middlewares[index++];
89
+ return middleware(req, dispatch);
90
+ }
91
+ return handler(req);
92
+ };
93
+ return dispatch();
94
+ };
95
+ }
96
+ //# sourceMappingURL=bun.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bun.js","sourceRoot":"","sources":["../../src/middleware/bun.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"express.d.ts","sourceRoot":"","sources":["../../src/middleware/express.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAKlD,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,UAAU,IAC9B,SAAS,iBAAiB,MASjD,KAAK,OAAO,EACZ,KAAK,QAAQ,EACb,MAAM,YAAY,KACjB,OAAO,CAAC,IAAI,CAAC,CA+BnB"}
1
+ {"version":3,"file":"express.d.ts","sourceRoot":"","sources":["../../src/middleware/express.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAMlD,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,UAAU,IAC9B,SAAS,iBAAiB,MASjD,KAAK,OAAO,EACZ,KAAK,QAAQ,EACb,MAAM,YAAY,KACjB,OAAO,CAAC,IAAI,CAAC,CAsCnB"}
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createExpressMiddleware = createExpressMiddleware;
4
4
  const headers_1 = require("../utils/headers");
5
+ const metrics_1 = require("../utils/metrics");
5
6
  const DEFAULT_KEY = (req) => req.ip ?? "unknown";
6
7
  function createExpressMiddleware(limiter) {
7
8
  return function middleware(options) {
@@ -11,17 +12,22 @@ function createExpressMiddleware(limiter) {
11
12
  const failOpen = options.failOpen ?? true;
12
13
  return async (req, res, next) => {
13
14
  const key = keyExtractor(req) ?? "unknown";
14
- let result;
15
- try {
16
- result = await strategy.consume(key);
17
- }
18
- catch {
15
+ const outcome = await (0, metrics_1.consumeRateLimit)({
16
+ strategy,
17
+ key,
18
+ options,
19
+ failOpen,
20
+ storeType: limiter.getStoreType(),
21
+ context: req,
22
+ });
23
+ if (outcome.status === "error") {
19
24
  if (failOpen) {
20
25
  return next();
21
26
  }
22
27
  res.status(503).json({ error: "Service Unavailable" });
23
28
  return;
24
29
  }
30
+ const result = outcome.result;
25
31
  if (sendHeaders) {
26
32
  (0, headers_1.setHeaders)(res, (0, headers_1.buildRateLimitHeaders)(result));
27
33
  }
@@ -1 +1 @@
1
- {"version":3,"file":"express.js","sourceRoot":"","sources":["../../src/middleware/express.ts"],"names":[],"mappings":";;AAOA,0DA4CC;AAhDD,8CAAqE;AAErE,MAAM,WAAW,GAAG,CAAC,GAAY,EAAU,EAAE,CAAC,GAAG,CAAC,EAAE,IAAI,SAAS,CAAC;AAElE,SAAgB,uBAAuB,CAAC,OAAmB;IACzD,OAAO,SAAS,UAAU,CAAC,OAA0B;QACnD,MAAM,QAAQ,GAAG,OAAO,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;QACjD,MAAM,YAAY,GAAG,CAAC,OAAO,CAAC,GAAG,IAAI,WAAW,CAEzB,CAAC;QACxB,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,KAAK,KAAK,CAAC;QAC9C,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,IAAI,CAAC;QAE1C,OAAO,KAAK,EACV,GAAY,EACZ,GAAa,EACb,IAAkB,EACH,EAAE;YACjB,MAAM,GAAG,GAAG,YAAY,CAAC,GAAG,CAAC,IAAI,SAAS,CAAC;YAE3C,IAAI,MAAM,CAAC;YACX,IAAI,CAAC;gBACH,MAAM,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YACvC,CAAC;YAAC,MAAM,CAAC;gBACP,IAAI,QAAQ,EAAE,CAAC;oBACb,OAAO,IAAI,EAAE,CAAC;gBAChB,CAAC;gBACD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,qBAAqB,EAAE,CAAC,CAAC;gBACvD,OAAO;YACT,CAAC;YAED,IAAI,WAAW,EAAE,CAAC;gBAChB,IAAA,oBAAU,EAAC,GAAG,EAAE,IAAA,+BAAqB,EAAC,MAAM,CAAC,CAAC,CAAC;YACjD,CAAC;YAED,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;gBACnB,IAAI,EAAE,CAAC;gBACP,OAAO;YACT,CAAC;YAED,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;gBAC3B,MAAM,OAAO,CAAC,cAAc,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;gBACvC,OAAO;YACT,CAAC;YAED,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC,CAAC;QACvD,CAAC,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"express.js","sourceRoot":"","sources":["../../src/middleware/express.ts"],"names":[],"mappings":";;AAQA,0DAmDC;AAxDD,8CAAqE;AACrE,8CAAoD;AAEpD,MAAM,WAAW,GAAG,CAAC,GAAY,EAAU,EAAE,CAAC,GAAG,CAAC,EAAE,IAAI,SAAS,CAAC;AAElE,SAAgB,uBAAuB,CAAC,OAAmB;IACzD,OAAO,SAAS,UAAU,CAAC,OAA0B;QACnD,MAAM,QAAQ,GAAG,OAAO,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;QACjD,MAAM,YAAY,GAAG,CAAC,OAAO,CAAC,GAAG,IAAI,WAAW,CAEzB,CAAC;QACxB,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,KAAK,KAAK,CAAC;QAC9C,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,IAAI,CAAC;QAE1C,OAAO,KAAK,EACV,GAAY,EACZ,GAAa,EACb,IAAkB,EACH,EAAE;YACjB,MAAM,GAAG,GAAG,YAAY,CAAC,GAAG,CAAC,IAAI,SAAS,CAAC;YAC3C,MAAM,OAAO,GAAG,MAAM,IAAA,0BAAgB,EAAC;gBACrC,QAAQ;gBACR,GAAG;gBACH,OAAO;gBACP,QAAQ;gBACR,SAAS,EAAE,OAAO,CAAC,YAAY,EAAE;gBACjC,OAAO,EAAE,GAAG;aACb,CAAC,CAAC;YAEH,IAAI,OAAO,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;gBAC/B,IAAI,QAAQ,EAAE,CAAC;oBACb,OAAO,IAAI,EAAE,CAAC;gBAChB,CAAC;gBACD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,qBAAqB,EAAE,CAAC,CAAC;gBACvD,OAAO;YACT,CAAC;YAED,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;YAE9B,IAAI,WAAW,EAAE,CAAC;gBAChB,IAAA,oBAAU,EAAC,GAAG,EAAE,IAAA,+BAAqB,EAAC,MAAM,CAAC,CAAC,CAAC;YACjD,CAAC;YAED,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;gBACnB,IAAI,EAAE,CAAC;gBACP,OAAO;YACT,CAAC;YAED,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;gBAC3B,MAAM,OAAO,CAAC,cAAc,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;gBACvC,OAAO;YACT,CAAC;YAED,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC,CAAC;QACvD,CAAC,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC"}
@@ -1,9 +1,9 @@
1
1
  import type { FastifyPluginAsync } from "fastify";
2
2
  import type { RedisLimit } from "../limiter";
3
- import type { MiddlewareOptions } from "../types";
4
- export type FastifyRateLimitOptions = MiddlewareOptions & {
3
+ import type { MiddlewareOptionsInput } from "../types";
4
+ export type FastifyRateLimitOptions = MiddlewareOptionsInput & {
5
5
  limiter: RedisLimit;
6
6
  };
7
- export declare function createFastifyPlugin(limiter: RedisLimit): FastifyPluginAsync<MiddlewareOptions>;
7
+ export declare function createFastifyPlugin(limiter: RedisLimit): FastifyPluginAsync<MiddlewareOptionsInput>;
8
8
  export declare const redisLimitPlugin: FastifyPluginAsync<FastifyRateLimitOptions>;
9
9
  //# sourceMappingURL=fastify.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"fastify.d.ts","sourceRoot":"","sources":["../../src/middleware/fastify.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAgC,MAAM,SAAS,CAAC;AAChF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAKlD,MAAM,MAAM,uBAAuB,GAAG,iBAAiB,GAAG;IACxD,OAAO,EAAE,UAAU,CAAC;CACrB,CAAC;AAaF,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,UAAU,GAAG,kBAAkB,CAAC,iBAAiB,CAAC,CAuC9F;AAED,eAAO,MAAM,gBAAgB,EAAE,kBAAkB,CAAC,uBAAuB,CAOxE,CAAC"}
1
+ {"version":3,"file":"fastify.d.ts","sourceRoot":"","sources":["../../src/middleware/fastify.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAgC,MAAM,SAAS,CAAC;AAChF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EAAqB,sBAAsB,EAAE,MAAM,UAAU,CAAC;AAM1E,MAAM,MAAM,uBAAuB,GAAG,sBAAsB,GAAG;IAC7D,OAAO,EAAE,UAAU,CAAC;CACrB,CAAC;AAaF,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,UAAU,GAClB,kBAAkB,CAAC,sBAAsB,CAAC,CAkD5C;AAED,eAAO,MAAM,gBAAgB,EAAE,kBAAkB,CAAC,uBAAuB,CAMxE,CAAC"}
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.redisLimitPlugin = void 0;
4
4
  exports.createFastifyPlugin = createFastifyPlugin;
5
5
  const headers_1 = require("../utils/headers");
6
+ const metrics_1 = require("../utils/metrics");
6
7
  const DEFAULT_KEY = (req) => req.ip;
7
8
  function setFastifyHeaders(reply, headers) {
8
9
  for (const [name, value] of Object.entries(headers)) {
@@ -13,29 +14,35 @@ function setFastifyHeaders(reply, headers) {
13
14
  }
14
15
  function createFastifyPlugin(limiter) {
15
16
  const plugin = async (fastify, options) => {
16
- const strategy = limiter.createStrategy(options);
17
- const keyExtractor = (options.key ?? DEFAULT_KEY);
18
- const sendHeaders = options.headers !== false;
19
- const failOpen = options.failOpen ?? true;
17
+ const resolved = limiter.resolveOptions(options);
18
+ const strategy = limiter.createStrategy(resolved);
19
+ const keyExtractor = (resolved.key ?? DEFAULT_KEY);
20
+ const sendHeaders = resolved.headers !== false;
21
+ const failOpen = resolved.failOpen ?? true;
20
22
  fastify.addHook("preHandler", async (request, reply) => {
21
23
  const key = keyExtractor(request) ?? "unknown";
22
- let result;
23
- try {
24
- result = await strategy.consume(key);
25
- }
26
- catch {
24
+ const outcome = await (0, metrics_1.consumeRateLimit)({
25
+ strategy,
26
+ key,
27
+ options: resolved,
28
+ failOpen,
29
+ storeType: limiter.getStoreType(),
30
+ context: request,
31
+ });
32
+ if (outcome.status === "error") {
27
33
  if (failOpen) {
28
34
  return;
29
35
  }
30
36
  reply.status(503).send({ error: "Service Unavailable" });
31
37
  return;
32
38
  }
39
+ const result = outcome.result;
33
40
  if (sendHeaders) {
34
41
  setFastifyHeaders(reply, (0, headers_1.buildRateLimitHeaders)(result));
35
42
  }
36
43
  if (!result.allowed) {
37
- if (options.onLimitReached) {
38
- await options.onLimitReached(request, reply);
44
+ if (resolved.onLimitReached) {
45
+ await resolved.onLimitReached(request, reply);
39
46
  return;
40
47
  }
41
48
  reply.status(429).send({ error: "Too Many Requests" });
@@ -46,8 +53,7 @@ function createFastifyPlugin(limiter) {
46
53
  }
47
54
  const redisLimitPlugin = async (fastify, options) => {
48
55
  const { limiter, ...rest } = options;
49
- const middlewareOptions = rest;
50
- await fastify.register(createFastifyPlugin(limiter), middlewareOptions);
56
+ await fastify.register(createFastifyPlugin(limiter), rest);
51
57
  };
52
58
  exports.redisLimitPlugin = redisLimitPlugin;
53
59
  //# sourceMappingURL=fastify.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"fastify.js","sourceRoot":"","sources":["../../src/middleware/fastify.ts"],"names":[],"mappings":";;;AAsBA,kDAuCC;AA1DD,8CAAyD;AAEzD,MAAM,WAAW,GAAG,CAAC,GAAmB,EAAU,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC;AAM5D,SAAS,iBAAiB,CACxB,KAAmB,EACnB,OAAiD;IAEjD,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACpD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAgB,mBAAmB,CAAC,OAAmB;IACrD,MAAM,MAAM,GAA0C,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE;QAC/E,MAAM,QAAQ,GAAG,OAAO,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;QACjD,MAAM,YAAY,GAAG,CAAC,OAAO,CAAC,GAAG,IAAI,WAAW,CAEzB,CAAC;QACxB,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,KAAK,KAAK,CAAC;QAC9C,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,IAAI,CAAC;QAE1C,OAAO,CAAC,OAAO,CAAC,YAAY,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;YACrD,MAAM,GAAG,GAAG,YAAY,CAAC,OAAO,CAAC,IAAI,SAAS,CAAC;YAE/C,IAAI,MAAM,CAAC;YACX,IAAI,CAAC;gBACH,MAAM,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YACvC,CAAC;YAAC,MAAM,CAAC;gBACP,IAAI,QAAQ,EAAE,CAAC;oBACb,OAAO;gBACT,CAAC;gBACD,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,qBAAqB,EAAE,CAAC,CAAC;gBACzD,OAAO;YACT,CAAC;YAED,IAAI,WAAW,EAAE,CAAC;gBAChB,iBAAiB,CAAC,KAAK,EAAE,IAAA,+BAAqB,EAAC,MAAM,CAAC,CAAC,CAAC;YAC1D,CAAC;YAED,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;gBACpB,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;oBAC3B,MAAM,OAAO,CAAC,cAAc,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;oBAC7C,OAAO;gBACT,CAAC;gBAED,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC,CAAC;YACzD,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,OAAO,MAAM,CAAC;AAChB,CAAC;AAEM,MAAM,gBAAgB,GAAgD,KAAK,EAChF,OAAO,EACP,OAAO,EACP,EAAE;IACF,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,GAAG,OAAO,CAAC;IACrC,MAAM,iBAAiB,GAAG,IAAyB,CAAC;IACpD,MAAM,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAC,OAAO,CAAC,EAAE,iBAAiB,CAAC,CAAC;AAC1E,CAAC,CAAC;AAPW,QAAA,gBAAgB,oBAO3B"}
1
+ {"version":3,"file":"fastify.js","sourceRoot":"","sources":["../../src/middleware/fastify.ts"],"names":[],"mappings":";;;AAuBA,kDAoDC;AAxED,8CAAyD;AACzD,8CAAoD;AAEpD,MAAM,WAAW,GAAG,CAAC,GAAmB,EAAU,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC;AAM5D,SAAS,iBAAiB,CACxB,KAAmB,EACnB,OAAiD;IAEjD,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACpD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAgB,mBAAmB,CACjC,OAAmB;IAEnB,MAAM,MAAM,GAA+C,KAAK,EAC9D,OAAO,EACP,OAAO,EACP,EAAE;QACF,MAAM,QAAQ,GAAG,OAAO,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;QACjD,MAAM,QAAQ,GAAG,OAAO,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;QAClD,MAAM,YAAY,GAAG,CAAC,QAAQ,CAAC,GAAG,IAAI,WAAW,CAE1B,CAAC;QACxB,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,KAAK,KAAK,CAAC;QAC/C,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,IAAI,IAAI,CAAC;QAE3C,OAAO,CAAC,OAAO,CAAC,YAAY,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;YACrD,MAAM,GAAG,GAAG,YAAY,CAAC,OAAO,CAAC,IAAI,SAAS,CAAC;YAC/C,MAAM,OAAO,GAAG,MAAM,IAAA,0BAAgB,EAAC;gBACrC,QAAQ;gBACR,GAAG;gBACH,OAAO,EAAE,QAAQ;gBACjB,QAAQ;gBACR,SAAS,EAAE,OAAO,CAAC,YAAY,EAAE;gBACjC,OAAO,EAAE,OAAO;aACjB,CAAC,CAAC;YAEH,IAAI,OAAO,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;gBAC/B,IAAI,QAAQ,EAAE,CAAC;oBACb,OAAO;gBACT,CAAC;gBACD,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,qBAAqB,EAAE,CAAC,CAAC;gBACzD,OAAO;YACT,CAAC;YAED,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;YAE9B,IAAI,WAAW,EAAE,CAAC;gBAChB,iBAAiB,CAAC,KAAK,EAAE,IAAA,+BAAqB,EAAC,MAAM,CAAC,CAAC,CAAC;YAC1D,CAAC;YAED,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;gBACpB,IAAI,QAAQ,CAAC,cAAc,EAAE,CAAC;oBAC5B,MAAM,QAAQ,CAAC,cAAc,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;oBAC9C,OAAO;gBACT,CAAC;gBAED,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC,CAAC;YACzD,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,OAAO,MAAM,CAAC;AAChB,CAAC;AAEM,MAAM,gBAAgB,GAAgD,KAAK,EAChF,OAAO,EACP,OAAO,EACP,EAAE;IACF,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,GAAG,OAAO,CAAC;IACrC,MAAM,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,CAAC;AAC7D,CAAC,CAAC;AANW,QAAA,gBAAgB,oBAM3B"}
@@ -0,0 +1,5 @@
1
+ import type { Context, Next } from "hono";
2
+ import type { RedisLimit } from "../limiter";
3
+ import type { MiddlewareOptions } from "../types";
4
+ export declare function createHonoMiddleware(limiter: RedisLimit): (options: MiddlewareOptions) => (c: Context, next: Next) => Promise<Response | void>;
5
+ //# sourceMappingURL=hono.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hono.d.ts","sourceRoot":"","sources":["../../src/middleware/hono.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC1C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAuBlD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,UAAU,IAC3B,SAAS,iBAAiB,MAQrC,GAAG,OAAO,EAAE,MAAM,IAAI,KAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAoClE"}
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createHonoMiddleware = createHonoMiddleware;
4
+ const headers_1 = require("../utils/headers");
5
+ const metrics_1 = require("../utils/metrics");
6
+ const DEFAULT_KEY = (c) => {
7
+ const forwarded = c.req.header("x-forwarded-for");
8
+ if (forwarded) {
9
+ return forwarded.split(",")[0].trim();
10
+ }
11
+ return c.req.header("x-real-ip") ?? "unknown";
12
+ };
13
+ function setHonoHeaders(c, headers) {
14
+ for (const [name, value] of Object.entries(headers)) {
15
+ if (value !== undefined) {
16
+ c.header(name, value);
17
+ }
18
+ }
19
+ }
20
+ function createHonoMiddleware(limiter) {
21
+ return function middleware(options) {
22
+ const strategy = limiter.createStrategy(options);
23
+ const keyExtractor = (options.key ?? DEFAULT_KEY);
24
+ const sendHeaders = options.headers !== false;
25
+ const failOpen = options.failOpen ?? true;
26
+ return async (c, next) => {
27
+ const key = keyExtractor(c) ?? "unknown";
28
+ const outcome = await (0, metrics_1.consumeRateLimit)({
29
+ strategy,
30
+ key,
31
+ options,
32
+ failOpen,
33
+ storeType: limiter.getStoreType(),
34
+ context: c,
35
+ });
36
+ if (outcome.status === "error") {
37
+ if (failOpen) {
38
+ return next();
39
+ }
40
+ return c.json({ error: "Service Unavailable" }, 503);
41
+ }
42
+ const result = outcome.result;
43
+ if (sendHeaders) {
44
+ setHonoHeaders(c, (0, headers_1.buildRateLimitHeaders)(result));
45
+ }
46
+ if (result.allowed) {
47
+ return next();
48
+ }
49
+ if (options.onLimitReached) {
50
+ await options.onLimitReached(c.req.raw, c);
51
+ return;
52
+ }
53
+ return c.json({ error: "Too Many Requests" }, 429);
54
+ };
55
+ };
56
+ }
57
+ //# sourceMappingURL=hono.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hono.js","sourceRoot":"","sources":["../../src/middleware/hono.ts"],"names":[],"mappings":";;AAyBA,oDA6CC;AAnED,8CAAyD;AACzD,8CAAoD;AAEpD,MAAM,WAAW,GAAG,CAAC,CAAU,EAAU,EAAE;IACzC,MAAM,SAAS,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC;IAClD,IAAI,SAAS,EAAE,CAAC;QACd,OAAO,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACxC,CAAC;IACD,OAAO,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,SAAS,CAAC;AAChD,CAAC,CAAC;AAEF,SAAS,cAAc,CACrB,CAAU,EACV,OAAiD;IAEjD,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACpD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QACxB,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAgB,oBAAoB,CAAC,OAAmB;IACtD,OAAO,SAAS,UAAU,CAAC,OAA0B;QACnD,MAAM,QAAQ,GAAG,OAAO,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;QACjD,MAAM,YAAY,GAAG,CAAC,OAAO,CAAC,GAAG,IAAI,WAAW,CAEzB,CAAC;QACxB,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,KAAK,KAAK,CAAC;QAC9C,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,IAAI,CAAC;QAE1C,OAAO,KAAK,EAAE,CAAU,EAAE,IAAU,EAA4B,EAAE;YAChE,MAAM,GAAG,GAAG,YAAY,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC;YACzC,MAAM,OAAO,GAAG,MAAM,IAAA,0BAAgB,EAAC;gBACrC,QAAQ;gBACR,GAAG;gBACH,OAAO;gBACP,QAAQ;gBACR,SAAS,EAAE,OAAO,CAAC,YAAY,EAAE;gBACjC,OAAO,EAAE,CAAC;aACX,CAAC,CAAC;YAEH,IAAI,OAAO,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;gBAC/B,IAAI,QAAQ,EAAE,CAAC;oBACb,OAAO,IAAI,EAAE,CAAC;gBAChB,CAAC;gBACD,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,qBAAqB,EAAE,EAAE,GAAG,CAAC,CAAC;YACvD,CAAC;YAED,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;YAE9B,IAAI,WAAW,EAAE,CAAC;gBAChB,cAAc,CAAC,CAAC,EAAE,IAAA,+BAAqB,EAAC,MAAM,CAAC,CAAC,CAAC;YACnD,CAAC;YAED,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;gBACnB,OAAO,IAAI,EAAE,CAAC;YAChB,CAAC;YAED,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;gBAC3B,MAAM,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;gBAC3C,OAAO;YACT,CAAC;YAED,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,mBAAmB,EAAE,EAAE,GAAG,CAAC,CAAC;QACrD,CAAC,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { Context, Next } from "koa";
2
+ import type { RedisLimit } from "../limiter";
3
+ import type { MiddlewareOptions } from "../types";
4
+ export declare function createKoaMiddleware(limiter: RedisLimit): (options: MiddlewareOptions) => (ctx: Context, next: Next) => Promise<void>;
5
+ //# sourceMappingURL=koa.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"koa.d.ts","sourceRoot":"","sources":["../../src/middleware/koa.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AACzC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAiBlD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,UAAU,IAC1B,SAAS,iBAAiB,MAQrC,KAAK,OAAO,EAAE,MAAM,IAAI,KAAG,OAAO,CAAC,IAAI,CAAC,CAuCzD"}
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createKoaMiddleware = createKoaMiddleware;
4
+ const headers_1 = require("../utils/headers");
5
+ const metrics_1 = require("../utils/metrics");
6
+ const DEFAULT_KEY = (ctx) => ctx.ip ?? "unknown";
7
+ function setKoaHeaders(ctx, headers) {
8
+ for (const [name, value] of Object.entries(headers)) {
9
+ if (value !== undefined) {
10
+ ctx.set(name, value);
11
+ }
12
+ }
13
+ }
14
+ function createKoaMiddleware(limiter) {
15
+ return function middleware(options) {
16
+ const strategy = limiter.createStrategy(options);
17
+ const keyExtractor = (options.key ?? DEFAULT_KEY);
18
+ const sendHeaders = options.headers !== false;
19
+ const failOpen = options.failOpen ?? true;
20
+ return async (ctx, next) => {
21
+ const key = keyExtractor(ctx) ?? "unknown";
22
+ const outcome = await (0, metrics_1.consumeRateLimit)({
23
+ strategy,
24
+ key,
25
+ options,
26
+ failOpen,
27
+ storeType: limiter.getStoreType(),
28
+ context: ctx,
29
+ });
30
+ if (outcome.status === "error") {
31
+ if (failOpen) {
32
+ return next();
33
+ }
34
+ ctx.status = 503;
35
+ ctx.body = { error: "Service Unavailable" };
36
+ return;
37
+ }
38
+ const result = outcome.result;
39
+ if (sendHeaders) {
40
+ setKoaHeaders(ctx, (0, headers_1.buildRateLimitHeaders)(result));
41
+ }
42
+ if (result.allowed) {
43
+ return next();
44
+ }
45
+ if (options.onLimitReached) {
46
+ await options.onLimitReached(ctx.request, ctx.response);
47
+ return;
48
+ }
49
+ ctx.status = 429;
50
+ ctx.body = { error: "Too Many Requests" };
51
+ };
52
+ };
53
+ }
54
+ //# sourceMappingURL=koa.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"koa.js","sourceRoot":"","sources":["../../src/middleware/koa.ts"],"names":[],"mappings":";;AAmBA,kDAgDC;AAhED,8CAAyD;AACzD,8CAAoD;AAEpD,MAAM,WAAW,GAAG,CAAC,GAAY,EAAU,EAAE,CAAC,GAAG,CAAC,EAAE,IAAI,SAAS,CAAC;AAElE,SAAS,aAAa,CACpB,GAAY,EACZ,OAAiD;IAEjD,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACpD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAgB,mBAAmB,CAAC,OAAmB;IACrD,OAAO,SAAS,UAAU,CAAC,OAA0B;QACnD,MAAM,QAAQ,GAAG,OAAO,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;QACjD,MAAM,YAAY,GAAG,CAAC,OAAO,CAAC,GAAG,IAAI,WAAW,CAEzB,CAAC;QACxB,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,KAAK,KAAK,CAAC;QAC9C,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,IAAI,CAAC;QAE1C,OAAO,KAAK,EAAE,GAAY,EAAE,IAAU,EAAiB,EAAE;YACvD,MAAM,GAAG,GAAG,YAAY,CAAC,GAAG,CAAC,IAAI,SAAS,CAAC;YAC3C,MAAM,OAAO,GAAG,MAAM,IAAA,0BAAgB,EAAC;gBACrC,QAAQ;gBACR,GAAG;gBACH,OAAO;gBACP,QAAQ;gBACR,SAAS,EAAE,OAAO,CAAC,YAAY,EAAE;gBACjC,OAAO,EAAE,GAAG;aACb,CAAC,CAAC;YAEH,IAAI,OAAO,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;gBAC/B,IAAI,QAAQ,EAAE,CAAC;oBACb,OAAO,IAAI,EAAE,CAAC;gBAChB,CAAC;gBACD,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC;gBACjB,GAAG,CAAC,IAAI,GAAG,EAAE,KAAK,EAAE,qBAAqB,EAAE,CAAC;gBAC5C,OAAO;YACT,CAAC;YAED,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;YAE9B,IAAI,WAAW,EAAE,CAAC;gBAChB,aAAa,CAAC,GAAG,EAAE,IAAA,+BAAqB,EAAC,MAAM,CAAC,CAAC,CAAC;YACpD,CAAC;YAED,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;gBACnB,OAAO,IAAI,EAAE,CAAC;YAChB,CAAC;YAED,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;gBAC3B,MAAM,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;gBACxD,OAAO;YACT,CAAC;YAED,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC;YACjB,GAAG,CAAC,IAAI,GAAG,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC;QAC5C,CAAC,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,14 @@
1
+ import { CanActivate, DynamicModule, type Type } from "@nestjs/common";
2
+ import type { RedisLimit } from "../limiter";
3
+ import type { MiddlewareOptionsInput } from "../types";
4
+ export declare const RATE_LIMIT_KEY = "limitly:rate-limit";
5
+ export declare const RateLimit: (options: MiddlewareOptionsInput) => import("@nestjs/common").CustomDecorator<string>;
6
+ export type NestRateLimitOptions = MiddlewareOptionsInput & {
7
+ limiter: RedisLimit;
8
+ global?: boolean;
9
+ };
10
+ export declare function createNestGuard(limiter: RedisLimit): (defaultOptions?: MiddlewareOptionsInput) => Type<CanActivate>;
11
+ export declare class LimitlyModule {
12
+ }
13
+ export declare function limitlyNestModule(options: NestRateLimitOptions): DynamicModule;
14
+ //# sourceMappingURL=nest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nest.d.ts","sourceRoot":"","sources":["../../src/middleware/nest.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,aAAa,EAQb,KAAK,IAAI,EACV,MAAM,gBAAgB,CAAC;AAGxB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AAMvD,eAAO,MAAM,cAAc,uBAAuB,CAAC;AAEnD,eAAO,MAAM,SAAS,GAAI,SAAS,sBAAsB,qDACnB,CAAC;AAEvC,MAAM,MAAM,oBAAoB,GAAG,sBAAsB,GAAG;IAC1D,OAAO,EAAE,UAAU,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,wBAAgB,eAAe,CAAC,OAAO,EAAE,UAAU,IAE/C,iBAAiB,sBAAsB,KACtC,IAAI,CAAC,WAAW,CAAC,CA+ErB;AAED,qBACa,aAAa;CAAG;AAE7B,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,oBAAoB,GAC5B,aAAa,CAUf"}