@discordjs/rest 3.0.0-dev.1757160090-352c9819b → 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/index.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/index.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/index.js CHANGED
@@ -139,7 +139,7 @@ var import_v102 = require("discord-api-types/v10");
139
139
  // src/lib/utils/constants.ts
140
140
  var import_util = require("@discordjs/util");
141
141
  var import_v10 = require("discord-api-types/v10");
142
- var DefaultUserAgent = `DiscordBot (https://discord.js.org, 3.0.0-dev.1757160090-352c9819b)`;
142
+ var DefaultUserAgent = `DiscordBot (https://discord.js.org, 3.0.0-dev.1757505703-f1bcff46b)`;
143
143
  var DefaultUserAgentAppendix = (0, import_util.getUserAgentAppendix)();
144
144
  var DefaultRestOptions = {
145
145
  agent: null,
@@ -152,6 +152,7 @@ var DefaultRestOptions = {
152
152
  offset: 50,
153
153
  rejectOnRateLimit: null,
154
154
  retries: 3,
155
+ retryBackoff: 0,
155
156
  timeout: 15e3,
156
157
  userAgentAppendix: DefaultUserAgentAppendix,
157
158
  version: import_v10.APIVersion,
@@ -681,6 +682,21 @@ function normalizeRateLimitOffset(offset, route) {
681
682
  return Math.max(0, result);
682
683
  }
683
684
  __name(normalizeRateLimitOffset, "normalizeRateLimitOffset");
685
+ function normalizeRetryBackoff(retryBackoff, route, statusCode, retryCount, requestBody) {
686
+ if (typeof retryBackoff === "number") {
687
+ return Math.max(0, retryBackoff) * (1 << retryCount);
688
+ }
689
+ return retryBackoff(route, statusCode, retryCount, requestBody);
690
+ }
691
+ __name(normalizeRetryBackoff, "normalizeRetryBackoff");
692
+ function normalizeTimeout(timeout, route, requestBody) {
693
+ if (typeof timeout === "number") {
694
+ return Math.max(0, timeout);
695
+ }
696
+ const result = timeout(route, requestBody);
697
+ return Math.max(0, result);
698
+ }
699
+ __name(normalizeTimeout, "normalizeTimeout");
684
700
 
685
701
  // src/lib/handlers/Shared.ts
686
702
  var authFalseWarningEmitted = false;
@@ -703,7 +719,10 @@ function incrementInvalidCount(manager) {
703
719
  __name(incrementInvalidCount, "incrementInvalidCount");
704
720
  async function makeNetworkRequest(manager, routeId, url, options, requestData, retries) {
705
721
  const controller = new AbortController();
706
- const timeout = setTimeout(() => controller.abort(), manager.options.timeout);
722
+ const timeout = setTimeout(
723
+ () => controller.abort(),
724
+ normalizeTimeout(manager.options.timeout, routeId.bucketRoute, requestData.body)
725
+ );
707
726
  if (requestData.signal) {
708
727
  if (requestData.signal.aborted) controller.abort();
709
728
  else requestData.signal.addEventListener("abort", () => controller.abort());
@@ -714,6 +733,19 @@ async function makeNetworkRequest(manager, routeId, url, options, requestData, r
714
733
  } catch (error) {
715
734
  if (!(error instanceof Error)) throw error;
716
735
  if (shouldRetry(error) && retries !== manager.options.retries) {
736
+ const backoff = normalizeRetryBackoff(
737
+ manager.options.retryBackoff,
738
+ routeId.bucketRoute,
739
+ null,
740
+ retries,
741
+ requestData.body
742
+ );
743
+ if (backoff === null) {
744
+ throw error;
745
+ }
746
+ if (backoff > 0) {
747
+ await sleep(backoff);
748
+ }
717
749
  return null;
718
750
  }
719
751
  throw error;
@@ -737,10 +769,23 @@ async function makeNetworkRequest(manager, routeId, url, options, requestData, r
737
769
  return res;
738
770
  }
739
771
  __name(makeNetworkRequest, "makeNetworkRequest");
740
- async function handleErrors(manager, res, method, url, requestData, retries) {
772
+ async function handleErrors(manager, res, method, url, requestData, retries, routeId) {
741
773
  const status = res.status;
742
774
  if (status >= 500 && status < 600) {
743
775
  if (retries !== manager.options.retries) {
776
+ const backoff = normalizeRetryBackoff(
777
+ manager.options.retryBackoff,
778
+ routeId.bucketRoute,
779
+ status,
780
+ retries,
781
+ requestData.body
782
+ );
783
+ if (backoff === null) {
784
+ throw new HTTPError(status, res.statusText, method, url, requestData);
785
+ }
786
+ if (backoff > 0) {
787
+ await sleep(backoff);
788
+ }
744
789
  return null;
745
790
  }
746
791
  throw new HTTPError(status, res.statusText, method, url, requestData);
@@ -864,7 +909,7 @@ var BurstHandler = class {
864
909
  await sleep(retryAfter);
865
910
  return this.runRequest(routeId, url, options, requestData, retries);
866
911
  } else {
867
- const handled = await handleErrors(this.manager, res, method, url, requestData, retries);
912
+ const handled = await handleErrors(this.manager, res, method, url, requestData, retries, routeId);
868
913
  if (handled === null) {
869
914
  return this.runRequest(routeId, url, options, requestData, ++retries);
870
915
  }
@@ -1166,7 +1211,7 @@ var SequentialHandler = class {
1166
1211
  }
1167
1212
  return this.runRequest(routeId, url, options, requestData, retries);
1168
1213
  } else {
1169
- const handled = await handleErrors(this.manager, res, method, url, requestData, retries);
1214
+ const handled = await handleErrors(this.manager, res, method, url, requestData, retries, routeId);
1170
1215
  if (handled === null) {
1171
1216
  return this.runRequest(routeId, url, options, requestData, ++retries);
1172
1217
  }
@@ -1495,7 +1540,7 @@ var REST = class _REST extends import_async_event_emitter.AsyncEventEmitter {
1495
1540
  };
1496
1541
 
1497
1542
  // src/shared.ts
1498
- var version = "3.0.0-dev.1757160090-352c9819b";
1543
+ var version = "3.0.0-dev.1757505703-f1bcff46b";
1499
1544
 
1500
1545
  // src/index.ts
1501
1546
  setDefaultStrategy((0, import_util2.shouldUseGlobalFetchAndWebSocket)() ? fetch : makeRequest);