@discordjs/rest 3.0.0-dev.1757116903-f7c77a73d → 3.0.0-dev.1757505703-f1bcff46b

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/web.d.mts CHANGED
@@ -136,12 +136,18 @@ interface RESTOptions {
136
136
  * @defaultValue `3`
137
137
  */
138
138
  retries: number;
139
+ /**
140
+ * The time to exponentially add before retrying a 5xx or aborted request
141
+ *
142
+ * @defaultValue `0`
143
+ */
144
+ retryBackoff: GetRetryBackoffFunction | number;
139
145
  /**
140
146
  * The time to wait in milliseconds before a request is aborted
141
147
  *
142
148
  * @defaultValue `15_000`
143
149
  */
144
- timeout: number;
150
+ timeout: GetTimeoutFunction | number;
145
151
  /**
146
152
  * Extra information to add to the user agent
147
153
  *
@@ -221,6 +227,23 @@ type RateLimitQueueFilter = (rateLimitData: RateLimitData) => Awaitable<boolean>
221
227
  * A function that determines the rate limit offset for a given request.
222
228
  */
223
229
  type GetRateLimitOffsetFunction = (route: string) => number;
230
+ /**
231
+ * A function that determines the backoff for a retry for a given request.
232
+ *
233
+ * @param route - The route that has encountered a server-side error
234
+ * @param statusCode - The status code received or `null` if aborted
235
+ * @param retryCount - The number of retries that have been attempted so far. The first call will be `0`
236
+ * @param requestBody - The body that was sent with the request
237
+ * @returns The delay for the current request or `null` to throw an error instead of retrying
238
+ */
239
+ type GetRetryBackoffFunction = (route: string, statusCode: number | null, retryCount: number, requestBody: unknown) => number | null;
240
+ /**
241
+ * A function that determines the timeout for a given request.
242
+ *
243
+ * @param route - The route that is being processed
244
+ * @param body - The body that will be sent with the request
245
+ */
246
+ type GetTimeoutFunction = (route: string, body: unknown) => number;
224
247
  interface APIRequest {
225
248
  /**
226
249
  * The data that was used to form the body of this request
@@ -413,6 +436,7 @@ declare const DefaultRestOptions: {
413
436
  readonly offset: 50;
414
437
  readonly rejectOnRateLimit: null;
415
438
  readonly retries: 3;
439
+ readonly retryBackoff: 0;
416
440
  readonly timeout: 15000;
417
441
  readonly userAgentAppendix: string;
418
442
  readonly version: "10";
@@ -925,4 +949,4 @@ declare function calculateUserDefaultAvatarIndex(userId: Snowflake): number;
925
949
  */
926
950
  declare const version: string;
927
951
 
928
- export { ALLOWED_EXTENSIONS, ALLOWED_SIZES, ALLOWED_STICKER_EXTENSIONS, type APIRequest, AUTH_UUID_NAMESPACE, type AuthData, type BaseImageURLOptions, BurstHandlerMajorIdKey, CDN, type CDNOptions, DefaultRestOptions, DefaultUserAgent, DefaultUserAgentAppendix, DiscordAPIError, type DiscordError, type DiscordErrorData, type DiscordErrorFieldInformation, type DiscordErrorGroupWrapper, type EmojiURLOptions, type EmojiURLOptionsNotWebp, type EmojiURLOptionsWebp, type GetRateLimitOffsetFunction, HTTPError, type HandlerRequestData, type HashData, type IHandler, type ImageExtension, type ImageURLOptions, type InternalRequest, type InvalidRequestWarningData, type OAuthErrorData, OverwrittenMimeTypes, REST, RESTEvents, type RESTOptions, type RateLimitData, RateLimitError, type RateLimitQueueFilter, type RawFile, type RequestBody, type RequestData, type RequestHeaders, RequestMethod, type ResponseLike, type RestEvents, type RestEventsMap, type RouteData, type RouteLike, type StickerExtension, calculateUserDefaultAvatarIndex, makeURLSearchParams, parseResponse, version };
952
+ export { ALLOWED_EXTENSIONS, ALLOWED_SIZES, ALLOWED_STICKER_EXTENSIONS, type APIRequest, AUTH_UUID_NAMESPACE, type AuthData, type BaseImageURLOptions, BurstHandlerMajorIdKey, CDN, type CDNOptions, DefaultRestOptions, DefaultUserAgent, DefaultUserAgentAppendix, DiscordAPIError, type DiscordError, type DiscordErrorData, type DiscordErrorFieldInformation, type DiscordErrorGroupWrapper, type EmojiURLOptions, type EmojiURLOptionsNotWebp, type EmojiURLOptionsWebp, type GetRateLimitOffsetFunction, type GetRetryBackoffFunction, type GetTimeoutFunction, HTTPError, type HandlerRequestData, type HashData, type IHandler, type ImageExtension, type ImageURLOptions, type InternalRequest, type InvalidRequestWarningData, type OAuthErrorData, OverwrittenMimeTypes, REST, RESTEvents, type RESTOptions, type RateLimitData, RateLimitError, type RateLimitQueueFilter, type RawFile, type RequestBody, type RequestData, type RequestHeaders, RequestMethod, type ResponseLike, type RestEvents, type RestEventsMap, type RouteData, type RouteLike, type StickerExtension, calculateUserDefaultAvatarIndex, makeURLSearchParams, parseResponse, version };
package/dist/web.d.ts CHANGED
@@ -136,12 +136,18 @@ interface RESTOptions {
136
136
  * @defaultValue `3`
137
137
  */
138
138
  retries: number;
139
+ /**
140
+ * The time to exponentially add before retrying a 5xx or aborted request
141
+ *
142
+ * @defaultValue `0`
143
+ */
144
+ retryBackoff: GetRetryBackoffFunction | number;
139
145
  /**
140
146
  * The time to wait in milliseconds before a request is aborted
141
147
  *
142
148
  * @defaultValue `15_000`
143
149
  */
144
- timeout: number;
150
+ timeout: GetTimeoutFunction | number;
145
151
  /**
146
152
  * Extra information to add to the user agent
147
153
  *
@@ -221,6 +227,23 @@ type RateLimitQueueFilter = (rateLimitData: RateLimitData) => Awaitable<boolean>
221
227
  * A function that determines the rate limit offset for a given request.
222
228
  */
223
229
  type GetRateLimitOffsetFunction = (route: string) => number;
230
+ /**
231
+ * A function that determines the backoff for a retry for a given request.
232
+ *
233
+ * @param route - The route that has encountered a server-side error
234
+ * @param statusCode - The status code received or `null` if aborted
235
+ * @param retryCount - The number of retries that have been attempted so far. The first call will be `0`
236
+ * @param requestBody - The body that was sent with the request
237
+ * @returns The delay for the current request or `null` to throw an error instead of retrying
238
+ */
239
+ type GetRetryBackoffFunction = (route: string, statusCode: number | null, retryCount: number, requestBody: unknown) => number | null;
240
+ /**
241
+ * A function that determines the timeout for a given request.
242
+ *
243
+ * @param route - The route that is being processed
244
+ * @param body - The body that will be sent with the request
245
+ */
246
+ type GetTimeoutFunction = (route: string, body: unknown) => number;
224
247
  interface APIRequest {
225
248
  /**
226
249
  * The data that was used to form the body of this request
@@ -413,6 +436,7 @@ declare const DefaultRestOptions: {
413
436
  readonly offset: 50;
414
437
  readonly rejectOnRateLimit: null;
415
438
  readonly retries: 3;
439
+ readonly retryBackoff: 0;
416
440
  readonly timeout: 15000;
417
441
  readonly userAgentAppendix: string;
418
442
  readonly version: "10";
@@ -925,4 +949,4 @@ declare function calculateUserDefaultAvatarIndex(userId: Snowflake): number;
925
949
  */
926
950
  declare const version: string;
927
951
 
928
- export { ALLOWED_EXTENSIONS, ALLOWED_SIZES, ALLOWED_STICKER_EXTENSIONS, type APIRequest, AUTH_UUID_NAMESPACE, type AuthData, type BaseImageURLOptions, BurstHandlerMajorIdKey, CDN, type CDNOptions, DefaultRestOptions, DefaultUserAgent, DefaultUserAgentAppendix, DiscordAPIError, type DiscordError, type DiscordErrorData, type DiscordErrorFieldInformation, type DiscordErrorGroupWrapper, type EmojiURLOptions, type EmojiURLOptionsNotWebp, type EmojiURLOptionsWebp, type GetRateLimitOffsetFunction, HTTPError, type HandlerRequestData, type HashData, type IHandler, type ImageExtension, type ImageURLOptions, type InternalRequest, type InvalidRequestWarningData, type OAuthErrorData, OverwrittenMimeTypes, REST, RESTEvents, type RESTOptions, type RateLimitData, RateLimitError, type RateLimitQueueFilter, type RawFile, type RequestBody, type RequestData, type RequestHeaders, RequestMethod, type ResponseLike, type RestEvents, type RestEventsMap, type RouteData, type RouteLike, type StickerExtension, calculateUserDefaultAvatarIndex, makeURLSearchParams, parseResponse, version };
952
+ export { ALLOWED_EXTENSIONS, ALLOWED_SIZES, ALLOWED_STICKER_EXTENSIONS, type APIRequest, AUTH_UUID_NAMESPACE, type AuthData, type BaseImageURLOptions, BurstHandlerMajorIdKey, CDN, type CDNOptions, DefaultRestOptions, DefaultUserAgent, DefaultUserAgentAppendix, DiscordAPIError, type DiscordError, type DiscordErrorData, type DiscordErrorFieldInformation, type DiscordErrorGroupWrapper, type EmojiURLOptions, type EmojiURLOptionsNotWebp, type EmojiURLOptionsWebp, type GetRateLimitOffsetFunction, type GetRetryBackoffFunction, type GetTimeoutFunction, HTTPError, type HandlerRequestData, type HashData, type IHandler, type ImageExtension, type ImageURLOptions, type InternalRequest, type InvalidRequestWarningData, type OAuthErrorData, OverwrittenMimeTypes, REST, RESTEvents, type RESTOptions, type RateLimitData, RateLimitError, type RateLimitQueueFilter, type RawFile, type RequestBody, type RequestData, type RequestHeaders, RequestMethod, type ResponseLike, type RestEvents, type RestEventsMap, type RouteData, type RouteLike, type StickerExtension, calculateUserDefaultAvatarIndex, makeURLSearchParams, parseResponse, version };
package/dist/web.js CHANGED
@@ -61,7 +61,7 @@ var import_v102 = require("discord-api-types/v10");
61
61
  // src/lib/utils/constants.ts
62
62
  var import_util = require("@discordjs/util");
63
63
  var import_v10 = require("discord-api-types/v10");
64
- var DefaultUserAgent = `DiscordBot (https://discord.js.org, 3.0.0-dev.1757116903-f7c77a73d)`;
64
+ var DefaultUserAgent = `DiscordBot (https://discord.js.org, 3.0.0-dev.1757505703-f1bcff46b)`;
65
65
  var DefaultUserAgentAppendix = (0, import_util.getUserAgentAppendix)();
66
66
  var DefaultRestOptions = {
67
67
  agent: null,
@@ -74,6 +74,7 @@ var DefaultRestOptions = {
74
74
  offset: 50,
75
75
  rejectOnRateLimit: null,
76
76
  retries: 3,
77
+ retryBackoff: 0,
77
78
  timeout: 15e3,
78
79
  userAgentAppendix: DefaultUserAgentAppendix,
79
80
  version: import_v10.APIVersion,
@@ -603,6 +604,21 @@ function normalizeRateLimitOffset(offset, route) {
603
604
  return Math.max(0, result);
604
605
  }
605
606
  __name(normalizeRateLimitOffset, "normalizeRateLimitOffset");
607
+ function normalizeRetryBackoff(retryBackoff, route, statusCode, retryCount, requestBody) {
608
+ if (typeof retryBackoff === "number") {
609
+ return Math.max(0, retryBackoff) * (1 << retryCount);
610
+ }
611
+ return retryBackoff(route, statusCode, retryCount, requestBody);
612
+ }
613
+ __name(normalizeRetryBackoff, "normalizeRetryBackoff");
614
+ function normalizeTimeout(timeout, route, requestBody) {
615
+ if (typeof timeout === "number") {
616
+ return Math.max(0, timeout);
617
+ }
618
+ const result = timeout(route, requestBody);
619
+ return Math.max(0, result);
620
+ }
621
+ __name(normalizeTimeout, "normalizeTimeout");
606
622
 
607
623
  // src/lib/handlers/Shared.ts
608
624
  var authFalseWarningEmitted = false;
@@ -625,7 +641,10 @@ function incrementInvalidCount(manager) {
625
641
  __name(incrementInvalidCount, "incrementInvalidCount");
626
642
  async function makeNetworkRequest(manager, routeId, url, options, requestData, retries) {
627
643
  const controller = new AbortController();
628
- const timeout = setTimeout(() => controller.abort(), manager.options.timeout);
644
+ const timeout = setTimeout(
645
+ () => controller.abort(),
646
+ normalizeTimeout(manager.options.timeout, routeId.bucketRoute, requestData.body)
647
+ );
629
648
  if (requestData.signal) {
630
649
  if (requestData.signal.aborted) controller.abort();
631
650
  else requestData.signal.addEventListener("abort", () => controller.abort());
@@ -636,6 +655,19 @@ async function makeNetworkRequest(manager, routeId, url, options, requestData, r
636
655
  } catch (error) {
637
656
  if (!(error instanceof Error)) throw error;
638
657
  if (shouldRetry(error) && retries !== manager.options.retries) {
658
+ const backoff = normalizeRetryBackoff(
659
+ manager.options.retryBackoff,
660
+ routeId.bucketRoute,
661
+ null,
662
+ retries,
663
+ requestData.body
664
+ );
665
+ if (backoff === null) {
666
+ throw error;
667
+ }
668
+ if (backoff > 0) {
669
+ await sleep(backoff);
670
+ }
639
671
  return null;
640
672
  }
641
673
  throw error;
@@ -659,10 +691,23 @@ async function makeNetworkRequest(manager, routeId, url, options, requestData, r
659
691
  return res;
660
692
  }
661
693
  __name(makeNetworkRequest, "makeNetworkRequest");
662
- async function handleErrors(manager, res, method, url, requestData, retries) {
694
+ async function handleErrors(manager, res, method, url, requestData, retries, routeId) {
663
695
  const status = res.status;
664
696
  if (status >= 500 && status < 600) {
665
697
  if (retries !== manager.options.retries) {
698
+ const backoff = normalizeRetryBackoff(
699
+ manager.options.retryBackoff,
700
+ routeId.bucketRoute,
701
+ status,
702
+ retries,
703
+ requestData.body
704
+ );
705
+ if (backoff === null) {
706
+ throw new HTTPError(status, res.statusText, method, url, requestData);
707
+ }
708
+ if (backoff > 0) {
709
+ await sleep(backoff);
710
+ }
666
711
  return null;
667
712
  }
668
713
  throw new HTTPError(status, res.statusText, method, url, requestData);
@@ -786,7 +831,7 @@ var BurstHandler = class {
786
831
  await sleep(retryAfter);
787
832
  return this.runRequest(routeId, url, options, requestData, retries);
788
833
  } else {
789
- const handled = await handleErrors(this.manager, res, method, url, requestData, retries);
834
+ const handled = await handleErrors(this.manager, res, method, url, requestData, retries, routeId);
790
835
  if (handled === null) {
791
836
  return this.runRequest(routeId, url, options, requestData, ++retries);
792
837
  }
@@ -1088,7 +1133,7 @@ var SequentialHandler = class {
1088
1133
  }
1089
1134
  return this.runRequest(routeId, url, options, requestData, retries);
1090
1135
  } else {
1091
- const handled = await handleErrors(this.manager, res, method, url, requestData, retries);
1136
+ const handled = await handleErrors(this.manager, res, method, url, requestData, retries, routeId);
1092
1137
  if (handled === null) {
1093
1138
  return this.runRequest(routeId, url, options, requestData, ++retries);
1094
1139
  }
@@ -1417,7 +1462,7 @@ var REST = class _REST extends import_async_event_emitter.AsyncEventEmitter {
1417
1462
  };
1418
1463
 
1419
1464
  // src/shared.ts
1420
- var version = "3.0.0-dev.1757116903-f7c77a73d";
1465
+ var version = "3.0.0-dev.1757505703-f1bcff46b";
1421
1466
 
1422
1467
  // src/web.ts
1423
1468
  setDefaultStrategy(fetch);