@fluojs/throttler 1.0.4 → 1.0.5

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.ko.md CHANGED
@@ -97,7 +97,7 @@ ThrottlerModule.forRoot({
97
97
 
98
98
  기본적으로 throttler는 raw socket `remoteAddress`만으로 클라이언트 식별자를 해석합니다. 배포가 `Forwarded`, `X-Forwarded-For`, `X-Real-IP`를 덮어쓰는 신뢰 가능한 리버스 프록시 뒤에 있다면 `trustProxyHeaders: true`로 명시적으로 opt-in 하세요. 신뢰 가능한 소켓 식별자나 프록시 식별자가 없으면 서로 다른 호출자를 같은 버킷으로 합치지 않도록 예외를 던집니다. API 키나 사용자 ID 등 다른 식별자를 사용하도록 커스터마이징할 수도 있습니다.
99
99
 
100
- 카운터는 route identity와 client identity로 구분됩니다. route 부분에는 method, path, version, handler identity가 포함되므로 서로 다른 핸들러가 실수로 같은 버킷을 공유하지 않습니다. 요청이 거부되면 `ThrottlerGuard`는 `429`를 반환하고 `Retry-After`를 설정합니다.
100
+ 카운터는 route identity와 client identity로 구분됩니다. route 부분에는 module, controller, method, path, version, handler identity가 포함되므로 서로 다른 route-handler 경계가 실수로 같은 버킷을 공유하지 않습니다. 요청이 거부되면 `ThrottlerGuard`는 `429`를 반환하고 `Retry-After`를 설정합니다.
101
101
 
102
102
  ```typescript
103
103
  ThrottlerModule.forRoot({
@@ -137,6 +137,7 @@ ThrottlerModule.forRoot({
137
137
 
138
138
  ### 모듈
139
139
  - `ThrottlerModule.forRoot(options)`: 검증된 throttler 옵션과 `ThrottlerGuard`를 모듈 그래프에 제공합니다.
140
+ - `ThrottlerModuleOptions`: `ThrottlerModule.forRoot(...)`가 받는 공개 options shape입니다.
140
141
  - 패키지 수준 등록은 `ThrottlerModule.forRoot(options)`를 통해 지원합니다. 내부 프로바이더 조합 헬퍼와 DI 토큰은 공개 계약에 포함되지 않습니다.
141
142
 
142
143
  `ttl`과 `limit`은 양의 finite integer여야 합니다. `global`은 기본값이 `true`입니다. throttler provider를 가져온 모듈 범위에만 유지하려면 `global: false`를 설정하세요. `trustProxyHeaders`와 `keyGenerator`로 client identity를 조정할 수 있으며, `keyGenerator`를 제공할 때는 함수여야 합니다. 모듈 옵션은 guard가 연결될 때 검증되고 값으로 캡처되므로, 호출자가 나중에 options 객체를 변경해도 실행 중인 throttling 정책은 바뀌지 않습니다. `store` 옵션을 제공하지 않으면 각 `ThrottlerGuard` 인스턴스가 자체 in-memory store를 소유합니다. 저장소를 공유하거나 외부에서 관리해야 한다면 `RedisThrottlerStore` 같은 `ThrottlerStore` 구현을 전달하세요.
package/README.md CHANGED
@@ -97,7 +97,7 @@ You can also pass any object that implements the `ThrottlerStore` contract throu
97
97
 
98
98
  By default, the throttler resolves client identity from the raw socket `remoteAddress` only. If your deployment sits behind a trusted reverse proxy that rewrites `Forwarded`, `X-Forwarded-For`, or `X-Real-IP`, opt in with `trustProxyHeaders: true`. If no trusted socket or proxy identity is available, it throws instead of collapsing unrelated callers into a shared bucket. You can also customize this to use API keys, user IDs, or other identifiers.
99
99
 
100
- Counters are scoped by route identity and client identity. The route portion includes method, path, version, and handler identity so different handlers do not share buckets accidentally. When a request is rejected, `ThrottlerGuard` returns `429` and sets `Retry-After`.
100
+ Counters are scoped by route identity and client identity. The route portion includes module, controller, method, path, version, and handler identity so different route-handler boundaries do not share buckets accidentally. When a request is rejected, `ThrottlerGuard` returns `429` and sets `Retry-After`.
101
101
 
102
102
  ```typescript
103
103
  ThrottlerModule.forRoot({
@@ -137,6 +137,7 @@ When migrating from `@nestjs/throttler`, treat `@fluojs/throttler` as an explici
137
137
 
138
138
  ### Modules
139
139
  - `ThrottlerModule.forRoot(options)`: Provides validated throttler options and `ThrottlerGuard` to the module graph.
140
+ - `ThrottlerModuleOptions`: Public options shape accepted by `ThrottlerModule.forRoot(...)`.
140
141
  - Package-level registration is supported through `ThrottlerModule.forRoot(options)`. Internal provider-composition helpers and DI tokens are not part of the public contract.
141
142
 
142
143
  `ttl` and `limit` must be positive finite integers. `global` defaults to `true`; set `global: false` when the throttler providers should stay scoped to the importing module. `trustProxyHeaders` and `keyGenerator` customize client identity; `keyGenerator`, when provided, must be a function. Module options are validated and captured by value when the guard is wired so later mutation of the caller's options object does not change live throttling policy. If no `store` option is supplied, each `ThrottlerGuard` instance owns its own in-memory store; pass a `ThrottlerStore` implementation such as `RedisThrottlerStore` when storage must be shared or externally managed.
@@ -1 +1 @@
1
- {"version":3,"file":"guard.d.ts","sourceRoot":"","sources":["../src/guard.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,KAAK,EAAE,KAAK,YAAY,EAAoD,MAAM,cAAc,CAAC;AAa/G,OAAO,KAAK,EAAE,sBAAsB,EAAuC,MAAM,YAAY,CAAC;AA4D9F;;GAEG;AACH,qBACa,cAAe,YAAW,KAAK;IAC1C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAyB;IAEjD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAA+D;IAEhG,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiB;gBAE3B,OAAO,EAAE,sBAAsB;IAO3C,OAAO,CAAC,iBAAiB;IAuCzB;;;;;;OAMG;IACG,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC;CAkC3D"}
1
+ {"version":3,"file":"guard.d.ts","sourceRoot":"","sources":["../src/guard.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,KAAK,EAAE,KAAK,YAAY,EAAoD,MAAM,cAAc,CAAC;AAa/G,OAAO,KAAK,EAAE,sBAAsB,EAAuC,MAAM,YAAY,CAAC;AAgE9F;;GAEG;AACH,qBACa,cAAe,YAAW,KAAK;IAC1C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAyB;IAEjD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAA+D;IAEhG,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiB;gBAE3B,OAAO,EAAE,sBAAsB;IAO3C,OAAO,CAAC,iBAAiB;IA8CzB;;;;;;OAMG;IACG,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC;CAkC3D"}
package/dist/guard.js CHANGED
@@ -35,7 +35,9 @@ function buildStoreKey(encodedHandlerKey, clientKey) {
35
35
  }
36
36
  function buildHandlerKey(handler) {
37
37
  const version = handler.route.version ?? handler.metadata.effectiveVersion ?? 'unversioned';
38
- return [`method:${handler.route.method}`, `path:${encodeURIComponent(handler.route.path)}`, `version:${encodeURIComponent(version)}`, `handler:${encodeURIComponent(handler.methodName)}`].join('|');
38
+ const moduleName = handler.metadata.moduleType?.name || '<moduleless>';
39
+ const controllerName = handler.controllerToken.name || '<anonymous-controller>';
40
+ return [`module:${encodeURIComponent(moduleName)}`, `controller:${encodeURIComponent(controllerName)}`, `method:${handler.route.method}`, `path:${encodeURIComponent(handler.route.path)}`, `version:${encodeURIComponent(version)}`, `handler:${encodeURIComponent(handler.methodName)}`].join('|');
39
41
  }
40
42
  function resolveRetryAfterSeconds(entry, now) {
41
43
  const retryAfterMs = entry.retryAfterMs ?? entry[throttlerRetryAfterMsSymbol];
@@ -68,7 +70,7 @@ class ThrottlerGuard {
68
70
  this.resolvedPolicies.set(handler.controllerToken, controllerPolicies);
69
71
  }
70
72
  const version = handler.route.version ?? handler.metadata.effectiveVersion ?? 'unversioned';
71
- const cacheKey = [handler.methodName, handler.route.method, handler.route.path, version].join('\u0000');
73
+ const cacheKey = [handler.metadata.moduleType?.name || '<moduleless>', handler.controllerToken.name || '<anonymous-controller>', handler.methodName, handler.route.method, handler.route.path, version].join('\u0000');
72
74
  const cachedPolicy = controllerPolicies.get(cacheKey);
73
75
  if (cachedPolicy) {
74
76
  return cachedPolicy;
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "redis",
10
10
  "decorator"
11
11
  ],
12
- "version": "1.0.4",
12
+ "version": "1.0.5",
13
13
  "private": false,
14
14
  "license": "MIT",
15
15
  "repository": {
@@ -36,14 +36,14 @@
36
36
  "dist"
37
37
  ],
38
38
  "dependencies": {
39
- "@fluojs/core": "^1.0.3",
40
- "@fluojs/di": "^1.1.0",
41
- "@fluojs/http": "^1.1.2",
42
- "@fluojs/runtime": "^1.1.8"
39
+ "@fluojs/core": "^1.1.0",
40
+ "@fluojs/di": "^2.0.0",
41
+ "@fluojs/http": "^2.0.1",
42
+ "@fluojs/runtime": "^2.0.1"
43
43
  },
44
44
  "peerDependencies": {
45
45
  "ioredis": "^5.0.0",
46
- "@fluojs/redis": "^1.0.2"
46
+ "@fluojs/redis": "^1.1.0"
47
47
  },
48
48
  "peerDependenciesMeta": {
49
49
  "@fluojs/redis": {
@@ -56,7 +56,7 @@
56
56
  "devDependencies": {
57
57
  "ioredis": "^5.10.0",
58
58
  "vitest": "^3.2.4",
59
- "@fluojs/testing": "^1.0.6"
59
+ "@fluojs/testing": "^2.0.0"
60
60
  },
61
61
  "scripts": {
62
62
  "prebuild": "node ../../tooling/scripts/clean-dist.mjs",