limitly 1.0.2 → 3.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.
- package/README.md +471 -22
- package/dist/algorithms/concurrency.d.ts +11 -0
- package/dist/algorithms/concurrency.d.ts.map +1 -0
- package/dist/algorithms/concurrency.js +19 -0
- package/dist/algorithms/concurrency.js.map +1 -0
- package/dist/algorithms/factory.d.ts +3 -2
- package/dist/algorithms/factory.d.ts.map +1 -1
- package/dist/algorithms/factory.js +9 -3
- package/dist/algorithms/factory.js.map +1 -1
- package/dist/algorithms/gcra.d.ts +10 -0
- package/dist/algorithms/gcra.d.ts.map +1 -0
- package/dist/algorithms/gcra.js +15 -0
- package/dist/algorithms/gcra.js.map +1 -0
- package/dist/algorithms/sliding-window.d.ts +4 -4
- package/dist/algorithms/sliding-window.d.ts.map +1 -1
- package/dist/algorithms/sliding-window.js +3 -23
- package/dist/algorithms/sliding-window.js.map +1 -1
- package/dist/algorithms/token-bucket.d.ts +4 -4
- package/dist/algorithms/token-bucket.d.ts.map +1 -1
- package/dist/algorithms/token-bucket.js +3 -20
- package/dist/algorithms/token-bucket.js.map +1 -1
- package/dist/index.d.ts +19 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +46 -1
- package/dist/index.js.map +1 -1
- package/dist/limiter.d.ts +23 -7
- package/dist/limiter.d.ts.map +1 -1
- package/dist/limiter.js +86 -16
- package/dist/limiter.js.map +1 -1
- package/dist/middleware/bun.d.ts +9 -0
- package/dist/middleware/bun.d.ts.map +1 -0
- package/dist/middleware/bun.js +107 -0
- package/dist/middleware/bun.js.map +1 -0
- package/dist/middleware/express.d.ts.map +1 -1
- package/dist/middleware/express.js +30 -14
- package/dist/middleware/express.js.map +1 -1
- package/dist/middleware/fastify.d.ts +3 -3
- package/dist/middleware/fastify.d.ts.map +1 -1
- package/dist/middleware/fastify.js +34 -17
- package/dist/middleware/fastify.js.map +1 -1
- package/dist/middleware/hono.d.ts +5 -0
- package/dist/middleware/hono.d.ts.map +1 -0
- package/dist/middleware/hono.js +71 -0
- package/dist/middleware/hono.js.map +1 -0
- package/dist/middleware/koa.d.ts +5 -0
- package/dist/middleware/koa.d.ts.map +1 -0
- package/dist/middleware/koa.js +65 -0
- package/dist/middleware/koa.js.map +1 -0
- package/dist/middleware/nest.d.ts +14 -0
- package/dist/middleware/nest.d.ts.map +1 -0
- package/dist/middleware/nest.js +112 -0
- package/dist/middleware/nest.js.map +1 -0
- package/dist/observability/index.d.ts +4 -0
- package/dist/observability/index.d.ts.map +1 -0
- package/dist/observability/index.js +10 -0
- package/dist/observability/index.js.map +1 -0
- package/dist/observability/opentelemetry.d.ts +28 -0
- package/dist/observability/opentelemetry.d.ts.map +1 -0
- package/dist/observability/opentelemetry.js +85 -0
- package/dist/observability/opentelemetry.js.map +1 -0
- package/dist/observability/prometheus.d.ts +27 -0
- package/dist/observability/prometheus.d.ts.map +1 -0
- package/dist/observability/prometheus.js +88 -0
- package/dist/observability/prometheus.js.map +1 -0
- package/dist/observability/types.d.ts +9 -0
- package/dist/observability/types.d.ts.map +1 -0
- package/dist/observability/types.js +3 -0
- package/dist/observability/types.js.map +1 -0
- package/dist/prometheus.d.ts +3 -0
- package/dist/prometheus.d.ts.map +1 -0
- package/dist/prometheus.js +9 -0
- package/dist/prometheus.js.map +1 -0
- package/dist/scripts/concurrencyAcquire.lua +34 -0
- package/dist/scripts/concurrencyRelease.lua +9 -0
- package/dist/scripts/gcra.lua +38 -0
- package/dist/stores/factory.d.ts +5 -0
- package/dist/stores/factory.d.ts.map +1 -0
- package/dist/stores/factory.js +40 -0
- package/dist/stores/factory.js.map +1 -0
- package/dist/stores/memcached-store.d.ts +16 -0
- package/dist/stores/memcached-store.d.ts.map +1 -0
- package/dist/stores/memcached-store.js +211 -0
- package/dist/stores/memcached-store.js.map +1 -0
- package/dist/stores/redis-store.d.ts +19 -0
- package/dist/stores/redis-store.d.ts.map +1 -0
- package/dist/stores/redis-store.js +97 -0
- package/dist/stores/redis-store.js.map +1 -0
- package/dist/stores/types.d.ts +11 -0
- package/dist/stores/types.d.ts.map +1 -0
- package/dist/stores/types.js +3 -0
- package/dist/stores/types.js.map +1 -0
- package/dist/types/index.d.ts +94 -5
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/defaults.d.ts +8 -0
- package/dist/utils/defaults.d.ts.map +1 -0
- package/dist/utils/defaults.js +100 -0
- package/dist/utils/defaults.js.map +1 -0
- package/dist/utils/limit-execution.d.ts +40 -0
- package/dist/utils/limit-execution.d.ts.map +1 -0
- package/dist/utils/limit-execution.js +50 -0
- package/dist/utils/limit-execution.js.map +1 -0
- package/dist/utils/memcached.d.ts +12 -0
- package/dist/utils/memcached.d.ts.map +1 -0
- package/dist/utils/memcached.js +103 -0
- package/dist/utils/memcached.js.map +1 -0
- package/dist/utils/metrics.d.ts +21 -0
- package/dist/utils/metrics.d.ts.map +1 -0
- package/dist/utils/metrics.js +99 -0
- package/dist/utils/metrics.js.map +1 -0
- package/dist/utils/redis.d.ts +5 -1
- package/dist/utils/redis.d.ts.map +1 -1
- package/dist/utils/redis.js +38 -3
- package/dist/utils/redis.js.map +1 -1
- package/dist/utils/scripts.d.ts +16 -2
- package/dist/utils/scripts.d.ts.map +1 -1
- package/dist/utils/scripts.js +79 -33
- package/dist/utils/scripts.js.map +1 -1
- package/package.json +86 -3
|
@@ -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 limit_execution_1 = require("../utils/limit-execution");
|
|
5
6
|
const DEFAULT_KEY = (req) => req.ip ?? "unknown";
|
|
6
7
|
function createExpressMiddleware(limiter) {
|
|
7
8
|
return function middleware(options) {
|
|
@@ -11,29 +12,44 @@ 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
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
const outcome = await (0, limit_execution_1.processLimitRequest)({
|
|
16
|
+
limiter,
|
|
17
|
+
strategy,
|
|
18
|
+
key,
|
|
19
|
+
options,
|
|
20
|
+
failOpen,
|
|
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
|
}
|
|
25
|
-
if (
|
|
26
|
-
(
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
+
if (outcome.status === "blocked") {
|
|
31
|
+
if (sendHeaders) {
|
|
32
|
+
(0, headers_1.setHeaders)(res, (0, headers_1.buildRateLimitHeaders)(outcome.result));
|
|
33
|
+
}
|
|
34
|
+
if (options.onLimitReached) {
|
|
35
|
+
await options.onLimitReached(req, res);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
res.status(429).json({ error: "Too Many Requests" });
|
|
30
39
|
return;
|
|
31
40
|
}
|
|
32
|
-
if (
|
|
33
|
-
|
|
34
|
-
|
|
41
|
+
if (sendHeaders) {
|
|
42
|
+
(0, headers_1.setHeaders)(res, (0, headers_1.buildRateLimitHeaders)(outcome.result));
|
|
43
|
+
}
|
|
44
|
+
if (outcome.slotId) {
|
|
45
|
+
(0, limit_execution_1.bindConcurrencyRelease)({
|
|
46
|
+
strategy,
|
|
47
|
+
key,
|
|
48
|
+
slotId: outcome.slotId,
|
|
49
|
+
emitter: res,
|
|
50
|
+
});
|
|
35
51
|
}
|
|
36
|
-
|
|
52
|
+
next();
|
|
37
53
|
};
|
|
38
54
|
};
|
|
39
55
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"express.js","sourceRoot":"","sources":["../../src/middleware/express.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"express.js","sourceRoot":"","sources":["../../src/middleware/express.ts"],"names":[],"mappings":";;AAWA,0DA8DC;AAtED,8CAAqE;AACrE,8DAGkC;AAElC,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,qCAAmB,EAAC;gBACxC,OAAO;gBACP,QAAQ;gBACR,GAAG;gBACH,OAAO;gBACP,QAAQ;gBACR,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,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;gBACjC,IAAI,WAAW,EAAE,CAAC;oBAChB,IAAA,oBAAU,EAAC,GAAG,EAAE,IAAA,+BAAqB,EAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;gBACzD,CAAC;gBAED,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;oBAC3B,MAAM,OAAO,CAAC,cAAc,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;oBACvC,OAAO;gBACT,CAAC;gBAED,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC,CAAC;gBACrD,OAAO;YACT,CAAC;YAED,IAAI,WAAW,EAAE,CAAC;gBAChB,IAAA,oBAAU,EAAC,GAAG,EAAE,IAAA,+BAAqB,EAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;YACzD,CAAC;YAED,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;gBACnB,IAAA,wCAAsB,EAAC;oBACrB,QAAQ;oBACR,GAAG;oBACH,MAAM,EAAE,OAAO,CAAC,MAAM;oBACtB,OAAO,EAAE,GAAG;iBACb,CAAC,CAAC;YACL,CAAC;YAED,IAAI,EAAE,CAAC;QACT,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 {
|
|
4
|
-
export type FastifyRateLimitOptions =
|
|
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<
|
|
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,
|
|
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;AAS1E,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,CA8D5C;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 limit_execution_1 = require("../utils/limit-execution");
|
|
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,32 +14,49 @@ function setFastifyHeaders(reply, headers) {
|
|
|
13
14
|
}
|
|
14
15
|
function createFastifyPlugin(limiter) {
|
|
15
16
|
const plugin = async (fastify, options) => {
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
const
|
|
19
|
-
const
|
|
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
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
const outcome = await (0, limit_execution_1.processLimitRequest)({
|
|
25
|
+
limiter,
|
|
26
|
+
strategy,
|
|
27
|
+
key,
|
|
28
|
+
options: resolved,
|
|
29
|
+
failOpen,
|
|
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
|
}
|
|
33
|
-
if (
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
if (
|
|
38
|
-
await
|
|
39
|
+
if (outcome.status === "blocked") {
|
|
40
|
+
if (sendHeaders) {
|
|
41
|
+
setFastifyHeaders(reply, (0, headers_1.buildRateLimitHeaders)(outcome.result));
|
|
42
|
+
}
|
|
43
|
+
if (resolved.onLimitReached) {
|
|
44
|
+
await resolved.onLimitReached(request, reply);
|
|
39
45
|
return;
|
|
40
46
|
}
|
|
41
47
|
reply.status(429).send({ error: "Too Many Requests" });
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (sendHeaders) {
|
|
51
|
+
setFastifyHeaders(reply, (0, headers_1.buildRateLimitHeaders)(outcome.result));
|
|
52
|
+
}
|
|
53
|
+
if (outcome.slotId) {
|
|
54
|
+
(0, limit_execution_1.bindConcurrencyRelease)({
|
|
55
|
+
strategy,
|
|
56
|
+
key,
|
|
57
|
+
slotId: outcome.slotId,
|
|
58
|
+
emitter: reply.raw,
|
|
59
|
+
});
|
|
42
60
|
}
|
|
43
61
|
});
|
|
44
62
|
};
|
|
@@ -46,8 +64,7 @@ function createFastifyPlugin(limiter) {
|
|
|
46
64
|
}
|
|
47
65
|
const redisLimitPlugin = async (fastify, options) => {
|
|
48
66
|
const { limiter, ...rest } = options;
|
|
49
|
-
|
|
50
|
-
await fastify.register(createFastifyPlugin(limiter), middlewareOptions);
|
|
67
|
+
await fastify.register(createFastifyPlugin(limiter), rest);
|
|
51
68
|
};
|
|
52
69
|
exports.redisLimitPlugin = redisLimitPlugin;
|
|
53
70
|
//# sourceMappingURL=fastify.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fastify.js","sourceRoot":"","sources":["../../src/middleware/fastify.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"fastify.js","sourceRoot":"","sources":["../../src/middleware/fastify.ts"],"names":[],"mappings":";;;AA0BA,kDAgEC;AAvFD,8CAAyD;AACzD,8DAGkC;AAElC,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,qCAAmB,EAAC;gBACxC,OAAO;gBACP,QAAQ;gBACR,GAAG;gBACH,OAAO,EAAE,QAAQ;gBACjB,QAAQ;gBACR,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,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;gBACjC,IAAI,WAAW,EAAE,CAAC;oBAChB,iBAAiB,CAAC,KAAK,EAAE,IAAA,+BAAqB,EAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;gBAClE,CAAC;gBAED,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;gBACvD,OAAO;YACT,CAAC;YAED,IAAI,WAAW,EAAE,CAAC;gBAChB,iBAAiB,CAAC,KAAK,EAAE,IAAA,+BAAqB,EAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;YAClE,CAAC;YAED,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;gBACnB,IAAA,wCAAsB,EAAC;oBACrB,QAAQ;oBACR,GAAG;oBACH,MAAM,EAAE,OAAO,CAAC,MAAM;oBACtB,OAAO,EAAE,KAAK,CAAC,GAAG;iBACnB,CAAC,CAAC;YACL,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;AA0BlD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,UAAU,IAC3B,SAAS,iBAAiB,MAQrC,GAAG,OAAO,EAAE,MAAM,IAAI,KAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAkDlE"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createHonoMiddleware = createHonoMiddleware;
|
|
4
|
+
const headers_1 = require("../utils/headers");
|
|
5
|
+
const limit_execution_1 = require("../utils/limit-execution");
|
|
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, limit_execution_1.processLimitRequest)({
|
|
29
|
+
limiter,
|
|
30
|
+
strategy,
|
|
31
|
+
key,
|
|
32
|
+
options,
|
|
33
|
+
failOpen,
|
|
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
|
+
if (outcome.status === "blocked") {
|
|
43
|
+
if (sendHeaders) {
|
|
44
|
+
setHonoHeaders(c, (0, headers_1.buildRateLimitHeaders)(outcome.result));
|
|
45
|
+
}
|
|
46
|
+
if (options.onLimitReached) {
|
|
47
|
+
await options.onLimitReached(c.req.raw, c);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
return c.json({ error: "Too Many Requests" }, 429);
|
|
51
|
+
}
|
|
52
|
+
if (sendHeaders) {
|
|
53
|
+
setHonoHeaders(c, (0, headers_1.buildRateLimitHeaders)(outcome.result));
|
|
54
|
+
}
|
|
55
|
+
if (outcome.slotId) {
|
|
56
|
+
try {
|
|
57
|
+
return await next();
|
|
58
|
+
}
|
|
59
|
+
finally {
|
|
60
|
+
await (0, limit_execution_1.releaseConcurrencySlot)({
|
|
61
|
+
strategy,
|
|
62
|
+
key,
|
|
63
|
+
slotId: outcome.slotId,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return next();
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=hono.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hono.js","sourceRoot":"","sources":["../../src/middleware/hono.ts"],"names":[],"mappings":"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"}
|
|
@@ -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;AAqBlD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,UAAU,IAC1B,SAAS,iBAAiB,MAQrC,KAAK,OAAO,EAAE,MAAM,IAAI,KAAG,OAAO,CAAC,IAAI,CAAC,CAmDzD"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createKoaMiddleware = createKoaMiddleware;
|
|
4
|
+
const headers_1 = require("../utils/headers");
|
|
5
|
+
const limit_execution_1 = require("../utils/limit-execution");
|
|
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, limit_execution_1.processLimitRequest)({
|
|
23
|
+
limiter,
|
|
24
|
+
strategy,
|
|
25
|
+
key,
|
|
26
|
+
options,
|
|
27
|
+
failOpen,
|
|
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
|
+
if (outcome.status === "blocked") {
|
|
39
|
+
if (sendHeaders) {
|
|
40
|
+
setKoaHeaders(ctx, (0, headers_1.buildRateLimitHeaders)(outcome.result));
|
|
41
|
+
}
|
|
42
|
+
if (options.onLimitReached) {
|
|
43
|
+
await options.onLimitReached(ctx.request, ctx.response);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
ctx.status = 429;
|
|
47
|
+
ctx.body = { error: "Too Many Requests" };
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (sendHeaders) {
|
|
51
|
+
setKoaHeaders(ctx, (0, headers_1.buildRateLimitHeaders)(outcome.result));
|
|
52
|
+
}
|
|
53
|
+
if (outcome.slotId) {
|
|
54
|
+
(0, limit_execution_1.bindConcurrencyRelease)({
|
|
55
|
+
strategy,
|
|
56
|
+
key,
|
|
57
|
+
slotId: outcome.slotId,
|
|
58
|
+
emitter: ctx.res,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
return next();
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=koa.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"koa.js","sourceRoot":"","sources":["../../src/middleware/koa.ts"],"names":[],"mappings":";;AAuBA,kDA4DC;AAhFD,8CAAyD;AACzD,8DAIkC;AAElC,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,qCAAmB,EAAC;gBACxC,OAAO;gBACP,QAAQ;gBACR,GAAG;gBACH,OAAO;gBACP,QAAQ;gBACR,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,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;gBACjC,IAAI,WAAW,EAAE,CAAC;oBAChB,aAAa,CAAC,GAAG,EAAE,IAAA,+BAAqB,EAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;gBAC5D,CAAC;gBAED,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;oBAC3B,MAAM,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;oBACxD,OAAO;gBACT,CAAC;gBAED,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC;gBACjB,GAAG,CAAC,IAAI,GAAG,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC;gBAC1C,OAAO;YACT,CAAC;YAED,IAAI,WAAW,EAAE,CAAC;gBAChB,aAAa,CAAC,GAAG,EAAE,IAAA,+BAAqB,EAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;YAC5D,CAAC;YAED,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;gBACnB,IAAA,wCAAsB,EAAC;oBACrB,QAAQ;oBACR,GAAG;oBACH,MAAM,EAAE,OAAO,CAAC,MAAM;oBACtB,OAAO,EAAE,GAAG,CAAC,GAAG;iBACjB,CAAC,CAAC;YACL,CAAC;YAED,OAAO,IAAI,EAAE,CAAC;QAChB,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;AASvD,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,CA0FrB;AAED,qBACa,aAAa;CAAG;AAE7B,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,oBAAoB,GAC5B,aAAa,CAUf"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
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
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
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
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.LimitlyModule = exports.RateLimit = exports.RATE_LIMIT_KEY = void 0;
|
|
13
|
+
exports.createNestGuard = createNestGuard;
|
|
14
|
+
exports.limitlyNestModule = limitlyNestModule;
|
|
15
|
+
const common_1 = require("@nestjs/common");
|
|
16
|
+
const core_1 = require("@nestjs/core");
|
|
17
|
+
const headers_1 = require("../utils/headers");
|
|
18
|
+
const limit_execution_1 = require("../utils/limit-execution");
|
|
19
|
+
const DEFAULT_KEY = (req) => req.ip ?? "unknown";
|
|
20
|
+
exports.RATE_LIMIT_KEY = "limitly:rate-limit";
|
|
21
|
+
const RateLimit = (options) => (0, common_1.SetMetadata)(exports.RATE_LIMIT_KEY, options);
|
|
22
|
+
exports.RateLimit = RateLimit;
|
|
23
|
+
function createNestGuard(limiter) {
|
|
24
|
+
return function guard(defaultOptions) {
|
|
25
|
+
let NestGuard = class NestGuard {
|
|
26
|
+
constructor(reflector) {
|
|
27
|
+
this.reflector = reflector;
|
|
28
|
+
}
|
|
29
|
+
async canActivate(context) {
|
|
30
|
+
const metadata = this.reflector.getAllAndOverride(exports.RATE_LIMIT_KEY, [context.getHandler(), context.getClass()]);
|
|
31
|
+
const shouldApply = metadata !== undefined ||
|
|
32
|
+
defaultOptions !== undefined ||
|
|
33
|
+
Object.keys(limiter.getDefaultOptions()).length > 0;
|
|
34
|
+
if (!shouldApply) {
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
const options = limiter.resolveOptions({
|
|
38
|
+
...defaultOptions,
|
|
39
|
+
...metadata,
|
|
40
|
+
});
|
|
41
|
+
const strategy = limiter.createStrategy(options);
|
|
42
|
+
const http = context.switchToHttp();
|
|
43
|
+
const request = http.getRequest();
|
|
44
|
+
const response = http.getResponse();
|
|
45
|
+
const keyExtractor = (options.key ?? DEFAULT_KEY);
|
|
46
|
+
const key = keyExtractor(request) ?? "unknown";
|
|
47
|
+
const sendHeaders = options.headers !== false;
|
|
48
|
+
const failOpen = options.failOpen ?? true;
|
|
49
|
+
const outcome = await (0, limit_execution_1.processLimitRequest)({
|
|
50
|
+
limiter,
|
|
51
|
+
strategy,
|
|
52
|
+
key,
|
|
53
|
+
options,
|
|
54
|
+
failOpen,
|
|
55
|
+
context: context,
|
|
56
|
+
});
|
|
57
|
+
if (outcome.status === "error") {
|
|
58
|
+
if (failOpen) {
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
throw new common_1.ServiceUnavailableException({
|
|
62
|
+
error: "Service Unavailable",
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
if (outcome.status === "blocked") {
|
|
66
|
+
if (sendHeaders) {
|
|
67
|
+
(0, headers_1.setHeaders)(response, (0, headers_1.buildRateLimitHeaders)(outcome.result));
|
|
68
|
+
}
|
|
69
|
+
if (options.onLimitReached) {
|
|
70
|
+
await options.onLimitReached(request, response);
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
throw new common_1.HttpException({ error: "Too Many Requests" }, common_1.HttpStatus.TOO_MANY_REQUESTS);
|
|
74
|
+
}
|
|
75
|
+
if (sendHeaders) {
|
|
76
|
+
(0, headers_1.setHeaders)(response, (0, headers_1.buildRateLimitHeaders)(outcome.result));
|
|
77
|
+
}
|
|
78
|
+
if (outcome.slotId) {
|
|
79
|
+
(0, limit_execution_1.bindConcurrencyRelease)({
|
|
80
|
+
strategy,
|
|
81
|
+
key,
|
|
82
|
+
slotId: outcome.slotId,
|
|
83
|
+
emitter: response,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
NestGuard = __decorate([
|
|
90
|
+
(0, common_1.Injectable)(),
|
|
91
|
+
__metadata("design:paramtypes", [core_1.Reflector])
|
|
92
|
+
], NestGuard);
|
|
93
|
+
return NestGuard;
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
let LimitlyModule = class LimitlyModule {
|
|
97
|
+
};
|
|
98
|
+
exports.LimitlyModule = LimitlyModule;
|
|
99
|
+
exports.LimitlyModule = LimitlyModule = __decorate([
|
|
100
|
+
(0, common_1.Module)({})
|
|
101
|
+
], LimitlyModule);
|
|
102
|
+
function limitlyNestModule(options) {
|
|
103
|
+
const { limiter, global, ...middlewareOptions } = options;
|
|
104
|
+
const Guard = createNestGuard(limiter)(middlewareOptions);
|
|
105
|
+
return {
|
|
106
|
+
module: LimitlyModule,
|
|
107
|
+
providers: [Guard],
|
|
108
|
+
exports: [Guard],
|
|
109
|
+
global: global ?? false,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=nest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nest.js","sourceRoot":"","sources":["../../src/middleware/nest.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { createOpenTelemetryInstrumentation, createOpenTelemetryMetricsHook, createOpenTelemetryTracer, DEFAULT_METER_NAME, DEFAULT_TRACER_NAME, } from "./opentelemetry";
|
|
2
|
+
export type { OpenTelemetryInstrumentationOptions, OpenTelemetryMetricsOptions, OpenTelemetryTracerOptions, } from "./opentelemetry";
|
|
3
|
+
export type { RateLimitSpan, RateLimitTracer } from "./types";
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/observability/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kCAAkC,EAClC,8BAA8B,EAC9B,yBAAyB,EACzB,kBAAkB,EAClB,mBAAmB,GACpB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACV,mCAAmC,EACnC,2BAA2B,EAC3B,0BAA0B,GAC3B,MAAM,iBAAiB,CAAC;AACzB,YAAY,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DEFAULT_TRACER_NAME = exports.DEFAULT_METER_NAME = exports.createOpenTelemetryTracer = exports.createOpenTelemetryMetricsHook = exports.createOpenTelemetryInstrumentation = void 0;
|
|
4
|
+
var opentelemetry_1 = require("./opentelemetry");
|
|
5
|
+
Object.defineProperty(exports, "createOpenTelemetryInstrumentation", { enumerable: true, get: function () { return opentelemetry_1.createOpenTelemetryInstrumentation; } });
|
|
6
|
+
Object.defineProperty(exports, "createOpenTelemetryMetricsHook", { enumerable: true, get: function () { return opentelemetry_1.createOpenTelemetryMetricsHook; } });
|
|
7
|
+
Object.defineProperty(exports, "createOpenTelemetryTracer", { enumerable: true, get: function () { return opentelemetry_1.createOpenTelemetryTracer; } });
|
|
8
|
+
Object.defineProperty(exports, "DEFAULT_METER_NAME", { enumerable: true, get: function () { return opentelemetry_1.DEFAULT_METER_NAME; } });
|
|
9
|
+
Object.defineProperty(exports, "DEFAULT_TRACER_NAME", { enumerable: true, get: function () { return opentelemetry_1.DEFAULT_TRACER_NAME; } });
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/observability/index.ts"],"names":[],"mappings":";;;AAAA,iDAMyB;AALvB,mIAAA,kCAAkC,OAAA;AAClC,+HAAA,8BAA8B,OAAA;AAC9B,0HAAA,yBAAyB,OAAA;AACzB,mHAAA,kBAAkB,OAAA;AAClB,oHAAA,mBAAmB,OAAA"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type Meter, type Tracer } from "@opentelemetry/api";
|
|
2
|
+
import type { RateLimitMetricsHook } from "../types";
|
|
3
|
+
import type { RateLimitTracer } from "./types";
|
|
4
|
+
export declare const DEFAULT_METER_NAME = "limitly";
|
|
5
|
+
export declare const DEFAULT_TRACER_NAME = "limitly";
|
|
6
|
+
export interface OpenTelemetryMetricsOptions {
|
|
7
|
+
/** OpenTelemetry meter. Defaults to `metrics.getMeter("limitly")`. */
|
|
8
|
+
meter?: Meter;
|
|
9
|
+
/** Meter scope name. Defaults to `"limitly"`. */
|
|
10
|
+
meterName?: string;
|
|
11
|
+
/** Include the rate limit key in metric attributes. Defaults to `false`. */
|
|
12
|
+
includeKey?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface OpenTelemetryTracerOptions {
|
|
15
|
+
/** OpenTelemetry tracer. Defaults to `trace.getTracer("limitly")`. */
|
|
16
|
+
tracer?: Tracer;
|
|
17
|
+
/** Tracer scope name. Defaults to `"limitly"`. */
|
|
18
|
+
tracerName?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface OpenTelemetryInstrumentationOptions extends OpenTelemetryMetricsOptions, OpenTelemetryTracerOptions {
|
|
21
|
+
}
|
|
22
|
+
export declare function createOpenTelemetryMetricsHook(options?: OpenTelemetryMetricsOptions): RateLimitMetricsHook;
|
|
23
|
+
export declare function createOpenTelemetryTracer(options?: OpenTelemetryTracerOptions): RateLimitTracer;
|
|
24
|
+
export declare function createOpenTelemetryInstrumentation(options?: OpenTelemetryInstrumentationOptions): {
|
|
25
|
+
tracer: RateLimitTracer;
|
|
26
|
+
onMetrics: RateLimitMetricsHook;
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=opentelemetry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opentelemetry.d.ts","sourceRoot":"","sources":["../../src/observability/opentelemetry.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,KAAK,EACV,KAAK,MAAM,EACZ,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAEV,oBAAoB,EACrB,MAAM,UAAU,CAAC;AAClB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C,eAAO,MAAM,kBAAkB,YAAY,CAAC;AAC5C,eAAO,MAAM,mBAAmB,YAAY,CAAC;AAE7C,MAAM,WAAW,2BAA2B;IAC1C,sEAAsE;IACtE,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,iDAAiD;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,4EAA4E;IAC5E,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,0BAA0B;IACzC,sEAAsE;IACtE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kDAAkD;IAClD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,mCACf,SAAQ,2BAA2B,EACjC,0BAA0B;CAAG;AAoDjC,wBAAgB,8BAA8B,CAC5C,OAAO,GAAE,2BAAgC,GACxC,oBAAoB,CAWtB;AAED,wBAAgB,yBAAyB,CACvC,OAAO,GAAE,0BAA+B,GACvC,eAAe,CA6BjB;AAED,wBAAgB,kCAAkC,CAChD,OAAO,GAAE,mCAAwC,GAChD;IACD,MAAM,EAAE,eAAe,CAAC;IACxB,SAAS,EAAE,oBAAoB,CAAC;CACjC,CAKA"}
|