@metamask-previews/rate-limit-controller 3.0.3-preview.eb58a59 → 4.0.1-preview.c9a5f6a5

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/CHANGELOG.md CHANGED
@@ -6,6 +6,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [4.0.1]
10
+ ### Changed
11
+ - Bump `@metamask/base-controller` to `^4.0.1` ([#3695](https://github.com/MetaMask/core/pull/3695))
12
+
13
+ ## [4.0.0]
14
+ ### Changed
15
+ - **BREAKING:** Enforce that `RateLimitedApi['method']` matches action handler type instead of using `any` ([#1890](https://github.com/MetaMask/core/pull/1890))
16
+ - **BREAKING:** Bump `@metamask/base-controller` to ^4.0.0 ([#2063](https://github.com/MetaMask/core/pull/2063))
17
+ - This is breaking because the type of the `messenger` has backward-incompatible changes. See the changelog for this package for more.
18
+
9
19
  ## [3.0.3]
10
20
  ### Changed
11
21
  - Bump dependency on `@metamask/base-controller` to ^3.2.3 ([#1747](https://github.com/MetaMask/core/pull/1747))
@@ -51,7 +61,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
51
61
 
52
62
  All changes listed after this point were applied to this package following the monorepo conversion.
53
63
 
54
- [Unreleased]: https://github.com/MetaMask/core/compare/@metamask/rate-limit-controller@3.0.3...HEAD
64
+ [Unreleased]: https://github.com/MetaMask/core/compare/@metamask/rate-limit-controller@4.0.1...HEAD
65
+ [4.0.1]: https://github.com/MetaMask/core/compare/@metamask/rate-limit-controller@4.0.0...@metamask/rate-limit-controller@4.0.1
66
+ [4.0.0]: https://github.com/MetaMask/core/compare/@metamask/rate-limit-controller@3.0.3...@metamask/rate-limit-controller@4.0.0
55
67
  [3.0.3]: https://github.com/MetaMask/core/compare/@metamask/rate-limit-controller@3.0.2...@metamask/rate-limit-controller@3.0.3
56
68
  [3.0.2]: https://github.com/MetaMask/core/compare/@metamask/rate-limit-controller@3.0.1...@metamask/rate-limit-controller@3.0.2
57
69
  [3.0.1]: https://github.com/MetaMask/core/compare/@metamask/rate-limit-controller@3.0.0...@metamask/rate-limit-controller@3.0.1
@@ -1,5 +1,5 @@
1
1
  import type { ActionConstraint, RestrictedControllerMessenger, ControllerGetStateAction, ControllerStateChangeEvent } from '@metamask/base-controller';
2
- import { BaseControllerV2 as BaseController } from '@metamask/base-controller';
2
+ import { BaseController } from '@metamask/base-controller';
3
3
  /**
4
4
  * @type RateLimitedApi
5
5
  * @property method - The method that is rate-limited.
@@ -1 +1 @@
1
- {"version":3,"file":"RateLimitController.d.ts","sourceRoot":"","sources":["../src/RateLimitController.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"RateLimitController.d.ts","sourceRoot":"","sources":["../src/RateLimitController.ts"],"names":[],"mappings":"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"}
@@ -19,7 +19,7 @@ const metadata = {
19
19
  /**
20
20
  * Controller with logic for rate-limiting API endpoints per requesting origin.
21
21
  */
22
- class RateLimitController extends base_controller_1.BaseControllerV2 {
22
+ class RateLimitController extends base_controller_1.BaseController {
23
23
  /**
24
24
  * Creates a RateLimitController instance.
25
25
  *
@@ -90,7 +90,11 @@ class RateLimitController extends base_controller_1.BaseControllerV2 {
90
90
  const rateLimitTimeout = (_a = this.implementations[api].rateLimitTimeout) !== null && _a !== void 0 ? _a : this.rateLimitTimeout;
91
91
  this.update((state) => {
92
92
  var _a;
93
+ // TODO: Replace `any` with type
94
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
93
95
  const previous = (_a = state.requests[api][origin]) !== null && _a !== void 0 ? _a : 0;
96
+ // TODO: Replace `any` with type
97
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
94
98
  state.requests[api][origin] = previous + 1;
95
99
  if (previous === 0) {
96
100
  setTimeout(() => this.resetRequestCount(api, origin), rateLimitTimeout);
@@ -105,6 +109,8 @@ class RateLimitController extends base_controller_1.BaseControllerV2 {
105
109
  */
106
110
  resetRequestCount(api, origin) {
107
111
  this.update((state) => {
112
+ // TODO: Replace `any` with type
113
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
108
114
  state.requests[api][origin] = 0;
109
115
  });
110
116
  }
@@ -1 +1 @@
1
- {"version":3,"file":"RateLimitController.js","sourceRoot":"","sources":["../src/RateLimitController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ActionConstraint,\n RestrictedControllerMessenger,\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n} from '@metamask/base-controller';\nimport { BaseControllerV2 as BaseController } from '@metamask/base-controller';\nimport { rpcErrors } from '@metamask/rpc-errors';\n\n/**\n * @type RateLimitedApi\n * @property method - The method that is rate-limited.\n * @property rateLimitTimeout - The time window in which the rate limit is applied (in ms).\n * @property rateLimitCount - The amount of calls an origin can make in the rate limit time window.\n */\nexport type RateLimitedApi = {\n method: ActionConstraint['handler'];\n rateLimitTimeout?: number;\n rateLimitCount?: number;\n};\n\n/**\n * @type RateLimitState\n * @property requests - Object containing number of requests in a given interval for each origin and api type combination\n */\nexport type RateLimitState<\n RateLimitedApis extends Record<string, RateLimitedApi>,\n> = {\n requests: Record<keyof RateLimitedApis, Record<string, number>>;\n};\n\nconst name = 'RateLimitController';\n\nexport type RateLimitStateChange<\n RateLimitedApis extends Record<string, RateLimitedApi>,\n> = ControllerStateChangeEvent<typeof name, RateLimitedApis>;\n\nexport type GetRateLimitState<\n RateLimitedApis extends Record<string, RateLimitedApi>,\n> = ControllerGetStateAction<typeof name, RateLimitedApis>;\n\nexport type CallApi<RateLimitedApis extends Record<string, RateLimitedApi>> = {\n type: `${typeof name}:call`;\n handler: RateLimitController<RateLimitedApis>['call'];\n};\n\nexport type RateLimitControllerActions<\n RateLimitedApis extends Record<string, RateLimitedApi>,\n> = GetRateLimitState<RateLimitedApis> | CallApi<RateLimitedApis>;\n\nexport type RateLimitControllerEvents<\n RateLimitedApis extends Record<string, RateLimitedApi>,\n> = RateLimitStateChange<RateLimitedApis>;\n\nexport type RateLimitMessenger<\n RateLimitedApis extends Record<string, RateLimitedApi>,\n> = RestrictedControllerMessenger<\n typeof name,\n RateLimitControllerActions<RateLimitedApis>,\n RateLimitControllerEvents<RateLimitedApis>,\n never,\n never\n>;\n\nconst metadata = {\n requests: { persist: false, anonymous: false },\n};\n\n/**\n * Controller with logic for rate-limiting API endpoints per requesting origin.\n */\nexport class RateLimitController<\n RateLimitedApis extends Record<string, RateLimitedApi>,\n> extends BaseController<\n typeof name,\n RateLimitState<RateLimitedApis>,\n RateLimitMessenger<RateLimitedApis>\n> {\n private readonly implementations;\n\n private readonly rateLimitTimeout;\n\n private readonly rateLimitCount;\n\n /**\n * Creates a RateLimitController instance.\n *\n * @param options - Constructor options.\n * @param options.messenger - A reference to the messaging system.\n * @param options.state - Initial state to set on this controller.\n * @param options.implementations - Mapping from API type to API implementation.\n * @param options.rateLimitTimeout - The time window in which the rate limit is applied (in ms).\n * @param options.rateLimitCount - The amount of calls an origin can make in the rate limit time window.\n */\n constructor({\n rateLimitTimeout = 5000,\n rateLimitCount = 1,\n messenger,\n state,\n implementations,\n }: {\n rateLimitTimeout?: number;\n rateLimitCount?: number;\n messenger: RateLimitMessenger<RateLimitedApis>;\n state?: Partial<RateLimitState<RateLimitedApis>>;\n implementations: RateLimitedApis;\n }) {\n const defaultState = {\n requests: Object.keys(implementations).reduce(\n (acc, key) => ({ ...acc, [key]: {} }),\n {} as Record<keyof RateLimitedApis, Record<string, number>>,\n ),\n };\n super({\n name,\n metadata,\n messenger,\n state: { ...defaultState, ...state },\n });\n this.implementations = implementations;\n this.rateLimitTimeout = rateLimitTimeout;\n this.rateLimitCount = rateLimitCount;\n\n this.messagingSystem.registerActionHandler(\n `${name}:call` as const,\n (\n origin: string,\n type: keyof RateLimitedApis,\n ...args: Parameters<RateLimitedApis[keyof RateLimitedApis]['method']>\n ) => this.call(origin, type, ...args),\n );\n }\n\n /**\n * Calls an API if the requesting origin is not rate-limited.\n *\n * @param origin - The requesting origin.\n * @param type - The type of API call to make.\n * @param args - Arguments for the API call.\n */\n async call<ApiType extends keyof RateLimitedApis>(\n origin: string,\n type: ApiType,\n ...args: Parameters<RateLimitedApis[ApiType]['method']>\n ): Promise<ReturnType<RateLimitedApis[ApiType]['method']>> {\n if (this.isRateLimited(type, origin)) {\n throw rpcErrors.limitExceeded({\n message: `\"${type.toString()}\" is currently rate-limited. Please try again later.`,\n });\n }\n this.recordRequest(type, origin);\n\n const implementation = this.implementations[type].method;\n\n if (!implementation) {\n throw new Error('Invalid api type');\n }\n\n return implementation(...args) as ReturnType<\n RateLimitedApis[ApiType]['method']\n >;\n }\n\n /**\n * Checks whether an origin is rate limited for the a specific API.\n *\n * @param api - The API the origin is trying to access.\n * @param origin - The origin trying to access the API.\n * @returns `true` if rate-limited, and `false` otherwise.\n */\n private isRateLimited(api: keyof RateLimitedApis, origin: string) {\n const rateLimitCount =\n this.implementations[api].rateLimitCount ?? this.rateLimitCount;\n return this.state.requests[api][origin] >= rateLimitCount;\n }\n\n /**\n * Records that an origin has made a request to call an API, for rate-limiting purposes.\n *\n * @param api - The API the origin is trying to access.\n * @param origin - The origin trying to access the API.\n */\n private recordRequest(api: keyof RateLimitedApis, origin: string) {\n const rateLimitTimeout =\n this.implementations[api].rateLimitTimeout ?? this.rateLimitTimeout;\n this.update((state) => {\n const previous = (state as any).requests[api][origin] ?? 0;\n (state as any).requests[api][origin] = previous + 1;\n\n if (previous === 0) {\n setTimeout(() => this.resetRequestCount(api, origin), rateLimitTimeout);\n }\n });\n }\n\n /**\n * Resets the request count for a given origin and API combination, for rate-limiting purposes.\n *\n * @param api - The API in question.\n * @param origin - The origin in question.\n */\n private resetRequestCount(api: keyof RateLimitedApis, origin: string) {\n this.update((state) => {\n (state as any).requests[api][origin] = 0;\n });\n }\n}\n"]}
1
+ {"version":3,"file":"RateLimitController.js","sourceRoot":"","sources":["../src/RateLimitController.ts"],"names":[],"mappings":";;;;;;;;;;;;AAMA,+DAA2D;AAC3D,qDAAiD;AAwBjD,MAAM,IAAI,GAAG,qBAAqB,CAAC;AAiCnC,MAAM,QAAQ,GAAG;IACf,QAAQ,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE;CAC/C,CAAC;AAEF;;GAEG;AACH,MAAa,mBAEX,SAAQ,gCAIT;IAOC;;;;;;;;;OASG;IACH,YAAY,EACV,gBAAgB,GAAG,IAAI,EACvB,cAAc,GAAG,CAAC,EAClB,SAAS,EACT,KAAK,EACL,eAAe,GAOhB;QACC,MAAM,YAAY,GAAG;YACnB,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,MAAM,CAC3C,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,iCAAM,GAAG,KAAE,CAAC,GAAG,CAAC,EAAE,EAAE,IAAG,EACrC,EAA2D,CAC5D;SACF,CAAC;QACF,KAAK,CAAC;YACJ,IAAI;YACJ,QAAQ;YACR,SAAS;YACT,KAAK,kCAAO,YAAY,GAAK,KAAK,CAAE;SACrC,CAAC,CAAC;QACH,IAAI,CAAC,eAAe,GAAG,eAAe,CAAC;QACvC,IAAI,CAAC,gBAAgB,GAAG,gBAAgB,CAAC;QACzC,IAAI,CAAC,cAAc,GAAG,cAAc,CAAC;QAErC,IAAI,CAAC,eAAe,CAAC,qBAAqB,CACxC,GAAG,IAAI,OAAgB,EACvB,CACE,MAAc,EACd,IAA2B,EAC3B,GAAG,IAAkE,EACrE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC,CACtC,CAAC;IACJ,CAAC;IAED;;;;;;OAMG;IACG,IAAI,CACR,MAAc,EACd,IAAa,EACb,GAAG,IAAoD;;YAEvD,IAAI,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE;gBACpC,MAAM,sBAAS,CAAC,aAAa,CAAC;oBAC5B,OAAO,EAAE,IAAI,IAAI,CAAC,QAAQ,EAAE,sDAAsD;iBACnF,CAAC,CAAC;aACJ;YACD,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YAEjC,MAAM,cAAc,GAAG,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;YAEzD,IAAI,CAAC,cAAc,EAAE;gBACnB,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC;aACrC;YAED,OAAO,cAAc,CAAC,GAAG,IAAI,CAE5B,CAAC;QACJ,CAAC;KAAA;IAED;;;;;;OAMG;IACK,aAAa,CAAC,GAA0B,EAAE,MAAc;;QAC9D,MAAM,cAAc,GAClB,MAAA,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,cAAc,mCAAI,IAAI,CAAC,cAAc,CAAC;QAClE,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,cAAc,CAAC;IAC5D,CAAC;IAED;;;;;OAKG;IACK,aAAa,CAAC,GAA0B,EAAE,MAAc;;QAC9D,MAAM,gBAAgB,GACpB,MAAA,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,gBAAgB,mCAAI,IAAI,CAAC,gBAAgB,CAAC;QACtE,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE;;YACpB,gCAAgC;YAChC,8DAA8D;YAC9D,MAAM,QAAQ,GAAG,MAAC,KAAa,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,mCAAI,CAAC,CAAC;YAC3D,gCAAgC;YAChC,8DAA8D;YAC7D,KAAa,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,GAAG,QAAQ,GAAG,CAAC,CAAC;YAEpD,IAAI,QAAQ,KAAK,CAAC,EAAE;gBAClB,UAAU,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,gBAAgB,CAAC,CAAC;aACzE;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;;OAKG;IACK,iBAAiB,CAAC,GAA0B,EAAE,MAAc;QAClE,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE;YACpB,gCAAgC;YAChC,8DAA8D;YAC7D,KAAa,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC3C,CAAC,CAAC,CAAC;IACL,CAAC;CACF;AA7ID,kDA6IC","sourcesContent":["import type {\n ActionConstraint,\n RestrictedControllerMessenger,\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport { rpcErrors } from '@metamask/rpc-errors';\n\n/**\n * @type RateLimitedApi\n * @property method - The method that is rate-limited.\n * @property rateLimitTimeout - The time window in which the rate limit is applied (in ms).\n * @property rateLimitCount - The amount of calls an origin can make in the rate limit time window.\n */\nexport type RateLimitedApi = {\n method: ActionConstraint['handler'];\n rateLimitTimeout?: number;\n rateLimitCount?: number;\n};\n\n/**\n * @type RateLimitState\n * @property requests - Object containing number of requests in a given interval for each origin and api type combination\n */\nexport type RateLimitState<\n RateLimitedApis extends Record<string, RateLimitedApi>,\n> = {\n requests: Record<keyof RateLimitedApis, Record<string, number>>;\n};\n\nconst name = 'RateLimitController';\n\nexport type RateLimitStateChange<\n RateLimitedApis extends Record<string, RateLimitedApi>,\n> = ControllerStateChangeEvent<typeof name, RateLimitedApis>;\n\nexport type GetRateLimitState<\n RateLimitedApis extends Record<string, RateLimitedApi>,\n> = ControllerGetStateAction<typeof name, RateLimitedApis>;\n\nexport type CallApi<RateLimitedApis extends Record<string, RateLimitedApi>> = {\n type: `${typeof name}:call`;\n handler: RateLimitController<RateLimitedApis>['call'];\n};\n\nexport type RateLimitControllerActions<\n RateLimitedApis extends Record<string, RateLimitedApi>,\n> = GetRateLimitState<RateLimitedApis> | CallApi<RateLimitedApis>;\n\nexport type RateLimitControllerEvents<\n RateLimitedApis extends Record<string, RateLimitedApi>,\n> = RateLimitStateChange<RateLimitedApis>;\n\nexport type RateLimitMessenger<\n RateLimitedApis extends Record<string, RateLimitedApi>,\n> = RestrictedControllerMessenger<\n typeof name,\n RateLimitControllerActions<RateLimitedApis>,\n RateLimitControllerEvents<RateLimitedApis>,\n never,\n never\n>;\n\nconst metadata = {\n requests: { persist: false, anonymous: false },\n};\n\n/**\n * Controller with logic for rate-limiting API endpoints per requesting origin.\n */\nexport class RateLimitController<\n RateLimitedApis extends Record<string, RateLimitedApi>,\n> extends BaseController<\n typeof name,\n RateLimitState<RateLimitedApis>,\n RateLimitMessenger<RateLimitedApis>\n> {\n private readonly implementations;\n\n private readonly rateLimitTimeout;\n\n private readonly rateLimitCount;\n\n /**\n * Creates a RateLimitController instance.\n *\n * @param options - Constructor options.\n * @param options.messenger - A reference to the messaging system.\n * @param options.state - Initial state to set on this controller.\n * @param options.implementations - Mapping from API type to API implementation.\n * @param options.rateLimitTimeout - The time window in which the rate limit is applied (in ms).\n * @param options.rateLimitCount - The amount of calls an origin can make in the rate limit time window.\n */\n constructor({\n rateLimitTimeout = 5000,\n rateLimitCount = 1,\n messenger,\n state,\n implementations,\n }: {\n rateLimitTimeout?: number;\n rateLimitCount?: number;\n messenger: RateLimitMessenger<RateLimitedApis>;\n state?: Partial<RateLimitState<RateLimitedApis>>;\n implementations: RateLimitedApis;\n }) {\n const defaultState = {\n requests: Object.keys(implementations).reduce(\n (acc, key) => ({ ...acc, [key]: {} }),\n {} as Record<keyof RateLimitedApis, Record<string, number>>,\n ),\n };\n super({\n name,\n metadata,\n messenger,\n state: { ...defaultState, ...state },\n });\n this.implementations = implementations;\n this.rateLimitTimeout = rateLimitTimeout;\n this.rateLimitCount = rateLimitCount;\n\n this.messagingSystem.registerActionHandler(\n `${name}:call` as const,\n (\n origin: string,\n type: keyof RateLimitedApis,\n ...args: Parameters<RateLimitedApis[keyof RateLimitedApis]['method']>\n ) => this.call(origin, type, ...args),\n );\n }\n\n /**\n * Calls an API if the requesting origin is not rate-limited.\n *\n * @param origin - The requesting origin.\n * @param type - The type of API call to make.\n * @param args - Arguments for the API call.\n */\n async call<ApiType extends keyof RateLimitedApis>(\n origin: string,\n type: ApiType,\n ...args: Parameters<RateLimitedApis[ApiType]['method']>\n ): Promise<ReturnType<RateLimitedApis[ApiType]['method']>> {\n if (this.isRateLimited(type, origin)) {\n throw rpcErrors.limitExceeded({\n message: `\"${type.toString()}\" is currently rate-limited. Please try again later.`,\n });\n }\n this.recordRequest(type, origin);\n\n const implementation = this.implementations[type].method;\n\n if (!implementation) {\n throw new Error('Invalid api type');\n }\n\n return implementation(...args) as ReturnType<\n RateLimitedApis[ApiType]['method']\n >;\n }\n\n /**\n * Checks whether an origin is rate limited for the a specific API.\n *\n * @param api - The API the origin is trying to access.\n * @param origin - The origin trying to access the API.\n * @returns `true` if rate-limited, and `false` otherwise.\n */\n private isRateLimited(api: keyof RateLimitedApis, origin: string) {\n const rateLimitCount =\n this.implementations[api].rateLimitCount ?? this.rateLimitCount;\n return this.state.requests[api][origin] >= rateLimitCount;\n }\n\n /**\n * Records that an origin has made a request to call an API, for rate-limiting purposes.\n *\n * @param api - The API the origin is trying to access.\n * @param origin - The origin trying to access the API.\n */\n private recordRequest(api: keyof RateLimitedApis, origin: string) {\n const rateLimitTimeout =\n this.implementations[api].rateLimitTimeout ?? this.rateLimitTimeout;\n this.update((state) => {\n // TODO: Replace `any` with type\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const previous = (state as any).requests[api][origin] ?? 0;\n // TODO: Replace `any` with type\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (state as any).requests[api][origin] = previous + 1;\n\n if (previous === 0) {\n setTimeout(() => this.resetRequestCount(api, origin), rateLimitTimeout);\n }\n });\n }\n\n /**\n * Resets the request count for a given origin and API combination, for rate-limiting purposes.\n *\n * @param api - The API in question.\n * @param origin - The origin in question.\n */\n private resetRequestCount(api: keyof RateLimitedApis, origin: string) {\n this.update((state) => {\n // TODO: Replace `any` with type\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (state as any).requests[api][origin] = 0;\n });\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metamask-previews/rate-limit-controller",
3
- "version": "3.0.3-preview.eb58a59",
3
+ "version": "4.0.1-preview.c9a5f6a5",
4
4
  "description": "Contains logic for rate-limiting API endpoints by requesting origin",
5
5
  "keywords": [
6
6
  "MetaMask",
@@ -22,6 +22,7 @@
22
22
  ],
23
23
  "scripts": {
24
24
  "build:docs": "typedoc",
25
+ "changelog:update": "../../scripts/update-changelog.sh @metamask/rate-limit-controller",
25
26
  "changelog:validate": "../../scripts/validate-changelog.sh @metamask/rate-limit-controller",
26
27
  "publish:preview": "yarn npm publish --tag preview",
27
28
  "test": "jest --reporters=jest-silent-reporter",
@@ -30,11 +31,11 @@
30
31
  "test:watch": "jest --watch"
31
32
  },
32
33
  "dependencies": {
33
- "@metamask/base-controller": "^3.2.3",
34
+ "@metamask/base-controller": "^4.0.1",
34
35
  "@metamask/rpc-errors": "^6.1.0"
35
36
  },
36
37
  "devDependencies": {
37
- "@metamask/auto-changelog": "^3.4.3",
38
+ "@metamask/auto-changelog": "^3.4.4",
38
39
  "@types/jest": "^27.4.1",
39
40
  "deepmerge": "^4.2.2",
40
41
  "jest": "^27.5.1",