@unikvs/rate-limit 0.0.13 → 0.0.14

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/index.d.ts CHANGED
@@ -28,14 +28,10 @@ export declare class RateLimitExceededError extends ErrorBase<RateLimitExceededE
28
28
  */
29
29
  type RateLimitInvalidOptionErrorMeta = {
30
30
  /**
31
- * 不正だったオプション名です。
32
- *
33
31
  * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit-invalid-option-name)
34
32
  */
35
33
  readonly name: string;
36
34
  /**
37
- * 指定された値です。
38
- *
39
35
  * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit-invalid-option-actual)
40
36
  */
41
37
  readonly actual: unknown;
@@ -45,8 +41,6 @@ type RateLimitInvalidOptionErrorMeta = {
45
41
  */
46
42
  type RateLimitInvalidOptionErrorArgs = ErrorOptions & RateLimitInvalidOptionErrorMeta;
47
43
  /**
48
- * コンストラクターに不正なオプションが渡されたときのエラーです。
49
- *
50
44
  * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#error-rate-limit-invalid-option)
51
45
  */
52
46
  export declare class RateLimitInvalidOptionError extends InvalidUsageErrorBase<RateLimitInvalidOptionErrorMeta> {
@@ -58,74 +52,49 @@ export declare class RateLimitInvalidOptionError extends InvalidUsageErrorBase<R
58
52
  //#endregion
59
53
  //#region ../src/rate-limit.d.ts
60
54
  /**
61
- * レート制限を超えたときの挙動です。
62
- *
63
- * - `"wait"` はトークンが補充されるまで待機します。
64
- * - `"throw"` は直ちにエラーを投げます。
65
- *
66
55
  * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit-strategy)
67
56
  */
68
57
  type RateLimitStrategy = "wait" | "throw";
69
58
  /**
70
- * 待機処理の実装です。テストで時刻を制御するときに差し替えます。
71
- *
72
59
  * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#irate-limit-sleep)
73
60
  */
74
61
  interface IRateLimitSleep {
75
62
  (ms: number, signal: AbortSignal): Promise<void>;
76
63
  }
77
64
  /**
78
- * RateLimit ミドルウェアのオプションです。
79
- *
80
65
  * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit-options)
81
66
  */
82
67
  type RateLimitOptions = {
83
68
  /**
84
- * 1 インターバルあたりに補充されるトークン数です。既定値は `1` です。
85
- *
86
69
  * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit-options-tokens-per-interval)
87
70
  */
88
71
  readonly tokensPerInterval?: number | undefined;
89
72
  /**
90
- * トークンを補充する間隔 (ミリ秒) です。既定値は `1000` です。
91
- *
92
73
  * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit-options-interval-ms)
93
74
  */
94
75
  readonly intervalMs?: number | undefined;
95
76
  /**
96
- * 保持できるトークンの上限です。既定値は `tokensPerInterval` です。
97
- *
98
77
  * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit-options-max-tokens)
99
78
  */
100
79
  readonly maxTokens?: number | undefined;
101
80
  /**
102
- * `maxTokens` の別名です。両方を指定した場合は `maxTokens` が優先されます。
103
- *
104
81
  * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit-options-burst)
105
82
  */
106
83
  readonly burst?: number | undefined;
107
84
  /**
108
- * レート制限を超えたときの挙動です。既定値は `"wait"` です。
109
- *
110
85
  * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit-options-strategy)
111
86
  */
112
87
  readonly strategy?: RateLimitStrategy | undefined;
113
88
  /**
114
- * 現在時刻 (epoch ミリ秒) を返す関数です。既定値は `Date.now` です。
115
- *
116
89
  * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit-options-now)
117
90
  */
118
91
  readonly now?: (() => number) | undefined;
119
92
  /**
120
- * 待機処理です。既定では `setTimeout` を使用します。
121
- *
122
93
  * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit-options-sleep)
123
94
  */
124
95
  readonly sleep?: IRateLimitSleep | undefined;
125
96
  };
126
97
  /**
127
- * トークンバケットで操作頻度を制限するミドルウェアです。
128
- *
129
98
  * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit)
130
99
  */
131
100
  declare class RateLimit extends PassThrough implements IMiddleware {
@@ -135,39 +104,26 @@ declare class RateLimit extends PassThrough implements IMiddleware {
135
104
  */
136
105
  override readonly name: string;
137
106
  /**
138
- * 1 インターバルあたりに補充されるトークン数です。
139
- *
140
107
  * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit)
141
108
  */
142
109
  readonly tokensPerInterval: number;
143
110
  /**
144
- * トークンを補充する間隔 (ミリ秒) です。
145
- *
146
111
  * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit)
147
112
  */
148
113
  readonly intervalMs: number;
149
114
  /**
150
- * 保持できるトークンの上限です。
151
- *
152
115
  * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit)
153
116
  */
154
117
  readonly maxTokens: number;
155
118
  /**
156
- * レート制限を超えたときの挙動です。
157
- *
158
119
  * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit)
159
120
  */
160
121
  readonly strategy: RateLimitStrategy;
161
122
  /**
162
- * RateLimit ミドルウェアを作成します。
163
- *
164
- * @param options トークン数と補充間隔などの設定です。
165
123
  * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit)
166
124
  */
167
125
  constructor(options?: RateLimitOptions);
168
126
  /**
169
- * 現在保持しているトークン数です。
170
- *
171
127
  * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit)
172
128
  */
173
129
  get availableTokens(): number;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/errors.ts","../src/rate-limit.ts"],"mappings":";;;;;;KAKY;;;;WAID;;;;;KAMC,6BAA6B,eAAe;;;;qBAK3C,+BAA+B,UAAU;;;;EAQpD,YAAmB,MAAM;;;;;KAsBf;;;;;;WAMD;;;;;;WAOA;;;;;KAMC,kCAAkC,eAAe;;;;;;qBAOhD,oCAAoC,sBAAsB;;;;EAQrE,YAAmB,MAAM;;;;;;;;;;;;KCtEf;;;;;;UAOK;GACd,YAAY,QAAQ,cAAc;;;;;;;KAQzB;;;;;;WAMD;;;;;;WAOA;;;;;;WAOA;;;;;;WAOA;;;;;;WAOA,WAAW;;;;;;WAOX;;;;;;WAOA,QAAQ;;;;;;;cAqCE,kBAAkB,uBAAuB;;;;;oBAInC;;;;;;WAOT;;;;;;WAOA;;;;;;WAOA;;;;;;WAOA,UAAU;;;;;;;EAkB1B,YAAmB,UAAS;;;;;;MAuDjB;EAMX,IAAiB,GAAG,YAAY,YAAY,MAAM,YAAY,QAAQ"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/errors.ts","../src/rate-limit.ts"],"mappings":";;;;;;KAKY;;;;WAID;;;;;KAMC,6BAA6B,eAAe;;;;qBAK3C,+BAA+B,UAAU;;;;EAQpD,YAAmB,MAAM;;;;;KAsBf;;;;WAID;;;;WAKA;;;;;KAMC,kCAAkC,eAAe;;;;qBAKhD,oCAAoC,sBAAsB;;;;EAQrE,YAAmB,MAAM;;;;;;;KCrEf;;;;UAKK;GACd,YAAY,QAAQ,cAAc;;;;;KAMzB;;;;WAID;;;;WAKA;;;;WAKA;;;;WAKA;;;;WAKA,WAAW;;;;WAKX;;;;WAKA,QAAQ;;;;;cAmCE,kBAAkB,uBAAuB;;;;;oBAInC;;;;WAKT;;;;WAKA;;;;WAKA;;;;WAKA,UAAU;;;;EAe1B,YAAmB,UAAS;;;;MAqDjB;EAMX,IAAiB,GAAG,YAAY,YAAY,MAAM,YAAY,QAAQ"}
package/dist/index.js CHANGED
@@ -20,8 +20,6 @@ _RateLimitExceededError = RateLimitExceededError;
20
20
  _RateLimitExceededError.prototype.name = "RateLimitExceededError";
21
21
  setErrorMessage(RateLimitExceededError, ({ retryAfterMs }) => `レート制限を超えました。${String(retryAfterMs)}ms 後に再試行してください。`, "ja");
22
22
  /**
23
- * コンストラクターに不正なオプションが渡されたときのエラーです。
24
- *
25
23
  * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#error-rate-limit-invalid-option)
26
24
  */
27
25
  var RateLimitInvalidOptionError = class extends InvalidUsageErrorBase {
@@ -118,15 +116,10 @@ var _lastRefill = /* @__PURE__ */ new WeakMap();
118
116
  var _tail = /* @__PURE__ */ new WeakMap();
119
117
  var _RateLimit_brand = /* @__PURE__ */ new WeakSet();
120
118
  /**
121
- * トークンバケットで操作頻度を制限するミドルウェアです。
122
- *
123
119
  * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit)
124
120
  */
125
121
  var RateLimit = class extends PassThrough {
126
122
  /**
127
- * RateLimit ミドルウェアを作成します。
128
- *
129
- * @param options トークン数と補充間隔などの設定です。
130
123
  * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit)
131
124
  */
132
125
  constructor(options = {}) {
@@ -166,8 +159,6 @@ var RateLimit = class extends PassThrough {
166
159
  _classPrivateFieldSet2(_tail, this, Promise.resolve());
167
160
  }
168
161
  /**
169
- * 現在保持しているトークン数です。
170
- *
171
162
  * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit)
172
163
  */
173
164
  get availableTokens() {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/errors.ts","../src/rate-limit.ts"],"sourcesContent":["import { type ErrorOptions, ErrorBase, setErrorMessage, InvalidUsageErrorBase } from \"@unikvs/core\";\n\n/**\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#error-rate-limit-exceeded)\n */\nexport type RateLimitExceededErrorMeta = {\n /**\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit-exceeded-retry-after-ms)\n */\n readonly retryAfterMs: number;\n};\n\n/**\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#error-rate-limit-exceeded)\n */\nexport type RateLimitExceededErrorArgs = ErrorOptions & RateLimitExceededErrorMeta;\n\n/**\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#error-rate-limit-exceeded)\n */\nexport class RateLimitExceededError extends ErrorBase<RateLimitExceededErrorMeta> {\n static {\n this.prototype.name = \"RateLimitExceededError\";\n }\n\n /**\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#error-rate-limit-exceeded)\n */\n public constructor(args: RateLimitExceededErrorArgs) {\n const { retryAfterMs, ...options } = args;\n const meta: RateLimitExceededErrorMeta = { retryAfterMs };\n super(\n meta,\n ({ retryAfterMs: messageRetryAfterMs }) =>\n `Rate limit exceeded. Retry after ${String(messageRetryAfterMs)}ms.`,\n options,\n );\n }\n}\n\nsetErrorMessage(\n RateLimitExceededError,\n ({ retryAfterMs }) =>\n `レート制限を超えました。${String(retryAfterMs)}ms 後に再試行してください。`,\n \"ja\",\n);\n\n/**\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#error-rate-limit-invalid-option)\n */\nexport type RateLimitInvalidOptionErrorMeta = {\n /**\n * 不正だったオプション名です。\n *\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit-invalid-option-name)\n */\n readonly name: string;\n\n /**\n * 指定された値です。\n *\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit-invalid-option-actual)\n */\n readonly actual: unknown;\n};\n\n/**\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#error-rate-limit-invalid-option)\n */\nexport type RateLimitInvalidOptionErrorArgs = ErrorOptions & RateLimitInvalidOptionErrorMeta;\n\n/**\n * コンストラクターに不正なオプションが渡されたときのエラーです。\n *\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#error-rate-limit-invalid-option)\n */\nexport class RateLimitInvalidOptionError extends InvalidUsageErrorBase<RateLimitInvalidOptionErrorMeta> {\n static {\n this.prototype.name = \"RateLimitInvalidOptionError\";\n }\n\n /**\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#error-rate-limit-invalid-option)\n */\n public constructor(args: RateLimitInvalidOptionErrorArgs) {\n const { name, actual, ...options } = args;\n const meta: RateLimitInvalidOptionErrorMeta = {\n name,\n actual,\n };\n super(\n meta,\n ({ name: messageName, actual: messageActual }) =>\n `Invalid RateLimit option ${JSON.stringify(messageName)}: ${formatActual(messageActual)}`,\n options,\n );\n }\n}\n\nsetErrorMessage(\n RateLimitInvalidOptionError,\n ({ name, actual }) =>\n `無効な RateLimit オプション ${JSON.stringify(name)}: ${formatActual(actual)}`,\n \"ja\",\n);\n\n/**\n * エラーメッセージに埋め込む実際の値を整形します。\n *\n * @param actual 整形する値です。\n *\n * @returns 整形した文字列を返します。\n */\nfunction formatActual(actual: unknown): string {\n if (typeof actual === \"string\") {\n return JSON.stringify(actual);\n }\n\n if (\n typeof actual === \"number\" ||\n typeof actual === \"boolean\" ||\n actual === null ||\n actual === undefined\n ) {\n return String(actual);\n }\n\n try {\n return JSON.stringify(actual) ?? \"[object Object]\";\n } catch {\n return \"[object Object]\";\n }\n}\n","import type { IMiddleware } from \"@unikvs/core\";\nimport { PassThrough } from \"@unikvs/passthrough\";\nimport { getAbortReason, throwIfAborted } from \"abort-signal-utils\";\n\nimport { RateLimitExceededError, RateLimitInvalidOptionError } from \"./errors.js\";\n\n/**\n * レート制限を超えたときの挙動です。\n *\n * - `\"wait\"` はトークンが補充されるまで待機します。\n * - `\"throw\"` は直ちにエラーを投げます。\n *\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit-strategy)\n */\nexport type RateLimitStrategy = \"wait\" | \"throw\";\n\n/**\n * 待機処理の実装です。テストで時刻を制御するときに差し替えます。\n *\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#irate-limit-sleep)\n */\nexport interface IRateLimitSleep {\n (ms: number, signal: AbortSignal): Promise<void>;\n}\n\n/**\n * RateLimit ミドルウェアのオプションです。\n *\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit-options)\n */\nexport type RateLimitOptions = {\n /**\n * 1 インターバルあたりに補充されるトークン数です。既定値は `1` です。\n *\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit-options-tokens-per-interval)\n */\n readonly tokensPerInterval?: number | undefined;\n\n /**\n * トークンを補充する間隔 (ミリ秒) です。既定値は `1000` です。\n *\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit-options-interval-ms)\n */\n readonly intervalMs?: number | undefined;\n\n /**\n * 保持できるトークンの上限です。既定値は `tokensPerInterval` です。\n *\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit-options-max-tokens)\n */\n readonly maxTokens?: number | undefined;\n\n /**\n * `maxTokens` の別名です。両方を指定した場合は `maxTokens` が優先されます。\n *\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit-options-burst)\n */\n readonly burst?: number | undefined;\n\n /**\n * レート制限を超えたときの挙動です。既定値は `\"wait\"` です。\n *\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit-options-strategy)\n */\n readonly strategy?: RateLimitStrategy | undefined;\n\n /**\n * 現在時刻 (epoch ミリ秒) を返す関数です。既定値は `Date.now` です。\n *\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit-options-now)\n */\n readonly now?: (() => number) | undefined;\n\n /**\n * 待機処理です。既定では `setTimeout` を使用します。\n *\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit-options-sleep)\n */\n readonly sleep?: IRateLimitSleep | undefined;\n};\n\nfunction defaultSleep(ms: number, signal: AbortSignal): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n if (signal.aborted) {\n reject(getAbortReason(signal));\n\n return;\n }\n\n const timer = setTimeout(() => {\n signal.removeEventListener(\"abort\", onAbort);\n resolve();\n }, ms);\n const onAbort = (): void => {\n clearTimeout(timer);\n reject(getAbortReason(signal));\n };\n signal.addEventListener(\"abort\", onAbort, { once: true });\n });\n}\n\nfunction assertPositiveNumber(name: string, value: number): void {\n if (typeof value !== \"number\" || !Number.isFinite(value) || value <= 0) {\n throw new RateLimitInvalidOptionError({\n name,\n actual: value,\n });\n }\n}\n\n/**\n * トークンバケットで操作頻度を制限するミドルウェアです。\n *\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit)\n */\nexport default class RateLimit extends PassThrough implements IMiddleware {\n /**\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit)\n */\n public override readonly name: string = \"RateLimit\";\n\n /**\n * 1 インターバルあたりに補充されるトークン数です。\n *\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit)\n */\n public readonly tokensPerInterval: number;\n\n /**\n * トークンを補充する間隔 (ミリ秒) です。\n *\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit)\n */\n public readonly intervalMs: number;\n\n /**\n * 保持できるトークンの上限です。\n *\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit)\n */\n public readonly maxTokens: number;\n\n /**\n * レート制限を超えたときの挙動です。\n *\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit)\n */\n public readonly strategy: RateLimitStrategy;\n\n readonly #now: () => number;\n\n readonly #sleep: IRateLimitSleep;\n\n #tokens: number;\n\n #lastRefill: number;\n\n #tail: Promise<void>;\n\n /**\n * RateLimit ミドルウェアを作成します。\n *\n * @param options トークン数と補充間隔などの設定です。\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit)\n */\n public constructor(options: RateLimitOptions = {}) {\n super();\n\n const {\n now = Date.now,\n burst,\n sleep = defaultSleep,\n strategy = \"wait\",\n maxTokens,\n intervalMs = 1000,\n tokensPerInterval = 1,\n } = options;\n assertPositiveNumber(\"tokensPerInterval\", tokensPerInterval);\n assertPositiveNumber(\"intervalMs\", intervalMs);\n\n const capacity = maxTokens ?? burst ?? tokensPerInterval;\n assertPositiveNumber(\"maxTokens\", capacity);\n\n if (strategy !== \"wait\" && strategy !== \"throw\") {\n throw new RateLimitInvalidOptionError({\n name: \"strategy\",\n actual: strategy,\n });\n }\n\n if (typeof now !== \"function\") {\n throw new RateLimitInvalidOptionError({\n name: \"now\",\n actual: now,\n });\n }\n\n if (typeof sleep !== \"function\") {\n throw new RateLimitInvalidOptionError({\n name: \"sleep\",\n actual: sleep,\n });\n }\n\n this.tokensPerInterval = tokensPerInterval;\n this.intervalMs = intervalMs;\n this.maxTokens = capacity;\n this.strategy = strategy;\n this.#now = now;\n this.#sleep = sleep;\n this.#tokens = capacity;\n this.#lastRefill = now();\n this.#tail = Promise.resolve();\n }\n\n /**\n * 現在保持しているトークン数です。\n *\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit)\n */\n public get availableTokens(): number {\n this.#refill();\n\n return this.#tokens;\n }\n\n public async use(c: IMiddleware.UseContext, next: IMiddleware.INext): Promise<void> {\n await this.#acquire(c.signal);\n\n await next();\n }\n\n async #acquire(signal: AbortSignal): Promise<void> {\n throwIfAborted(signal);\n\n let release!: () => void;\n const previous = this.#tail;\n this.#tail = new Promise<void>((resolve) => {\n release = resolve;\n });\n await previous;\n\n try {\n for (;;) {\n throwIfAborted(signal);\n this.#refill();\n\n if (this.#tokens >= 1) {\n this.#tokens -= 1;\n\n return;\n }\n\n if (this.strategy === \"throw\") {\n throw new RateLimitExceededError({ retryAfterMs: this.#retryAfterMs() });\n }\n\n await this.#sleep(this.#retryAfterMs(), signal);\n }\n } finally {\n release();\n }\n }\n\n #refill(): void {\n const now = this.#now();\n const elapsed = now - this.#lastRefill;\n\n if (elapsed <= 0) {\n return;\n }\n\n this.#tokens = Math.min(\n this.maxTokens,\n this.#tokens + (elapsed * this.tokensPerInterval) / this.intervalMs,\n );\n this.#lastRefill = now;\n }\n\n #retryAfterMs(): number {\n const deficit = 1 - this.#tokens;\n\n return Math.max(0, Math.ceil((deficit * this.intervalMs) / this.tokensPerInterval));\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/errors.ts","../src/rate-limit.ts"],"sourcesContent":["import { type ErrorOptions, ErrorBase, setErrorMessage, InvalidUsageErrorBase } from \"@unikvs/core\";\n\n/**\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#error-rate-limit-exceeded)\n */\nexport type RateLimitExceededErrorMeta = {\n /**\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit-exceeded-retry-after-ms)\n */\n readonly retryAfterMs: number;\n};\n\n/**\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#error-rate-limit-exceeded)\n */\nexport type RateLimitExceededErrorArgs = ErrorOptions & RateLimitExceededErrorMeta;\n\n/**\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#error-rate-limit-exceeded)\n */\nexport class RateLimitExceededError extends ErrorBase<RateLimitExceededErrorMeta> {\n static {\n this.prototype.name = \"RateLimitExceededError\";\n }\n\n /**\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#error-rate-limit-exceeded)\n */\n public constructor(args: RateLimitExceededErrorArgs) {\n const { retryAfterMs, ...options } = args;\n const meta: RateLimitExceededErrorMeta = { retryAfterMs };\n super(\n meta,\n ({ retryAfterMs: messageRetryAfterMs }) =>\n `Rate limit exceeded. Retry after ${String(messageRetryAfterMs)}ms.`,\n options,\n );\n }\n}\n\nsetErrorMessage(\n RateLimitExceededError,\n ({ retryAfterMs }) =>\n `レート制限を超えました。${String(retryAfterMs)}ms 後に再試行してください。`,\n \"ja\",\n);\n\n/**\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#error-rate-limit-invalid-option)\n */\nexport type RateLimitInvalidOptionErrorMeta = {\n /**\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit-invalid-option-name)\n */\n readonly name: string;\n\n /**\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit-invalid-option-actual)\n */\n readonly actual: unknown;\n};\n\n/**\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#error-rate-limit-invalid-option)\n */\nexport type RateLimitInvalidOptionErrorArgs = ErrorOptions & RateLimitInvalidOptionErrorMeta;\n\n/**\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#error-rate-limit-invalid-option)\n */\nexport class RateLimitInvalidOptionError extends InvalidUsageErrorBase<RateLimitInvalidOptionErrorMeta> {\n static {\n this.prototype.name = \"RateLimitInvalidOptionError\";\n }\n\n /**\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#error-rate-limit-invalid-option)\n */\n public constructor(args: RateLimitInvalidOptionErrorArgs) {\n const { name, actual, ...options } = args;\n const meta: RateLimitInvalidOptionErrorMeta = {\n name,\n actual,\n };\n super(\n meta,\n ({ name: messageName, actual: messageActual }) =>\n `Invalid RateLimit option ${JSON.stringify(messageName)}: ${formatActual(messageActual)}`,\n options,\n );\n }\n}\n\nsetErrorMessage(\n RateLimitInvalidOptionError,\n ({ name, actual }) =>\n `無効な RateLimit オプション ${JSON.stringify(name)}: ${formatActual(actual)}`,\n \"ja\",\n);\n\n/**\n * エラーメッセージに埋め込む実際の値を整形します。\n *\n * @param actual 整形する値です。\n *\n * @returns 整形した文字列を返します。\n */\nfunction formatActual(actual: unknown): string {\n if (typeof actual === \"string\") {\n return JSON.stringify(actual);\n }\n\n if (\n typeof actual === \"number\" ||\n typeof actual === \"boolean\" ||\n actual === null ||\n actual === undefined\n ) {\n return String(actual);\n }\n\n try {\n return JSON.stringify(actual) ?? \"[object Object]\";\n } catch {\n return \"[object Object]\";\n }\n}\n","import type { IMiddleware } from \"@unikvs/core\";\nimport { PassThrough } from \"@unikvs/passthrough\";\nimport { getAbortReason, throwIfAborted } from \"abort-signal-utils\";\n\nimport { RateLimitExceededError, RateLimitInvalidOptionError } from \"./errors.js\";\n\n/**\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit-strategy)\n */\nexport type RateLimitStrategy = \"wait\" | \"throw\";\n\n/**\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#irate-limit-sleep)\n */\nexport interface IRateLimitSleep {\n (ms: number, signal: AbortSignal): Promise<void>;\n}\n\n/**\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit-options)\n */\nexport type RateLimitOptions = {\n /**\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit-options-tokens-per-interval)\n */\n readonly tokensPerInterval?: number | undefined;\n\n /**\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit-options-interval-ms)\n */\n readonly intervalMs?: number | undefined;\n\n /**\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit-options-max-tokens)\n */\n readonly maxTokens?: number | undefined;\n\n /**\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit-options-burst)\n */\n readonly burst?: number | undefined;\n\n /**\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit-options-strategy)\n */\n readonly strategy?: RateLimitStrategy | undefined;\n\n /**\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit-options-now)\n */\n readonly now?: (() => number) | undefined;\n\n /**\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit-options-sleep)\n */\n readonly sleep?: IRateLimitSleep | undefined;\n};\n\nfunction defaultSleep(ms: number, signal: AbortSignal): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n if (signal.aborted) {\n reject(getAbortReason(signal));\n\n return;\n }\n\n const timer = setTimeout(() => {\n signal.removeEventListener(\"abort\", onAbort);\n resolve();\n }, ms);\n const onAbort = (): void => {\n clearTimeout(timer);\n reject(getAbortReason(signal));\n };\n signal.addEventListener(\"abort\", onAbort, { once: true });\n });\n}\n\nfunction assertPositiveNumber(name: string, value: number): void {\n if (typeof value !== \"number\" || !Number.isFinite(value) || value <= 0) {\n throw new RateLimitInvalidOptionError({\n name,\n actual: value,\n });\n }\n}\n\n/**\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit)\n */\nexport default class RateLimit extends PassThrough implements IMiddleware {\n /**\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit)\n */\n public override readonly name: string = \"RateLimit\";\n\n /**\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit)\n */\n public readonly tokensPerInterval: number;\n\n /**\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit)\n */\n public readonly intervalMs: number;\n\n /**\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit)\n */\n public readonly maxTokens: number;\n\n /**\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit)\n */\n public readonly strategy: RateLimitStrategy;\n\n readonly #now: () => number;\n\n readonly #sleep: IRateLimitSleep;\n\n #tokens: number;\n\n #lastRefill: number;\n\n #tail: Promise<void>;\n\n /**\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit)\n */\n public constructor(options: RateLimitOptions = {}) {\n super();\n\n const {\n now = Date.now,\n burst,\n sleep = defaultSleep,\n strategy = \"wait\",\n maxTokens,\n intervalMs = 1000,\n tokensPerInterval = 1,\n } = options;\n assertPositiveNumber(\"tokensPerInterval\", tokensPerInterval);\n assertPositiveNumber(\"intervalMs\", intervalMs);\n\n const capacity = maxTokens ?? burst ?? tokensPerInterval;\n assertPositiveNumber(\"maxTokens\", capacity);\n\n if (strategy !== \"wait\" && strategy !== \"throw\") {\n throw new RateLimitInvalidOptionError({\n name: \"strategy\",\n actual: strategy,\n });\n }\n\n if (typeof now !== \"function\") {\n throw new RateLimitInvalidOptionError({\n name: \"now\",\n actual: now,\n });\n }\n\n if (typeof sleep !== \"function\") {\n throw new RateLimitInvalidOptionError({\n name: \"sleep\",\n actual: sleep,\n });\n }\n\n this.tokensPerInterval = tokensPerInterval;\n this.intervalMs = intervalMs;\n this.maxTokens = capacity;\n this.strategy = strategy;\n this.#now = now;\n this.#sleep = sleep;\n this.#tokens = capacity;\n this.#lastRefill = now();\n this.#tail = Promise.resolve();\n }\n\n /**\n * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit)\n */\n public get availableTokens(): number {\n this.#refill();\n\n return this.#tokens;\n }\n\n public async use(c: IMiddleware.UseContext, next: IMiddleware.INext): Promise<void> {\n await this.#acquire(c.signal);\n\n await next();\n }\n\n async #acquire(signal: AbortSignal): Promise<void> {\n throwIfAborted(signal);\n\n let release!: () => void;\n const previous = this.#tail;\n this.#tail = new Promise<void>((resolve) => {\n release = resolve;\n });\n await previous;\n\n try {\n for (;;) {\n throwIfAborted(signal);\n this.#refill();\n\n if (this.#tokens >= 1) {\n this.#tokens -= 1;\n\n return;\n }\n\n if (this.strategy === \"throw\") {\n throw new RateLimitExceededError({ retryAfterMs: this.#retryAfterMs() });\n }\n\n await this.#sleep(this.#retryAfterMs(), signal);\n }\n } finally {\n release();\n }\n }\n\n #refill(): void {\n const now = this.#now();\n const elapsed = now - this.#lastRefill;\n\n if (elapsed <= 0) {\n return;\n }\n\n this.#tokens = Math.min(\n this.maxTokens,\n this.#tokens + (elapsed * this.tokensPerInterval) / this.intervalMs,\n );\n this.#lastRefill = now;\n }\n\n #retryAfterMs(): number {\n const deficit = 1 - this.#tokens;\n\n return Math.max(0, Math.ceil((deficit * this.intervalMs) / this.tokensPerInterval));\n }\n}\n"],"mappings":";;;;;;;;;AAoBA,IAAa,yBAAb,cAA4C,UAAsC;;;;CAQhF,YAAmB,MAAkC;EACnD,MAAM,EAAE,cAAc,GAAG,YAAY;EAErC,MACE,EAFyC,aAEtC,IACF,EAAE,cAAc,0BACf,oCAAoC,OAAO,mBAAmB,EAAE,MAClE,OACF;CACF;AACF;;AAhBI,wBAAK,UAAU,OAAO;AAkB1B,gBACE,yBACC,EAAE,mBACD,eAAe,OAAO,YAAY,EAAE,kBACtC,IACF;;;;AAyBA,IAAa,8BAAb,cAAiD,sBAAuD;;;;CAQtG,YAAmB,MAAuC;EACxD,MAAM,EAAE,MAAM,QAAQ,GAAG,YAAY;EAKrC,MACE;GAJA;GACA;EAGG,IACF,EAAE,MAAM,aAAa,QAAQ,oBAC5B,4BAA4B,KAAK,UAAU,WAAW,EAAE,IAAI,aAAa,aAAa,KACxF,OACF;CACF;AACF;;AAnBI,6BAAK,UAAU,OAAO;AAqB1B,gBACE,8BACC,EAAE,MAAM,aACP,uBAAuB,KAAK,UAAU,IAAI,EAAE,IAAI,aAAa,MAAM,KACrE,IACF;;;;;;;;AASA,SAAS,aAAa,QAAyB;CAC7C,IAAI,OAAO,WAAW,UACpB,OAAO,KAAK,UAAU,MAAM;CAG9B,IACE,OAAO,WAAW,YAClB,OAAO,WAAW,aAClB,WAAW,QACX,WAAW,KAAA,GAEX,OAAO,OAAO,MAAM;CAGtB,IAAI;EACF,OAAO,KAAK,UAAU,MAAM,KAAK;CACnC,QAAQ;EACN,OAAO;CACT;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACpEA,SAAS,aAAa,IAAY,QAAoC;CACpE,OAAO,IAAI,SAAe,SAAS,WAAW;EAC5C,IAAI,OAAO,SAAS;GAClB,OAAO,eAAe,MAAM,CAAC;GAE7B;EACF;EAEA,MAAM,QAAQ,iBAAiB;GAC7B,OAAO,oBAAoB,SAAS,OAAO;GAC3C,QAAQ;EACV,GAAG,EAAE;EACL,MAAM,gBAAsB;GAC1B,aAAa,KAAK;GAClB,OAAO,eAAe,MAAM,CAAC;EAC/B;EACA,OAAO,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;CAC1D,CAAC;AACH;AAEA,SAAS,qBAAqB,MAAc,OAAqB;CAC/D,IAAI,OAAO,UAAU,YAAY,CAAC,OAAO,SAAS,KAAK,KAAK,SAAS,GACnE,MAAM,IAAI,4BAA4B;EACpC;EACA,QAAQ;CACV,CAAC;AAEL;;;;;;;;;;AAKA,IAAqB,YAArB,cAAuC,YAAmC;;;;CAuCxE,YAAmB,UAA4B,CAAC,GAAG;EACjD,MAAM;;EApCR,KAAyB,OAAe;;;;;;EAsCtC,MAAM,EACJ,MAAM,KAAK,KACX,OACA,QAAQ,cACR,WAAW,QACX,WACA,aAAa,KACb,oBAAoB,MAClB;EACJ,qBAAqB,qBAAqB,iBAAiB;EAC3D,qBAAqB,cAAc,UAAU;EAE7C,MAAM,WAAW,aAAa,SAAS;EACvC,qBAAqB,aAAa,QAAQ;EAE1C,IAAI,aAAa,UAAU,aAAa,SACtC,MAAM,IAAI,4BAA4B;GACpC,MAAM;GACN,QAAQ;EACV,CAAC;EAGH,IAAI,OAAO,QAAQ,YACjB,MAAM,IAAI,4BAA4B;GACpC,MAAM;GACN,QAAQ;EACV,CAAC;EAGH,IAAI,OAAO,UAAU,YACnB,MAAM,IAAI,4BAA4B;GACpC,MAAM;GACN,QAAQ;EACV,CAAC;EAGH,KAAK,oBAAoB;EACzB,KAAK,aAAa;EAClB,KAAK,YAAY;EACjB,KAAK,WAAW;EAChB,uBAAA,MAAA,MAAY,GAAA;EACZ,uBAAA,QAAA,MAAc,KAAA;EACd,uBAAA,SAAA,MAAe,QAAA;EACf,uBAAA,aAAA,MAAmB,IAAI,CAAA;EACvB,uBAAA,OAAA,MAAa,QAAQ,QAAQ,CAAA;CAC/B;;;;CAKA,IAAW,kBAA0B;EACnC,kBAAA,kBAAA,MAAA,OAAA,CAAA,CAAA,KAAA,IAAa;EAEb,OAAA,uBAAA,SAAO,IAAA;CACT;CAEA,MAAa,IAAI,GAA2B,MAAwC;EAClF,MAAA,kBAAA,kBAAM,MAAA,QAAA,CAAA,CAAA,KAAA,MAAc,EAAE,MAAM;EAE5B,MAAM,KAAK;CACb;AAsDF;AApDE,eAAA,SAAe,QAAoC;CACjD,eAAe,MAAM;CAErB,IAAI;CACJ,MAAM,WAAA,uBAAA,OAAW,IAAA;CACjB,uBAAA,OAAA,MAAa,IAAI,SAAe,YAAY;EAC1C,UAAU;CACZ,CAAC,CAAA;CACD,MAAM;CAEN,IAAI;EACF,SAAS;GACP,eAAe,MAAM;GACrB,kBAAA,kBAAA,MAAA,OAAA,CAAA,CAAA,KAAA,IAAa;GAEb,IAAA,uBAAA,SAAI,IAAA,KAAgB,GAAG;IACrB,uBAAA,SAAA,MAAA,uBAAA,SAAA,IAAA,IAAgB,CAAA;IAEhB;GACF;GAEA,IAAI,KAAK,aAAa,SACpB,MAAM,IAAI,uBAAuB,EAAE,cAAA,kBAAA,kBAAc,MAAA,aAAA,CAAA,CAAA,KAAA,IAAmB,EAAE,CAAC;GAGzE,MAAA,uBAAA,QAAM,IAAA,CAAA,CAAA,KAAA,MAAA,kBAAA,kBAAY,MAAA,aAAA,CAAA,CAAA,KAAA,IAAmB,GAAG,MAAM;EAChD;CACF,UAAU;EACR,QAAQ;CACV;AACF;AAEA,SAAA,UAAgB;CACd,MAAM,MAAA,uBAAA,MAAM,IAAA,CAAA,CAAA,KAAA,IAAU;CACtB,MAAM,UAAU,MAAA,uBAAA,aAAM,IAAA;CAEtB,IAAI,WAAW,GACb;CAGF,uBAAA,SAAA,MAAe,KAAK,IAClB,KAAK,WAAA,uBAAA,SACL,IAAA,IAAgB,UAAU,KAAK,oBAAqB,KAAK,UAC3D,CAAA;CACA,uBAAA,aAAA,MAAmB,GAAA;AACrB;AAEA,SAAA,gBAAwB;CACtB,MAAM,UAAU,IAAA,uBAAA,SAAI,IAAA;CAEpB,OAAO,KAAK,IAAI,GAAG,KAAK,KAAM,UAAU,KAAK,aAAc,KAAK,iBAAiB,CAAC;AACpF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unikvs/rate-limit",
3
- "version": "0.0.13",
3
+ "version": "0.0.14",
4
4
  "description": "Transformer plugin that limits operations per time window with a token bucket.",
5
5
  "homepage": "https://tai-kun.github.io/unikvs/",
6
6
  "license": "MIT",
@@ -24,8 +24,8 @@
24
24
  }
25
25
  },
26
26
  "dependencies": {
27
- "@unikvs/core": "0.0.13",
28
- "@unikvs/passthrough": "0.0.13",
27
+ "@unikvs/core": "0.0.14",
28
+ "@unikvs/passthrough": "0.0.14",
29
29
  "abort-signal-utils": "^0.0.6"
30
30
  },
31
31
  "devDependencies": {
package/src/errors.ts CHANGED
@@ -50,15 +50,11 @@ setErrorMessage(
50
50
  */
51
51
  export type RateLimitInvalidOptionErrorMeta = {
52
52
  /**
53
- * 不正だったオプション名です。
54
- *
55
53
  * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit-invalid-option-name)
56
54
  */
57
55
  readonly name: string;
58
56
 
59
57
  /**
60
- * 指定された値です。
61
- *
62
58
  * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit-invalid-option-actual)
63
59
  */
64
60
  readonly actual: unknown;
@@ -70,8 +66,6 @@ export type RateLimitInvalidOptionErrorMeta = {
70
66
  export type RateLimitInvalidOptionErrorArgs = ErrorOptions & RateLimitInvalidOptionErrorMeta;
71
67
 
72
68
  /**
73
- * コンストラクターに不正なオプションが渡されたときのエラーです。
74
- *
75
69
  * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#error-rate-limit-invalid-option)
76
70
  */
77
71
  export class RateLimitInvalidOptionError extends InvalidUsageErrorBase<RateLimitInvalidOptionErrorMeta> {
package/src/rate-limit.ts CHANGED
@@ -5,18 +5,11 @@ import { getAbortReason, throwIfAborted } from "abort-signal-utils";
5
5
  import { RateLimitExceededError, RateLimitInvalidOptionError } from "./errors.js";
6
6
 
7
7
  /**
8
- * レート制限を超えたときの挙動です。
9
- *
10
- * - `"wait"` はトークンが補充されるまで待機します。
11
- * - `"throw"` は直ちにエラーを投げます。
12
- *
13
8
  * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit-strategy)
14
9
  */
15
10
  export type RateLimitStrategy = "wait" | "throw";
16
11
 
17
12
  /**
18
- * 待機処理の実装です。テストで時刻を制御するときに差し替えます。
19
- *
20
13
  * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#irate-limit-sleep)
21
14
  */
22
15
  export interface IRateLimitSleep {
@@ -24,56 +17,40 @@ export interface IRateLimitSleep {
24
17
  }
25
18
 
26
19
  /**
27
- * RateLimit ミドルウェアのオプションです。
28
- *
29
20
  * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit-options)
30
21
  */
31
22
  export type RateLimitOptions = {
32
23
  /**
33
- * 1 インターバルあたりに補充されるトークン数です。既定値は `1` です。
34
- *
35
24
  * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit-options-tokens-per-interval)
36
25
  */
37
26
  readonly tokensPerInterval?: number | undefined;
38
27
 
39
28
  /**
40
- * トークンを補充する間隔 (ミリ秒) です。既定値は `1000` です。
41
- *
42
29
  * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit-options-interval-ms)
43
30
  */
44
31
  readonly intervalMs?: number | undefined;
45
32
 
46
33
  /**
47
- * 保持できるトークンの上限です。既定値は `tokensPerInterval` です。
48
- *
49
34
  * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit-options-max-tokens)
50
35
  */
51
36
  readonly maxTokens?: number | undefined;
52
37
 
53
38
  /**
54
- * `maxTokens` の別名です。両方を指定した場合は `maxTokens` が優先されます。
55
- *
56
39
  * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit-options-burst)
57
40
  */
58
41
  readonly burst?: number | undefined;
59
42
 
60
43
  /**
61
- * レート制限を超えたときの挙動です。既定値は `"wait"` です。
62
- *
63
44
  * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit-options-strategy)
64
45
  */
65
46
  readonly strategy?: RateLimitStrategy | undefined;
66
47
 
67
48
  /**
68
- * 現在時刻 (epoch ミリ秒) を返す関数です。既定値は `Date.now` です。
69
- *
70
49
  * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit-options-now)
71
50
  */
72
51
  readonly now?: (() => number) | undefined;
73
52
 
74
53
  /**
75
- * 待機処理です。既定では `setTimeout` を使用します。
76
- *
77
54
  * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit-options-sleep)
78
55
  */
79
56
  readonly sleep?: IRateLimitSleep | undefined;
@@ -109,8 +86,6 @@ function assertPositiveNumber(name: string, value: number): void {
109
86
  }
110
87
 
111
88
  /**
112
- * トークンバケットで操作頻度を制限するミドルウェアです。
113
- *
114
89
  * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit)
115
90
  */
116
91
  export default class RateLimit extends PassThrough implements IMiddleware {
@@ -120,29 +95,21 @@ export default class RateLimit extends PassThrough implements IMiddleware {
120
95
  public override readonly name: string = "RateLimit";
121
96
 
122
97
  /**
123
- * 1 インターバルあたりに補充されるトークン数です。
124
- *
125
98
  * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit)
126
99
  */
127
100
  public readonly tokensPerInterval: number;
128
101
 
129
102
  /**
130
- * トークンを補充する間隔 (ミリ秒) です。
131
- *
132
103
  * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit)
133
104
  */
134
105
  public readonly intervalMs: number;
135
106
 
136
107
  /**
137
- * 保持できるトークンの上限です。
138
- *
139
108
  * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit)
140
109
  */
141
110
  public readonly maxTokens: number;
142
111
 
143
112
  /**
144
- * レート制限を超えたときの挙動です。
145
- *
146
113
  * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit)
147
114
  */
148
115
  public readonly strategy: RateLimitStrategy;
@@ -158,9 +125,6 @@ export default class RateLimit extends PassThrough implements IMiddleware {
158
125
  #tail: Promise<void>;
159
126
 
160
127
  /**
161
- * RateLimit ミドルウェアを作成します。
162
- *
163
- * @param options トークン数と補充間隔などの設定です。
164
128
  * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit)
165
129
  */
166
130
  public constructor(options: RateLimitOptions = {}) {
@@ -214,8 +178,6 @@ export default class RateLimit extends PassThrough implements IMiddleware {
214
178
  }
215
179
 
216
180
  /**
217
- * 現在保持しているトークン数です。
218
- *
219
181
  * [API Reference](https://tai-kun.github.io/unikvs/packages/rate-limit#rate-limit)
220
182
  */
221
183
  public get availableTokens(): number {