Skip to content

Commit 6df233d

Browse files
authored
feat: present x-ratelimit-scope for 429s hit (#9973)
* feat: present x-ratelimit-scope for 429s hit * fix: get scope from headers for burst too
1 parent 0aa7dc1 commit 6df233d

File tree

4 files changed

+19
-1
lines changed

4 files changed

+19
-1
lines changed

packages/rest/src/lib/errors/RateLimitError.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ export class RateLimitError extends Error implements RateLimitData {
2121

2222
public sublimitTimeout: number;
2323

24+
public scope: RateLimitData['scope'];
25+
2426
public constructor({
2527
timeToReset,
2628
limit,
@@ -32,6 +34,7 @@ export class RateLimitError extends Error implements RateLimitData {
3234
global,
3335
retryAfter,
3436
sublimitTimeout,
37+
scope,
3538
}: RateLimitData) {
3639
super();
3740
this.timeToReset = timeToReset;
@@ -44,6 +47,7 @@ export class RateLimitError extends Error implements RateLimitData {
4447
this.global = global;
4548
this.retryAfter = retryAfter;
4649
this.sublimitTimeout = sublimitTimeout;
50+
this.scope = scope;
4751
}
4852

4953
/**

packages/rest/src/lib/handlers/BurstHandler.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type { RequestInit } from 'undici';
22
import type { REST } from '../REST.js';
33
import type { IHandler } from '../interfaces/Handler.js';
44
import { RESTEvents } from '../utils/constants.js';
5-
import type { ResponseLike, HandlerRequestData, RouteData } from '../utils/types.js';
5+
import type { ResponseLike, HandlerRequestData, RouteData, RateLimitData } from '../utils/types.js';
66
import { onRateLimit, sleep } from '../utils/utils.js';
77
import { handleErrors, incrementInvalidCount, makeNetworkRequest } from './Shared.js';
88

@@ -102,6 +102,7 @@ export class BurstHandler implements IHandler {
102102
} else if (status === 429) {
103103
// Unexpected ratelimit
104104
const isGlobal = res.headers.has('X-RateLimit-Global');
105+
const scope = (res.headers.get('X-RateLimit-Scope') ?? 'user') as RateLimitData['scope'];
105106

106107
await onRateLimit(this.manager, {
107108
global: isGlobal,
@@ -114,6 +115,7 @@ export class BurstHandler implements IHandler {
114115
timeToReset: retryAfter,
115116
retryAfter,
116117
sublimitTimeout: 0,
118+
scope,
117119
});
118120

119121
this.debug(
@@ -128,6 +130,7 @@ export class BurstHandler implements IHandler {
128130
` Limit : ${Number.POSITIVE_INFINITY}`,
129131
` Retry After : ${retryAfter}ms`,
130132
` Sublimit : None`,
133+
` Scope : ${scope}`,
131134
].join('\n'),
132135
);
133136

packages/rest/src/lib/handlers/SequentialHandler.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,7 @@ export class SequentialHandler implements IHandler {
237237
timeToReset: timeout,
238238
retryAfter: timeout,
239239
sublimitTimeout: 0,
240+
scope: 'user',
240241
};
241242

242243
// Let library users know they have hit a rate limit
@@ -281,6 +282,7 @@ export class SequentialHandler implements IHandler {
281282
const reset = res.headers.get('X-RateLimit-Reset-After');
282283
const hash = res.headers.get('X-RateLimit-Bucket');
283284
const retry = res.headers.get('Retry-After');
285+
const scope = (res.headers.get('X-RateLimit-Scope') ?? 'user') as RateLimitData['scope'];
284286

285287
// Update the total number of requests that can be made before the rate limit resets
286288
this.limit = limit ? Number(limit) : Number.POSITIVE_INFINITY;
@@ -359,6 +361,7 @@ export class SequentialHandler implements IHandler {
359361
timeToReset: timeout,
360362
retryAfter,
361363
sublimitTimeout: sublimitTimeout ?? 0,
364+
scope,
362365
});
363366

364367
this.debug(
@@ -373,6 +376,7 @@ export class SequentialHandler implements IHandler {
373376
` Limit : ${limit}`,
374377
` Retry After : ${retryAfter}ms`,
375378
` Sublimit : ${sublimitTimeout ? `${sublimitTimeout}ms` : 'None'}`,
379+
` Scope : ${scope}`,
376380
].join('\n'),
377381
);
378382

packages/rest/src/lib/utils/types.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,13 @@ export interface RateLimitData {
164164
* The route being hit in this request
165165
*/
166166
route: string;
167+
/**
168+
* The scope of the rate limit that was hit.
169+
*
170+
* This can be `user` for rate limits that are per client, `global` for rate limits that affect all clients or `shared` for rate limits that
171+
* are shared per resource.
172+
*/
173+
scope: 'global' | 'shared' | 'user';
167174
/**
168175
* The time, in milliseconds, that will need to pass before the sublimit lock for the route resets, and requests that fall under a sublimit
169176
* can be retried

0 commit comments

Comments
 (0)