diff options
Diffstat (limited to 'node_modules/@discordjs/rest/dist')
19 files changed, 7065 insertions, 0 deletions
diff --git a/node_modules/@discordjs/rest/dist/index.d.mts b/node_modules/@discordjs/rest/dist/index.d.mts new file mode 100644 index 0000000..2417e2e --- /dev/null +++ b/node_modules/@discordjs/rest/dist/index.d.mts @@ -0,0 +1,510 @@ +import { R as ResponseLike, a as RawFile, I as InternalRequest, b as RateLimitData, c as RestEventsMap, H as HashData, d as IHandler, e as RESTOptions, f as RouteLike, g as RequestData } from './types-65527f29.js'; +export { A as APIRequest, m as HandlerRequestData, j as InvalidRequestWarningData, i as RateLimitQueueFilter, k as RequestHeaders, l as RequestMethod, h as RestEvents, n as RouteData } from './types-65527f29.js'; +import * as url from 'url'; +import { Snowflake } from 'discord-api-types/v10'; +import * as undici from 'undici'; +import { Dispatcher } from 'undici'; +import { Collection } from '@discordjs/collection'; +import { AsyncEventEmitter } from '@vladfrangu/async_event_emitter'; +import 'node:stream'; +import 'node:stream/web'; + +declare const DefaultUserAgent: `DiscordBot (https://discord.js.org, ${string})`; +/** + * The default string to append onto the user agent. + */ +declare const DefaultUserAgentAppendix: string; +declare const DefaultRestOptions: { + readonly agent: null; + readonly api: "https://discord.com/api"; + readonly authPrefix: "Bot"; + readonly cdn: "https://cdn.discordapp.com"; + readonly headers: {}; + readonly invalidRequestWarningInterval: 0; + readonly globalRequestsPerSecond: 50; + readonly offset: 50; + readonly rejectOnRateLimit: null; + readonly retries: 3; + readonly timeout: 15000; + readonly userAgentAppendix: string; + readonly version: "10"; + readonly hashSweepInterval: 14400000; + readonly hashLifetime: 86400000; + readonly handlerSweepInterval: 3600000; + readonly makeRequest: (url: string, init: undici.RequestInit) => Promise<ResponseLike>; +}; +/** + * The events that the REST manager emits + */ +declare enum RESTEvents { + Debug = "restDebug", + HandlerSweep = "handlerSweep", + HashSweep = "hashSweep", + InvalidRequestWarning = "invalidRequestWarning", + RateLimited = "rateLimited", + Response = "response" +} +declare const ALLOWED_EXTENSIONS: readonly ["webp", "png", "jpg", "jpeg", "gif"]; +declare const ALLOWED_STICKER_EXTENSIONS: readonly ["png", "json", "gif"]; +declare const ALLOWED_SIZES: readonly [16, 32, 64, 128, 256, 512, 1024, 2048, 4096]; +type ImageExtension = (typeof ALLOWED_EXTENSIONS)[number]; +type StickerExtension = (typeof ALLOWED_STICKER_EXTENSIONS)[number]; +type ImageSize = (typeof ALLOWED_SIZES)[number]; +declare const OverwrittenMimeTypes: { + readonly 'image/apng': "image/png"; +}; +declare const BurstHandlerMajorIdKey = "burst"; + +/** + * The options used for image URLs + */ +interface BaseImageURLOptions { + /** + * The extension to use for the image URL + * + * @defaultValue `'webp'` + */ + extension?: ImageExtension; + /** + * The size specified in the image URL + */ + size?: ImageSize; +} +/** + * The options used for image URLs with animated content + */ +interface ImageURLOptions extends BaseImageURLOptions { + /** + * Whether or not to prefer the static version of an image asset. + */ + forceStatic?: boolean; +} +/** + * The options to use when making a CDN URL + */ +interface MakeURLOptions { + /** + * The allowed extensions that can be used + */ + allowedExtensions?: readonly string[]; + /** + * The extension to use for the image URL + * + * @defaultValue `'webp'` + */ + extension?: string | undefined; + /** + * The size specified in the image URL + */ + size?: ImageSize; +} +/** + * The CDN link builder + */ +declare class CDN { + private readonly base; + constructor(base?: string); + /** + * Generates an app asset URL for a client's asset. + * + * @param clientId - The client id that has the asset + * @param assetHash - The hash provided by Discord for this asset + * @param options - Optional options for the asset + */ + appAsset(clientId: string, assetHash: string, options?: Readonly<BaseImageURLOptions>): string; + /** + * Generates an app icon URL for a client's icon. + * + * @param clientId - The client id that has the icon + * @param iconHash - The hash provided by Discord for this icon + * @param options - Optional options for the icon + */ + appIcon(clientId: string, iconHash: string, options?: Readonly<BaseImageURLOptions>): string; + /** + * Generates an avatar URL, e.g. for a user or a webhook. + * + * @param id - The id that has the icon + * @param avatarHash - The hash provided by Discord for this avatar + * @param options - Optional options for the avatar + */ + avatar(id: string, avatarHash: string, options?: Readonly<ImageURLOptions>): string; + /** + * Generates a user avatar decoration URL. + * + * @param userId - The id of the user + * @param userAvatarDecoration - The hash provided by Discord for this avatar decoration + * @param options - Optional options for the avatar decoration + */ + avatarDecoration(userId: string, userAvatarDecoration: string, options?: Readonly<BaseImageURLOptions>): string; + /** + * Generates a banner URL, e.g. for a user or a guild. + * + * @param id - The id that has the banner splash + * @param bannerHash - The hash provided by Discord for this banner + * @param options - Optional options for the banner + */ + banner(id: string, bannerHash: string, options?: Readonly<ImageURLOptions>): string; + /** + * Generates an icon URL for a channel, e.g. a group DM. + * + * @param channelId - The channel id that has the icon + * @param iconHash - The hash provided by Discord for this channel + * @param options - Optional options for the icon + */ + channelIcon(channelId: string, iconHash: string, options?: Readonly<BaseImageURLOptions>): string; + /** + * Generates a default avatar URL + * + * @param index - The default avatar index + * @remarks + * To calculate the index for a user do `(userId >> 22) % 6`, + * or `discriminator % 5` if they're using the legacy username system. + */ + defaultAvatar(index: number): string; + /** + * Generates a discovery splash URL for a guild's discovery splash. + * + * @param guildId - The guild id that has the discovery splash + * @param splashHash - The hash provided by Discord for this splash + * @param options - Optional options for the splash + */ + discoverySplash(guildId: string, splashHash: string, options?: Readonly<BaseImageURLOptions>): string; + /** + * Generates an emoji's URL for an emoji. + * + * @param emojiId - The emoji id + * @param extension - The extension of the emoji + */ + emoji(emojiId: string, extension?: ImageExtension): string; + /** + * Generates a guild member avatar URL. + * + * @param guildId - The id of the guild + * @param userId - The id of the user + * @param avatarHash - The hash provided by Discord for this avatar + * @param options - Optional options for the avatar + */ + guildMemberAvatar(guildId: string, userId: string, avatarHash: string, options?: Readonly<ImageURLOptions>): string; + /** + * Generates a guild member banner URL. + * + * @param guildId - The id of the guild + * @param userId - The id of the user + * @param bannerHash - The hash provided by Discord for this banner + * @param options - Optional options for the banner + */ + guildMemberBanner(guildId: string, userId: string, bannerHash: string, options?: Readonly<ImageURLOptions>): string; + /** + * Generates an icon URL, e.g. for a guild. + * + * @param id - The id that has the icon splash + * @param iconHash - The hash provided by Discord for this icon + * @param options - Optional options for the icon + */ + icon(id: string, iconHash: string, options?: Readonly<ImageURLOptions>): string; + /** + * Generates a URL for the icon of a role + * + * @param roleId - The id of the role that has the icon + * @param roleIconHash - The hash provided by Discord for this role icon + * @param options - Optional options for the role icon + */ + roleIcon(roleId: string, roleIconHash: string, options?: Readonly<BaseImageURLOptions>): string; + /** + * Generates a guild invite splash URL for a guild's invite splash. + * + * @param guildId - The guild id that has the invite splash + * @param splashHash - The hash provided by Discord for this splash + * @param options - Optional options for the splash + */ + splash(guildId: string, splashHash: string, options?: Readonly<BaseImageURLOptions>): string; + /** + * Generates a sticker URL. + * + * @param stickerId - The sticker id + * @param extension - The extension of the sticker + * @privateRemarks + * Stickers cannot have a `.webp` extension, so we default to a `.png` + */ + sticker(stickerId: string, extension?: StickerExtension): string; + /** + * Generates a sticker pack banner URL. + * + * @param bannerId - The banner id + * @param options - Optional options for the banner + */ + stickerPackBanner(bannerId: string, options?: Readonly<BaseImageURLOptions>): string; + /** + * Generates a team icon URL for a team's icon. + * + * @param teamId - The team id that has the icon + * @param iconHash - The hash provided by Discord for this icon + * @param options - Optional options for the icon + */ + teamIcon(teamId: string, iconHash: string, options?: Readonly<BaseImageURLOptions>): string; + /** + * Generates a cover image for a guild scheduled event. + * + * @param scheduledEventId - The scheduled event id + * @param coverHash - The hash provided by discord for this cover image + * @param options - Optional options for the cover image + */ + guildScheduledEventCover(scheduledEventId: string, coverHash: string, options?: Readonly<BaseImageURLOptions>): string; + /** + * Constructs the URL for the resource, checking whether or not `hash` starts with `a_` if `dynamic` is set to `true`. + * + * @param route - The base cdn route + * @param hash - The hash provided by Discord for this icon + * @param options - Optional options for the link + */ + private dynamicMakeURL; + /** + * Constructs the URL for the resource + * + * @param route - The base cdn route + * @param options - The extension/size options for the link + */ + private makeURL; +} + +interface DiscordErrorFieldInformation { + code: string; + message: string; +} +interface DiscordErrorGroupWrapper { + _errors: DiscordError[]; +} +type DiscordError = DiscordErrorFieldInformation | DiscordErrorGroupWrapper | string | { + [k: string]: DiscordError; +}; +interface DiscordErrorData { + code: number; + errors?: DiscordError; + message: string; +} +interface OAuthErrorData { + error: string; + error_description?: string; +} +interface RequestBody { + files: RawFile[] | undefined; + json: unknown | undefined; +} +/** + * Represents an API error returned by Discord + */ +declare class DiscordAPIError extends Error { + rawError: DiscordErrorData | OAuthErrorData; + code: number | string; + status: number; + method: string; + url: string; + requestBody: RequestBody; + /** + * @param rawError - The error reported by Discord + * @param code - The error code reported by Discord + * @param status - The status code of the response + * @param method - The method of the request that erred + * @param url - The url of the request that erred + * @param bodyData - The unparsed data for the request that errored + */ + constructor(rawError: DiscordErrorData | OAuthErrorData, code: number | string, status: number, method: string, url: string, bodyData: Pick<InternalRequest, 'body' | 'files'>); + /** + * The name of the error + */ + get name(): string; + private static getMessage; + private static flattenDiscordError; +} + +/** + * Represents a HTTP error + */ +declare class HTTPError extends Error { + status: number; + method: string; + url: string; + requestBody: RequestBody; + name: string; + /** + * @param status - The status code of the response + * @param statusText - The status text of the response + * @param method - The method of the request that erred + * @param url - The url of the request that erred + * @param bodyData - The unparsed data for the request that errored + */ + constructor(status: number, statusText: string, method: string, url: string, bodyData: Pick<InternalRequest, 'body' | 'files'>); +} + +declare class RateLimitError extends Error implements RateLimitData { + timeToReset: number; + limit: number; + method: string; + hash: string; + url: string; + route: string; + majorParameter: string; + global: boolean; + constructor({ timeToReset, limit, method, hash, url, route, majorParameter, global }: RateLimitData); + /** + * The name of the error + */ + get name(): string; +} + +/** + * Represents the class that manages handlers for endpoints + */ +declare class REST extends AsyncEventEmitter<RestEventsMap> { + #private; + /** + * The {@link https://undici.nodejs.org/#/docs/api/Agent | Agent} for all requests + * performed by this manager. + */ + agent: Dispatcher | null; + readonly cdn: CDN; + /** + * The number of requests remaining in the global bucket + */ + globalRemaining: number; + /** + * The promise used to wait out the global rate limit + */ + globalDelay: Promise<void> | null; + /** + * The timestamp at which the global bucket resets + */ + globalReset: number; + /** + * API bucket hashes that are cached from provided routes + */ + readonly hashes: Collection<string, HashData>; + /** + * Request handlers created from the bucket hash and the major parameters + */ + readonly handlers: Collection<string, IHandler>; + private hashTimer; + private handlerTimer; + readonly options: RESTOptions; + constructor(options?: Partial<RESTOptions>); + private setupSweepers; + /** + * Runs a get request from the api + * + * @param fullRoute - The full route to query + * @param options - Optional request options + */ + get(fullRoute: RouteLike, options?: RequestData): Promise<unknown>; + /** + * Runs a delete request from the api + * + * @param fullRoute - The full route to query + * @param options - Optional request options + */ + delete(fullRoute: RouteLike, options?: RequestData): Promise<unknown>; + /** + * Runs a post request from the api + * + * @param fullRoute - The full route to query + * @param options - Optional request options + */ + post(fullRoute: RouteLike, options?: RequestData): Promise<unknown>; + /** + * Runs a put request from the api + * + * @param fullRoute - The full route to query + * @param options - Optional request options + */ + put(fullRoute: RouteLike, options?: RequestData): Promise<unknown>; + /** + * Runs a patch request from the api + * + * @param fullRoute - The full route to query + * @param options - Optional request options + */ + patch(fullRoute: RouteLike, options?: RequestData): Promise<unknown>; + /** + * Runs a request from the api + * + * @param options - Request options + */ + request(options: InternalRequest): Promise<unknown>; + /** + * Sets the default agent to use for requests performed by this manager + * + * @param agent - The agent to use + */ + setAgent(agent: Dispatcher): this; + /** + * Sets the authorization token that should be used for requests + * + * @param token - The authorization token to use + */ + setToken(token: string): this; + /** + * Queues a request to be sent + * + * @param request - All the information needed to make a request + * @returns The response from the api request + */ + queueRequest(request: InternalRequest): Promise<ResponseLike>; + /** + * Creates a new rate limit handler from a hash, based on the hash and the major parameter + * + * @param hash - The hash for the route + * @param majorParameter - The major parameter for this handler + * @internal + */ + private createHandler; + /** + * Formats the request data to a usable format for fetch + * + * @param request - The request data + */ + private resolveRequest; + /** + * Stops the hash sweeping interval + */ + clearHashSweeper(): void; + /** + * Stops the request handler sweeping interval + */ + clearHandlerSweeper(): void; + /** + * Generates route data for an endpoint:method + * + * @param endpoint - The raw endpoint to generalize + * @param method - The HTTP method this endpoint is called without + * @internal + */ + private static generateRouteData; +} + +/** + * Creates and populates an URLSearchParams instance from an object, stripping + * out null and undefined values, while also coercing non-strings to strings. + * + * @param options - The options to use + * @returns A populated URLSearchParams instance + */ +declare function makeURLSearchParams<T extends object>(options?: Readonly<T>): url.URLSearchParams; +/** + * Converts the response to usable data + * + * @param res - The fetch response + */ +declare function parseResponse(res: ResponseLike): Promise<unknown>; +/** + * Calculates the default avatar index for a given user id. + * + * @param userId - The user id to calculate the default avatar index for + */ +declare function calculateUserDefaultAvatarIndex(userId: Snowflake): number; + +/** + * The {@link https://github.com/discordjs/discord.js/blob/main/packages/rest/#readme | @discordjs/rest} version + * that you are currently using. + */ +declare const version: string; + +export { ALLOWED_EXTENSIONS, ALLOWED_SIZES, ALLOWED_STICKER_EXTENSIONS, BaseImageURLOptions, BurstHandlerMajorIdKey, CDN, DefaultRestOptions, DefaultUserAgent, DefaultUserAgentAppendix, DiscordAPIError, DiscordErrorData, HTTPError, HashData, ImageExtension, ImageSize, ImageURLOptions, InternalRequest, MakeURLOptions, OAuthErrorData, OverwrittenMimeTypes, REST, RESTEvents, RESTOptions, RateLimitData, RateLimitError, RawFile, RequestBody, RequestData, ResponseLike, RestEventsMap, RouteLike, StickerExtension, calculateUserDefaultAvatarIndex, makeURLSearchParams, parseResponse, version }; diff --git a/node_modules/@discordjs/rest/dist/index.d.ts b/node_modules/@discordjs/rest/dist/index.d.ts new file mode 100644 index 0000000..2417e2e --- /dev/null +++ b/node_modules/@discordjs/rest/dist/index.d.ts @@ -0,0 +1,510 @@ +import { R as ResponseLike, a as RawFile, I as InternalRequest, b as RateLimitData, c as RestEventsMap, H as HashData, d as IHandler, e as RESTOptions, f as RouteLike, g as RequestData } from './types-65527f29.js'; +export { A as APIRequest, m as HandlerRequestData, j as InvalidRequestWarningData, i as RateLimitQueueFilter, k as RequestHeaders, l as RequestMethod, h as RestEvents, n as RouteData } from './types-65527f29.js'; +import * as url from 'url'; +import { Snowflake } from 'discord-api-types/v10'; +import * as undici from 'undici'; +import { Dispatcher } from 'undici'; +import { Collection } from '@discordjs/collection'; +import { AsyncEventEmitter } from '@vladfrangu/async_event_emitter'; +import 'node:stream'; +import 'node:stream/web'; + +declare const DefaultUserAgent: `DiscordBot (https://discord.js.org, ${string})`; +/** + * The default string to append onto the user agent. + */ +declare const DefaultUserAgentAppendix: string; +declare const DefaultRestOptions: { + readonly agent: null; + readonly api: "https://discord.com/api"; + readonly authPrefix: "Bot"; + readonly cdn: "https://cdn.discordapp.com"; + readonly headers: {}; + readonly invalidRequestWarningInterval: 0; + readonly globalRequestsPerSecond: 50; + readonly offset: 50; + readonly rejectOnRateLimit: null; + readonly retries: 3; + readonly timeout: 15000; + readonly userAgentAppendix: string; + readonly version: "10"; + readonly hashSweepInterval: 14400000; + readonly hashLifetime: 86400000; + readonly handlerSweepInterval: 3600000; + readonly makeRequest: (url: string, init: undici.RequestInit) => Promise<ResponseLike>; +}; +/** + * The events that the REST manager emits + */ +declare enum RESTEvents { + Debug = "restDebug", + HandlerSweep = "handlerSweep", + HashSweep = "hashSweep", + InvalidRequestWarning = "invalidRequestWarning", + RateLimited = "rateLimited", + Response = "response" +} +declare const ALLOWED_EXTENSIONS: readonly ["webp", "png", "jpg", "jpeg", "gif"]; +declare const ALLOWED_STICKER_EXTENSIONS: readonly ["png", "json", "gif"]; +declare const ALLOWED_SIZES: readonly [16, 32, 64, 128, 256, 512, 1024, 2048, 4096]; +type ImageExtension = (typeof ALLOWED_EXTENSIONS)[number]; +type StickerExtension = (typeof ALLOWED_STICKER_EXTENSIONS)[number]; +type ImageSize = (typeof ALLOWED_SIZES)[number]; +declare const OverwrittenMimeTypes: { + readonly 'image/apng': "image/png"; +}; +declare const BurstHandlerMajorIdKey = "burst"; + +/** + * The options used for image URLs + */ +interface BaseImageURLOptions { + /** + * The extension to use for the image URL + * + * @defaultValue `'webp'` + */ + extension?: ImageExtension; + /** + * The size specified in the image URL + */ + size?: ImageSize; +} +/** + * The options used for image URLs with animated content + */ +interface ImageURLOptions extends BaseImageURLOptions { + /** + * Whether or not to prefer the static version of an image asset. + */ + forceStatic?: boolean; +} +/** + * The options to use when making a CDN URL + */ +interface MakeURLOptions { + /** + * The allowed extensions that can be used + */ + allowedExtensions?: readonly string[]; + /** + * The extension to use for the image URL + * + * @defaultValue `'webp'` + */ + extension?: string | undefined; + /** + * The size specified in the image URL + */ + size?: ImageSize; +} +/** + * The CDN link builder + */ +declare class CDN { + private readonly base; + constructor(base?: string); + /** + * Generates an app asset URL for a client's asset. + * + * @param clientId - The client id that has the asset + * @param assetHash - The hash provided by Discord for this asset + * @param options - Optional options for the asset + */ + appAsset(clientId: string, assetHash: string, options?: Readonly<BaseImageURLOptions>): string; + /** + * Generates an app icon URL for a client's icon. + * + * @param clientId - The client id that has the icon + * @param iconHash - The hash provided by Discord for this icon + * @param options - Optional options for the icon + */ + appIcon(clientId: string, iconHash: string, options?: Readonly<BaseImageURLOptions>): string; + /** + * Generates an avatar URL, e.g. for a user or a webhook. + * + * @param id - The id that has the icon + * @param avatarHash - The hash provided by Discord for this avatar + * @param options - Optional options for the avatar + */ + avatar(id: string, avatarHash: string, options?: Readonly<ImageURLOptions>): string; + /** + * Generates a user avatar decoration URL. + * + * @param userId - The id of the user + * @param userAvatarDecoration - The hash provided by Discord for this avatar decoration + * @param options - Optional options for the avatar decoration + */ + avatarDecoration(userId: string, userAvatarDecoration: string, options?: Readonly<BaseImageURLOptions>): string; + /** + * Generates a banner URL, e.g. for a user or a guild. + * + * @param id - The id that has the banner splash + * @param bannerHash - The hash provided by Discord for this banner + * @param options - Optional options for the banner + */ + banner(id: string, bannerHash: string, options?: Readonly<ImageURLOptions>): string; + /** + * Generates an icon URL for a channel, e.g. a group DM. + * + * @param channelId - The channel id that has the icon + * @param iconHash - The hash provided by Discord for this channel + * @param options - Optional options for the icon + */ + channelIcon(channelId: string, iconHash: string, options?: Readonly<BaseImageURLOptions>): string; + /** + * Generates a default avatar URL + * + * @param index - The default avatar index + * @remarks + * To calculate the index for a user do `(userId >> 22) % 6`, + * or `discriminator % 5` if they're using the legacy username system. + */ + defaultAvatar(index: number): string; + /** + * Generates a discovery splash URL for a guild's discovery splash. + * + * @param guildId - The guild id that has the discovery splash + * @param splashHash - The hash provided by Discord for this splash + * @param options - Optional options for the splash + */ + discoverySplash(guildId: string, splashHash: string, options?: Readonly<BaseImageURLOptions>): string; + /** + * Generates an emoji's URL for an emoji. + * + * @param emojiId - The emoji id + * @param extension - The extension of the emoji + */ + emoji(emojiId: string, extension?: ImageExtension): string; + /** + * Generates a guild member avatar URL. + * + * @param guildId - The id of the guild + * @param userId - The id of the user + * @param avatarHash - The hash provided by Discord for this avatar + * @param options - Optional options for the avatar + */ + guildMemberAvatar(guildId: string, userId: string, avatarHash: string, options?: Readonly<ImageURLOptions>): string; + /** + * Generates a guild member banner URL. + * + * @param guildId - The id of the guild + * @param userId - The id of the user + * @param bannerHash - The hash provided by Discord for this banner + * @param options - Optional options for the banner + */ + guildMemberBanner(guildId: string, userId: string, bannerHash: string, options?: Readonly<ImageURLOptions>): string; + /** + * Generates an icon URL, e.g. for a guild. + * + * @param id - The id that has the icon splash + * @param iconHash - The hash provided by Discord for this icon + * @param options - Optional options for the icon + */ + icon(id: string, iconHash: string, options?: Readonly<ImageURLOptions>): string; + /** + * Generates a URL for the icon of a role + * + * @param roleId - The id of the role that has the icon + * @param roleIconHash - The hash provided by Discord for this role icon + * @param options - Optional options for the role icon + */ + roleIcon(roleId: string, roleIconHash: string, options?: Readonly<BaseImageURLOptions>): string; + /** + * Generates a guild invite splash URL for a guild's invite splash. + * + * @param guildId - The guild id that has the invite splash + * @param splashHash - The hash provided by Discord for this splash + * @param options - Optional options for the splash + */ + splash(guildId: string, splashHash: string, options?: Readonly<BaseImageURLOptions>): string; + /** + * Generates a sticker URL. + * + * @param stickerId - The sticker id + * @param extension - The extension of the sticker + * @privateRemarks + * Stickers cannot have a `.webp` extension, so we default to a `.png` + */ + sticker(stickerId: string, extension?: StickerExtension): string; + /** + * Generates a sticker pack banner URL. + * + * @param bannerId - The banner id + * @param options - Optional options for the banner + */ + stickerPackBanner(bannerId: string, options?: Readonly<BaseImageURLOptions>): string; + /** + * Generates a team icon URL for a team's icon. + * + * @param teamId - The team id that has the icon + * @param iconHash - The hash provided by Discord for this icon + * @param options - Optional options for the icon + */ + teamIcon(teamId: string, iconHash: string, options?: Readonly<BaseImageURLOptions>): string; + /** + * Generates a cover image for a guild scheduled event. + * + * @param scheduledEventId - The scheduled event id + * @param coverHash - The hash provided by discord for this cover image + * @param options - Optional options for the cover image + */ + guildScheduledEventCover(scheduledEventId: string, coverHash: string, options?: Readonly<BaseImageURLOptions>): string; + /** + * Constructs the URL for the resource, checking whether or not `hash` starts with `a_` if `dynamic` is set to `true`. + * + * @param route - The base cdn route + * @param hash - The hash provided by Discord for this icon + * @param options - Optional options for the link + */ + private dynamicMakeURL; + /** + * Constructs the URL for the resource + * + * @param route - The base cdn route + * @param options - The extension/size options for the link + */ + private makeURL; +} + +interface DiscordErrorFieldInformation { + code: string; + message: string; +} +interface DiscordErrorGroupWrapper { + _errors: DiscordError[]; +} +type DiscordError = DiscordErrorFieldInformation | DiscordErrorGroupWrapper | string | { + [k: string]: DiscordError; +}; +interface DiscordErrorData { + code: number; + errors?: DiscordError; + message: string; +} +interface OAuthErrorData { + error: string; + error_description?: string; +} +interface RequestBody { + files: RawFile[] | undefined; + json: unknown | undefined; +} +/** + * Represents an API error returned by Discord + */ +declare class DiscordAPIError extends Error { + rawError: DiscordErrorData | OAuthErrorData; + code: number | string; + status: number; + method: string; + url: string; + requestBody: RequestBody; + /** + * @param rawError - The error reported by Discord + * @param code - The error code reported by Discord + * @param status - The status code of the response + * @param method - The method of the request that erred + * @param url - The url of the request that erred + * @param bodyData - The unparsed data for the request that errored + */ + constructor(rawError: DiscordErrorData | OAuthErrorData, code: number | string, status: number, method: string, url: string, bodyData: Pick<InternalRequest, 'body' | 'files'>); + /** + * The name of the error + */ + get name(): string; + private static getMessage; + private static flattenDiscordError; +} + +/** + * Represents a HTTP error + */ +declare class HTTPError extends Error { + status: number; + method: string; + url: string; + requestBody: RequestBody; + name: string; + /** + * @param status - The status code of the response + * @param statusText - The status text of the response + * @param method - The method of the request that erred + * @param url - The url of the request that erred + * @param bodyData - The unparsed data for the request that errored + */ + constructor(status: number, statusText: string, method: string, url: string, bodyData: Pick<InternalRequest, 'body' | 'files'>); +} + +declare class RateLimitError extends Error implements RateLimitData { + timeToReset: number; + limit: number; + method: string; + hash: string; + url: string; + route: string; + majorParameter: string; + global: boolean; + constructor({ timeToReset, limit, method, hash, url, route, majorParameter, global }: RateLimitData); + /** + * The name of the error + */ + get name(): string; +} + +/** + * Represents the class that manages handlers for endpoints + */ +declare class REST extends AsyncEventEmitter<RestEventsMap> { + #private; + /** + * The {@link https://undici.nodejs.org/#/docs/api/Agent | Agent} for all requests + * performed by this manager. + */ + agent: Dispatcher | null; + readonly cdn: CDN; + /** + * The number of requests remaining in the global bucket + */ + globalRemaining: number; + /** + * The promise used to wait out the global rate limit + */ + globalDelay: Promise<void> | null; + /** + * The timestamp at which the global bucket resets + */ + globalReset: number; + /** + * API bucket hashes that are cached from provided routes + */ + readonly hashes: Collection<string, HashData>; + /** + * Request handlers created from the bucket hash and the major parameters + */ + readonly handlers: Collection<string, IHandler>; + private hashTimer; + private handlerTimer; + readonly options: RESTOptions; + constructor(options?: Partial<RESTOptions>); + private setupSweepers; + /** + * Runs a get request from the api + * + * @param fullRoute - The full route to query + * @param options - Optional request options + */ + get(fullRoute: RouteLike, options?: RequestData): Promise<unknown>; + /** + * Runs a delete request from the api + * + * @param fullRoute - The full route to query + * @param options - Optional request options + */ + delete(fullRoute: RouteLike, options?: RequestData): Promise<unknown>; + /** + * Runs a post request from the api + * + * @param fullRoute - The full route to query + * @param options - Optional request options + */ + post(fullRoute: RouteLike, options?: RequestData): Promise<unknown>; + /** + * Runs a put request from the api + * + * @param fullRoute - The full route to query + * @param options - Optional request options + */ + put(fullRoute: RouteLike, options?: RequestData): Promise<unknown>; + /** + * Runs a patch request from the api + * + * @param fullRoute - The full route to query + * @param options - Optional request options + */ + patch(fullRoute: RouteLike, options?: RequestData): Promise<unknown>; + /** + * Runs a request from the api + * + * @param options - Request options + */ + request(options: InternalRequest): Promise<unknown>; + /** + * Sets the default agent to use for requests performed by this manager + * + * @param agent - The agent to use + */ + setAgent(agent: Dispatcher): this; + /** + * Sets the authorization token that should be used for requests + * + * @param token - The authorization token to use + */ + setToken(token: string): this; + /** + * Queues a request to be sent + * + * @param request - All the information needed to make a request + * @returns The response from the api request + */ + queueRequest(request: InternalRequest): Promise<ResponseLike>; + /** + * Creates a new rate limit handler from a hash, based on the hash and the major parameter + * + * @param hash - The hash for the route + * @param majorParameter - The major parameter for this handler + * @internal + */ + private createHandler; + /** + * Formats the request data to a usable format for fetch + * + * @param request - The request data + */ + private resolveRequest; + /** + * Stops the hash sweeping interval + */ + clearHashSweeper(): void; + /** + * Stops the request handler sweeping interval + */ + clearHandlerSweeper(): void; + /** + * Generates route data for an endpoint:method + * + * @param endpoint - The raw endpoint to generalize + * @param method - The HTTP method this endpoint is called without + * @internal + */ + private static generateRouteData; +} + +/** + * Creates and populates an URLSearchParams instance from an object, stripping + * out null and undefined values, while also coercing non-strings to strings. + * + * @param options - The options to use + * @returns A populated URLSearchParams instance + */ +declare function makeURLSearchParams<T extends object>(options?: Readonly<T>): url.URLSearchParams; +/** + * Converts the response to usable data + * + * @param res - The fetch response + */ +declare function parseResponse(res: ResponseLike): Promise<unknown>; +/** + * Calculates the default avatar index for a given user id. + * + * @param userId - The user id to calculate the default avatar index for + */ +declare function calculateUserDefaultAvatarIndex(userId: Snowflake): number; + +/** + * The {@link https://github.com/discordjs/discord.js/blob/main/packages/rest/#readme | @discordjs/rest} version + * that you are currently using. + */ +declare const version: string; + +export { ALLOWED_EXTENSIONS, ALLOWED_SIZES, ALLOWED_STICKER_EXTENSIONS, BaseImageURLOptions, BurstHandlerMajorIdKey, CDN, DefaultRestOptions, DefaultUserAgent, DefaultUserAgentAppendix, DiscordAPIError, DiscordErrorData, HTTPError, HashData, ImageExtension, ImageSize, ImageURLOptions, InternalRequest, MakeURLOptions, OAuthErrorData, OverwrittenMimeTypes, REST, RESTEvents, RESTOptions, RateLimitData, RateLimitError, RawFile, RequestBody, RequestData, ResponseLike, RestEventsMap, RouteLike, StickerExtension, calculateUserDefaultAvatarIndex, makeURLSearchParams, parseResponse, version }; diff --git a/node_modules/@discordjs/rest/dist/index.js b/node_modules/@discordjs/rest/dist/index.js new file mode 100644 index 0000000..16a6d46 --- /dev/null +++ b/node_modules/@discordjs/rest/dist/index.js @@ -0,0 +1,1423 @@ +"use strict"; +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); + +// src/index.ts +var src_exports = {}; +__export(src_exports, { + ALLOWED_EXTENSIONS: () => ALLOWED_EXTENSIONS, + ALLOWED_SIZES: () => ALLOWED_SIZES, + ALLOWED_STICKER_EXTENSIONS: () => ALLOWED_STICKER_EXTENSIONS, + BurstHandlerMajorIdKey: () => BurstHandlerMajorIdKey, + CDN: () => CDN, + DefaultRestOptions: () => DefaultRestOptions, + DefaultUserAgent: () => DefaultUserAgent, + DefaultUserAgentAppendix: () => DefaultUserAgentAppendix, + DiscordAPIError: () => DiscordAPIError, + HTTPError: () => HTTPError, + OverwrittenMimeTypes: () => OverwrittenMimeTypes, + REST: () => REST, + RESTEvents: () => RESTEvents, + RateLimitError: () => RateLimitError, + RequestMethod: () => RequestMethod, + calculateUserDefaultAvatarIndex: () => calculateUserDefaultAvatarIndex, + makeURLSearchParams: () => makeURLSearchParams, + parseResponse: () => parseResponse, + version: () => version +}); +module.exports = __toCommonJS(src_exports); +var import_node_buffer = require("buffer"); +var import_util2 = require("@discordjs/util"); +var import_undici2 = require("undici"); + +// src/environment.ts +var defaultStrategy; +function setDefaultStrategy(newStrategy) { + defaultStrategy = newStrategy; +} +__name(setDefaultStrategy, "setDefaultStrategy"); +function getDefaultStrategy() { + return defaultStrategy; +} +__name(getDefaultStrategy, "getDefaultStrategy"); + +// src/strategies/undiciRequest.ts +var import_node_http = require("http"); +var import_node_url = require("url"); +var import_node_util = require("util"); +var import_undici = require("undici"); +async function makeRequest(url, init) { + const options = { + ...init, + body: await resolveBody(init.body) + }; + const res = await (0, import_undici.request)(url, options); + return { + body: res.body, + async arrayBuffer() { + return res.body.arrayBuffer(); + }, + async json() { + return res.body.json(); + }, + async text() { + return res.body.text(); + }, + get bodyUsed() { + return res.body.bodyUsed; + }, + headers: new import_undici.Headers(res.headers), + status: res.statusCode, + statusText: import_node_http.STATUS_CODES[res.statusCode], + ok: res.statusCode >= 200 && res.statusCode < 300 + }; +} +__name(makeRequest, "makeRequest"); +async function resolveBody(body) { + if (body == null) { + return null; + } else if (typeof body === "string") { + return body; + } else if (import_node_util.types.isUint8Array(body)) { + return body; + } else if (import_node_util.types.isArrayBuffer(body)) { + return new Uint8Array(body); + } else if (body instanceof import_node_url.URLSearchParams) { + return body.toString(); + } else if (body instanceof DataView) { + return new Uint8Array(body.buffer); + } else if (body instanceof Blob) { + return new Uint8Array(await body.arrayBuffer()); + } else if (body instanceof FormData) { + return body; + } else if (body[Symbol.iterator]) { + const chunks = [...body]; + return Buffer.concat(chunks); + } else if (body[Symbol.asyncIterator]) { + const chunks = []; + for await (const chunk of body) { + chunks.push(chunk); + } + return Buffer.concat(chunks); + } + throw new TypeError(`Unable to resolve body.`); +} +__name(resolveBody, "resolveBody"); + +// src/lib/utils/constants.ts +var import_util = require("@discordjs/util"); +var import_v10 = require("discord-api-types/v10"); +var DefaultUserAgent = `DiscordBot (https://discord.js.org, 2.0.1)`; +var DefaultUserAgentAppendix = (0, import_util.getUserAgentAppendix)(); +var DefaultRestOptions = { + agent: null, + api: "https://discord.com/api", + authPrefix: "Bot", + cdn: "https://cdn.discordapp.com", + headers: {}, + invalidRequestWarningInterval: 0, + globalRequestsPerSecond: 50, + offset: 50, + rejectOnRateLimit: null, + retries: 3, + timeout: 15e3, + userAgentAppendix: DefaultUserAgentAppendix, + version: import_v10.APIVersion, + hashSweepInterval: 144e5, + // 4 Hours + hashLifetime: 864e5, + // 24 Hours + handlerSweepInterval: 36e5, + // 1 Hour + async makeRequest(...args) { + return getDefaultStrategy()(...args); + } +}; +var RESTEvents = /* @__PURE__ */ ((RESTEvents2) => { + RESTEvents2["Debug"] = "restDebug"; + RESTEvents2["HandlerSweep"] = "handlerSweep"; + RESTEvents2["HashSweep"] = "hashSweep"; + RESTEvents2["InvalidRequestWarning"] = "invalidRequestWarning"; + RESTEvents2["RateLimited"] = "rateLimited"; + RESTEvents2["Response"] = "response"; + return RESTEvents2; +})(RESTEvents || {}); +var ALLOWED_EXTENSIONS = ["webp", "png", "jpg", "jpeg", "gif"]; +var ALLOWED_STICKER_EXTENSIONS = ["png", "json", "gif"]; +var ALLOWED_SIZES = [16, 32, 64, 128, 256, 512, 1024, 2048, 4096]; +var OverwrittenMimeTypes = { + // https://github.com/discordjs/discord.js/issues/8557 + "image/apng": "image/png" +}; +var BurstHandlerMajorIdKey = "burst"; + +// src/lib/CDN.ts +var CDN = class { + constructor(base = DefaultRestOptions.cdn) { + this.base = base; + } + static { + __name(this, "CDN"); + } + /** + * Generates an app asset URL for a client's asset. + * + * @param clientId - The client id that has the asset + * @param assetHash - The hash provided by Discord for this asset + * @param options - Optional options for the asset + */ + appAsset(clientId, assetHash, options) { + return this.makeURL(`/app-assets/${clientId}/${assetHash}`, options); + } + /** + * Generates an app icon URL for a client's icon. + * + * @param clientId - The client id that has the icon + * @param iconHash - The hash provided by Discord for this icon + * @param options - Optional options for the icon + */ + appIcon(clientId, iconHash, options) { + return this.makeURL(`/app-icons/${clientId}/${iconHash}`, options); + } + /** + * Generates an avatar URL, e.g. for a user or a webhook. + * + * @param id - The id that has the icon + * @param avatarHash - The hash provided by Discord for this avatar + * @param options - Optional options for the avatar + */ + avatar(id, avatarHash, options) { + return this.dynamicMakeURL(`/avatars/${id}/${avatarHash}`, avatarHash, options); + } + /** + * Generates a user avatar decoration URL. + * + * @param userId - The id of the user + * @param userAvatarDecoration - The hash provided by Discord for this avatar decoration + * @param options - Optional options for the avatar decoration + */ + avatarDecoration(userId, userAvatarDecoration, options) { + return this.makeURL(`/avatar-decorations/${userId}/${userAvatarDecoration}`, options); + } + /** + * Generates a banner URL, e.g. for a user or a guild. + * + * @param id - The id that has the banner splash + * @param bannerHash - The hash provided by Discord for this banner + * @param options - Optional options for the banner + */ + banner(id, bannerHash, options) { + return this.dynamicMakeURL(`/banners/${id}/${bannerHash}`, bannerHash, options); + } + /** + * Generates an icon URL for a channel, e.g. a group DM. + * + * @param channelId - The channel id that has the icon + * @param iconHash - The hash provided by Discord for this channel + * @param options - Optional options for the icon + */ + channelIcon(channelId, iconHash, options) { + return this.makeURL(`/channel-icons/${channelId}/${iconHash}`, options); + } + /** + * Generates a default avatar URL + * + * @param index - The default avatar index + * @remarks + * To calculate the index for a user do `(userId >> 22) % 6`, + * or `discriminator % 5` if they're using the legacy username system. + */ + defaultAvatar(index) { + return this.makeURL(`/embed/avatars/${index}`, { extension: "png" }); + } + /** + * Generates a discovery splash URL for a guild's discovery splash. + * + * @param guildId - The guild id that has the discovery splash + * @param splashHash - The hash provided by Discord for this splash + * @param options - Optional options for the splash + */ + discoverySplash(guildId, splashHash, options) { + return this.makeURL(`/discovery-splashes/${guildId}/${splashHash}`, options); + } + /** + * Generates an emoji's URL for an emoji. + * + * @param emojiId - The emoji id + * @param extension - The extension of the emoji + */ + emoji(emojiId, extension) { + return this.makeURL(`/emojis/${emojiId}`, { extension }); + } + /** + * Generates a guild member avatar URL. + * + * @param guildId - The id of the guild + * @param userId - The id of the user + * @param avatarHash - The hash provided by Discord for this avatar + * @param options - Optional options for the avatar + */ + guildMemberAvatar(guildId, userId, avatarHash, options) { + return this.dynamicMakeURL(`/guilds/${guildId}/users/${userId}/avatars/${avatarHash}`, avatarHash, options); + } + /** + * Generates a guild member banner URL. + * + * @param guildId - The id of the guild + * @param userId - The id of the user + * @param bannerHash - The hash provided by Discord for this banner + * @param options - Optional options for the banner + */ + guildMemberBanner(guildId, userId, bannerHash, options) { + return this.dynamicMakeURL(`/guilds/${guildId}/users/${userId}/banner`, bannerHash, options); + } + /** + * Generates an icon URL, e.g. for a guild. + * + * @param id - The id that has the icon splash + * @param iconHash - The hash provided by Discord for this icon + * @param options - Optional options for the icon + */ + icon(id, iconHash, options) { + return this.dynamicMakeURL(`/icons/${id}/${iconHash}`, iconHash, options); + } + /** + * Generates a URL for the icon of a role + * + * @param roleId - The id of the role that has the icon + * @param roleIconHash - The hash provided by Discord for this role icon + * @param options - Optional options for the role icon + */ + roleIcon(roleId, roleIconHash, options) { + return this.makeURL(`/role-icons/${roleId}/${roleIconHash}`, options); + } + /** + * Generates a guild invite splash URL for a guild's invite splash. + * + * @param guildId - The guild id that has the invite splash + * @param splashHash - The hash provided by Discord for this splash + * @param options - Optional options for the splash + */ + splash(guildId, splashHash, options) { + return this.makeURL(`/splashes/${guildId}/${splashHash}`, options); + } + /** + * Generates a sticker URL. + * + * @param stickerId - The sticker id + * @param extension - The extension of the sticker + * @privateRemarks + * Stickers cannot have a `.webp` extension, so we default to a `.png` + */ + sticker(stickerId, extension = "png") { + return this.makeURL(`/stickers/${stickerId}`, { allowedExtensions: ALLOWED_STICKER_EXTENSIONS, extension }); + } + /** + * Generates a sticker pack banner URL. + * + * @param bannerId - The banner id + * @param options - Optional options for the banner + */ + stickerPackBanner(bannerId, options) { + return this.makeURL(`/app-assets/710982414301790216/store/${bannerId}`, options); + } + /** + * Generates a team icon URL for a team's icon. + * + * @param teamId - The team id that has the icon + * @param iconHash - The hash provided by Discord for this icon + * @param options - Optional options for the icon + */ + teamIcon(teamId, iconHash, options) { + return this.makeURL(`/team-icons/${teamId}/${iconHash}`, options); + } + /** + * Generates a cover image for a guild scheduled event. + * + * @param scheduledEventId - The scheduled event id + * @param coverHash - The hash provided by discord for this cover image + * @param options - Optional options for the cover image + */ + guildScheduledEventCover(scheduledEventId, coverHash, options) { + return this.makeURL(`/guild-events/${scheduledEventId}/${coverHash}`, options); + } + /** + * Constructs the URL for the resource, checking whether or not `hash` starts with `a_` if `dynamic` is set to `true`. + * + * @param route - The base cdn route + * @param hash - The hash provided by Discord for this icon + * @param options - Optional options for the link + */ + dynamicMakeURL(route, hash, { forceStatic = false, ...options } = {}) { + return this.makeURL(route, !forceStatic && hash.startsWith("a_") ? { ...options, extension: "gif" } : options); + } + /** + * Constructs the URL for the resource + * + * @param route - The base cdn route + * @param options - The extension/size options for the link + */ + makeURL(route, { allowedExtensions = ALLOWED_EXTENSIONS, extension = "webp", size } = {}) { + extension = String(extension).toLowerCase(); + if (!allowedExtensions.includes(extension)) { + throw new RangeError(`Invalid extension provided: ${extension} +Must be one of: ${allowedExtensions.join(", ")}`); + } + if (size && !ALLOWED_SIZES.includes(size)) { + throw new RangeError(`Invalid size provided: ${size} +Must be one of: ${ALLOWED_SIZES.join(", ")}`); + } + const url = new URL(`${this.base}${route}.${extension}`); + if (size) { + url.searchParams.set("size", String(size)); + } + return url.toString(); + } +}; + +// src/lib/errors/DiscordAPIError.ts +function isErrorGroupWrapper(error) { + return Reflect.has(error, "_errors"); +} +__name(isErrorGroupWrapper, "isErrorGroupWrapper"); +function isErrorResponse(error) { + return typeof Reflect.get(error, "message") === "string"; +} +__name(isErrorResponse, "isErrorResponse"); +var DiscordAPIError = class _DiscordAPIError extends Error { + /** + * @param rawError - The error reported by Discord + * @param code - The error code reported by Discord + * @param status - The status code of the response + * @param method - The method of the request that erred + * @param url - The url of the request that erred + * @param bodyData - The unparsed data for the request that errored + */ + constructor(rawError, code, status, method, url, bodyData) { + super(_DiscordAPIError.getMessage(rawError)); + this.rawError = rawError; + this.code = code; + this.status = status; + this.method = method; + this.url = url; + this.requestBody = { files: bodyData.files, json: bodyData.body }; + } + static { + __name(this, "DiscordAPIError"); + } + requestBody; + /** + * The name of the error + */ + get name() { + return `${_DiscordAPIError.name}[${this.code}]`; + } + static getMessage(error) { + let flattened = ""; + if ("code" in error) { + if (error.errors) { + flattened = [...this.flattenDiscordError(error.errors)].join("\n"); + } + return error.message && flattened ? `${error.message} +${flattened}` : error.message || flattened || "Unknown Error"; + } + return error.error_description ?? "No Description"; + } + static *flattenDiscordError(obj, key = "") { + if (isErrorResponse(obj)) { + return yield `${key.length ? `${key}[${obj.code}]` : `${obj.code}`}: ${obj.message}`.trim(); + } + for (const [otherKey, val] of Object.entries(obj)) { + const nextKey = otherKey.startsWith("_") ? key : key ? Number.isNaN(Number(otherKey)) ? `${key}.${otherKey}` : `${key}[${otherKey}]` : otherKey; + if (typeof val === "string") { + yield val; + } else if (isErrorGroupWrapper(val)) { + for (const error of val._errors) { + yield* this.flattenDiscordError(error, nextKey); + } + } else { + yield* this.flattenDiscordError(val, nextKey); + } + } + } +}; + +// src/lib/errors/HTTPError.ts +var HTTPError = class _HTTPError extends Error { + /** + * @param status - The status code of the response + * @param statusText - The status text of the response + * @param method - The method of the request that erred + * @param url - The url of the request that erred + * @param bodyData - The unparsed data for the request that errored + */ + constructor(status, statusText, method, url, bodyData) { + super(statusText); + this.status = status; + this.method = method; + this.url = url; + this.requestBody = { files: bodyData.files, json: bodyData.body }; + } + static { + __name(this, "HTTPError"); + } + requestBody; + name = _HTTPError.name; +}; + +// src/lib/errors/RateLimitError.ts +var RateLimitError = class _RateLimitError extends Error { + static { + __name(this, "RateLimitError"); + } + timeToReset; + limit; + method; + hash; + url; + route; + majorParameter; + global; + constructor({ timeToReset, limit, method, hash, url, route, majorParameter, global }) { + super(); + this.timeToReset = timeToReset; + this.limit = limit; + this.method = method; + this.hash = hash; + this.url = url; + this.route = route; + this.majorParameter = majorParameter; + this.global = global; + } + /** + * The name of the error + */ + get name() { + return `${_RateLimitError.name}[${this.route}]`; + } +}; + +// src/lib/REST.ts +var import_collection = require("@discordjs/collection"); +var import_snowflake = require("@sapphire/snowflake"); +var import_async_event_emitter = require("@vladfrangu/async_event_emitter"); +var import_magic_bytes = require("magic-bytes.js"); + +// src/lib/utils/types.ts +var RequestMethod = /* @__PURE__ */ ((RequestMethod2) => { + RequestMethod2["Delete"] = "DELETE"; + RequestMethod2["Get"] = "GET"; + RequestMethod2["Patch"] = "PATCH"; + RequestMethod2["Post"] = "POST"; + RequestMethod2["Put"] = "PUT"; + return RequestMethod2; +})(RequestMethod || {}); + +// src/lib/utils/utils.ts +function serializeSearchParam(value) { + switch (typeof value) { + case "string": + return value; + case "number": + case "bigint": + case "boolean": + return value.toString(); + case "object": + if (value === null) + return null; + if (value instanceof Date) { + return Number.isNaN(value.getTime()) ? null : value.toISOString(); + } + if (typeof value.toString === "function" && value.toString !== Object.prototype.toString) + return value.toString(); + return null; + default: + return null; + } +} +__name(serializeSearchParam, "serializeSearchParam"); +function makeURLSearchParams(options) { + const params = new URLSearchParams(); + if (!options) + return params; + for (const [key, value] of Object.entries(options)) { + const serialized = serializeSearchParam(value); + if (serialized !== null) + params.append(key, serialized); + } + return params; +} +__name(makeURLSearchParams, "makeURLSearchParams"); +async function parseResponse(res) { + if (res.headers.get("Content-Type")?.startsWith("application/json")) { + return res.json(); + } + return res.arrayBuffer(); +} +__name(parseResponse, "parseResponse"); +function hasSublimit(bucketRoute, body, method) { + if (bucketRoute === "/channels/:id") { + if (typeof body !== "object" || body === null) + return false; + if (method !== "PATCH" /* Patch */) + return false; + const castedBody = body; + return ["name", "topic"].some((key) => Reflect.has(castedBody, key)); + } + return true; +} +__name(hasSublimit, "hasSublimit"); +function shouldRetry(error) { + if (error.name === "AbortError") + return true; + return "code" in error && error.code === "ECONNRESET" || error.message.includes("ECONNRESET"); +} +__name(shouldRetry, "shouldRetry"); +async function onRateLimit(manager, rateLimitData) { + const { options } = manager; + if (!options.rejectOnRateLimit) + return; + const shouldThrow = typeof options.rejectOnRateLimit === "function" ? await options.rejectOnRateLimit(rateLimitData) : options.rejectOnRateLimit.some((route) => rateLimitData.route.startsWith(route.toLowerCase())); + if (shouldThrow) { + throw new RateLimitError(rateLimitData); + } +} +__name(onRateLimit, "onRateLimit"); +function calculateUserDefaultAvatarIndex(userId) { + return Number(BigInt(userId) >> 22n) % 6; +} +__name(calculateUserDefaultAvatarIndex, "calculateUserDefaultAvatarIndex"); +async function sleep(ms) { + return new Promise((resolve) => { + setTimeout(() => resolve(), ms); + }); +} +__name(sleep, "sleep"); +function isBufferLike(value) { + return value instanceof ArrayBuffer || value instanceof Uint8Array || value instanceof Uint8ClampedArray; +} +__name(isBufferLike, "isBufferLike"); + +// src/lib/handlers/Shared.ts +var invalidCount = 0; +var invalidCountResetTime = null; +function incrementInvalidCount(manager) { + if (!invalidCountResetTime || invalidCountResetTime < Date.now()) { + invalidCountResetTime = Date.now() + 1e3 * 60 * 10; + invalidCount = 0; + } + invalidCount++; + const emitInvalid = manager.options.invalidRequestWarningInterval > 0 && invalidCount % manager.options.invalidRequestWarningInterval === 0; + if (emitInvalid) { + manager.emit("invalidRequestWarning" /* InvalidRequestWarning */, { + count: invalidCount, + remainingTime: invalidCountResetTime - Date.now() + }); + } +} +__name(incrementInvalidCount, "incrementInvalidCount"); +async function makeNetworkRequest(manager, routeId, url, options, requestData, retries) { + const controller = new AbortController(); + const timeout = setTimeout(() => controller.abort(), manager.options.timeout); + if (requestData.signal) { + if (requestData.signal.aborted) + controller.abort(); + else + requestData.signal.addEventListener("abort", () => controller.abort()); + } + let res; + try { + res = await manager.options.makeRequest(url, { ...options, signal: controller.signal }); + } catch (error) { + if (!(error instanceof Error)) + throw error; + if (shouldRetry(error) && retries !== manager.options.retries) { + return null; + } + throw error; + } finally { + clearTimeout(timeout); + } + if (manager.listenerCount("response" /* Response */)) { + manager.emit( + "response" /* Response */, + { + method: options.method ?? "get", + path: routeId.original, + route: routeId.bucketRoute, + options, + data: requestData, + retries + }, + res instanceof Response ? res.clone() : { ...res } + ); + } + return res; +} +__name(makeNetworkRequest, "makeNetworkRequest"); +async function handleErrors(manager, res, method, url, requestData, retries) { + const status = res.status; + if (status >= 500 && status < 600) { + if (retries !== manager.options.retries) { + return null; + } + throw new HTTPError(status, res.statusText, method, url, requestData); + } else { + if (status >= 400 && status < 500) { + if (status === 401 && requestData.auth) { + manager.setToken(null); + } + const data = await parseResponse(res); + throw new DiscordAPIError(data, "code" in data ? data.code : data.error, status, method, url, requestData); + } + return res; + } +} +__name(handleErrors, "handleErrors"); + +// src/lib/handlers/BurstHandler.ts +var BurstHandler = class { + /** + * @param manager - The request manager + * @param hash - The hash that this RequestHandler handles + * @param majorParameter - The major parameter for this handler + */ + constructor(manager, hash, majorParameter) { + this.manager = manager; + this.hash = hash; + this.majorParameter = majorParameter; + this.id = `${hash}:${majorParameter}`; + } + static { + __name(this, "BurstHandler"); + } + /** + * {@inheritdoc IHandler.id} + */ + id; + /** + * {@inheritDoc IHandler.inactive} + */ + inactive = false; + /** + * Emits a debug message + * + * @param message - The message to debug + */ + debug(message) { + this.manager.emit("restDebug" /* Debug */, `[REST ${this.id}] ${message}`); + } + /** + * {@inheritDoc IHandler.queueRequest} + */ + async queueRequest(routeId, url, options, requestData) { + return this.runRequest(routeId, url, options, requestData); + } + /** + * The method that actually makes the request to the API, and updates info about the bucket accordingly + * + * @param routeId - The generalized API route with literal ids for major parameters + * @param url - The fully resolved URL to make the request to + * @param options - The fetch options needed to make the request + * @param requestData - Extra data from the user's request needed for errors and additional processing + * @param retries - The number of retries this request has already attempted (recursion) + */ + async runRequest(routeId, url, options, requestData, retries = 0) { + const method = options.method ?? "get"; + const res = await makeNetworkRequest(this.manager, routeId, url, options, requestData, retries); + if (res === null) { + return this.runRequest(routeId, url, options, requestData, ++retries); + } + const status = res.status; + let retryAfter = 0; + const retry = res.headers.get("Retry-After"); + if (retry) + retryAfter = Number(retry) * 1e3 + this.manager.options.offset; + if (status === 401 || status === 403 || status === 429) { + incrementInvalidCount(this.manager); + } + if (status >= 200 && status < 300) { + return res; + } else if (status === 429) { + const isGlobal = res.headers.has("X-RateLimit-Global"); + await onRateLimit(this.manager, { + timeToReset: retryAfter, + limit: Number.POSITIVE_INFINITY, + method, + hash: this.hash, + url, + route: routeId.bucketRoute, + majorParameter: this.majorParameter, + global: isGlobal + }); + this.debug( + [ + "Encountered unexpected 429 rate limit", + ` Global : ${isGlobal}`, + ` Method : ${method}`, + ` URL : ${url}`, + ` Bucket : ${routeId.bucketRoute}`, + ` Major parameter: ${routeId.majorParameter}`, + ` Hash : ${this.hash}`, + ` Limit : ${Number.POSITIVE_INFINITY}`, + ` Retry After : ${retryAfter}ms`, + ` Sublimit : None` + ].join("\n") + ); + await sleep(retryAfter); + return this.runRequest(routeId, url, options, requestData, retries); + } else { + const handled = await handleErrors(this.manager, res, method, url, requestData, retries); + if (handled === null) { + return this.runRequest(routeId, url, options, requestData, ++retries); + } + return handled; + } + } +}; + +// src/lib/handlers/SequentialHandler.ts +var import_async_queue = require("@sapphire/async-queue"); +var SequentialHandler = class { + /** + * @param manager - The request manager + * @param hash - The hash that this RequestHandler handles + * @param majorParameter - The major parameter for this handler + */ + constructor(manager, hash, majorParameter) { + this.manager = manager; + this.hash = hash; + this.majorParameter = majorParameter; + this.id = `${hash}:${majorParameter}`; + } + static { + __name(this, "SequentialHandler"); + } + /** + * {@inheritDoc IHandler.id} + */ + id; + /** + * The time this rate limit bucket will reset + */ + reset = -1; + /** + * The remaining requests that can be made before we are rate limited + */ + remaining = 1; + /** + * The total number of requests that can be made before we are rate limited + */ + limit = Number.POSITIVE_INFINITY; + /** + * The interface used to sequence async requests sequentially + */ + #asyncQueue = new import_async_queue.AsyncQueue(); + /** + * The interface used to sequence sublimited async requests sequentially + */ + #sublimitedQueue = null; + /** + * A promise wrapper for when the sublimited queue is finished being processed or null when not being processed + */ + #sublimitPromise = null; + /** + * Whether the sublimit queue needs to be shifted in the finally block + */ + #shiftSublimit = false; + /** + * {@inheritDoc IHandler.inactive} + */ + get inactive() { + return this.#asyncQueue.remaining === 0 && (this.#sublimitedQueue === null || this.#sublimitedQueue.remaining === 0) && !this.limited; + } + /** + * If the rate limit bucket is currently limited by the global limit + */ + get globalLimited() { + return this.manager.globalRemaining <= 0 && Date.now() < this.manager.globalReset; + } + /** + * If the rate limit bucket is currently limited by its limit + */ + get localLimited() { + return this.remaining <= 0 && Date.now() < this.reset; + } + /** + * If the rate limit bucket is currently limited + */ + get limited() { + return this.globalLimited || this.localLimited; + } + /** + * The time until queued requests can continue + */ + get timeToReset() { + return this.reset + this.manager.options.offset - Date.now(); + } + /** + * Emits a debug message + * + * @param message - The message to debug + */ + debug(message) { + this.manager.emit("restDebug" /* Debug */, `[REST ${this.id}] ${message}`); + } + /** + * Delay all requests for the specified amount of time, handling global rate limits + * + * @param time - The amount of time to delay all requests for + */ + async globalDelayFor(time) { + await sleep(time); + this.manager.globalDelay = null; + } + /** + * {@inheritDoc IHandler.queueRequest} + */ + async queueRequest(routeId, url, options, requestData) { + let queue = this.#asyncQueue; + let queueType = 0 /* Standard */; + if (this.#sublimitedQueue && hasSublimit(routeId.bucketRoute, requestData.body, options.method)) { + queue = this.#sublimitedQueue; + queueType = 1 /* Sublimit */; + } + await queue.wait({ signal: requestData.signal }); + if (queueType === 0 /* Standard */) { + if (this.#sublimitedQueue && hasSublimit(routeId.bucketRoute, requestData.body, options.method)) { + queue = this.#sublimitedQueue; + const wait = queue.wait(); + this.#asyncQueue.shift(); + await wait; + } else if (this.#sublimitPromise) { + await this.#sublimitPromise.promise; + } + } + try { + return await this.runRequest(routeId, url, options, requestData); + } finally { + queue.shift(); + if (this.#shiftSublimit) { + this.#shiftSublimit = false; + this.#sublimitedQueue?.shift(); + } + if (this.#sublimitedQueue?.remaining === 0) { + this.#sublimitPromise?.resolve(); + this.#sublimitedQueue = null; + } + } + } + /** + * The method that actually makes the request to the api, and updates info about the bucket accordingly + * + * @param routeId - The generalized api route with literal ids for major parameters + * @param url - The fully resolved url to make the request to + * @param options - The fetch options needed to make the request + * @param requestData - Extra data from the user's request needed for errors and additional processing + * @param retries - The number of retries this request has already attempted (recursion) + */ + async runRequest(routeId, url, options, requestData, retries = 0) { + while (this.limited) { + const isGlobal = this.globalLimited; + let limit2; + let timeout; + let delay; + if (isGlobal) { + limit2 = this.manager.options.globalRequestsPerSecond; + timeout = this.manager.globalReset + this.manager.options.offset - Date.now(); + if (!this.manager.globalDelay) { + this.manager.globalDelay = this.globalDelayFor(timeout); + } + delay = this.manager.globalDelay; + } else { + limit2 = this.limit; + timeout = this.timeToReset; + delay = sleep(timeout); + } + const rateLimitData = { + timeToReset: timeout, + limit: limit2, + method: options.method ?? "get", + hash: this.hash, + url, + route: routeId.bucketRoute, + majorParameter: this.majorParameter, + global: isGlobal + }; + this.manager.emit("rateLimited" /* RateLimited */, rateLimitData); + await onRateLimit(this.manager, rateLimitData); + if (isGlobal) { + this.debug(`Global rate limit hit, blocking all requests for ${timeout}ms`); + } else { + this.debug(`Waiting ${timeout}ms for rate limit to pass`); + } + await delay; + } + if (!this.manager.globalReset || this.manager.globalReset < Date.now()) { + this.manager.globalReset = Date.now() + 1e3; + this.manager.globalRemaining = this.manager.options.globalRequestsPerSecond; + } + this.manager.globalRemaining--; + const method = options.method ?? "get"; + const res = await makeNetworkRequest(this.manager, routeId, url, options, requestData, retries); + if (res === null) { + return this.runRequest(routeId, url, options, requestData, ++retries); + } + const status = res.status; + let retryAfter = 0; + const limit = res.headers.get("X-RateLimit-Limit"); + const remaining = res.headers.get("X-RateLimit-Remaining"); + const reset = res.headers.get("X-RateLimit-Reset-After"); + const hash = res.headers.get("X-RateLimit-Bucket"); + const retry = res.headers.get("Retry-After"); + this.limit = limit ? Number(limit) : Number.POSITIVE_INFINITY; + this.remaining = remaining ? Number(remaining) : 1; + this.reset = reset ? Number(reset) * 1e3 + Date.now() + this.manager.options.offset : Date.now(); + if (retry) + retryAfter = Number(retry) * 1e3 + this.manager.options.offset; + if (hash && hash !== this.hash) { + this.debug(["Received bucket hash update", ` Old Hash : ${this.hash}`, ` New Hash : ${hash}`].join("\n")); + this.manager.hashes.set(`${method}:${routeId.bucketRoute}`, { value: hash, lastAccess: Date.now() }); + } else if (hash) { + const hashData = this.manager.hashes.get(`${method}:${routeId.bucketRoute}`); + if (hashData) { + hashData.lastAccess = Date.now(); + } + } + let sublimitTimeout = null; + if (retryAfter > 0) { + if (res.headers.has("X-RateLimit-Global")) { + this.manager.globalRemaining = 0; + this.manager.globalReset = Date.now() + retryAfter; + } else if (!this.localLimited) { + sublimitTimeout = retryAfter; + } + } + if (status === 401 || status === 403 || status === 429) { + incrementInvalidCount(this.manager); + } + if (res.ok) { + return res; + } else if (status === 429) { + const isGlobal = this.globalLimited; + let limit2; + let timeout; + if (isGlobal) { + limit2 = this.manager.options.globalRequestsPerSecond; + timeout = this.manager.globalReset + this.manager.options.offset - Date.now(); + } else { + limit2 = this.limit; + timeout = this.timeToReset; + } + await onRateLimit(this.manager, { + timeToReset: timeout, + limit: limit2, + method, + hash: this.hash, + url, + route: routeId.bucketRoute, + majorParameter: this.majorParameter, + global: isGlobal + }); + this.debug( + [ + "Encountered unexpected 429 rate limit", + ` Global : ${isGlobal.toString()}`, + ` Method : ${method}`, + ` URL : ${url}`, + ` Bucket : ${routeId.bucketRoute}`, + ` Major parameter: ${routeId.majorParameter}`, + ` Hash : ${this.hash}`, + ` Limit : ${limit2}`, + ` Retry After : ${retryAfter}ms`, + ` Sublimit : ${sublimitTimeout ? `${sublimitTimeout}ms` : "None"}` + ].join("\n") + ); + if (sublimitTimeout) { + const firstSublimit = !this.#sublimitedQueue; + if (firstSublimit) { + this.#sublimitedQueue = new import_async_queue.AsyncQueue(); + void this.#sublimitedQueue.wait(); + this.#asyncQueue.shift(); + } + this.#sublimitPromise?.resolve(); + this.#sublimitPromise = null; + await sleep(sublimitTimeout); + let resolve; + const promise = new Promise((res2) => resolve = res2); + this.#sublimitPromise = { promise, resolve }; + if (firstSublimit) { + await this.#asyncQueue.wait(); + this.#shiftSublimit = true; + } + } + return this.runRequest(routeId, url, options, requestData, retries); + } else { + const handled = await handleErrors(this.manager, res, method, url, requestData, retries); + if (handled === null) { + return this.runRequest(routeId, url, options, requestData, ++retries); + } + return handled; + } + } +}; + +// src/lib/REST.ts +var REST = class _REST extends import_async_event_emitter.AsyncEventEmitter { + static { + __name(this, "REST"); + } + /** + * The {@link https://undici.nodejs.org/#/docs/api/Agent | Agent} for all requests + * performed by this manager. + */ + agent = null; + cdn; + /** + * The number of requests remaining in the global bucket + */ + globalRemaining; + /** + * The promise used to wait out the global rate limit + */ + globalDelay = null; + /** + * The timestamp at which the global bucket resets + */ + globalReset = -1; + /** + * API bucket hashes that are cached from provided routes + */ + hashes = new import_collection.Collection(); + /** + * Request handlers created from the bucket hash and the major parameters + */ + handlers = new import_collection.Collection(); + #token = null; + hashTimer; + handlerTimer; + options; + constructor(options = {}) { + super(); + this.cdn = new CDN(options.cdn ?? DefaultRestOptions.cdn); + this.options = { ...DefaultRestOptions, ...options }; + this.options.offset = Math.max(0, this.options.offset); + this.globalRemaining = Math.max(1, this.options.globalRequestsPerSecond); + this.agent = options.agent ?? null; + this.setupSweepers(); + } + setupSweepers() { + const validateMaxInterval = /* @__PURE__ */ __name((interval) => { + if (interval > 144e5) { + throw new Error("Cannot set an interval greater than 4 hours"); + } + }, "validateMaxInterval"); + if (this.options.hashSweepInterval !== 0 && this.options.hashSweepInterval !== Number.POSITIVE_INFINITY) { + validateMaxInterval(this.options.hashSweepInterval); + this.hashTimer = setInterval(() => { + const sweptHashes = new import_collection.Collection(); + const currentDate = Date.now(); + this.hashes.sweep((val, key) => { + if (val.lastAccess === -1) + return false; + const shouldSweep = Math.floor(currentDate - val.lastAccess) > this.options.hashLifetime; + if (shouldSweep) { + sweptHashes.set(key, val); + this.emit("restDebug" /* Debug */, `Hash ${val.value} for ${key} swept due to lifetime being exceeded`); + } + return shouldSweep; + }); + this.emit("hashSweep" /* HashSweep */, sweptHashes); + }, this.options.hashSweepInterval); + this.hashTimer.unref?.(); + } + if (this.options.handlerSweepInterval !== 0 && this.options.handlerSweepInterval !== Number.POSITIVE_INFINITY) { + validateMaxInterval(this.options.handlerSweepInterval); + this.handlerTimer = setInterval(() => { + const sweptHandlers = new import_collection.Collection(); + this.handlers.sweep((val, key) => { + const { inactive } = val; + if (inactive) { + sweptHandlers.set(key, val); + this.emit("restDebug" /* Debug */, `Handler ${val.id} for ${key} swept due to being inactive`); + } + return inactive; + }); + this.emit("handlerSweep" /* HandlerSweep */, sweptHandlers); + }, this.options.handlerSweepInterval); + this.handlerTimer.unref?.(); + } + } + /** + * Runs a get request from the api + * + * @param fullRoute - The full route to query + * @param options - Optional request options + */ + async get(fullRoute, options = {}) { + return this.request({ ...options, fullRoute, method: "GET" /* Get */ }); + } + /** + * Runs a delete request from the api + * + * @param fullRoute - The full route to query + * @param options - Optional request options + */ + async delete(fullRoute, options = {}) { + return this.request({ ...options, fullRoute, method: "DELETE" /* Delete */ }); + } + /** + * Runs a post request from the api + * + * @param fullRoute - The full route to query + * @param options - Optional request options + */ + async post(fullRoute, options = {}) { + return this.request({ ...options, fullRoute, method: "POST" /* Post */ }); + } + /** + * Runs a put request from the api + * + * @param fullRoute - The full route to query + * @param options - Optional request options + */ + async put(fullRoute, options = {}) { + return this.request({ ...options, fullRoute, method: "PUT" /* Put */ }); + } + /** + * Runs a patch request from the api + * + * @param fullRoute - The full route to query + * @param options - Optional request options + */ + async patch(fullRoute, options = {}) { + return this.request({ ...options, fullRoute, method: "PATCH" /* Patch */ }); + } + /** + * Runs a request from the api + * + * @param options - Request options + */ + async request(options) { + const response = await this.queueRequest(options); + return parseResponse(response); + } + /** + * Sets the default agent to use for requests performed by this manager + * + * @param agent - The agent to use + */ + setAgent(agent) { + this.agent = agent; + return this; + } + /** + * Sets the authorization token that should be used for requests + * + * @param token - The authorization token to use + */ + setToken(token) { + this.#token = token; + return this; + } + /** + * Queues a request to be sent + * + * @param request - All the information needed to make a request + * @returns The response from the api request + */ + async queueRequest(request2) { + const routeId = _REST.generateRouteData(request2.fullRoute, request2.method); + const hash = this.hashes.get(`${request2.method}:${routeId.bucketRoute}`) ?? { + value: `Global(${request2.method}:${routeId.bucketRoute})`, + lastAccess: -1 + }; + const handler = this.handlers.get(`${hash.value}:${routeId.majorParameter}`) ?? this.createHandler(hash.value, routeId.majorParameter); + const { url, fetchOptions } = await this.resolveRequest(request2); + return handler.queueRequest(routeId, url, fetchOptions, { + body: request2.body, + files: request2.files, + auth: request2.auth !== false, + signal: request2.signal + }); + } + /** + * Creates a new rate limit handler from a hash, based on the hash and the major parameter + * + * @param hash - The hash for the route + * @param majorParameter - The major parameter for this handler + * @internal + */ + createHandler(hash, majorParameter) { + const queue = majorParameter === BurstHandlerMajorIdKey ? new BurstHandler(this, hash, majorParameter) : new SequentialHandler(this, hash, majorParameter); + this.handlers.set(queue.id, queue); + return queue; + } + /** + * Formats the request data to a usable format for fetch + * + * @param request - The request data + */ + async resolveRequest(request2) { + const { options } = this; + let query = ""; + if (request2.query) { + const resolvedQuery = request2.query.toString(); + if (resolvedQuery !== "") { + query = `?${resolvedQuery}`; + } + } + const headers = { + ...this.options.headers, + "User-Agent": `${DefaultUserAgent} ${options.userAgentAppendix}`.trim() + }; + if (request2.auth !== false) { + if (!this.#token) { + throw new Error("Expected token to be set for this request, but none was present"); + } + headers.Authorization = `${request2.authPrefix ?? this.options.authPrefix} ${this.#token}`; + } + if (request2.reason?.length) { + headers["X-Audit-Log-Reason"] = encodeURIComponent(request2.reason); + } + const url = `${options.api}${request2.versioned === false ? "" : `/v${options.version}`}${request2.fullRoute}${query}`; + let finalBody; + let additionalHeaders = {}; + if (request2.files?.length) { + const formData = new FormData(); + for (const [index, file] of request2.files.entries()) { + const fileKey = file.key ?? `files[${index}]`; + if (isBufferLike(file.data)) { + let contentType = file.contentType; + if (!contentType) { + const [parsedType] = (0, import_magic_bytes.filetypeinfo)(file.data); + if (parsedType) { + contentType = OverwrittenMimeTypes[parsedType.mime] ?? parsedType.mime ?? "application/octet-stream"; + } + } + formData.append(fileKey, new Blob([file.data], { type: contentType }), file.name); + } else { + formData.append(fileKey, new Blob([`${file.data}`], { type: file.contentType }), file.name); + } + } + if (request2.body != null) { + if (request2.appendToFormData) { + for (const [key, value] of Object.entries(request2.body)) { + formData.append(key, value); + } + } else { + formData.append("payload_json", JSON.stringify(request2.body)); + } + } + finalBody = formData; + } else if (request2.body != null) { + if (request2.passThroughBody) { + finalBody = request2.body; + } else { + finalBody = JSON.stringify(request2.body); + additionalHeaders = { "Content-Type": "application/json" }; + } + } + const method = request2.method.toUpperCase(); + const fetchOptions = { + // Set body to null on get / head requests. This does not follow fetch spec (likely because it causes subtle bugs) but is aligned with what request was doing + body: ["GET", "HEAD"].includes(method) ? null : finalBody, + headers: { ...request2.headers, ...additionalHeaders, ...headers }, + method, + // Prioritize setting an agent per request, use the agent for this instance otherwise. + dispatcher: request2.dispatcher ?? this.agent ?? void 0 + }; + return { url, fetchOptions }; + } + /** + * Stops the hash sweeping interval + */ + clearHashSweeper() { + clearInterval(this.hashTimer); + } + /** + * Stops the request handler sweeping interval + */ + clearHandlerSweeper() { + clearInterval(this.handlerTimer); + } + /** + * Generates route data for an endpoint:method + * + * @param endpoint - The raw endpoint to generalize + * @param method - The HTTP method this endpoint is called without + * @internal + */ + static generateRouteData(endpoint, method) { + if (endpoint.startsWith("/interactions/") && endpoint.endsWith("/callback")) { + return { + majorParameter: BurstHandlerMajorIdKey, + bucketRoute: "/interactions/:id/:token/callback", + original: endpoint + }; + } + const majorIdMatch = /^\/(?:channels|guilds|webhooks)\/(\d{17,19})/.exec(endpoint); + const majorId = majorIdMatch?.[1] ?? "global"; + const baseRoute = endpoint.replaceAll(/\d{17,19}/g, ":id").replace(/\/reactions\/(.*)/, "/reactions/:reaction"); + let exceptions = ""; + if (method === "DELETE" /* Delete */ && baseRoute === "/channels/:id/messages/:id") { + const id = /\d{17,19}$/.exec(endpoint)[0]; + const timestamp = import_snowflake.DiscordSnowflake.timestampFrom(id); + if (Date.now() - timestamp > 1e3 * 60 * 60 * 24 * 14) { + exceptions += "/Delete Old Message"; + } + } + return { + majorParameter: majorId, + bucketRoute: baseRoute + exceptions, + original: endpoint + }; + } +}; + +// src/shared.ts +var version = "2.0.1"; + +// src/index.ts +globalThis.FormData ??= import_undici2.FormData; +globalThis.Blob ??= import_node_buffer.Blob; +setDefaultStrategy((0, import_util2.shouldUseGlobalFetchAndWebSocket)() ? fetch : makeRequest); +// Annotate the CommonJS export names for ESM import in node: +0 && (module.exports = { + ALLOWED_EXTENSIONS, + ALLOWED_SIZES, + ALLOWED_STICKER_EXTENSIONS, + BurstHandlerMajorIdKey, + CDN, + DefaultRestOptions, + DefaultUserAgent, + DefaultUserAgentAppendix, + DiscordAPIError, + HTTPError, + OverwrittenMimeTypes, + REST, + RESTEvents, + RateLimitError, + RequestMethod, + calculateUserDefaultAvatarIndex, + makeURLSearchParams, + parseResponse, + version +}); +//# sourceMappingURL=index.js.map
\ No newline at end of file diff --git a/node_modules/@discordjs/rest/dist/index.js.map b/node_modules/@discordjs/rest/dist/index.js.map new file mode 100644 index 0000000..b57aca4 --- /dev/null +++ b/node_modules/@discordjs/rest/dist/index.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../src/index.ts","../src/environment.ts","../src/strategies/undiciRequest.ts","../src/lib/utils/constants.ts","../src/lib/CDN.ts","../src/lib/errors/DiscordAPIError.ts","../src/lib/errors/HTTPError.ts","../src/lib/errors/RateLimitError.ts","../src/lib/REST.ts","../src/lib/utils/types.ts","../src/lib/utils/utils.ts","../src/lib/handlers/Shared.ts","../src/lib/handlers/BurstHandler.ts","../src/lib/handlers/SequentialHandler.ts","../src/shared.ts"],"sourcesContent":["import { Blob } from 'node:buffer';\nimport { shouldUseGlobalFetchAndWebSocket } from '@discordjs/util';\nimport { FormData } from 'undici';\nimport { setDefaultStrategy } from './environment.js';\nimport { makeRequest } from './strategies/undiciRequest.js';\n\n// TODO(ckohen): remove once node engine req is bumped to > v18\n(globalThis as any).FormData ??= FormData;\nglobalThis.Blob ??= Blob;\n\nsetDefaultStrategy(shouldUseGlobalFetchAndWebSocket() ? fetch : makeRequest);\n\nexport * from './shared.js';\n","import type { RESTOptions } from './shared.js';\n\nlet defaultStrategy: RESTOptions['makeRequest'];\n\nexport function setDefaultStrategy(newStrategy: RESTOptions['makeRequest']) {\n\tdefaultStrategy = newStrategy;\n}\n\nexport function getDefaultStrategy() {\n\treturn defaultStrategy;\n}\n","import { STATUS_CODES } from 'node:http';\nimport { URLSearchParams } from 'node:url';\nimport { types } from 'node:util';\nimport { type RequestInit, request, Headers } from 'undici';\nimport type { ResponseLike } from '../shared.js';\n\nexport type RequestOptions = Exclude<Parameters<typeof request>[1], undefined>;\n\nexport async function makeRequest(url: string, init: RequestInit): Promise<ResponseLike> {\n\t// The cast is necessary because `headers` and `method` are narrower types in `undici.request`\n\t// our request path guarantees they are of acceptable type for `undici.request`\n\tconst options = {\n\t\t...init,\n\t\tbody: await resolveBody(init.body),\n\t} as RequestOptions;\n\tconst res = await request(url, options);\n\treturn {\n\t\tbody: res.body,\n\t\tasync arrayBuffer() {\n\t\t\treturn res.body.arrayBuffer();\n\t\t},\n\t\tasync json() {\n\t\t\treturn res.body.json();\n\t\t},\n\t\tasync text() {\n\t\t\treturn res.body.text();\n\t\t},\n\t\tget bodyUsed() {\n\t\t\treturn res.body.bodyUsed;\n\t\t},\n\t\theaders: new Headers(res.headers as Record<string, string[] | string>),\n\t\tstatus: res.statusCode,\n\t\tstatusText: STATUS_CODES[res.statusCode]!,\n\t\tok: res.statusCode >= 200 && res.statusCode < 300,\n\t};\n}\n\nexport async function resolveBody(body: RequestInit['body']): Promise<Exclude<RequestOptions['body'], undefined>> {\n\t// eslint-disable-next-line no-eq-null, eqeqeq\n\tif (body == null) {\n\t\treturn null;\n\t} else if (typeof body === 'string') {\n\t\treturn body;\n\t} else if (types.isUint8Array(body)) {\n\t\treturn body;\n\t} else if (types.isArrayBuffer(body)) {\n\t\treturn new Uint8Array(body);\n\t} else if (body instanceof URLSearchParams) {\n\t\treturn body.toString();\n\t} else if (body instanceof DataView) {\n\t\treturn new Uint8Array(body.buffer);\n\t} else if (body instanceof Blob) {\n\t\treturn new Uint8Array(await body.arrayBuffer());\n\t} else if (body instanceof FormData) {\n\t\treturn body;\n\t} else if ((body as Iterable<Uint8Array>)[Symbol.iterator]) {\n\t\tconst chunks = [...(body as Iterable<Uint8Array>)];\n\n\t\treturn Buffer.concat(chunks);\n\t} else if ((body as AsyncIterable<Uint8Array>)[Symbol.asyncIterator]) {\n\t\tconst chunks: Uint8Array[] = [];\n\n\t\tfor await (const chunk of body as AsyncIterable<Uint8Array>) {\n\t\t\tchunks.push(chunk);\n\t\t}\n\n\t\treturn Buffer.concat(chunks);\n\t}\n\n\tthrow new TypeError(`Unable to resolve body.`);\n}\n","import { getUserAgentAppendix } from '@discordjs/util';\nimport { APIVersion } from 'discord-api-types/v10';\nimport { getDefaultStrategy } from '../../environment.js';\nimport type { RESTOptions, ResponseLike } from './types.js';\n\nexport const DefaultUserAgent =\n\t`DiscordBot (https://discord.js.org, 2.0.1)` as `DiscordBot (https://discord.js.org, ${string})`;\n\n/**\n * The default string to append onto the user agent.\n */\nexport const DefaultUserAgentAppendix = getUserAgentAppendix();\n\nexport const DefaultRestOptions = {\n\tagent: null,\n\tapi: 'https://discord.com/api',\n\tauthPrefix: 'Bot',\n\tcdn: 'https://cdn.discordapp.com',\n\theaders: {},\n\tinvalidRequestWarningInterval: 0,\n\tglobalRequestsPerSecond: 50,\n\toffset: 50,\n\trejectOnRateLimit: null,\n\tretries: 3,\n\ttimeout: 15_000,\n\tuserAgentAppendix: DefaultUserAgentAppendix,\n\tversion: APIVersion,\n\thashSweepInterval: 14_400_000, // 4 Hours\n\thashLifetime: 86_400_000, // 24 Hours\n\thandlerSweepInterval: 3_600_000, // 1 Hour\n\tasync makeRequest(...args): Promise<ResponseLike> {\n\t\treturn getDefaultStrategy()(...args);\n\t},\n} as const satisfies Required<RESTOptions>;\n\n/**\n * The events that the REST manager emits\n */\nexport enum RESTEvents {\n\tDebug = 'restDebug',\n\tHandlerSweep = 'handlerSweep',\n\tHashSweep = 'hashSweep',\n\tInvalidRequestWarning = 'invalidRequestWarning',\n\tRateLimited = 'rateLimited',\n\tResponse = 'response',\n}\n\nexport const ALLOWED_EXTENSIONS = ['webp', 'png', 'jpg', 'jpeg', 'gif'] as const satisfies readonly string[];\nexport const ALLOWED_STICKER_EXTENSIONS = ['png', 'json', 'gif'] as const satisfies readonly string[];\nexport const ALLOWED_SIZES = [16, 32, 64, 128, 256, 512, 1_024, 2_048, 4_096] as const satisfies readonly number[];\n\nexport type ImageExtension = (typeof ALLOWED_EXTENSIONS)[number];\nexport type StickerExtension = (typeof ALLOWED_STICKER_EXTENSIONS)[number];\nexport type ImageSize = (typeof ALLOWED_SIZES)[number];\n\nexport const OverwrittenMimeTypes = {\n\t// https://github.com/discordjs/discord.js/issues/8557\n\t'image/apng': 'image/png',\n} as const satisfies Readonly<Record<string, string>>;\n\nexport const BurstHandlerMajorIdKey = 'burst';\n","/* eslint-disable jsdoc/check-param-names */\nimport {\n\tALLOWED_EXTENSIONS,\n\tALLOWED_SIZES,\n\tALLOWED_STICKER_EXTENSIONS,\n\tDefaultRestOptions,\n\ttype ImageExtension,\n\ttype ImageSize,\n\ttype StickerExtension,\n} from './utils/constants.js';\n\n/**\n * The options used for image URLs\n */\nexport interface BaseImageURLOptions {\n\t/**\n\t * The extension to use for the image URL\n\t *\n\t * @defaultValue `'webp'`\n\t */\n\textension?: ImageExtension;\n\t/**\n\t * The size specified in the image URL\n\t */\n\tsize?: ImageSize;\n}\n\n/**\n * The options used for image URLs with animated content\n */\nexport interface ImageURLOptions extends BaseImageURLOptions {\n\t/**\n\t * Whether or not to prefer the static version of an image asset.\n\t */\n\tforceStatic?: boolean;\n}\n\n/**\n * The options to use when making a CDN URL\n */\nexport interface MakeURLOptions {\n\t/**\n\t * The allowed extensions that can be used\n\t */\n\tallowedExtensions?: readonly string[];\n\t/**\n\t * The extension to use for the image URL\n\t *\n\t * @defaultValue `'webp'`\n\t */\n\textension?: string | undefined;\n\t/**\n\t * The size specified in the image URL\n\t */\n\tsize?: ImageSize;\n}\n\n/**\n * The CDN link builder\n */\nexport class CDN {\n\tpublic constructor(private readonly base: string = DefaultRestOptions.cdn) {}\n\n\t/**\n\t * Generates an app asset URL for a client's asset.\n\t *\n\t * @param clientId - The client id that has the asset\n\t * @param assetHash - The hash provided by Discord for this asset\n\t * @param options - Optional options for the asset\n\t */\n\tpublic appAsset(clientId: string, assetHash: string, options?: Readonly<BaseImageURLOptions>): string {\n\t\treturn this.makeURL(`/app-assets/${clientId}/${assetHash}`, options);\n\t}\n\n\t/**\n\t * Generates an app icon URL for a client's icon.\n\t *\n\t * @param clientId - The client id that has the icon\n\t * @param iconHash - The hash provided by Discord for this icon\n\t * @param options - Optional options for the icon\n\t */\n\tpublic appIcon(clientId: string, iconHash: string, options?: Readonly<BaseImageURLOptions>): string {\n\t\treturn this.makeURL(`/app-icons/${clientId}/${iconHash}`, options);\n\t}\n\n\t/**\n\t * Generates an avatar URL, e.g. for a user or a webhook.\n\t *\n\t * @param id - The id that has the icon\n\t * @param avatarHash - The hash provided by Discord for this avatar\n\t * @param options - Optional options for the avatar\n\t */\n\tpublic avatar(id: string, avatarHash: string, options?: Readonly<ImageURLOptions>): string {\n\t\treturn this.dynamicMakeURL(`/avatars/${id}/${avatarHash}`, avatarHash, options);\n\t}\n\n\t/**\n\t * Generates a user avatar decoration URL.\n\t *\n\t * @param userId - The id of the user\n\t * @param userAvatarDecoration - The hash provided by Discord for this avatar decoration\n\t * @param options - Optional options for the avatar decoration\n\t */\n\tpublic avatarDecoration(\n\t\tuserId: string,\n\t\tuserAvatarDecoration: string,\n\t\toptions?: Readonly<BaseImageURLOptions>,\n\t): string {\n\t\treturn this.makeURL(`/avatar-decorations/${userId}/${userAvatarDecoration}`, options);\n\t}\n\n\t/**\n\t * Generates a banner URL, e.g. for a user or a guild.\n\t *\n\t * @param id - The id that has the banner splash\n\t * @param bannerHash - The hash provided by Discord for this banner\n\t * @param options - Optional options for the banner\n\t */\n\tpublic banner(id: string, bannerHash: string, options?: Readonly<ImageURLOptions>): string {\n\t\treturn this.dynamicMakeURL(`/banners/${id}/${bannerHash}`, bannerHash, options);\n\t}\n\n\t/**\n\t * Generates an icon URL for a channel, e.g. a group DM.\n\t *\n\t * @param channelId - The channel id that has the icon\n\t * @param iconHash - The hash provided by Discord for this channel\n\t * @param options - Optional options for the icon\n\t */\n\tpublic channelIcon(channelId: string, iconHash: string, options?: Readonly<BaseImageURLOptions>): string {\n\t\treturn this.makeURL(`/channel-icons/${channelId}/${iconHash}`, options);\n\t}\n\n\t/**\n\t * Generates a default avatar URL\n\t *\n\t * @param index - The default avatar index\n\t * @remarks\n\t * To calculate the index for a user do `(userId >> 22) % 6`,\n\t * or `discriminator % 5` if they're using the legacy username system.\n\t */\n\tpublic defaultAvatar(index: number): string {\n\t\treturn this.makeURL(`/embed/avatars/${index}`, { extension: 'png' });\n\t}\n\n\t/**\n\t * Generates a discovery splash URL for a guild's discovery splash.\n\t *\n\t * @param guildId - The guild id that has the discovery splash\n\t * @param splashHash - The hash provided by Discord for this splash\n\t * @param options - Optional options for the splash\n\t */\n\tpublic discoverySplash(guildId: string, splashHash: string, options?: Readonly<BaseImageURLOptions>): string {\n\t\treturn this.makeURL(`/discovery-splashes/${guildId}/${splashHash}`, options);\n\t}\n\n\t/**\n\t * Generates an emoji's URL for an emoji.\n\t *\n\t * @param emojiId - The emoji id\n\t * @param extension - The extension of the emoji\n\t */\n\tpublic emoji(emojiId: string, extension?: ImageExtension): string {\n\t\treturn this.makeURL(`/emojis/${emojiId}`, { extension });\n\t}\n\n\t/**\n\t * Generates a guild member avatar URL.\n\t *\n\t * @param guildId - The id of the guild\n\t * @param userId - The id of the user\n\t * @param avatarHash - The hash provided by Discord for this avatar\n\t * @param options - Optional options for the avatar\n\t */\n\tpublic guildMemberAvatar(\n\t\tguildId: string,\n\t\tuserId: string,\n\t\tavatarHash: string,\n\t\toptions?: Readonly<ImageURLOptions>,\n\t): string {\n\t\treturn this.dynamicMakeURL(`/guilds/${guildId}/users/${userId}/avatars/${avatarHash}`, avatarHash, options);\n\t}\n\n\t/**\n\t * Generates a guild member banner URL.\n\t *\n\t * @param guildId - The id of the guild\n\t * @param userId - The id of the user\n\t * @param bannerHash - The hash provided by Discord for this banner\n\t * @param options - Optional options for the banner\n\t */\n\tpublic guildMemberBanner(\n\t\tguildId: string,\n\t\tuserId: string,\n\t\tbannerHash: string,\n\t\toptions?: Readonly<ImageURLOptions>,\n\t): string {\n\t\treturn this.dynamicMakeURL(`/guilds/${guildId}/users/${userId}/banner`, bannerHash, options);\n\t}\n\n\t/**\n\t * Generates an icon URL, e.g. for a guild.\n\t *\n\t * @param id - The id that has the icon splash\n\t * @param iconHash - The hash provided by Discord for this icon\n\t * @param options - Optional options for the icon\n\t */\n\tpublic icon(id: string, iconHash: string, options?: Readonly<ImageURLOptions>): string {\n\t\treturn this.dynamicMakeURL(`/icons/${id}/${iconHash}`, iconHash, options);\n\t}\n\n\t/**\n\t * Generates a URL for the icon of a role\n\t *\n\t * @param roleId - The id of the role that has the icon\n\t * @param roleIconHash - The hash provided by Discord for this role icon\n\t * @param options - Optional options for the role icon\n\t */\n\tpublic roleIcon(roleId: string, roleIconHash: string, options?: Readonly<BaseImageURLOptions>): string {\n\t\treturn this.makeURL(`/role-icons/${roleId}/${roleIconHash}`, options);\n\t}\n\n\t/**\n\t * Generates a guild invite splash URL for a guild's invite splash.\n\t *\n\t * @param guildId - The guild id that has the invite splash\n\t * @param splashHash - The hash provided by Discord for this splash\n\t * @param options - Optional options for the splash\n\t */\n\tpublic splash(guildId: string, splashHash: string, options?: Readonly<BaseImageURLOptions>): string {\n\t\treturn this.makeURL(`/splashes/${guildId}/${splashHash}`, options);\n\t}\n\n\t/**\n\t * Generates a sticker URL.\n\t *\n\t * @param stickerId - The sticker id\n\t * @param extension - The extension of the sticker\n\t * @privateRemarks\n\t * Stickers cannot have a `.webp` extension, so we default to a `.png`\n\t */\n\tpublic sticker(stickerId: string, extension: StickerExtension = 'png'): string {\n\t\treturn this.makeURL(`/stickers/${stickerId}`, { allowedExtensions: ALLOWED_STICKER_EXTENSIONS, extension });\n\t}\n\n\t/**\n\t * Generates a sticker pack banner URL.\n\t *\n\t * @param bannerId - The banner id\n\t * @param options - Optional options for the banner\n\t */\n\tpublic stickerPackBanner(bannerId: string, options?: Readonly<BaseImageURLOptions>): string {\n\t\treturn this.makeURL(`/app-assets/710982414301790216/store/${bannerId}`, options);\n\t}\n\n\t/**\n\t * Generates a team icon URL for a team's icon.\n\t *\n\t * @param teamId - The team id that has the icon\n\t * @param iconHash - The hash provided by Discord for this icon\n\t * @param options - Optional options for the icon\n\t */\n\tpublic teamIcon(teamId: string, iconHash: string, options?: Readonly<BaseImageURLOptions>): string {\n\t\treturn this.makeURL(`/team-icons/${teamId}/${iconHash}`, options);\n\t}\n\n\t/**\n\t * Generates a cover image for a guild scheduled event.\n\t *\n\t * @param scheduledEventId - The scheduled event id\n\t * @param coverHash - The hash provided by discord for this cover image\n\t * @param options - Optional options for the cover image\n\t */\n\tpublic guildScheduledEventCover(\n\t\tscheduledEventId: string,\n\t\tcoverHash: string,\n\t\toptions?: Readonly<BaseImageURLOptions>,\n\t): string {\n\t\treturn this.makeURL(`/guild-events/${scheduledEventId}/${coverHash}`, options);\n\t}\n\n\t/**\n\t * Constructs the URL for the resource, checking whether or not `hash` starts with `a_` if `dynamic` is set to `true`.\n\t *\n\t * @param route - The base cdn route\n\t * @param hash - The hash provided by Discord for this icon\n\t * @param options - Optional options for the link\n\t */\n\tprivate dynamicMakeURL(\n\t\troute: string,\n\t\thash: string,\n\t\t{ forceStatic = false, ...options }: Readonly<ImageURLOptions> = {},\n\t): string {\n\t\treturn this.makeURL(route, !forceStatic && hash.startsWith('a_') ? { ...options, extension: 'gif' } : options);\n\t}\n\n\t/**\n\t * Constructs the URL for the resource\n\t *\n\t * @param route - The base cdn route\n\t * @param options - The extension/size options for the link\n\t */\n\tprivate makeURL(\n\t\troute: string,\n\t\t{ allowedExtensions = ALLOWED_EXTENSIONS, extension = 'webp', size }: Readonly<MakeURLOptions> = {},\n\t): string {\n\t\t// eslint-disable-next-line no-param-reassign\n\t\textension = String(extension).toLowerCase();\n\n\t\tif (!allowedExtensions.includes(extension)) {\n\t\t\tthrow new RangeError(`Invalid extension provided: ${extension}\\nMust be one of: ${allowedExtensions.join(', ')}`);\n\t\t}\n\n\t\tif (size && !ALLOWED_SIZES.includes(size)) {\n\t\t\tthrow new RangeError(`Invalid size provided: ${size}\\nMust be one of: ${ALLOWED_SIZES.join(', ')}`);\n\t\t}\n\n\t\tconst url = new URL(`${this.base}${route}.${extension}`);\n\n\t\tif (size) {\n\t\t\turl.searchParams.set('size', String(size));\n\t\t}\n\n\t\treturn url.toString();\n\t}\n}\n","import type { InternalRequest, RawFile } from '../utils/types.js';\n\ninterface DiscordErrorFieldInformation {\n\tcode: string;\n\tmessage: string;\n}\n\ninterface DiscordErrorGroupWrapper {\n\t_errors: DiscordError[];\n}\n\ntype DiscordError = DiscordErrorFieldInformation | DiscordErrorGroupWrapper | string | { [k: string]: DiscordError };\n\nexport interface DiscordErrorData {\n\tcode: number;\n\terrors?: DiscordError;\n\tmessage: string;\n}\n\nexport interface OAuthErrorData {\n\terror: string;\n\terror_description?: string;\n}\n\nexport interface RequestBody {\n\tfiles: RawFile[] | undefined;\n\tjson: unknown | undefined;\n}\n\nfunction isErrorGroupWrapper(error: DiscordError): error is DiscordErrorGroupWrapper {\n\treturn Reflect.has(error as Record<string, unknown>, '_errors');\n}\n\nfunction isErrorResponse(error: DiscordError): error is DiscordErrorFieldInformation {\n\treturn typeof Reflect.get(error as Record<string, unknown>, 'message') === 'string';\n}\n\n/**\n * Represents an API error returned by Discord\n */\nexport class DiscordAPIError extends Error {\n\tpublic requestBody: RequestBody;\n\n\t/**\n\t * @param rawError - The error reported by Discord\n\t * @param code - The error code reported by Discord\n\t * @param status - The status code of the response\n\t * @param method - The method of the request that erred\n\t * @param url - The url of the request that erred\n\t * @param bodyData - The unparsed data for the request that errored\n\t */\n\tpublic constructor(\n\t\tpublic rawError: DiscordErrorData | OAuthErrorData,\n\t\tpublic code: number | string,\n\t\tpublic status: number,\n\t\tpublic method: string,\n\t\tpublic url: string,\n\t\tbodyData: Pick<InternalRequest, 'body' | 'files'>,\n\t) {\n\t\tsuper(DiscordAPIError.getMessage(rawError));\n\n\t\tthis.requestBody = { files: bodyData.files, json: bodyData.body };\n\t}\n\n\t/**\n\t * The name of the error\n\t */\n\tpublic override get name(): string {\n\t\treturn `${DiscordAPIError.name}[${this.code}]`;\n\t}\n\n\tprivate static getMessage(error: DiscordErrorData | OAuthErrorData) {\n\t\tlet flattened = '';\n\t\tif ('code' in error) {\n\t\t\tif (error.errors) {\n\t\t\t\tflattened = [...this.flattenDiscordError(error.errors)].join('\\n');\n\t\t\t}\n\n\t\t\treturn error.message && flattened\n\t\t\t\t? `${error.message}\\n${flattened}`\n\t\t\t\t: error.message || flattened || 'Unknown Error';\n\t\t}\n\n\t\treturn error.error_description ?? 'No Description';\n\t}\n\n\tprivate static *flattenDiscordError(obj: DiscordError, key = ''): IterableIterator<string> {\n\t\tif (isErrorResponse(obj)) {\n\t\t\treturn yield `${key.length ? `${key}[${obj.code}]` : `${obj.code}`}: ${obj.message}`.trim();\n\t\t}\n\n\t\tfor (const [otherKey, val] of Object.entries(obj)) {\n\t\t\tconst nextKey = otherKey.startsWith('_')\n\t\t\t\t? key\n\t\t\t\t: key\n\t\t\t\t? Number.isNaN(Number(otherKey))\n\t\t\t\t\t? `${key}.${otherKey}`\n\t\t\t\t\t: `${key}[${otherKey}]`\n\t\t\t\t: otherKey;\n\n\t\t\tif (typeof val === 'string') {\n\t\t\t\tyield val;\n\t\t\t} else if (isErrorGroupWrapper(val)) {\n\t\t\t\tfor (const error of val._errors) {\n\t\t\t\t\tyield* this.flattenDiscordError(error, nextKey);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tyield* this.flattenDiscordError(val, nextKey);\n\t\t\t}\n\t\t}\n\t}\n}\n","import type { InternalRequest } from '../utils/types.js';\nimport type { RequestBody } from './DiscordAPIError.js';\n\n/**\n * Represents a HTTP error\n */\nexport class HTTPError extends Error {\n\tpublic requestBody: RequestBody;\n\n\tpublic override name = HTTPError.name;\n\n\t/**\n\t * @param status - The status code of the response\n\t * @param statusText - The status text of the response\n\t * @param method - The method of the request that erred\n\t * @param url - The url of the request that erred\n\t * @param bodyData - The unparsed data for the request that errored\n\t */\n\tpublic constructor(\n\t\tpublic status: number,\n\t\tstatusText: string,\n\t\tpublic method: string,\n\t\tpublic url: string,\n\t\tbodyData: Pick<InternalRequest, 'body' | 'files'>,\n\t) {\n\t\tsuper(statusText);\n\t\tthis.requestBody = { files: bodyData.files, json: bodyData.body };\n\t}\n}\n","import type { RateLimitData } from '../utils/types.js';\n\nexport class RateLimitError extends Error implements RateLimitData {\n\tpublic timeToReset: number;\n\n\tpublic limit: number;\n\n\tpublic method: string;\n\n\tpublic hash: string;\n\n\tpublic url: string;\n\n\tpublic route: string;\n\n\tpublic majorParameter: string;\n\n\tpublic global: boolean;\n\n\tpublic constructor({ timeToReset, limit, method, hash, url, route, majorParameter, global }: RateLimitData) {\n\t\tsuper();\n\t\tthis.timeToReset = timeToReset;\n\t\tthis.limit = limit;\n\t\tthis.method = method;\n\t\tthis.hash = hash;\n\t\tthis.url = url;\n\t\tthis.route = route;\n\t\tthis.majorParameter = majorParameter;\n\t\tthis.global = global;\n\t}\n\n\t/**\n\t * The name of the error\n\t */\n\tpublic override get name(): string {\n\t\treturn `${RateLimitError.name}[${this.route}]`;\n\t}\n}\n","import { Collection } from '@discordjs/collection';\nimport { DiscordSnowflake } from '@sapphire/snowflake';\nimport { AsyncEventEmitter } from '@vladfrangu/async_event_emitter';\nimport { filetypeinfo } from 'magic-bytes.js';\nimport type { RequestInit, BodyInit, Dispatcher } from 'undici';\nimport { CDN } from './CDN.js';\nimport { BurstHandler } from './handlers/BurstHandler.js';\nimport { SequentialHandler } from './handlers/SequentialHandler.js';\nimport type { IHandler } from './interfaces/Handler.js';\nimport {\n\tBurstHandlerMajorIdKey,\n\tDefaultRestOptions,\n\tDefaultUserAgent,\n\tOverwrittenMimeTypes,\n\tRESTEvents,\n} from './utils/constants.js';\nimport { RequestMethod } from './utils/types.js';\nimport type {\n\tRESTOptions,\n\tResponseLike,\n\tRestEventsMap,\n\tHashData,\n\tInternalRequest,\n\tRouteLike,\n\tRequestHeaders,\n\tRouteData,\n\tRequestData,\n} from './utils/types.js';\nimport { isBufferLike, parseResponse } from './utils/utils.js';\n\n/**\n * Represents the class that manages handlers for endpoints\n */\nexport class REST extends AsyncEventEmitter<RestEventsMap> {\n\t/**\n\t * The {@link https://undici.nodejs.org/#/docs/api/Agent | Agent} for all requests\n\t * performed by this manager.\n\t */\n\tpublic agent: Dispatcher | null = null;\n\n\tpublic readonly cdn: CDN;\n\n\t/**\n\t * The number of requests remaining in the global bucket\n\t */\n\tpublic globalRemaining: number;\n\n\t/**\n\t * The promise used to wait out the global rate limit\n\t */\n\tpublic globalDelay: Promise<void> | null = null;\n\n\t/**\n\t * The timestamp at which the global bucket resets\n\t */\n\tpublic globalReset = -1;\n\n\t/**\n\t * API bucket hashes that are cached from provided routes\n\t */\n\tpublic readonly hashes = new Collection<string, HashData>();\n\n\t/**\n\t * Request handlers created from the bucket hash and the major parameters\n\t */\n\tpublic readonly handlers = new Collection<string, IHandler>();\n\n\t#token: string | null = null;\n\n\tprivate hashTimer!: NodeJS.Timer | number;\n\n\tprivate handlerTimer!: NodeJS.Timer | number;\n\n\tpublic readonly options: RESTOptions;\n\n\tpublic constructor(options: Partial<RESTOptions> = {}) {\n\t\tsuper();\n\t\tthis.cdn = new CDN(options.cdn ?? DefaultRestOptions.cdn);\n\t\tthis.options = { ...DefaultRestOptions, ...options };\n\t\tthis.options.offset = Math.max(0, this.options.offset);\n\t\tthis.globalRemaining = Math.max(1, this.options.globalRequestsPerSecond);\n\t\tthis.agent = options.agent ?? null;\n\n\t\t// Start sweepers\n\t\tthis.setupSweepers();\n\t}\n\n\tprivate setupSweepers() {\n\t\t// eslint-disable-next-line unicorn/consistent-function-scoping\n\t\tconst validateMaxInterval = (interval: number) => {\n\t\t\tif (interval > 14_400_000) {\n\t\t\t\tthrow new Error('Cannot set an interval greater than 4 hours');\n\t\t\t}\n\t\t};\n\n\t\tif (this.options.hashSweepInterval !== 0 && this.options.hashSweepInterval !== Number.POSITIVE_INFINITY) {\n\t\t\tvalidateMaxInterval(this.options.hashSweepInterval);\n\t\t\tthis.hashTimer = setInterval(() => {\n\t\t\t\tconst sweptHashes = new Collection<string, HashData>();\n\t\t\t\tconst currentDate = Date.now();\n\n\t\t\t\t// Begin sweeping hash based on lifetimes\n\t\t\t\tthis.hashes.sweep((val, key) => {\n\t\t\t\t\t// `-1` indicates a global hash\n\t\t\t\t\tif (val.lastAccess === -1) return false;\n\n\t\t\t\t\t// Check if lifetime has been exceeded\n\t\t\t\t\tconst shouldSweep = Math.floor(currentDate - val.lastAccess) > this.options.hashLifetime;\n\n\t\t\t\t\t// Add hash to collection of swept hashes\n\t\t\t\t\tif (shouldSweep) {\n\t\t\t\t\t\t// Add to swept hashes\n\t\t\t\t\t\tsweptHashes.set(key, val);\n\n\t\t\t\t\t\t// Emit debug information\n\t\t\t\t\t\tthis.emit(RESTEvents.Debug, `Hash ${val.value} for ${key} swept due to lifetime being exceeded`);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn shouldSweep;\n\t\t\t\t});\n\n\t\t\t\t// Fire event\n\t\t\t\tthis.emit(RESTEvents.HashSweep, sweptHashes);\n\t\t\t}, this.options.hashSweepInterval);\n\n\t\t\tthis.hashTimer.unref?.();\n\t\t}\n\n\t\tif (this.options.handlerSweepInterval !== 0 && this.options.handlerSweepInterval !== Number.POSITIVE_INFINITY) {\n\t\t\tvalidateMaxInterval(this.options.handlerSweepInterval);\n\t\t\tthis.handlerTimer = setInterval(() => {\n\t\t\t\tconst sweptHandlers = new Collection<string, IHandler>();\n\n\t\t\t\t// Begin sweeping handlers based on activity\n\t\t\t\tthis.handlers.sweep((val, key) => {\n\t\t\t\t\tconst { inactive } = val;\n\n\t\t\t\t\t// Collect inactive handlers\n\t\t\t\t\tif (inactive) {\n\t\t\t\t\t\tsweptHandlers.set(key, val);\n\t\t\t\t\t\tthis.emit(RESTEvents.Debug, `Handler ${val.id} for ${key} swept due to being inactive`);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn inactive;\n\t\t\t\t});\n\n\t\t\t\t// Fire event\n\t\t\t\tthis.emit(RESTEvents.HandlerSweep, sweptHandlers);\n\t\t\t}, this.options.handlerSweepInterval);\n\n\t\t\tthis.handlerTimer.unref?.();\n\t\t}\n\t}\n\n\t/**\n\t * Runs a get request from the api\n\t *\n\t * @param fullRoute - The full route to query\n\t * @param options - Optional request options\n\t */\n\tpublic async get(fullRoute: RouteLike, options: RequestData = {}) {\n\t\treturn this.request({ ...options, fullRoute, method: RequestMethod.Get });\n\t}\n\n\t/**\n\t * Runs a delete request from the api\n\t *\n\t * @param fullRoute - The full route to query\n\t * @param options - Optional request options\n\t */\n\tpublic async delete(fullRoute: RouteLike, options: RequestData = {}) {\n\t\treturn this.request({ ...options, fullRoute, method: RequestMethod.Delete });\n\t}\n\n\t/**\n\t * Runs a post request from the api\n\t *\n\t * @param fullRoute - The full route to query\n\t * @param options - Optional request options\n\t */\n\tpublic async post(fullRoute: RouteLike, options: RequestData = {}) {\n\t\treturn this.request({ ...options, fullRoute, method: RequestMethod.Post });\n\t}\n\n\t/**\n\t * Runs a put request from the api\n\t *\n\t * @param fullRoute - The full route to query\n\t * @param options - Optional request options\n\t */\n\tpublic async put(fullRoute: RouteLike, options: RequestData = {}) {\n\t\treturn this.request({ ...options, fullRoute, method: RequestMethod.Put });\n\t}\n\n\t/**\n\t * Runs a patch request from the api\n\t *\n\t * @param fullRoute - The full route to query\n\t * @param options - Optional request options\n\t */\n\tpublic async patch(fullRoute: RouteLike, options: RequestData = {}) {\n\t\treturn this.request({ ...options, fullRoute, method: RequestMethod.Patch });\n\t}\n\n\t/**\n\t * Runs a request from the api\n\t *\n\t * @param options - Request options\n\t */\n\tpublic async request(options: InternalRequest) {\n\t\tconst response = await this.queueRequest(options);\n\t\treturn parseResponse(response);\n\t}\n\n\t/**\n\t * Sets the default agent to use for requests performed by this manager\n\t *\n\t * @param agent - The agent to use\n\t */\n\tpublic setAgent(agent: Dispatcher) {\n\t\tthis.agent = agent;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the authorization token that should be used for requests\n\t *\n\t * @param token - The authorization token to use\n\t */\n\tpublic setToken(token: string) {\n\t\tthis.#token = token;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Queues a request to be sent\n\t *\n\t * @param request - All the information needed to make a request\n\t * @returns The response from the api request\n\t */\n\tpublic async queueRequest(request: InternalRequest): Promise<ResponseLike> {\n\t\t// Generalize the endpoint to its route data\n\t\tconst routeId = REST.generateRouteData(request.fullRoute, request.method);\n\t\t// Get the bucket hash for the generic route, or point to a global route otherwise\n\t\tconst hash = this.hashes.get(`${request.method}:${routeId.bucketRoute}`) ?? {\n\t\t\tvalue: `Global(${request.method}:${routeId.bucketRoute})`,\n\t\t\tlastAccess: -1,\n\t\t};\n\n\t\t// Get the request handler for the obtained hash, with its major parameter\n\t\tconst handler =\n\t\t\tthis.handlers.get(`${hash.value}:${routeId.majorParameter}`) ??\n\t\t\tthis.createHandler(hash.value, routeId.majorParameter);\n\n\t\t// Resolve the request into usable fetch options\n\t\tconst { url, fetchOptions } = await this.resolveRequest(request);\n\n\t\t// Queue the request\n\t\treturn handler.queueRequest(routeId, url, fetchOptions, {\n\t\t\tbody: request.body,\n\t\t\tfiles: request.files,\n\t\t\tauth: request.auth !== false,\n\t\t\tsignal: request.signal,\n\t\t});\n\t}\n\n\t/**\n\t * Creates a new rate limit handler from a hash, based on the hash and the major parameter\n\t *\n\t * @param hash - The hash for the route\n\t * @param majorParameter - The major parameter for this handler\n\t * @internal\n\t */\n\tprivate createHandler(hash: string, majorParameter: string) {\n\t\t// Create the async request queue to handle requests\n\t\tconst queue =\n\t\t\tmajorParameter === BurstHandlerMajorIdKey\n\t\t\t\t? new BurstHandler(this, hash, majorParameter)\n\t\t\t\t: new SequentialHandler(this, hash, majorParameter);\n\t\t// Save the queue based on its id\n\t\tthis.handlers.set(queue.id, queue);\n\n\t\treturn queue;\n\t}\n\n\t/**\n\t * Formats the request data to a usable format for fetch\n\t *\n\t * @param request - The request data\n\t */\n\tprivate async resolveRequest(request: InternalRequest): Promise<{ fetchOptions: RequestInit; url: string }> {\n\t\tconst { options } = this;\n\n\t\tlet query = '';\n\n\t\t// If a query option is passed, use it\n\t\tif (request.query) {\n\t\t\tconst resolvedQuery = request.query.toString();\n\t\t\tif (resolvedQuery !== '') {\n\t\t\t\tquery = `?${resolvedQuery}`;\n\t\t\t}\n\t\t}\n\n\t\t// Create the required headers\n\t\tconst headers: RequestHeaders = {\n\t\t\t...this.options.headers,\n\t\t\t'User-Agent': `${DefaultUserAgent} ${options.userAgentAppendix}`.trim(),\n\t\t};\n\n\t\t// If this request requires authorization (allowing non-\"authorized\" requests for webhooks)\n\t\tif (request.auth !== false) {\n\t\t\t// If we haven't received a token, throw an error\n\t\t\tif (!this.#token) {\n\t\t\t\tthrow new Error('Expected token to be set for this request, but none was present');\n\t\t\t}\n\n\t\t\theaders.Authorization = `${request.authPrefix ?? this.options.authPrefix} ${this.#token}`;\n\t\t}\n\n\t\t// If a reason was set, set it's appropriate header\n\t\tif (request.reason?.length) {\n\t\t\theaders['X-Audit-Log-Reason'] = encodeURIComponent(request.reason);\n\t\t}\n\n\t\t// Format the full request URL (api base, optional version, endpoint, optional querystring)\n\t\tconst url = `${options.api}${request.versioned === false ? '' : `/v${options.version}`}${\n\t\t\trequest.fullRoute\n\t\t}${query}`;\n\n\t\tlet finalBody: RequestInit['body'];\n\t\tlet additionalHeaders: Record<string, string> = {};\n\n\t\tif (request.files?.length) {\n\t\t\tconst formData = new FormData();\n\n\t\t\t// Attach all files to the request\n\t\t\tfor (const [index, file] of request.files.entries()) {\n\t\t\t\tconst fileKey = file.key ?? `files[${index}]`;\n\n\t\t\t\t// https://developer.mozilla.org/en-US/docs/Web/API/FormData/append#parameters\n\t\t\t\t// FormData.append only accepts a string or Blob.\n\t\t\t\t// https://developer.mozilla.org/en-US/docs/Web/API/Blob/Blob#parameters\n\t\t\t\t// The Blob constructor accepts TypedArray/ArrayBuffer, strings, and Blobs.\n\t\t\t\tif (isBufferLike(file.data)) {\n\t\t\t\t\t// Try to infer the content type from the buffer if one isn't passed\n\t\t\t\t\tlet contentType = file.contentType;\n\n\t\t\t\t\tif (!contentType) {\n\t\t\t\t\t\tconst [parsedType] = filetypeinfo(file.data);\n\n\t\t\t\t\t\tif (parsedType) {\n\t\t\t\t\t\t\tcontentType =\n\t\t\t\t\t\t\t\tOverwrittenMimeTypes[parsedType.mime as keyof typeof OverwrittenMimeTypes] ??\n\t\t\t\t\t\t\t\tparsedType.mime ??\n\t\t\t\t\t\t\t\t'application/octet-stream';\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tformData.append(fileKey, new Blob([file.data], { type: contentType }), file.name);\n\t\t\t\t} else {\n\t\t\t\t\tformData.append(fileKey, new Blob([`${file.data}`], { type: file.contentType }), file.name);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If a JSON body was added as well, attach it to the form data, using payload_json unless otherwise specified\n\t\t\t// eslint-disable-next-line no-eq-null, eqeqeq\n\t\t\tif (request.body != null) {\n\t\t\t\tif (request.appendToFormData) {\n\t\t\t\t\tfor (const [key, value] of Object.entries(request.body as Record<string, unknown>)) {\n\t\t\t\t\t\tformData.append(key, value);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tformData.append('payload_json', JSON.stringify(request.body));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Set the final body to the form data\n\t\t\tfinalBody = formData;\n\n\t\t\t// eslint-disable-next-line no-eq-null, eqeqeq\n\t\t} else if (request.body != null) {\n\t\t\tif (request.passThroughBody) {\n\t\t\t\tfinalBody = request.body as BodyInit;\n\t\t\t} else {\n\t\t\t\t// Stringify the JSON data\n\t\t\t\tfinalBody = JSON.stringify(request.body);\n\t\t\t\t// Set the additional headers to specify the content-type\n\t\t\t\tadditionalHeaders = { 'Content-Type': 'application/json' };\n\t\t\t}\n\t\t}\n\n\t\tconst method = request.method.toUpperCase();\n\n\t\t// The non null assertions in the following block are due to exactOptionalPropertyTypes, they have been tested to work with undefined\n\t\tconst fetchOptions: RequestInit = {\n\t\t\t// Set body to null on get / head requests. This does not follow fetch spec (likely because it causes subtle bugs) but is aligned with what request was doing\n\t\t\tbody: ['GET', 'HEAD'].includes(method) ? null : finalBody!,\n\t\t\theaders: { ...request.headers, ...additionalHeaders, ...headers } as Record<string, string>,\n\t\t\tmethod,\n\t\t\t// Prioritize setting an agent per request, use the agent for this instance otherwise.\n\t\t\tdispatcher: request.dispatcher ?? this.agent ?? undefined!,\n\t\t};\n\n\t\treturn { url, fetchOptions };\n\t}\n\n\t/**\n\t * Stops the hash sweeping interval\n\t */\n\tpublic clearHashSweeper() {\n\t\tclearInterval(this.hashTimer);\n\t}\n\n\t/**\n\t * Stops the request handler sweeping interval\n\t */\n\tpublic clearHandlerSweeper() {\n\t\tclearInterval(this.handlerTimer);\n\t}\n\n\t/**\n\t * Generates route data for an endpoint:method\n\t *\n\t * @param endpoint - The raw endpoint to generalize\n\t * @param method - The HTTP method this endpoint is called without\n\t * @internal\n\t */\n\tprivate static generateRouteData(endpoint: RouteLike, method: RequestMethod): RouteData {\n\t\tif (endpoint.startsWith('/interactions/') && endpoint.endsWith('/callback')) {\n\t\t\treturn {\n\t\t\t\tmajorParameter: BurstHandlerMajorIdKey,\n\t\t\t\tbucketRoute: '/interactions/:id/:token/callback',\n\t\t\t\toriginal: endpoint,\n\t\t\t};\n\t\t}\n\n\t\tconst majorIdMatch = /^\\/(?:channels|guilds|webhooks)\\/(\\d{17,19})/.exec(endpoint);\n\n\t\t// Get the major id for this route - global otherwise\n\t\tconst majorId = majorIdMatch?.[1] ?? 'global';\n\n\t\tconst baseRoute = endpoint\n\t\t\t// Strip out all ids\n\t\t\t.replaceAll(/\\d{17,19}/g, ':id')\n\t\t\t// Strip out reaction as they fall under the same bucket\n\t\t\t.replace(/\\/reactions\\/(.*)/, '/reactions/:reaction');\n\n\t\tlet exceptions = '';\n\n\t\t// Hard-Code Old Message Deletion Exception (2 week+ old messages are a different bucket)\n\t\t// https://github.com/discord/discord-api-docs/issues/1295\n\t\tif (method === RequestMethod.Delete && baseRoute === '/channels/:id/messages/:id') {\n\t\t\tconst id = /\\d{17,19}$/.exec(endpoint)![0]!;\n\t\t\tconst timestamp = DiscordSnowflake.timestampFrom(id);\n\t\t\tif (Date.now() - timestamp > 1_000 * 60 * 60 * 24 * 14) {\n\t\t\t\texceptions += '/Delete Old Message';\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tmajorParameter: majorId,\n\t\t\tbucketRoute: baseRoute + exceptions,\n\t\t\toriginal: endpoint,\n\t\t};\n\t}\n}\n","import type { Readable } from 'node:stream';\nimport type { ReadableStream } from 'node:stream/web';\nimport type { Collection } from '@discordjs/collection';\nimport type { Agent, Dispatcher, RequestInit, BodyInit, Response } from 'undici';\nimport type { IHandler } from '../interfaces/Handler.js';\n\nexport interface RestEvents {\n\thandlerSweep: [sweptHandlers: Collection<string, IHandler>];\n\thashSweep: [sweptHashes: Collection<string, HashData>];\n\tinvalidRequestWarning: [invalidRequestInfo: InvalidRequestWarningData];\n\trateLimited: [rateLimitInfo: RateLimitData];\n\tresponse: [request: APIRequest, response: ResponseLike];\n\trestDebug: [info: string];\n}\n\nexport type RestEventsMap = {\n\t[K in keyof RestEvents]: RestEvents[K];\n};\n\n/**\n * Options to be passed when creating the REST instance\n */\nexport interface RESTOptions {\n\t/**\n\t * The agent to set globally\n\t */\n\tagent: Dispatcher | null;\n\t/**\n\t * The base api path, without version\n\t *\n\t * @defaultValue `'https://discord.com/api'`\n\t */\n\tapi: string;\n\t/**\n\t * The authorization prefix to use for requests, useful if you want to use\n\t * bearer tokens\n\t *\n\t * @defaultValue `'Bot'`\n\t */\n\tauthPrefix: 'Bearer' | 'Bot';\n\t/**\n\t * The cdn path\n\t *\n\t * @defaultValue `'https://cdn.discordapp.com'`\n\t */\n\tcdn: string;\n\t/**\n\t * How many requests to allow sending per second (Infinity for unlimited, 50 for the standard global limit used by Discord)\n\t *\n\t * @defaultValue `50`\n\t */\n\tglobalRequestsPerSecond: number;\n\t/**\n\t * The amount of time in milliseconds that passes between each hash sweep. (defaults to 1h)\n\t *\n\t * @defaultValue `3_600_000`\n\t */\n\thandlerSweepInterval: number;\n\t/**\n\t * The maximum amount of time a hash can exist in milliseconds without being hit with a request (defaults to 24h)\n\t *\n\t * @defaultValue `86_400_000`\n\t */\n\thashLifetime: number;\n\t/**\n\t * The amount of time in milliseconds that passes between each hash sweep. (defaults to 4h)\n\t *\n\t * @defaultValue `14_400_000`\n\t */\n\thashSweepInterval: number;\n\t/**\n\t * Additional headers to send for all API requests\n\t *\n\t * @defaultValue `{}`\n\t */\n\theaders: Record<string, string>;\n\t/**\n\t * The number of invalid REST requests (those that return 401, 403, or 429) in a 10 minute window between emitted warnings (0 for no warnings).\n\t * That is, if set to 500, warnings will be emitted at invalid request number 500, 1000, 1500, and so on.\n\t *\n\t * @defaultValue `0`\n\t */\n\tinvalidRequestWarningInterval: number;\n\t/**\n\t * The method called to perform the actual HTTP request given a url and web `fetch` options\n\t * For example, to use global fetch, simply provide `makeRequest: fetch`\n\t */\n\tmakeRequest(url: string, init: RequestInit): Promise<ResponseLike>;\n\t/**\n\t * The extra offset to add to rate limits in milliseconds\n\t *\n\t * @defaultValue `50`\n\t */\n\toffset: number;\n\t/**\n\t * Determines how rate limiting and pre-emptive throttling should be handled.\n\t * When an array of strings, each element is treated as a prefix for the request route\n\t * (e.g. `/channels` to match any route starting with `/channels` such as `/channels/:id/messages`)\n\t * for which to throw {@link RateLimitError}s. All other request routes will be queued normally\n\t *\n\t * @defaultValue `null`\n\t */\n\trejectOnRateLimit: RateLimitQueueFilter | string[] | null;\n\t/**\n\t * The number of retries for errors with the 500 code, or errors\n\t * that timeout\n\t *\n\t * @defaultValue `3`\n\t */\n\tretries: number;\n\t/**\n\t * The time to wait in milliseconds before a request is aborted\n\t *\n\t * @defaultValue `15_000`\n\t */\n\ttimeout: number;\n\t/**\n\t * Extra information to add to the user agent\n\t *\n\t * @defaultValue DefaultUserAgentAppendix\n\t */\n\tuserAgentAppendix: string;\n\t/**\n\t * The version of the API to use\n\t *\n\t * @defaultValue `'10'`\n\t */\n\tversion: string;\n}\n\n/**\n * Data emitted on `RESTEvents.RateLimited`\n */\nexport interface RateLimitData {\n\t/**\n\t * Whether the rate limit that was reached was the global limit\n\t */\n\tglobal: boolean;\n\t/**\n\t * The bucket hash for this request\n\t */\n\thash: string;\n\t/**\n\t * The amount of requests we can perform before locking requests\n\t */\n\tlimit: number;\n\t/**\n\t * The major parameter of the route\n\t *\n\t * For example, in `/channels/x`, this will be `x`.\n\t * If there is no major parameter (e.g: `/bot/gateway`) this will be `global`.\n\t */\n\tmajorParameter: string;\n\t/**\n\t * The HTTP method being performed\n\t */\n\tmethod: string;\n\t/**\n\t * The route being hit in this request\n\t */\n\troute: string;\n\t/**\n\t * The time, in milliseconds, until the request-lock is reset\n\t */\n\ttimeToReset: number;\n\t/**\n\t * The full URL for this request\n\t */\n\turl: string;\n}\n\n/**\n * A function that determines whether the rate limit hit should throw an Error\n */\nexport type RateLimitQueueFilter = (rateLimitData: RateLimitData) => Promise<boolean> | boolean;\n\nexport interface APIRequest {\n\t/**\n\t * The data that was used to form the body of this request\n\t */\n\tdata: HandlerRequestData;\n\t/**\n\t * The HTTP method used in this request\n\t */\n\tmethod: string;\n\t/**\n\t * Additional HTTP options for this request\n\t */\n\toptions: RequestInit;\n\t/**\n\t * The full path used to make the request\n\t */\n\tpath: RouteLike;\n\t/**\n\t * The number of times this request has been attempted\n\t */\n\tretries: number;\n\t/**\n\t * The API route identifying the ratelimit for this request\n\t */\n\troute: string;\n}\n\nexport interface ResponseLike\n\textends Pick<Response, 'arrayBuffer' | 'bodyUsed' | 'headers' | 'json' | 'ok' | 'status' | 'statusText' | 'text'> {\n\tbody: Readable | ReadableStream | null;\n}\n\nexport interface InvalidRequestWarningData {\n\t/**\n\t * Number of invalid requests that have been made in the window\n\t */\n\tcount: number;\n\t/**\n\t * Time in milliseconds remaining before the count resets\n\t */\n\tremainingTime: number;\n}\n\n/**\n * Represents a file to be added to the request\n */\nexport interface RawFile {\n\t/**\n\t * Content-Type of the file\n\t */\n\tcontentType?: string;\n\t/**\n\t * The actual data for the file\n\t */\n\tdata: Buffer | Uint8Array | boolean | number | string;\n\t/**\n\t * An explicit key to use for key of the formdata field for this file.\n\t * When not provided, the index of the file in the files array is used in the form `files[${index}]`.\n\t * If you wish to alter the placeholder snowflake, you must provide this property in the same form (`files[${placeholder}]`)\n\t */\n\tkey?: string;\n\t/**\n\t * The name of the file\n\t */\n\tname: string;\n}\n\n/**\n * Represents possible data to be given to an endpoint\n */\nexport interface RequestData {\n\t/**\n\t * Whether to append JSON data to form data instead of `payload_json` when sending files\n\t */\n\tappendToFormData?: boolean;\n\t/**\n\t * If this request needs the `Authorization` header\n\t *\n\t * @defaultValue `true`\n\t */\n\tauth?: boolean;\n\t/**\n\t * The authorization prefix to use for this request, useful if you use this with bearer tokens\n\t *\n\t * @defaultValue `'Bot'`\n\t */\n\tauthPrefix?: 'Bearer' | 'Bot';\n\t/**\n\t * The body to send to this request.\n\t * If providing as BodyInit, set `passThroughBody: true`\n\t */\n\tbody?: BodyInit | unknown;\n\t/**\n\t * The {@link https://undici.nodejs.org/#/docs/api/Agent | Agent} to use for the request.\n\t */\n\tdispatcher?: Agent;\n\t/**\n\t * Files to be attached to this request\n\t */\n\tfiles?: RawFile[] | undefined;\n\t/**\n\t * Additional headers to add to this request\n\t */\n\theaders?: Record<string, string>;\n\t/**\n\t * Whether to pass-through the body property directly to `fetch()`.\n\t * <warn>This only applies when files is NOT present</warn>\n\t */\n\tpassThroughBody?: boolean;\n\t/**\n\t * Query string parameters to append to the called endpoint\n\t */\n\tquery?: URLSearchParams;\n\t/**\n\t * Reason to show in the audit logs\n\t */\n\treason?: string | undefined;\n\t/**\n\t * The signal to abort the queue entry or the REST call, where applicable\n\t */\n\tsignal?: AbortSignal | undefined;\n\t/**\n\t * If this request should be versioned\n\t *\n\t * @defaultValue `true`\n\t */\n\tversioned?: boolean;\n}\n\n/**\n * Possible headers for an API call\n */\nexport interface RequestHeaders {\n\tAuthorization?: string;\n\t'User-Agent': string;\n\t'X-Audit-Log-Reason'?: string;\n}\n\n/**\n * Possible API methods to be used when doing requests\n */\nexport enum RequestMethod {\n\tDelete = 'DELETE',\n\tGet = 'GET',\n\tPatch = 'PATCH',\n\tPost = 'POST',\n\tPut = 'PUT',\n}\n\nexport type RouteLike = `/${string}`;\n\n/**\n * Internal request options\n *\n * @internal\n */\nexport interface InternalRequest extends RequestData {\n\tfullRoute: RouteLike;\n\tmethod: RequestMethod;\n}\n\nexport type HandlerRequestData = Pick<InternalRequest, 'auth' | 'body' | 'files' | 'signal'>;\n\n/**\n * Parsed route data for an endpoint\n *\n * @internal\n */\nexport interface RouteData {\n\tbucketRoute: string;\n\tmajorParameter: string;\n\toriginal: RouteLike;\n}\n\n/**\n * Represents a hash and its associated fields\n *\n * @internal\n */\nexport interface HashData {\n\tlastAccess: number;\n\tvalue: string;\n}\n","import type { RESTPatchAPIChannelJSONBody, Snowflake } from 'discord-api-types/v10';\nimport type { REST } from '../REST.js';\nimport { RateLimitError } from '../errors/RateLimitError.js';\nimport { RequestMethod, type RateLimitData, type ResponseLike } from './types.js';\n\nfunction serializeSearchParam(value: unknown): string | null {\n\tswitch (typeof value) {\n\t\tcase 'string':\n\t\t\treturn value;\n\t\tcase 'number':\n\t\tcase 'bigint':\n\t\tcase 'boolean':\n\t\t\treturn value.toString();\n\t\tcase 'object':\n\t\t\tif (value === null) return null;\n\t\t\tif (value instanceof Date) {\n\t\t\t\treturn Number.isNaN(value.getTime()) ? null : value.toISOString();\n\t\t\t}\n\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-base-to-string\n\t\t\tif (typeof value.toString === 'function' && value.toString !== Object.prototype.toString) return value.toString();\n\t\t\treturn null;\n\t\tdefault:\n\t\t\treturn null;\n\t}\n}\n\n/**\n * Creates and populates an URLSearchParams instance from an object, stripping\n * out null and undefined values, while also coercing non-strings to strings.\n *\n * @param options - The options to use\n * @returns A populated URLSearchParams instance\n */\nexport function makeURLSearchParams<T extends object>(options?: Readonly<T>) {\n\tconst params = new URLSearchParams();\n\tif (!options) return params;\n\n\tfor (const [key, value] of Object.entries(options)) {\n\t\tconst serialized = serializeSearchParam(value);\n\t\tif (serialized !== null) params.append(key, serialized);\n\t}\n\n\treturn params;\n}\n\n/**\n * Converts the response to usable data\n *\n * @param res - The fetch response\n */\nexport async function parseResponse(res: ResponseLike): Promise<unknown> {\n\tif (res.headers.get('Content-Type')?.startsWith('application/json')) {\n\t\treturn res.json();\n\t}\n\n\treturn res.arrayBuffer();\n}\n\n/**\n * Check whether a request falls under a sublimit\n *\n * @param bucketRoute - The buckets route identifier\n * @param body - The options provided as JSON data\n * @param method - The HTTP method that will be used to make the request\n * @returns Whether the request falls under a sublimit\n */\nexport function hasSublimit(bucketRoute: string, body?: unknown, method?: string): boolean {\n\t// TODO: Update for new sublimits\n\t// Currently known sublimits:\n\t// Editing channel `name` or `topic`\n\tif (bucketRoute === '/channels/:id') {\n\t\tif (typeof body !== 'object' || body === null) return false;\n\t\t// This should never be a POST body, but just in case\n\t\tif (method !== RequestMethod.Patch) return false;\n\t\tconst castedBody = body as RESTPatchAPIChannelJSONBody;\n\t\treturn ['name', 'topic'].some((key) => Reflect.has(castedBody, key));\n\t}\n\n\t// If we are checking if a request has a sublimit on a route not checked above, sublimit all requests to avoid a flood of 429s\n\treturn true;\n}\n\n/**\n * Check whether an error indicates that a retry can be attempted\n *\n * @param error - The error thrown by the network request\n * @returns Whether the error indicates a retry should be attempted\n */\nexport function shouldRetry(error: Error | NodeJS.ErrnoException) {\n\t// Retry for possible timed out requests\n\tif (error.name === 'AbortError') return true;\n\t// Downlevel ECONNRESET to retry as it may be recoverable\n\treturn ('code' in error && error.code === 'ECONNRESET') || error.message.includes('ECONNRESET');\n}\n\n/**\n * Determines whether the request should be queued or whether a RateLimitError should be thrown\n *\n * @internal\n */\nexport async function onRateLimit(manager: REST, rateLimitData: RateLimitData) {\n\tconst { options } = manager;\n\tif (!options.rejectOnRateLimit) return;\n\n\tconst shouldThrow =\n\t\ttypeof options.rejectOnRateLimit === 'function'\n\t\t\t? await options.rejectOnRateLimit(rateLimitData)\n\t\t\t: options.rejectOnRateLimit.some((route) => rateLimitData.route.startsWith(route.toLowerCase()));\n\tif (shouldThrow) {\n\t\tthrow new RateLimitError(rateLimitData);\n\t}\n}\n\n/**\n * Calculates the default avatar index for a given user id.\n *\n * @param userId - The user id to calculate the default avatar index for\n */\nexport function calculateUserDefaultAvatarIndex(userId: Snowflake) {\n\treturn Number(BigInt(userId) >> 22n) % 6;\n}\n\n/**\n * Sleeps for a given amount of time.\n *\n * @param ms - The amount of time (in milliseconds) to sleep for\n */\nexport async function sleep(ms: number): Promise<void> {\n\treturn new Promise<void>((resolve) => {\n\t\tsetTimeout(() => resolve(), ms);\n\t});\n}\n\n/**\n * Verifies that a value is a buffer-like object.\n *\n * @param value - The value to check\n */\nexport function isBufferLike(value: unknown): value is ArrayBuffer | Buffer | Uint8Array | Uint8ClampedArray {\n\treturn value instanceof ArrayBuffer || value instanceof Uint8Array || value instanceof Uint8ClampedArray;\n}\n","import type { RequestInit } from 'undici';\nimport type { REST } from '../REST.js';\nimport type { DiscordErrorData, OAuthErrorData } from '../errors/DiscordAPIError.js';\nimport { DiscordAPIError } from '../errors/DiscordAPIError.js';\nimport { HTTPError } from '../errors/HTTPError.js';\nimport { RESTEvents } from '../utils/constants.js';\nimport type { ResponseLike, HandlerRequestData, RouteData } from '../utils/types.js';\nimport { parseResponse, shouldRetry } from '../utils/utils.js';\n\n/**\n * Invalid request limiting is done on a per-IP basis, not a per-token basis.\n * The best we can do is track invalid counts process-wide (on the theory that\n * users could have multiple bots run from one process) rather than per-bot.\n * Therefore, store these at file scope here rather than in the client's\n * RESTManager object.\n */\nlet invalidCount = 0;\nlet invalidCountResetTime: number | null = null;\n\n/**\n * Increment the invalid request count and emit warning if necessary\n *\n * @internal\n */\nexport function incrementInvalidCount(manager: REST) {\n\tif (!invalidCountResetTime || invalidCountResetTime < Date.now()) {\n\t\tinvalidCountResetTime = Date.now() + 1_000 * 60 * 10;\n\t\tinvalidCount = 0;\n\t}\n\n\tinvalidCount++;\n\n\tconst emitInvalid =\n\t\tmanager.options.invalidRequestWarningInterval > 0 &&\n\t\tinvalidCount % manager.options.invalidRequestWarningInterval === 0;\n\tif (emitInvalid) {\n\t\t// Let library users know periodically about invalid requests\n\t\tmanager.emit(RESTEvents.InvalidRequestWarning, {\n\t\t\tcount: invalidCount,\n\t\t\tremainingTime: invalidCountResetTime - Date.now(),\n\t\t});\n\t}\n}\n\n/**\n * Performs the actual network request for a request handler\n *\n * @param manager - The manager that holds options and emits informational events\n * @param routeId - The generalized api route with literal ids for major parameters\n * @param url - The fully resolved url to make the request to\n * @param options - The fetch options needed to make the request\n * @param requestData - Extra data from the user's request needed for errors and additional processing\n * @param retries - The number of retries this request has already attempted (recursion occurs on the handler)\n * @returns The respond from the network or `null` when the request should be retried\n * @internal\n */\nexport async function makeNetworkRequest(\n\tmanager: REST,\n\trouteId: RouteData,\n\turl: string,\n\toptions: RequestInit,\n\trequestData: HandlerRequestData,\n\tretries: number,\n) {\n\tconst controller = new AbortController();\n\tconst timeout = setTimeout(() => controller.abort(), manager.options.timeout);\n\tif (requestData.signal) {\n\t\t// If the user signal was aborted, abort the controller, else abort the local signal.\n\t\t// The reason why we don't re-use the user's signal, is because users may use the same signal for multiple\n\t\t// requests, and we do not want to cause unexpected side-effects.\n\t\tif (requestData.signal.aborted) controller.abort();\n\t\telse requestData.signal.addEventListener('abort', () => controller.abort());\n\t}\n\n\tlet res: ResponseLike;\n\ttry {\n\t\tres = await manager.options.makeRequest(url, { ...options, signal: controller.signal });\n\t} catch (error: unknown) {\n\t\tif (!(error instanceof Error)) throw error;\n\t\t// Retry the specified number of times if needed\n\t\tif (shouldRetry(error) && retries !== manager.options.retries) {\n\t\t\t// Retry is handled by the handler upon receiving null\n\t\t\treturn null;\n\t\t}\n\n\t\tthrow error;\n\t} finally {\n\t\tclearTimeout(timeout);\n\t}\n\n\tif (manager.listenerCount(RESTEvents.Response)) {\n\t\tmanager.emit(\n\t\t\tRESTEvents.Response,\n\t\t\t{\n\t\t\t\tmethod: options.method ?? 'get',\n\t\t\t\tpath: routeId.original,\n\t\t\t\troute: routeId.bucketRoute,\n\t\t\t\toptions,\n\t\t\t\tdata: requestData,\n\t\t\t\tretries,\n\t\t\t},\n\t\t\tres instanceof Response ? res.clone() : { ...res },\n\t\t);\n\t}\n\n\treturn res;\n}\n\n/**\n * Handles 5xx and 4xx errors (not 429's) conventionally. 429's should be handled before calling this function\n *\n * @param manager - The manager that holds options and emits informational events\n * @param res - The response received from {@link makeNetworkRequest}\n * @param method - The method used to make the request\n * @param url - The fully resolved url to make the request to\n * @param requestData - Extra data from the user's request needed for errors and additional processing\n * @param retries - The number of retries this request has already attempted (recursion occurs on the handler)\n * @returns - The response if the status code is not handled or null to request a retry\n */\nexport async function handleErrors(\n\tmanager: REST,\n\tres: ResponseLike,\n\tmethod: string,\n\turl: string,\n\trequestData: HandlerRequestData,\n\tretries: number,\n) {\n\tconst status = res.status;\n\tif (status >= 500 && status < 600) {\n\t\t// Retry the specified number of times for possible server side issues\n\t\tif (retries !== manager.options.retries) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// We are out of retries, throw an error\n\t\tthrow new HTTPError(status, res.statusText, method, url, requestData);\n\t} else {\n\t\t// Handle possible malformed requests\n\t\tif (status >= 400 && status < 500) {\n\t\t\t// If we receive this status code, it means the token we had is no longer valid.\n\t\t\tif (status === 401 && requestData.auth) {\n\t\t\t\tmanager.setToken(null!);\n\t\t\t}\n\n\t\t\t// The request will not succeed for some reason, parse the error returned from the api\n\t\t\tconst data = (await parseResponse(res)) as DiscordErrorData | OAuthErrorData;\n\t\t\t// throw the API error\n\t\t\tthrow new DiscordAPIError(data, 'code' in data ? data.code : data.error, status, method, url, requestData);\n\t\t}\n\n\t\treturn res;\n\t}\n}\n","import type { RequestInit } from 'undici';\nimport type { REST } from '../REST.js';\nimport type { IHandler } from '../interfaces/Handler.js';\nimport { RESTEvents } from '../utils/constants.js';\nimport type { ResponseLike, HandlerRequestData, RouteData } from '../utils/types.js';\nimport { onRateLimit, sleep } from '../utils/utils.js';\nimport { handleErrors, incrementInvalidCount, makeNetworkRequest } from './Shared.js';\n\n/**\n * The structure used to handle burst requests for a given bucket.\n * Burst requests have no ratelimit handling but allow for pre- and post-processing\n * of data in the same manner as sequentially queued requests.\n *\n * @remarks\n * This queue may still emit a rate limit error if an unexpected 429 is hit\n */\nexport class BurstHandler implements IHandler {\n\t/**\n\t * {@inheritdoc IHandler.id}\n\t */\n\tpublic readonly id: string;\n\n\t/**\n\t * {@inheritDoc IHandler.inactive}\n\t */\n\tpublic inactive = false;\n\n\t/**\n\t * @param manager - The request manager\n\t * @param hash - The hash that this RequestHandler handles\n\t * @param majorParameter - The major parameter for this handler\n\t */\n\tpublic constructor(\n\t\tprivate readonly manager: REST,\n\t\tprivate readonly hash: string,\n\t\tprivate readonly majorParameter: string,\n\t) {\n\t\tthis.id = `${hash}:${majorParameter}`;\n\t}\n\n\t/**\n\t * Emits a debug message\n\t *\n\t * @param message - The message to debug\n\t */\n\tprivate debug(message: string) {\n\t\tthis.manager.emit(RESTEvents.Debug, `[REST ${this.id}] ${message}`);\n\t}\n\n\t/**\n\t * {@inheritDoc IHandler.queueRequest}\n\t */\n\tpublic async queueRequest(\n\t\trouteId: RouteData,\n\t\turl: string,\n\t\toptions: RequestInit,\n\t\trequestData: HandlerRequestData,\n\t): Promise<ResponseLike> {\n\t\treturn this.runRequest(routeId, url, options, requestData);\n\t}\n\n\t/**\n\t * The method that actually makes the request to the API, and updates info about the bucket accordingly\n\t *\n\t * @param routeId - The generalized API route with literal ids for major parameters\n\t * @param url - The fully resolved URL to make the request to\n\t * @param options - The fetch options needed to make the request\n\t * @param requestData - Extra data from the user's request needed for errors and additional processing\n\t * @param retries - The number of retries this request has already attempted (recursion)\n\t */\n\tprivate async runRequest(\n\t\trouteId: RouteData,\n\t\turl: string,\n\t\toptions: RequestInit,\n\t\trequestData: HandlerRequestData,\n\t\tretries = 0,\n\t): Promise<ResponseLike> {\n\t\tconst method = options.method ?? 'get';\n\n\t\tconst res = await makeNetworkRequest(this.manager, routeId, url, options, requestData, retries);\n\n\t\t// Retry requested\n\t\tif (res === null) {\n\t\t\t// eslint-disable-next-line no-param-reassign\n\t\t\treturn this.runRequest(routeId, url, options, requestData, ++retries);\n\t\t}\n\n\t\tconst status = res.status;\n\t\tlet retryAfter = 0;\n\t\tconst retry = res.headers.get('Retry-After');\n\n\t\t// Amount of time in milliseconds until we should retry if rate limited (globally or otherwise)\n\t\tif (retry) retryAfter = Number(retry) * 1_000 + this.manager.options.offset;\n\n\t\t// Count the invalid requests\n\t\tif (status === 401 || status === 403 || status === 429) {\n\t\t\tincrementInvalidCount(this.manager);\n\t\t}\n\n\t\tif (status >= 200 && status < 300) {\n\t\t\treturn res;\n\t\t} else if (status === 429) {\n\t\t\t// Unexpected ratelimit\n\t\t\tconst isGlobal = res.headers.has('X-RateLimit-Global');\n\t\t\tawait onRateLimit(this.manager, {\n\t\t\t\ttimeToReset: retryAfter,\n\t\t\t\tlimit: Number.POSITIVE_INFINITY,\n\t\t\t\tmethod,\n\t\t\t\thash: this.hash,\n\t\t\t\turl,\n\t\t\t\troute: routeId.bucketRoute,\n\t\t\t\tmajorParameter: this.majorParameter,\n\t\t\t\tglobal: isGlobal,\n\t\t\t});\n\t\t\tthis.debug(\n\t\t\t\t[\n\t\t\t\t\t'Encountered unexpected 429 rate limit',\n\t\t\t\t\t` Global : ${isGlobal}`,\n\t\t\t\t\t` Method : ${method}`,\n\t\t\t\t\t` URL : ${url}`,\n\t\t\t\t\t` Bucket : ${routeId.bucketRoute}`,\n\t\t\t\t\t` Major parameter: ${routeId.majorParameter}`,\n\t\t\t\t\t` Hash : ${this.hash}`,\n\t\t\t\t\t` Limit : ${Number.POSITIVE_INFINITY}`,\n\t\t\t\t\t` Retry After : ${retryAfter}ms`,\n\t\t\t\t\t` Sublimit : None`,\n\t\t\t\t].join('\\n'),\n\t\t\t);\n\n\t\t\t// We are bypassing all other limits, but an encountered limit should be respected (it's probably a non-punished rate limit anyways)\n\t\t\tawait sleep(retryAfter);\n\n\t\t\t// Since this is not a server side issue, the next request should pass, so we don't bump the retries counter\n\t\t\treturn this.runRequest(routeId, url, options, requestData, retries);\n\t\t} else {\n\t\t\tconst handled = await handleErrors(this.manager, res, method, url, requestData, retries);\n\t\t\tif (handled === null) {\n\t\t\t\t// eslint-disable-next-line no-param-reassign\n\t\t\t\treturn this.runRequest(routeId, url, options, requestData, ++retries);\n\t\t\t}\n\n\t\t\treturn handled;\n\t\t}\n\t}\n}\n","import { AsyncQueue } from '@sapphire/async-queue';\nimport type { RequestInit } from 'undici';\nimport type { REST } from '../REST.js';\nimport type { IHandler } from '../interfaces/Handler.js';\nimport { RESTEvents } from '../utils/constants.js';\nimport type { RateLimitData, ResponseLike, HandlerRequestData, RouteData } from '../utils/types.js';\nimport { hasSublimit, onRateLimit, sleep } from '../utils/utils.js';\nimport { handleErrors, incrementInvalidCount, makeNetworkRequest } from './Shared.js';\n\nconst enum QueueType {\n\tStandard,\n\tSublimit,\n}\n\n/**\n * The structure used to handle sequential requests for a given bucket\n */\nexport class SequentialHandler implements IHandler {\n\t/**\n\t * {@inheritDoc IHandler.id}\n\t */\n\tpublic readonly id: string;\n\n\t/**\n\t * The time this rate limit bucket will reset\n\t */\n\tprivate reset = -1;\n\n\t/**\n\t * The remaining requests that can be made before we are rate limited\n\t */\n\tprivate remaining = 1;\n\n\t/**\n\t * The total number of requests that can be made before we are rate limited\n\t */\n\tprivate limit = Number.POSITIVE_INFINITY;\n\n\t/**\n\t * The interface used to sequence async requests sequentially\n\t */\n\t#asyncQueue = new AsyncQueue();\n\n\t/**\n\t * The interface used to sequence sublimited async requests sequentially\n\t */\n\t#sublimitedQueue: AsyncQueue | null = null;\n\n\t/**\n\t * A promise wrapper for when the sublimited queue is finished being processed or null when not being processed\n\t */\n\t#sublimitPromise: { promise: Promise<void>; resolve(): void } | null = null;\n\n\t/**\n\t * Whether the sublimit queue needs to be shifted in the finally block\n\t */\n\t#shiftSublimit = false;\n\n\t/**\n\t * @param manager - The request manager\n\t * @param hash - The hash that this RequestHandler handles\n\t * @param majorParameter - The major parameter for this handler\n\t */\n\tpublic constructor(\n\t\tprivate readonly manager: REST,\n\t\tprivate readonly hash: string,\n\t\tprivate readonly majorParameter: string,\n\t) {\n\t\tthis.id = `${hash}:${majorParameter}`;\n\t}\n\n\t/**\n\t * {@inheritDoc IHandler.inactive}\n\t */\n\tpublic get inactive(): boolean {\n\t\treturn (\n\t\t\tthis.#asyncQueue.remaining === 0 &&\n\t\t\t(this.#sublimitedQueue === null || this.#sublimitedQueue.remaining === 0) &&\n\t\t\t!this.limited\n\t\t);\n\t}\n\n\t/**\n\t * If the rate limit bucket is currently limited by the global limit\n\t */\n\tprivate get globalLimited(): boolean {\n\t\treturn this.manager.globalRemaining <= 0 && Date.now() < this.manager.globalReset;\n\t}\n\n\t/**\n\t * If the rate limit bucket is currently limited by its limit\n\t */\n\tprivate get localLimited(): boolean {\n\t\treturn this.remaining <= 0 && Date.now() < this.reset;\n\t}\n\n\t/**\n\t * If the rate limit bucket is currently limited\n\t */\n\tprivate get limited(): boolean {\n\t\treturn this.globalLimited || this.localLimited;\n\t}\n\n\t/**\n\t * The time until queued requests can continue\n\t */\n\tprivate get timeToReset(): number {\n\t\treturn this.reset + this.manager.options.offset - Date.now();\n\t}\n\n\t/**\n\t * Emits a debug message\n\t *\n\t * @param message - The message to debug\n\t */\n\tprivate debug(message: string) {\n\t\tthis.manager.emit(RESTEvents.Debug, `[REST ${this.id}] ${message}`);\n\t}\n\n\t/**\n\t * Delay all requests for the specified amount of time, handling global rate limits\n\t *\n\t * @param time - The amount of time to delay all requests for\n\t */\n\tprivate async globalDelayFor(time: number): Promise<void> {\n\t\tawait sleep(time);\n\t\tthis.manager.globalDelay = null;\n\t}\n\n\t/**\n\t * {@inheritDoc IHandler.queueRequest}\n\t */\n\tpublic async queueRequest(\n\t\trouteId: RouteData,\n\t\turl: string,\n\t\toptions: RequestInit,\n\t\trequestData: HandlerRequestData,\n\t): Promise<ResponseLike> {\n\t\tlet queue = this.#asyncQueue;\n\t\tlet queueType = QueueType.Standard;\n\t\t// Separate sublimited requests when already sublimited\n\t\tif (this.#sublimitedQueue && hasSublimit(routeId.bucketRoute, requestData.body, options.method)) {\n\t\t\tqueue = this.#sublimitedQueue!;\n\t\t\tqueueType = QueueType.Sublimit;\n\t\t}\n\n\t\t// Wait for any previous requests to be completed before this one is run\n\t\tawait queue.wait({ signal: requestData.signal });\n\t\t// This set handles retroactively sublimiting requests\n\t\tif (queueType === QueueType.Standard) {\n\t\t\tif (this.#sublimitedQueue && hasSublimit(routeId.bucketRoute, requestData.body, options.method)) {\n\t\t\t\t/**\n\t\t\t\t * Remove the request from the standard queue, it should never be possible to get here while processing the\n\t\t\t\t * sublimit queue so there is no need to worry about shifting the wrong request\n\t\t\t\t */\n\t\t\t\tqueue = this.#sublimitedQueue!;\n\t\t\t\tconst wait = queue.wait();\n\t\t\t\tthis.#asyncQueue.shift();\n\t\t\t\tawait wait;\n\t\t\t} else if (this.#sublimitPromise) {\n\t\t\t\t// Stall requests while the sublimit queue gets processed\n\t\t\t\tawait this.#sublimitPromise.promise;\n\t\t\t}\n\t\t}\n\n\t\ttry {\n\t\t\t// Make the request, and return the results\n\t\t\treturn await this.runRequest(routeId, url, options, requestData);\n\t\t} finally {\n\t\t\t// Allow the next request to fire\n\t\t\tqueue.shift();\n\t\t\tif (this.#shiftSublimit) {\n\t\t\t\tthis.#shiftSublimit = false;\n\t\t\t\tthis.#sublimitedQueue?.shift();\n\t\t\t}\n\n\t\t\t// If this request is the last request in a sublimit\n\t\t\tif (this.#sublimitedQueue?.remaining === 0) {\n\t\t\t\tthis.#sublimitPromise?.resolve();\n\t\t\t\tthis.#sublimitedQueue = null;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * The method that actually makes the request to the api, and updates info about the bucket accordingly\n\t *\n\t * @param routeId - The generalized api route with literal ids for major parameters\n\t * @param url - The fully resolved url to make the request to\n\t * @param options - The fetch options needed to make the request\n\t * @param requestData - Extra data from the user's request needed for errors and additional processing\n\t * @param retries - The number of retries this request has already attempted (recursion)\n\t */\n\tprivate async runRequest(\n\t\trouteId: RouteData,\n\t\turl: string,\n\t\toptions: RequestInit,\n\t\trequestData: HandlerRequestData,\n\t\tretries = 0,\n\t): Promise<ResponseLike> {\n\t\t/*\n\t\t * After calculations have been done, pre-emptively stop further requests\n\t\t * Potentially loop until this task can run if e.g. the global rate limit is hit twice\n\t\t */\n\t\twhile (this.limited) {\n\t\t\tconst isGlobal = this.globalLimited;\n\t\t\tlet limit: number;\n\t\t\tlet timeout: number;\n\t\t\tlet delay: Promise<void>;\n\n\t\t\tif (isGlobal) {\n\t\t\t\t// Set RateLimitData based on the global limit\n\t\t\t\tlimit = this.manager.options.globalRequestsPerSecond;\n\t\t\t\ttimeout = this.manager.globalReset + this.manager.options.offset - Date.now();\n\t\t\t\t// If this is the first task to reach the global timeout, set the global delay\n\t\t\t\tif (!this.manager.globalDelay) {\n\t\t\t\t\t// The global delay function clears the global delay state when it is resolved\n\t\t\t\t\tthis.manager.globalDelay = this.globalDelayFor(timeout);\n\t\t\t\t}\n\n\t\t\t\tdelay = this.manager.globalDelay;\n\t\t\t} else {\n\t\t\t\t// Set RateLimitData based on the route-specific limit\n\t\t\t\tlimit = this.limit;\n\t\t\t\ttimeout = this.timeToReset;\n\t\t\t\tdelay = sleep(timeout);\n\t\t\t}\n\n\t\t\tconst rateLimitData: RateLimitData = {\n\t\t\t\ttimeToReset: timeout,\n\t\t\t\tlimit,\n\t\t\t\tmethod: options.method ?? 'get',\n\t\t\t\thash: this.hash,\n\t\t\t\turl,\n\t\t\t\troute: routeId.bucketRoute,\n\t\t\t\tmajorParameter: this.majorParameter,\n\t\t\t\tglobal: isGlobal,\n\t\t\t};\n\t\t\t// Let library users know they have hit a rate limit\n\t\t\tthis.manager.emit(RESTEvents.RateLimited, rateLimitData);\n\t\t\t// Determine whether a RateLimitError should be thrown\n\t\t\tawait onRateLimit(this.manager, rateLimitData);\n\t\t\t// When not erroring, emit debug for what is happening\n\t\t\tif (isGlobal) {\n\t\t\t\tthis.debug(`Global rate limit hit, blocking all requests for ${timeout}ms`);\n\t\t\t} else {\n\t\t\t\tthis.debug(`Waiting ${timeout}ms for rate limit to pass`);\n\t\t\t}\n\n\t\t\t// Wait the remaining time left before the rate limit resets\n\t\t\tawait delay;\n\t\t}\n\n\t\t// As the request goes out, update the global usage information\n\t\tif (!this.manager.globalReset || this.manager.globalReset < Date.now()) {\n\t\t\tthis.manager.globalReset = Date.now() + 1_000;\n\t\t\tthis.manager.globalRemaining = this.manager.options.globalRequestsPerSecond;\n\t\t}\n\n\t\tthis.manager.globalRemaining--;\n\n\t\tconst method = options.method ?? 'get';\n\n\t\tconst res = await makeNetworkRequest(this.manager, routeId, url, options, requestData, retries);\n\n\t\t// Retry requested\n\t\tif (res === null) {\n\t\t\t// eslint-disable-next-line no-param-reassign\n\t\t\treturn this.runRequest(routeId, url, options, requestData, ++retries);\n\t\t}\n\n\t\tconst status = res.status;\n\t\tlet retryAfter = 0;\n\n\t\tconst limit = res.headers.get('X-RateLimit-Limit');\n\t\tconst remaining = res.headers.get('X-RateLimit-Remaining');\n\t\tconst reset = res.headers.get('X-RateLimit-Reset-After');\n\t\tconst hash = res.headers.get('X-RateLimit-Bucket');\n\t\tconst retry = res.headers.get('Retry-After');\n\n\t\t// Update the total number of requests that can be made before the rate limit resets\n\t\tthis.limit = limit ? Number(limit) : Number.POSITIVE_INFINITY;\n\t\t// Update the number of remaining requests that can be made before the rate limit resets\n\t\tthis.remaining = remaining ? Number(remaining) : 1;\n\t\t// Update the time when this rate limit resets (reset-after is in seconds)\n\t\tthis.reset = reset ? Number(reset) * 1_000 + Date.now() + this.manager.options.offset : Date.now();\n\n\t\t// Amount of time in milliseconds until we should retry if rate limited (globally or otherwise)\n\t\tif (retry) retryAfter = Number(retry) * 1_000 + this.manager.options.offset;\n\n\t\t// Handle buckets via the hash header retroactively\n\t\tif (hash && hash !== this.hash) {\n\t\t\t// Let library users know when rate limit buckets have been updated\n\t\t\tthis.debug(['Received bucket hash update', ` Old Hash : ${this.hash}`, ` New Hash : ${hash}`].join('\\n'));\n\t\t\t// This queue will eventually be eliminated via attrition\n\t\t\tthis.manager.hashes.set(`${method}:${routeId.bucketRoute}`, { value: hash, lastAccess: Date.now() });\n\t\t} else if (hash) {\n\t\t\t// Handle the case where hash value doesn't change\n\t\t\t// Fetch the hash data from the manager\n\t\t\tconst hashData = this.manager.hashes.get(`${method}:${routeId.bucketRoute}`);\n\n\t\t\t// When fetched, update the last access of the hash\n\t\t\tif (hashData) {\n\t\t\t\thashData.lastAccess = Date.now();\n\t\t\t}\n\t\t}\n\n\t\t// Handle retryAfter, which means we have actually hit a rate limit\n\t\tlet sublimitTimeout: number | null = null;\n\t\tif (retryAfter > 0) {\n\t\t\tif (res.headers.has('X-RateLimit-Global')) {\n\t\t\t\tthis.manager.globalRemaining = 0;\n\t\t\t\tthis.manager.globalReset = Date.now() + retryAfter;\n\t\t\t} else if (!this.localLimited) {\n\t\t\t\t/*\n\t\t\t\t * This is a sublimit (e.g. 2 channel name changes/10 minutes) since the headers don't indicate a\n\t\t\t\t * route-wide rate limit. Don't update remaining or reset to avoid rate limiting the whole\n\t\t\t\t * endpoint, just set a reset time on the request itself to avoid retrying too soon.\n\t\t\t\t */\n\t\t\t\tsublimitTimeout = retryAfter;\n\t\t\t}\n\t\t}\n\n\t\t// Count the invalid requests\n\t\tif (status === 401 || status === 403 || status === 429) {\n\t\t\tincrementInvalidCount(this.manager);\n\t\t}\n\n\t\tif (res.ok) {\n\t\t\treturn res;\n\t\t} else if (status === 429) {\n\t\t\t// A rate limit was hit - this may happen if the route isn't associated with an official bucket hash yet, or when first globally rate limited\n\t\t\tconst isGlobal = this.globalLimited;\n\t\t\tlet limit: number;\n\t\t\tlet timeout: number;\n\n\t\t\tif (isGlobal) {\n\t\t\t\t// Set RateLimitData based on the global limit\n\t\t\t\tlimit = this.manager.options.globalRequestsPerSecond;\n\t\t\t\ttimeout = this.manager.globalReset + this.manager.options.offset - Date.now();\n\t\t\t} else {\n\t\t\t\t// Set RateLimitData based on the route-specific limit\n\t\t\t\tlimit = this.limit;\n\t\t\t\ttimeout = this.timeToReset;\n\t\t\t}\n\n\t\t\tawait onRateLimit(this.manager, {\n\t\t\t\ttimeToReset: timeout,\n\t\t\t\tlimit,\n\t\t\t\tmethod,\n\t\t\t\thash: this.hash,\n\t\t\t\turl,\n\t\t\t\troute: routeId.bucketRoute,\n\t\t\t\tmajorParameter: this.majorParameter,\n\t\t\t\tglobal: isGlobal,\n\t\t\t});\n\t\t\tthis.debug(\n\t\t\t\t[\n\t\t\t\t\t'Encountered unexpected 429 rate limit',\n\t\t\t\t\t` Global : ${isGlobal.toString()}`,\n\t\t\t\t\t` Method : ${method}`,\n\t\t\t\t\t` URL : ${url}`,\n\t\t\t\t\t` Bucket : ${routeId.bucketRoute}`,\n\t\t\t\t\t` Major parameter: ${routeId.majorParameter}`,\n\t\t\t\t\t` Hash : ${this.hash}`,\n\t\t\t\t\t` Limit : ${limit}`,\n\t\t\t\t\t` Retry After : ${retryAfter}ms`,\n\t\t\t\t\t` Sublimit : ${sublimitTimeout ? `${sublimitTimeout}ms` : 'None'}`,\n\t\t\t\t].join('\\n'),\n\t\t\t);\n\t\t\t// If caused by a sublimit, wait it out here so other requests on the route can be handled\n\t\t\tif (sublimitTimeout) {\n\t\t\t\t// Normally the sublimit queue will not exist, however, if a sublimit is hit while in the sublimit queue, it will\n\t\t\t\tconst firstSublimit = !this.#sublimitedQueue;\n\t\t\t\tif (firstSublimit) {\n\t\t\t\t\tthis.#sublimitedQueue = new AsyncQueue();\n\t\t\t\t\tvoid this.#sublimitedQueue.wait();\n\t\t\t\t\tthis.#asyncQueue.shift();\n\t\t\t\t}\n\n\t\t\t\tthis.#sublimitPromise?.resolve();\n\t\t\t\tthis.#sublimitPromise = null;\n\t\t\t\tawait sleep(sublimitTimeout);\n\t\t\t\tlet resolve: () => void;\n\t\t\t\t// eslint-disable-next-line promise/param-names, no-promise-executor-return\n\t\t\t\tconst promise = new Promise<void>((res) => (resolve = res));\n\t\t\t\tthis.#sublimitPromise = { promise, resolve: resolve! };\n\t\t\t\tif (firstSublimit) {\n\t\t\t\t\t// Re-queue this request so it can be shifted by the finally\n\t\t\t\t\tawait this.#asyncQueue.wait();\n\t\t\t\t\tthis.#shiftSublimit = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Since this is not a server side issue, the next request should pass, so we don't bump the retries counter\n\t\t\treturn this.runRequest(routeId, url, options, requestData, retries);\n\t\t} else {\n\t\t\tconst handled = await handleErrors(this.manager, res, method, url, requestData, retries);\n\t\t\tif (handled === null) {\n\t\t\t\t// eslint-disable-next-line no-param-reassign\n\t\t\t\treturn this.runRequest(routeId, url, options, requestData, ++retries);\n\t\t\t}\n\n\t\t\treturn handled;\n\t\t}\n\t}\n}\n","export * from './lib/CDN.js';\nexport * from './lib/errors/DiscordAPIError.js';\nexport * from './lib/errors/HTTPError.js';\nexport * from './lib/errors/RateLimitError.js';\nexport * from './lib/REST.js';\nexport * from './lib/utils/constants.js';\nexport * from './lib/utils/types.js';\nexport { calculateUserDefaultAvatarIndex, makeURLSearchParams, parseResponse } from './lib/utils/utils.js';\n\n/**\n * The {@link https://github.com/discordjs/discord.js/blob/main/packages/rest/#readme | @discordjs/rest} version\n * that you are currently using.\n */\n// This needs to explicitly be `string` so it is not typed as a \"const string\" that gets injected by esbuild\nexport const version = '2.0.1' as string;\n"],"mappings":"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","names":["import_util","import_undici","RESTEvents","RequestMethod","limit","res","request"]}
\ No newline at end of file diff --git a/node_modules/@discordjs/rest/dist/index.mjs b/node_modules/@discordjs/rest/dist/index.mjs new file mode 100644 index 0000000..476da37 --- /dev/null +++ b/node_modules/@discordjs/rest/dist/index.mjs @@ -0,0 +1,1382 @@ +var __defProp = Object.defineProperty; +var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); + +// src/index.ts +import { Blob as Blob2 } from "node:buffer"; +import { shouldUseGlobalFetchAndWebSocket } from "@discordjs/util"; +import { FormData as FormData2 } from "undici"; + +// src/environment.ts +var defaultStrategy; +function setDefaultStrategy(newStrategy) { + defaultStrategy = newStrategy; +} +__name(setDefaultStrategy, "setDefaultStrategy"); +function getDefaultStrategy() { + return defaultStrategy; +} +__name(getDefaultStrategy, "getDefaultStrategy"); + +// src/strategies/undiciRequest.ts +import { STATUS_CODES } from "node:http"; +import { URLSearchParams as URLSearchParams2 } from "node:url"; +import { types } from "node:util"; +import { request, Headers } from "undici"; +async function makeRequest(url, init) { + const options = { + ...init, + body: await resolveBody(init.body) + }; + const res = await request(url, options); + return { + body: res.body, + async arrayBuffer() { + return res.body.arrayBuffer(); + }, + async json() { + return res.body.json(); + }, + async text() { + return res.body.text(); + }, + get bodyUsed() { + return res.body.bodyUsed; + }, + headers: new Headers(res.headers), + status: res.statusCode, + statusText: STATUS_CODES[res.statusCode], + ok: res.statusCode >= 200 && res.statusCode < 300 + }; +} +__name(makeRequest, "makeRequest"); +async function resolveBody(body) { + if (body == null) { + return null; + } else if (typeof body === "string") { + return body; + } else if (types.isUint8Array(body)) { + return body; + } else if (types.isArrayBuffer(body)) { + return new Uint8Array(body); + } else if (body instanceof URLSearchParams2) { + return body.toString(); + } else if (body instanceof DataView) { + return new Uint8Array(body.buffer); + } else if (body instanceof Blob) { + return new Uint8Array(await body.arrayBuffer()); + } else if (body instanceof FormData) { + return body; + } else if (body[Symbol.iterator]) { + const chunks = [...body]; + return Buffer.concat(chunks); + } else if (body[Symbol.asyncIterator]) { + const chunks = []; + for await (const chunk of body) { + chunks.push(chunk); + } + return Buffer.concat(chunks); + } + throw new TypeError(`Unable to resolve body.`); +} +__name(resolveBody, "resolveBody"); + +// src/lib/utils/constants.ts +import { getUserAgentAppendix } from "@discordjs/util"; +import { APIVersion } from "discord-api-types/v10"; +var DefaultUserAgent = `DiscordBot (https://discord.js.org, 2.0.1)`; +var DefaultUserAgentAppendix = getUserAgentAppendix(); +var DefaultRestOptions = { + agent: null, + api: "https://discord.com/api", + authPrefix: "Bot", + cdn: "https://cdn.discordapp.com", + headers: {}, + invalidRequestWarningInterval: 0, + globalRequestsPerSecond: 50, + offset: 50, + rejectOnRateLimit: null, + retries: 3, + timeout: 15e3, + userAgentAppendix: DefaultUserAgentAppendix, + version: APIVersion, + hashSweepInterval: 144e5, + // 4 Hours + hashLifetime: 864e5, + // 24 Hours + handlerSweepInterval: 36e5, + // 1 Hour + async makeRequest(...args) { + return getDefaultStrategy()(...args); + } +}; +var RESTEvents = /* @__PURE__ */ ((RESTEvents2) => { + RESTEvents2["Debug"] = "restDebug"; + RESTEvents2["HandlerSweep"] = "handlerSweep"; + RESTEvents2["HashSweep"] = "hashSweep"; + RESTEvents2["InvalidRequestWarning"] = "invalidRequestWarning"; + RESTEvents2["RateLimited"] = "rateLimited"; + RESTEvents2["Response"] = "response"; + return RESTEvents2; +})(RESTEvents || {}); +var ALLOWED_EXTENSIONS = ["webp", "png", "jpg", "jpeg", "gif"]; +var ALLOWED_STICKER_EXTENSIONS = ["png", "json", "gif"]; +var ALLOWED_SIZES = [16, 32, 64, 128, 256, 512, 1024, 2048, 4096]; +var OverwrittenMimeTypes = { + // https://github.com/discordjs/discord.js/issues/8557 + "image/apng": "image/png" +}; +var BurstHandlerMajorIdKey = "burst"; + +// src/lib/CDN.ts +var CDN = class { + constructor(base = DefaultRestOptions.cdn) { + this.base = base; + } + static { + __name(this, "CDN"); + } + /** + * Generates an app asset URL for a client's asset. + * + * @param clientId - The client id that has the asset + * @param assetHash - The hash provided by Discord for this asset + * @param options - Optional options for the asset + */ + appAsset(clientId, assetHash, options) { + return this.makeURL(`/app-assets/${clientId}/${assetHash}`, options); + } + /** + * Generates an app icon URL for a client's icon. + * + * @param clientId - The client id that has the icon + * @param iconHash - The hash provided by Discord for this icon + * @param options - Optional options for the icon + */ + appIcon(clientId, iconHash, options) { + return this.makeURL(`/app-icons/${clientId}/${iconHash}`, options); + } + /** + * Generates an avatar URL, e.g. for a user or a webhook. + * + * @param id - The id that has the icon + * @param avatarHash - The hash provided by Discord for this avatar + * @param options - Optional options for the avatar + */ + avatar(id, avatarHash, options) { + return this.dynamicMakeURL(`/avatars/${id}/${avatarHash}`, avatarHash, options); + } + /** + * Generates a user avatar decoration URL. + * + * @param userId - The id of the user + * @param userAvatarDecoration - The hash provided by Discord for this avatar decoration + * @param options - Optional options for the avatar decoration + */ + avatarDecoration(userId, userAvatarDecoration, options) { + return this.makeURL(`/avatar-decorations/${userId}/${userAvatarDecoration}`, options); + } + /** + * Generates a banner URL, e.g. for a user or a guild. + * + * @param id - The id that has the banner splash + * @param bannerHash - The hash provided by Discord for this banner + * @param options - Optional options for the banner + */ + banner(id, bannerHash, options) { + return this.dynamicMakeURL(`/banners/${id}/${bannerHash}`, bannerHash, options); + } + /** + * Generates an icon URL for a channel, e.g. a group DM. + * + * @param channelId - The channel id that has the icon + * @param iconHash - The hash provided by Discord for this channel + * @param options - Optional options for the icon + */ + channelIcon(channelId, iconHash, options) { + return this.makeURL(`/channel-icons/${channelId}/${iconHash}`, options); + } + /** + * Generates a default avatar URL + * + * @param index - The default avatar index + * @remarks + * To calculate the index for a user do `(userId >> 22) % 6`, + * or `discriminator % 5` if they're using the legacy username system. + */ + defaultAvatar(index) { + return this.makeURL(`/embed/avatars/${index}`, { extension: "png" }); + } + /** + * Generates a discovery splash URL for a guild's discovery splash. + * + * @param guildId - The guild id that has the discovery splash + * @param splashHash - The hash provided by Discord for this splash + * @param options - Optional options for the splash + */ + discoverySplash(guildId, splashHash, options) { + return this.makeURL(`/discovery-splashes/${guildId}/${splashHash}`, options); + } + /** + * Generates an emoji's URL for an emoji. + * + * @param emojiId - The emoji id + * @param extension - The extension of the emoji + */ + emoji(emojiId, extension) { + return this.makeURL(`/emojis/${emojiId}`, { extension }); + } + /** + * Generates a guild member avatar URL. + * + * @param guildId - The id of the guild + * @param userId - The id of the user + * @param avatarHash - The hash provided by Discord for this avatar + * @param options - Optional options for the avatar + */ + guildMemberAvatar(guildId, userId, avatarHash, options) { + return this.dynamicMakeURL(`/guilds/${guildId}/users/${userId}/avatars/${avatarHash}`, avatarHash, options); + } + /** + * Generates a guild member banner URL. + * + * @param guildId - The id of the guild + * @param userId - The id of the user + * @param bannerHash - The hash provided by Discord for this banner + * @param options - Optional options for the banner + */ + guildMemberBanner(guildId, userId, bannerHash, options) { + return this.dynamicMakeURL(`/guilds/${guildId}/users/${userId}/banner`, bannerHash, options); + } + /** + * Generates an icon URL, e.g. for a guild. + * + * @param id - The id that has the icon splash + * @param iconHash - The hash provided by Discord for this icon + * @param options - Optional options for the icon + */ + icon(id, iconHash, options) { + return this.dynamicMakeURL(`/icons/${id}/${iconHash}`, iconHash, options); + } + /** + * Generates a URL for the icon of a role + * + * @param roleId - The id of the role that has the icon + * @param roleIconHash - The hash provided by Discord for this role icon + * @param options - Optional options for the role icon + */ + roleIcon(roleId, roleIconHash, options) { + return this.makeURL(`/role-icons/${roleId}/${roleIconHash}`, options); + } + /** + * Generates a guild invite splash URL for a guild's invite splash. + * + * @param guildId - The guild id that has the invite splash + * @param splashHash - The hash provided by Discord for this splash + * @param options - Optional options for the splash + */ + splash(guildId, splashHash, options) { + return this.makeURL(`/splashes/${guildId}/${splashHash}`, options); + } + /** + * Generates a sticker URL. + * + * @param stickerId - The sticker id + * @param extension - The extension of the sticker + * @privateRemarks + * Stickers cannot have a `.webp` extension, so we default to a `.png` + */ + sticker(stickerId, extension = "png") { + return this.makeURL(`/stickers/${stickerId}`, { allowedExtensions: ALLOWED_STICKER_EXTENSIONS, extension }); + } + /** + * Generates a sticker pack banner URL. + * + * @param bannerId - The banner id + * @param options - Optional options for the banner + */ + stickerPackBanner(bannerId, options) { + return this.makeURL(`/app-assets/710982414301790216/store/${bannerId}`, options); + } + /** + * Generates a team icon URL for a team's icon. + * + * @param teamId - The team id that has the icon + * @param iconHash - The hash provided by Discord for this icon + * @param options - Optional options for the icon + */ + teamIcon(teamId, iconHash, options) { + return this.makeURL(`/team-icons/${teamId}/${iconHash}`, options); + } + /** + * Generates a cover image for a guild scheduled event. + * + * @param scheduledEventId - The scheduled event id + * @param coverHash - The hash provided by discord for this cover image + * @param options - Optional options for the cover image + */ + guildScheduledEventCover(scheduledEventId, coverHash, options) { + return this.makeURL(`/guild-events/${scheduledEventId}/${coverHash}`, options); + } + /** + * Constructs the URL for the resource, checking whether or not `hash` starts with `a_` if `dynamic` is set to `true`. + * + * @param route - The base cdn route + * @param hash - The hash provided by Discord for this icon + * @param options - Optional options for the link + */ + dynamicMakeURL(route, hash, { forceStatic = false, ...options } = {}) { + return this.makeURL(route, !forceStatic && hash.startsWith("a_") ? { ...options, extension: "gif" } : options); + } + /** + * Constructs the URL for the resource + * + * @param route - The base cdn route + * @param options - The extension/size options for the link + */ + makeURL(route, { allowedExtensions = ALLOWED_EXTENSIONS, extension = "webp", size } = {}) { + extension = String(extension).toLowerCase(); + if (!allowedExtensions.includes(extension)) { + throw new RangeError(`Invalid extension provided: ${extension} +Must be one of: ${allowedExtensions.join(", ")}`); + } + if (size && !ALLOWED_SIZES.includes(size)) { + throw new RangeError(`Invalid size provided: ${size} +Must be one of: ${ALLOWED_SIZES.join(", ")}`); + } + const url = new URL(`${this.base}${route}.${extension}`); + if (size) { + url.searchParams.set("size", String(size)); + } + return url.toString(); + } +}; + +// src/lib/errors/DiscordAPIError.ts +function isErrorGroupWrapper(error) { + return Reflect.has(error, "_errors"); +} +__name(isErrorGroupWrapper, "isErrorGroupWrapper"); +function isErrorResponse(error) { + return typeof Reflect.get(error, "message") === "string"; +} +__name(isErrorResponse, "isErrorResponse"); +var DiscordAPIError = class _DiscordAPIError extends Error { + /** + * @param rawError - The error reported by Discord + * @param code - The error code reported by Discord + * @param status - The status code of the response + * @param method - The method of the request that erred + * @param url - The url of the request that erred + * @param bodyData - The unparsed data for the request that errored + */ + constructor(rawError, code, status, method, url, bodyData) { + super(_DiscordAPIError.getMessage(rawError)); + this.rawError = rawError; + this.code = code; + this.status = status; + this.method = method; + this.url = url; + this.requestBody = { files: bodyData.files, json: bodyData.body }; + } + static { + __name(this, "DiscordAPIError"); + } + requestBody; + /** + * The name of the error + */ + get name() { + return `${_DiscordAPIError.name}[${this.code}]`; + } + static getMessage(error) { + let flattened = ""; + if ("code" in error) { + if (error.errors) { + flattened = [...this.flattenDiscordError(error.errors)].join("\n"); + } + return error.message && flattened ? `${error.message} +${flattened}` : error.message || flattened || "Unknown Error"; + } + return error.error_description ?? "No Description"; + } + static *flattenDiscordError(obj, key = "") { + if (isErrorResponse(obj)) { + return yield `${key.length ? `${key}[${obj.code}]` : `${obj.code}`}: ${obj.message}`.trim(); + } + for (const [otherKey, val] of Object.entries(obj)) { + const nextKey = otherKey.startsWith("_") ? key : key ? Number.isNaN(Number(otherKey)) ? `${key}.${otherKey}` : `${key}[${otherKey}]` : otherKey; + if (typeof val === "string") { + yield val; + } else if (isErrorGroupWrapper(val)) { + for (const error of val._errors) { + yield* this.flattenDiscordError(error, nextKey); + } + } else { + yield* this.flattenDiscordError(val, nextKey); + } + } + } +}; + +// src/lib/errors/HTTPError.ts +var HTTPError = class _HTTPError extends Error { + /** + * @param status - The status code of the response + * @param statusText - The status text of the response + * @param method - The method of the request that erred + * @param url - The url of the request that erred + * @param bodyData - The unparsed data for the request that errored + */ + constructor(status, statusText, method, url, bodyData) { + super(statusText); + this.status = status; + this.method = method; + this.url = url; + this.requestBody = { files: bodyData.files, json: bodyData.body }; + } + static { + __name(this, "HTTPError"); + } + requestBody; + name = _HTTPError.name; +}; + +// src/lib/errors/RateLimitError.ts +var RateLimitError = class _RateLimitError extends Error { + static { + __name(this, "RateLimitError"); + } + timeToReset; + limit; + method; + hash; + url; + route; + majorParameter; + global; + constructor({ timeToReset, limit, method, hash, url, route, majorParameter, global }) { + super(); + this.timeToReset = timeToReset; + this.limit = limit; + this.method = method; + this.hash = hash; + this.url = url; + this.route = route; + this.majorParameter = majorParameter; + this.global = global; + } + /** + * The name of the error + */ + get name() { + return `${_RateLimitError.name}[${this.route}]`; + } +}; + +// src/lib/REST.ts +import { Collection } from "@discordjs/collection"; +import { DiscordSnowflake } from "@sapphire/snowflake"; +import { AsyncEventEmitter } from "@vladfrangu/async_event_emitter"; +import { filetypeinfo } from "magic-bytes.js"; + +// src/lib/utils/types.ts +var RequestMethod = /* @__PURE__ */ ((RequestMethod2) => { + RequestMethod2["Delete"] = "DELETE"; + RequestMethod2["Get"] = "GET"; + RequestMethod2["Patch"] = "PATCH"; + RequestMethod2["Post"] = "POST"; + RequestMethod2["Put"] = "PUT"; + return RequestMethod2; +})(RequestMethod || {}); + +// src/lib/utils/utils.ts +function serializeSearchParam(value) { + switch (typeof value) { + case "string": + return value; + case "number": + case "bigint": + case "boolean": + return value.toString(); + case "object": + if (value === null) + return null; + if (value instanceof Date) { + return Number.isNaN(value.getTime()) ? null : value.toISOString(); + } + if (typeof value.toString === "function" && value.toString !== Object.prototype.toString) + return value.toString(); + return null; + default: + return null; + } +} +__name(serializeSearchParam, "serializeSearchParam"); +function makeURLSearchParams(options) { + const params = new URLSearchParams(); + if (!options) + return params; + for (const [key, value] of Object.entries(options)) { + const serialized = serializeSearchParam(value); + if (serialized !== null) + params.append(key, serialized); + } + return params; +} +__name(makeURLSearchParams, "makeURLSearchParams"); +async function parseResponse(res) { + if (res.headers.get("Content-Type")?.startsWith("application/json")) { + return res.json(); + } + return res.arrayBuffer(); +} +__name(parseResponse, "parseResponse"); +function hasSublimit(bucketRoute, body, method) { + if (bucketRoute === "/channels/:id") { + if (typeof body !== "object" || body === null) + return false; + if (method !== "PATCH" /* Patch */) + return false; + const castedBody = body; + return ["name", "topic"].some((key) => Reflect.has(castedBody, key)); + } + return true; +} +__name(hasSublimit, "hasSublimit"); +function shouldRetry(error) { + if (error.name === "AbortError") + return true; + return "code" in error && error.code === "ECONNRESET" || error.message.includes("ECONNRESET"); +} +__name(shouldRetry, "shouldRetry"); +async function onRateLimit(manager, rateLimitData) { + const { options } = manager; + if (!options.rejectOnRateLimit) + return; + const shouldThrow = typeof options.rejectOnRateLimit === "function" ? await options.rejectOnRateLimit(rateLimitData) : options.rejectOnRateLimit.some((route) => rateLimitData.route.startsWith(route.toLowerCase())); + if (shouldThrow) { + throw new RateLimitError(rateLimitData); + } +} +__name(onRateLimit, "onRateLimit"); +function calculateUserDefaultAvatarIndex(userId) { + return Number(BigInt(userId) >> 22n) % 6; +} +__name(calculateUserDefaultAvatarIndex, "calculateUserDefaultAvatarIndex"); +async function sleep(ms) { + return new Promise((resolve) => { + setTimeout(() => resolve(), ms); + }); +} +__name(sleep, "sleep"); +function isBufferLike(value) { + return value instanceof ArrayBuffer || value instanceof Uint8Array || value instanceof Uint8ClampedArray; +} +__name(isBufferLike, "isBufferLike"); + +// src/lib/handlers/Shared.ts +var invalidCount = 0; +var invalidCountResetTime = null; +function incrementInvalidCount(manager) { + if (!invalidCountResetTime || invalidCountResetTime < Date.now()) { + invalidCountResetTime = Date.now() + 1e3 * 60 * 10; + invalidCount = 0; + } + invalidCount++; + const emitInvalid = manager.options.invalidRequestWarningInterval > 0 && invalidCount % manager.options.invalidRequestWarningInterval === 0; + if (emitInvalid) { + manager.emit("invalidRequestWarning" /* InvalidRequestWarning */, { + count: invalidCount, + remainingTime: invalidCountResetTime - Date.now() + }); + } +} +__name(incrementInvalidCount, "incrementInvalidCount"); +async function makeNetworkRequest(manager, routeId, url, options, requestData, retries) { + const controller = new AbortController(); + const timeout = setTimeout(() => controller.abort(), manager.options.timeout); + if (requestData.signal) { + if (requestData.signal.aborted) + controller.abort(); + else + requestData.signal.addEventListener("abort", () => controller.abort()); + } + let res; + try { + res = await manager.options.makeRequest(url, { ...options, signal: controller.signal }); + } catch (error) { + if (!(error instanceof Error)) + throw error; + if (shouldRetry(error) && retries !== manager.options.retries) { + return null; + } + throw error; + } finally { + clearTimeout(timeout); + } + if (manager.listenerCount("response" /* Response */)) { + manager.emit( + "response" /* Response */, + { + method: options.method ?? "get", + path: routeId.original, + route: routeId.bucketRoute, + options, + data: requestData, + retries + }, + res instanceof Response ? res.clone() : { ...res } + ); + } + return res; +} +__name(makeNetworkRequest, "makeNetworkRequest"); +async function handleErrors(manager, res, method, url, requestData, retries) { + const status = res.status; + if (status >= 500 && status < 600) { + if (retries !== manager.options.retries) { + return null; + } + throw new HTTPError(status, res.statusText, method, url, requestData); + } else { + if (status >= 400 && status < 500) { + if (status === 401 && requestData.auth) { + manager.setToken(null); + } + const data = await parseResponse(res); + throw new DiscordAPIError(data, "code" in data ? data.code : data.error, status, method, url, requestData); + } + return res; + } +} +__name(handleErrors, "handleErrors"); + +// src/lib/handlers/BurstHandler.ts +var BurstHandler = class { + /** + * @param manager - The request manager + * @param hash - The hash that this RequestHandler handles + * @param majorParameter - The major parameter for this handler + */ + constructor(manager, hash, majorParameter) { + this.manager = manager; + this.hash = hash; + this.majorParameter = majorParameter; + this.id = `${hash}:${majorParameter}`; + } + static { + __name(this, "BurstHandler"); + } + /** + * {@inheritdoc IHandler.id} + */ + id; + /** + * {@inheritDoc IHandler.inactive} + */ + inactive = false; + /** + * Emits a debug message + * + * @param message - The message to debug + */ + debug(message) { + this.manager.emit("restDebug" /* Debug */, `[REST ${this.id}] ${message}`); + } + /** + * {@inheritDoc IHandler.queueRequest} + */ + async queueRequest(routeId, url, options, requestData) { + return this.runRequest(routeId, url, options, requestData); + } + /** + * The method that actually makes the request to the API, and updates info about the bucket accordingly + * + * @param routeId - The generalized API route with literal ids for major parameters + * @param url - The fully resolved URL to make the request to + * @param options - The fetch options needed to make the request + * @param requestData - Extra data from the user's request needed for errors and additional processing + * @param retries - The number of retries this request has already attempted (recursion) + */ + async runRequest(routeId, url, options, requestData, retries = 0) { + const method = options.method ?? "get"; + const res = await makeNetworkRequest(this.manager, routeId, url, options, requestData, retries); + if (res === null) { + return this.runRequest(routeId, url, options, requestData, ++retries); + } + const status = res.status; + let retryAfter = 0; + const retry = res.headers.get("Retry-After"); + if (retry) + retryAfter = Number(retry) * 1e3 + this.manager.options.offset; + if (status === 401 || status === 403 || status === 429) { + incrementInvalidCount(this.manager); + } + if (status >= 200 && status < 300) { + return res; + } else if (status === 429) { + const isGlobal = res.headers.has("X-RateLimit-Global"); + await onRateLimit(this.manager, { + timeToReset: retryAfter, + limit: Number.POSITIVE_INFINITY, + method, + hash: this.hash, + url, + route: routeId.bucketRoute, + majorParameter: this.majorParameter, + global: isGlobal + }); + this.debug( + [ + "Encountered unexpected 429 rate limit", + ` Global : ${isGlobal}`, + ` Method : ${method}`, + ` URL : ${url}`, + ` Bucket : ${routeId.bucketRoute}`, + ` Major parameter: ${routeId.majorParameter}`, + ` Hash : ${this.hash}`, + ` Limit : ${Number.POSITIVE_INFINITY}`, + ` Retry After : ${retryAfter}ms`, + ` Sublimit : None` + ].join("\n") + ); + await sleep(retryAfter); + return this.runRequest(routeId, url, options, requestData, retries); + } else { + const handled = await handleErrors(this.manager, res, method, url, requestData, retries); + if (handled === null) { + return this.runRequest(routeId, url, options, requestData, ++retries); + } + return handled; + } + } +}; + +// src/lib/handlers/SequentialHandler.ts +import { AsyncQueue } from "@sapphire/async-queue"; +var SequentialHandler = class { + /** + * @param manager - The request manager + * @param hash - The hash that this RequestHandler handles + * @param majorParameter - The major parameter for this handler + */ + constructor(manager, hash, majorParameter) { + this.manager = manager; + this.hash = hash; + this.majorParameter = majorParameter; + this.id = `${hash}:${majorParameter}`; + } + static { + __name(this, "SequentialHandler"); + } + /** + * {@inheritDoc IHandler.id} + */ + id; + /** + * The time this rate limit bucket will reset + */ + reset = -1; + /** + * The remaining requests that can be made before we are rate limited + */ + remaining = 1; + /** + * The total number of requests that can be made before we are rate limited + */ + limit = Number.POSITIVE_INFINITY; + /** + * The interface used to sequence async requests sequentially + */ + #asyncQueue = new AsyncQueue(); + /** + * The interface used to sequence sublimited async requests sequentially + */ + #sublimitedQueue = null; + /** + * A promise wrapper for when the sublimited queue is finished being processed or null when not being processed + */ + #sublimitPromise = null; + /** + * Whether the sublimit queue needs to be shifted in the finally block + */ + #shiftSublimit = false; + /** + * {@inheritDoc IHandler.inactive} + */ + get inactive() { + return this.#asyncQueue.remaining === 0 && (this.#sublimitedQueue === null || this.#sublimitedQueue.remaining === 0) && !this.limited; + } + /** + * If the rate limit bucket is currently limited by the global limit + */ + get globalLimited() { + return this.manager.globalRemaining <= 0 && Date.now() < this.manager.globalReset; + } + /** + * If the rate limit bucket is currently limited by its limit + */ + get localLimited() { + return this.remaining <= 0 && Date.now() < this.reset; + } + /** + * If the rate limit bucket is currently limited + */ + get limited() { + return this.globalLimited || this.localLimited; + } + /** + * The time until queued requests can continue + */ + get timeToReset() { + return this.reset + this.manager.options.offset - Date.now(); + } + /** + * Emits a debug message + * + * @param message - The message to debug + */ + debug(message) { + this.manager.emit("restDebug" /* Debug */, `[REST ${this.id}] ${message}`); + } + /** + * Delay all requests for the specified amount of time, handling global rate limits + * + * @param time - The amount of time to delay all requests for + */ + async globalDelayFor(time) { + await sleep(time); + this.manager.globalDelay = null; + } + /** + * {@inheritDoc IHandler.queueRequest} + */ + async queueRequest(routeId, url, options, requestData) { + let queue = this.#asyncQueue; + let queueType = 0 /* Standard */; + if (this.#sublimitedQueue && hasSublimit(routeId.bucketRoute, requestData.body, options.method)) { + queue = this.#sublimitedQueue; + queueType = 1 /* Sublimit */; + } + await queue.wait({ signal: requestData.signal }); + if (queueType === 0 /* Standard */) { + if (this.#sublimitedQueue && hasSublimit(routeId.bucketRoute, requestData.body, options.method)) { + queue = this.#sublimitedQueue; + const wait = queue.wait(); + this.#asyncQueue.shift(); + await wait; + } else if (this.#sublimitPromise) { + await this.#sublimitPromise.promise; + } + } + try { + return await this.runRequest(routeId, url, options, requestData); + } finally { + queue.shift(); + if (this.#shiftSublimit) { + this.#shiftSublimit = false; + this.#sublimitedQueue?.shift(); + } + if (this.#sublimitedQueue?.remaining === 0) { + this.#sublimitPromise?.resolve(); + this.#sublimitedQueue = null; + } + } + } + /** + * The method that actually makes the request to the api, and updates info about the bucket accordingly + * + * @param routeId - The generalized api route with literal ids for major parameters + * @param url - The fully resolved url to make the request to + * @param options - The fetch options needed to make the request + * @param requestData - Extra data from the user's request needed for errors and additional processing + * @param retries - The number of retries this request has already attempted (recursion) + */ + async runRequest(routeId, url, options, requestData, retries = 0) { + while (this.limited) { + const isGlobal = this.globalLimited; + let limit2; + let timeout; + let delay; + if (isGlobal) { + limit2 = this.manager.options.globalRequestsPerSecond; + timeout = this.manager.globalReset + this.manager.options.offset - Date.now(); + if (!this.manager.globalDelay) { + this.manager.globalDelay = this.globalDelayFor(timeout); + } + delay = this.manager.globalDelay; + } else { + limit2 = this.limit; + timeout = this.timeToReset; + delay = sleep(timeout); + } + const rateLimitData = { + timeToReset: timeout, + limit: limit2, + method: options.method ?? "get", + hash: this.hash, + url, + route: routeId.bucketRoute, + majorParameter: this.majorParameter, + global: isGlobal + }; + this.manager.emit("rateLimited" /* RateLimited */, rateLimitData); + await onRateLimit(this.manager, rateLimitData); + if (isGlobal) { + this.debug(`Global rate limit hit, blocking all requests for ${timeout}ms`); + } else { + this.debug(`Waiting ${timeout}ms for rate limit to pass`); + } + await delay; + } + if (!this.manager.globalReset || this.manager.globalReset < Date.now()) { + this.manager.globalReset = Date.now() + 1e3; + this.manager.globalRemaining = this.manager.options.globalRequestsPerSecond; + } + this.manager.globalRemaining--; + const method = options.method ?? "get"; + const res = await makeNetworkRequest(this.manager, routeId, url, options, requestData, retries); + if (res === null) { + return this.runRequest(routeId, url, options, requestData, ++retries); + } + const status = res.status; + let retryAfter = 0; + const limit = res.headers.get("X-RateLimit-Limit"); + const remaining = res.headers.get("X-RateLimit-Remaining"); + const reset = res.headers.get("X-RateLimit-Reset-After"); + const hash = res.headers.get("X-RateLimit-Bucket"); + const retry = res.headers.get("Retry-After"); + this.limit = limit ? Number(limit) : Number.POSITIVE_INFINITY; + this.remaining = remaining ? Number(remaining) : 1; + this.reset = reset ? Number(reset) * 1e3 + Date.now() + this.manager.options.offset : Date.now(); + if (retry) + retryAfter = Number(retry) * 1e3 + this.manager.options.offset; + if (hash && hash !== this.hash) { + this.debug(["Received bucket hash update", ` Old Hash : ${this.hash}`, ` New Hash : ${hash}`].join("\n")); + this.manager.hashes.set(`${method}:${routeId.bucketRoute}`, { value: hash, lastAccess: Date.now() }); + } else if (hash) { + const hashData = this.manager.hashes.get(`${method}:${routeId.bucketRoute}`); + if (hashData) { + hashData.lastAccess = Date.now(); + } + } + let sublimitTimeout = null; + if (retryAfter > 0) { + if (res.headers.has("X-RateLimit-Global")) { + this.manager.globalRemaining = 0; + this.manager.globalReset = Date.now() + retryAfter; + } else if (!this.localLimited) { + sublimitTimeout = retryAfter; + } + } + if (status === 401 || status === 403 || status === 429) { + incrementInvalidCount(this.manager); + } + if (res.ok) { + return res; + } else if (status === 429) { + const isGlobal = this.globalLimited; + let limit2; + let timeout; + if (isGlobal) { + limit2 = this.manager.options.globalRequestsPerSecond; + timeout = this.manager.globalReset + this.manager.options.offset - Date.now(); + } else { + limit2 = this.limit; + timeout = this.timeToReset; + } + await onRateLimit(this.manager, { + timeToReset: timeout, + limit: limit2, + method, + hash: this.hash, + url, + route: routeId.bucketRoute, + majorParameter: this.majorParameter, + global: isGlobal + }); + this.debug( + [ + "Encountered unexpected 429 rate limit", + ` Global : ${isGlobal.toString()}`, + ` Method : ${method}`, + ` URL : ${url}`, + ` Bucket : ${routeId.bucketRoute}`, + ` Major parameter: ${routeId.majorParameter}`, + ` Hash : ${this.hash}`, + ` Limit : ${limit2}`, + ` Retry After : ${retryAfter}ms`, + ` Sublimit : ${sublimitTimeout ? `${sublimitTimeout}ms` : "None"}` + ].join("\n") + ); + if (sublimitTimeout) { + const firstSublimit = !this.#sublimitedQueue; + if (firstSublimit) { + this.#sublimitedQueue = new AsyncQueue(); + void this.#sublimitedQueue.wait(); + this.#asyncQueue.shift(); + } + this.#sublimitPromise?.resolve(); + this.#sublimitPromise = null; + await sleep(sublimitTimeout); + let resolve; + const promise = new Promise((res2) => resolve = res2); + this.#sublimitPromise = { promise, resolve }; + if (firstSublimit) { + await this.#asyncQueue.wait(); + this.#shiftSublimit = true; + } + } + return this.runRequest(routeId, url, options, requestData, retries); + } else { + const handled = await handleErrors(this.manager, res, method, url, requestData, retries); + if (handled === null) { + return this.runRequest(routeId, url, options, requestData, ++retries); + } + return handled; + } + } +}; + +// src/lib/REST.ts +var REST = class _REST extends AsyncEventEmitter { + static { + __name(this, "REST"); + } + /** + * The {@link https://undici.nodejs.org/#/docs/api/Agent | Agent} for all requests + * performed by this manager. + */ + agent = null; + cdn; + /** + * The number of requests remaining in the global bucket + */ + globalRemaining; + /** + * The promise used to wait out the global rate limit + */ + globalDelay = null; + /** + * The timestamp at which the global bucket resets + */ + globalReset = -1; + /** + * API bucket hashes that are cached from provided routes + */ + hashes = new Collection(); + /** + * Request handlers created from the bucket hash and the major parameters + */ + handlers = new Collection(); + #token = null; + hashTimer; + handlerTimer; + options; + constructor(options = {}) { + super(); + this.cdn = new CDN(options.cdn ?? DefaultRestOptions.cdn); + this.options = { ...DefaultRestOptions, ...options }; + this.options.offset = Math.max(0, this.options.offset); + this.globalRemaining = Math.max(1, this.options.globalRequestsPerSecond); + this.agent = options.agent ?? null; + this.setupSweepers(); + } + setupSweepers() { + const validateMaxInterval = /* @__PURE__ */ __name((interval) => { + if (interval > 144e5) { + throw new Error("Cannot set an interval greater than 4 hours"); + } + }, "validateMaxInterval"); + if (this.options.hashSweepInterval !== 0 && this.options.hashSweepInterval !== Number.POSITIVE_INFINITY) { + validateMaxInterval(this.options.hashSweepInterval); + this.hashTimer = setInterval(() => { + const sweptHashes = new Collection(); + const currentDate = Date.now(); + this.hashes.sweep((val, key) => { + if (val.lastAccess === -1) + return false; + const shouldSweep = Math.floor(currentDate - val.lastAccess) > this.options.hashLifetime; + if (shouldSweep) { + sweptHashes.set(key, val); + this.emit("restDebug" /* Debug */, `Hash ${val.value} for ${key} swept due to lifetime being exceeded`); + } + return shouldSweep; + }); + this.emit("hashSweep" /* HashSweep */, sweptHashes); + }, this.options.hashSweepInterval); + this.hashTimer.unref?.(); + } + if (this.options.handlerSweepInterval !== 0 && this.options.handlerSweepInterval !== Number.POSITIVE_INFINITY) { + validateMaxInterval(this.options.handlerSweepInterval); + this.handlerTimer = setInterval(() => { + const sweptHandlers = new Collection(); + this.handlers.sweep((val, key) => { + const { inactive } = val; + if (inactive) { + sweptHandlers.set(key, val); + this.emit("restDebug" /* Debug */, `Handler ${val.id} for ${key} swept due to being inactive`); + } + return inactive; + }); + this.emit("handlerSweep" /* HandlerSweep */, sweptHandlers); + }, this.options.handlerSweepInterval); + this.handlerTimer.unref?.(); + } + } + /** + * Runs a get request from the api + * + * @param fullRoute - The full route to query + * @param options - Optional request options + */ + async get(fullRoute, options = {}) { + return this.request({ ...options, fullRoute, method: "GET" /* Get */ }); + } + /** + * Runs a delete request from the api + * + * @param fullRoute - The full route to query + * @param options - Optional request options + */ + async delete(fullRoute, options = {}) { + return this.request({ ...options, fullRoute, method: "DELETE" /* Delete */ }); + } + /** + * Runs a post request from the api + * + * @param fullRoute - The full route to query + * @param options - Optional request options + */ + async post(fullRoute, options = {}) { + return this.request({ ...options, fullRoute, method: "POST" /* Post */ }); + } + /** + * Runs a put request from the api + * + * @param fullRoute - The full route to query + * @param options - Optional request options + */ + async put(fullRoute, options = {}) { + return this.request({ ...options, fullRoute, method: "PUT" /* Put */ }); + } + /** + * Runs a patch request from the api + * + * @param fullRoute - The full route to query + * @param options - Optional request options + */ + async patch(fullRoute, options = {}) { + return this.request({ ...options, fullRoute, method: "PATCH" /* Patch */ }); + } + /** + * Runs a request from the api + * + * @param options - Request options + */ + async request(options) { + const response = await this.queueRequest(options); + return parseResponse(response); + } + /** + * Sets the default agent to use for requests performed by this manager + * + * @param agent - The agent to use + */ + setAgent(agent) { + this.agent = agent; + return this; + } + /** + * Sets the authorization token that should be used for requests + * + * @param token - The authorization token to use + */ + setToken(token) { + this.#token = token; + return this; + } + /** + * Queues a request to be sent + * + * @param request - All the information needed to make a request + * @returns The response from the api request + */ + async queueRequest(request2) { + const routeId = _REST.generateRouteData(request2.fullRoute, request2.method); + const hash = this.hashes.get(`${request2.method}:${routeId.bucketRoute}`) ?? { + value: `Global(${request2.method}:${routeId.bucketRoute})`, + lastAccess: -1 + }; + const handler = this.handlers.get(`${hash.value}:${routeId.majorParameter}`) ?? this.createHandler(hash.value, routeId.majorParameter); + const { url, fetchOptions } = await this.resolveRequest(request2); + return handler.queueRequest(routeId, url, fetchOptions, { + body: request2.body, + files: request2.files, + auth: request2.auth !== false, + signal: request2.signal + }); + } + /** + * Creates a new rate limit handler from a hash, based on the hash and the major parameter + * + * @param hash - The hash for the route + * @param majorParameter - The major parameter for this handler + * @internal + */ + createHandler(hash, majorParameter) { + const queue = majorParameter === BurstHandlerMajorIdKey ? new BurstHandler(this, hash, majorParameter) : new SequentialHandler(this, hash, majorParameter); + this.handlers.set(queue.id, queue); + return queue; + } + /** + * Formats the request data to a usable format for fetch + * + * @param request - The request data + */ + async resolveRequest(request2) { + const { options } = this; + let query = ""; + if (request2.query) { + const resolvedQuery = request2.query.toString(); + if (resolvedQuery !== "") { + query = `?${resolvedQuery}`; + } + } + const headers = { + ...this.options.headers, + "User-Agent": `${DefaultUserAgent} ${options.userAgentAppendix}`.trim() + }; + if (request2.auth !== false) { + if (!this.#token) { + throw new Error("Expected token to be set for this request, but none was present"); + } + headers.Authorization = `${request2.authPrefix ?? this.options.authPrefix} ${this.#token}`; + } + if (request2.reason?.length) { + headers["X-Audit-Log-Reason"] = encodeURIComponent(request2.reason); + } + const url = `${options.api}${request2.versioned === false ? "" : `/v${options.version}`}${request2.fullRoute}${query}`; + let finalBody; + let additionalHeaders = {}; + if (request2.files?.length) { + const formData = new FormData(); + for (const [index, file] of request2.files.entries()) { + const fileKey = file.key ?? `files[${index}]`; + if (isBufferLike(file.data)) { + let contentType = file.contentType; + if (!contentType) { + const [parsedType] = filetypeinfo(file.data); + if (parsedType) { + contentType = OverwrittenMimeTypes[parsedType.mime] ?? parsedType.mime ?? "application/octet-stream"; + } + } + formData.append(fileKey, new Blob([file.data], { type: contentType }), file.name); + } else { + formData.append(fileKey, new Blob([`${file.data}`], { type: file.contentType }), file.name); + } + } + if (request2.body != null) { + if (request2.appendToFormData) { + for (const [key, value] of Object.entries(request2.body)) { + formData.append(key, value); + } + } else { + formData.append("payload_json", JSON.stringify(request2.body)); + } + } + finalBody = formData; + } else if (request2.body != null) { + if (request2.passThroughBody) { + finalBody = request2.body; + } else { + finalBody = JSON.stringify(request2.body); + additionalHeaders = { "Content-Type": "application/json" }; + } + } + const method = request2.method.toUpperCase(); + const fetchOptions = { + // Set body to null on get / head requests. This does not follow fetch spec (likely because it causes subtle bugs) but is aligned with what request was doing + body: ["GET", "HEAD"].includes(method) ? null : finalBody, + headers: { ...request2.headers, ...additionalHeaders, ...headers }, + method, + // Prioritize setting an agent per request, use the agent for this instance otherwise. + dispatcher: request2.dispatcher ?? this.agent ?? void 0 + }; + return { url, fetchOptions }; + } + /** + * Stops the hash sweeping interval + */ + clearHashSweeper() { + clearInterval(this.hashTimer); + } + /** + * Stops the request handler sweeping interval + */ + clearHandlerSweeper() { + clearInterval(this.handlerTimer); + } + /** + * Generates route data for an endpoint:method + * + * @param endpoint - The raw endpoint to generalize + * @param method - The HTTP method this endpoint is called without + * @internal + */ + static generateRouteData(endpoint, method) { + if (endpoint.startsWith("/interactions/") && endpoint.endsWith("/callback")) { + return { + majorParameter: BurstHandlerMajorIdKey, + bucketRoute: "/interactions/:id/:token/callback", + original: endpoint + }; + } + const majorIdMatch = /^\/(?:channels|guilds|webhooks)\/(\d{17,19})/.exec(endpoint); + const majorId = majorIdMatch?.[1] ?? "global"; + const baseRoute = endpoint.replaceAll(/\d{17,19}/g, ":id").replace(/\/reactions\/(.*)/, "/reactions/:reaction"); + let exceptions = ""; + if (method === "DELETE" /* Delete */ && baseRoute === "/channels/:id/messages/:id") { + const id = /\d{17,19}$/.exec(endpoint)[0]; + const timestamp = DiscordSnowflake.timestampFrom(id); + if (Date.now() - timestamp > 1e3 * 60 * 60 * 24 * 14) { + exceptions += "/Delete Old Message"; + } + } + return { + majorParameter: majorId, + bucketRoute: baseRoute + exceptions, + original: endpoint + }; + } +}; + +// src/shared.ts +var version = "2.0.1"; + +// src/index.ts +globalThis.FormData ??= FormData2; +globalThis.Blob ??= Blob2; +setDefaultStrategy(shouldUseGlobalFetchAndWebSocket() ? fetch : makeRequest); +export { + ALLOWED_EXTENSIONS, + ALLOWED_SIZES, + ALLOWED_STICKER_EXTENSIONS, + BurstHandlerMajorIdKey, + CDN, + DefaultRestOptions, + DefaultUserAgent, + DefaultUserAgentAppendix, + DiscordAPIError, + HTTPError, + OverwrittenMimeTypes, + REST, + RESTEvents, + RateLimitError, + RequestMethod, + calculateUserDefaultAvatarIndex, + makeURLSearchParams, + parseResponse, + version +}; +//# sourceMappingURL=index.mjs.map
\ No newline at end of file diff --git a/node_modules/@discordjs/rest/dist/index.mjs.map b/node_modules/@discordjs/rest/dist/index.mjs.map new file mode 100644 index 0000000..51a8dfd --- /dev/null +++ b/node_modules/@discordjs/rest/dist/index.mjs.map @@ -0,0 +1 @@ +{"version":3,"sources":["../src/index.ts","../src/environment.ts","../src/strategies/undiciRequest.ts","../src/lib/utils/constants.ts","../src/lib/CDN.ts","../src/lib/errors/DiscordAPIError.ts","../src/lib/errors/HTTPError.ts","../src/lib/errors/RateLimitError.ts","../src/lib/REST.ts","../src/lib/utils/types.ts","../src/lib/utils/utils.ts","../src/lib/handlers/Shared.ts","../src/lib/handlers/BurstHandler.ts","../src/lib/handlers/SequentialHandler.ts","../src/shared.ts"],"sourcesContent":["import { Blob } from 'node:buffer';\nimport { shouldUseGlobalFetchAndWebSocket } from '@discordjs/util';\nimport { FormData } from 'undici';\nimport { setDefaultStrategy } from './environment.js';\nimport { makeRequest } from './strategies/undiciRequest.js';\n\n// TODO(ckohen): remove once node engine req is bumped to > v18\n(globalThis as any).FormData ??= FormData;\nglobalThis.Blob ??= Blob;\n\nsetDefaultStrategy(shouldUseGlobalFetchAndWebSocket() ? fetch : makeRequest);\n\nexport * from './shared.js';\n","import type { RESTOptions } from './shared.js';\n\nlet defaultStrategy: RESTOptions['makeRequest'];\n\nexport function setDefaultStrategy(newStrategy: RESTOptions['makeRequest']) {\n\tdefaultStrategy = newStrategy;\n}\n\nexport function getDefaultStrategy() {\n\treturn defaultStrategy;\n}\n","import { STATUS_CODES } from 'node:http';\nimport { URLSearchParams } from 'node:url';\nimport { types } from 'node:util';\nimport { type RequestInit, request, Headers } from 'undici';\nimport type { ResponseLike } from '../shared.js';\n\nexport type RequestOptions = Exclude<Parameters<typeof request>[1], undefined>;\n\nexport async function makeRequest(url: string, init: RequestInit): Promise<ResponseLike> {\n\t// The cast is necessary because `headers` and `method` are narrower types in `undici.request`\n\t// our request path guarantees they are of acceptable type for `undici.request`\n\tconst options = {\n\t\t...init,\n\t\tbody: await resolveBody(init.body),\n\t} as RequestOptions;\n\tconst res = await request(url, options);\n\treturn {\n\t\tbody: res.body,\n\t\tasync arrayBuffer() {\n\t\t\treturn res.body.arrayBuffer();\n\t\t},\n\t\tasync json() {\n\t\t\treturn res.body.json();\n\t\t},\n\t\tasync text() {\n\t\t\treturn res.body.text();\n\t\t},\n\t\tget bodyUsed() {\n\t\t\treturn res.body.bodyUsed;\n\t\t},\n\t\theaders: new Headers(res.headers as Record<string, string[] | string>),\n\t\tstatus: res.statusCode,\n\t\tstatusText: STATUS_CODES[res.statusCode]!,\n\t\tok: res.statusCode >= 200 && res.statusCode < 300,\n\t};\n}\n\nexport async function resolveBody(body: RequestInit['body']): Promise<Exclude<RequestOptions['body'], undefined>> {\n\t// eslint-disable-next-line no-eq-null, eqeqeq\n\tif (body == null) {\n\t\treturn null;\n\t} else if (typeof body === 'string') {\n\t\treturn body;\n\t} else if (types.isUint8Array(body)) {\n\t\treturn body;\n\t} else if (types.isArrayBuffer(body)) {\n\t\treturn new Uint8Array(body);\n\t} else if (body instanceof URLSearchParams) {\n\t\treturn body.toString();\n\t} else if (body instanceof DataView) {\n\t\treturn new Uint8Array(body.buffer);\n\t} else if (body instanceof Blob) {\n\t\treturn new Uint8Array(await body.arrayBuffer());\n\t} else if (body instanceof FormData) {\n\t\treturn body;\n\t} else if ((body as Iterable<Uint8Array>)[Symbol.iterator]) {\n\t\tconst chunks = [...(body as Iterable<Uint8Array>)];\n\n\t\treturn Buffer.concat(chunks);\n\t} else if ((body as AsyncIterable<Uint8Array>)[Symbol.asyncIterator]) {\n\t\tconst chunks: Uint8Array[] = [];\n\n\t\tfor await (const chunk of body as AsyncIterable<Uint8Array>) {\n\t\t\tchunks.push(chunk);\n\t\t}\n\n\t\treturn Buffer.concat(chunks);\n\t}\n\n\tthrow new TypeError(`Unable to resolve body.`);\n}\n","import { getUserAgentAppendix } from '@discordjs/util';\nimport { APIVersion } from 'discord-api-types/v10';\nimport { getDefaultStrategy } from '../../environment.js';\nimport type { RESTOptions, ResponseLike } from './types.js';\n\nexport const DefaultUserAgent =\n\t`DiscordBot (https://discord.js.org, 2.0.1)` as `DiscordBot (https://discord.js.org, ${string})`;\n\n/**\n * The default string to append onto the user agent.\n */\nexport const DefaultUserAgentAppendix = getUserAgentAppendix();\n\nexport const DefaultRestOptions = {\n\tagent: null,\n\tapi: 'https://discord.com/api',\n\tauthPrefix: 'Bot',\n\tcdn: 'https://cdn.discordapp.com',\n\theaders: {},\n\tinvalidRequestWarningInterval: 0,\n\tglobalRequestsPerSecond: 50,\n\toffset: 50,\n\trejectOnRateLimit: null,\n\tretries: 3,\n\ttimeout: 15_000,\n\tuserAgentAppendix: DefaultUserAgentAppendix,\n\tversion: APIVersion,\n\thashSweepInterval: 14_400_000, // 4 Hours\n\thashLifetime: 86_400_000, // 24 Hours\n\thandlerSweepInterval: 3_600_000, // 1 Hour\n\tasync makeRequest(...args): Promise<ResponseLike> {\n\t\treturn getDefaultStrategy()(...args);\n\t},\n} as const satisfies Required<RESTOptions>;\n\n/**\n * The events that the REST manager emits\n */\nexport enum RESTEvents {\n\tDebug = 'restDebug',\n\tHandlerSweep = 'handlerSweep',\n\tHashSweep = 'hashSweep',\n\tInvalidRequestWarning = 'invalidRequestWarning',\n\tRateLimited = 'rateLimited',\n\tResponse = 'response',\n}\n\nexport const ALLOWED_EXTENSIONS = ['webp', 'png', 'jpg', 'jpeg', 'gif'] as const satisfies readonly string[];\nexport const ALLOWED_STICKER_EXTENSIONS = ['png', 'json', 'gif'] as const satisfies readonly string[];\nexport const ALLOWED_SIZES = [16, 32, 64, 128, 256, 512, 1_024, 2_048, 4_096] as const satisfies readonly number[];\n\nexport type ImageExtension = (typeof ALLOWED_EXTENSIONS)[number];\nexport type StickerExtension = (typeof ALLOWED_STICKER_EXTENSIONS)[number];\nexport type ImageSize = (typeof ALLOWED_SIZES)[number];\n\nexport const OverwrittenMimeTypes = {\n\t// https://github.com/discordjs/discord.js/issues/8557\n\t'image/apng': 'image/png',\n} as const satisfies Readonly<Record<string, string>>;\n\nexport const BurstHandlerMajorIdKey = 'burst';\n","/* eslint-disable jsdoc/check-param-names */\nimport {\n\tALLOWED_EXTENSIONS,\n\tALLOWED_SIZES,\n\tALLOWED_STICKER_EXTENSIONS,\n\tDefaultRestOptions,\n\ttype ImageExtension,\n\ttype ImageSize,\n\ttype StickerExtension,\n} from './utils/constants.js';\n\n/**\n * The options used for image URLs\n */\nexport interface BaseImageURLOptions {\n\t/**\n\t * The extension to use for the image URL\n\t *\n\t * @defaultValue `'webp'`\n\t */\n\textension?: ImageExtension;\n\t/**\n\t * The size specified in the image URL\n\t */\n\tsize?: ImageSize;\n}\n\n/**\n * The options used for image URLs with animated content\n */\nexport interface ImageURLOptions extends BaseImageURLOptions {\n\t/**\n\t * Whether or not to prefer the static version of an image asset.\n\t */\n\tforceStatic?: boolean;\n}\n\n/**\n * The options to use when making a CDN URL\n */\nexport interface MakeURLOptions {\n\t/**\n\t * The allowed extensions that can be used\n\t */\n\tallowedExtensions?: readonly string[];\n\t/**\n\t * The extension to use for the image URL\n\t *\n\t * @defaultValue `'webp'`\n\t */\n\textension?: string | undefined;\n\t/**\n\t * The size specified in the image URL\n\t */\n\tsize?: ImageSize;\n}\n\n/**\n * The CDN link builder\n */\nexport class CDN {\n\tpublic constructor(private readonly base: string = DefaultRestOptions.cdn) {}\n\n\t/**\n\t * Generates an app asset URL for a client's asset.\n\t *\n\t * @param clientId - The client id that has the asset\n\t * @param assetHash - The hash provided by Discord for this asset\n\t * @param options - Optional options for the asset\n\t */\n\tpublic appAsset(clientId: string, assetHash: string, options?: Readonly<BaseImageURLOptions>): string {\n\t\treturn this.makeURL(`/app-assets/${clientId}/${assetHash}`, options);\n\t}\n\n\t/**\n\t * Generates an app icon URL for a client's icon.\n\t *\n\t * @param clientId - The client id that has the icon\n\t * @param iconHash - The hash provided by Discord for this icon\n\t * @param options - Optional options for the icon\n\t */\n\tpublic appIcon(clientId: string, iconHash: string, options?: Readonly<BaseImageURLOptions>): string {\n\t\treturn this.makeURL(`/app-icons/${clientId}/${iconHash}`, options);\n\t}\n\n\t/**\n\t * Generates an avatar URL, e.g. for a user or a webhook.\n\t *\n\t * @param id - The id that has the icon\n\t * @param avatarHash - The hash provided by Discord for this avatar\n\t * @param options - Optional options for the avatar\n\t */\n\tpublic avatar(id: string, avatarHash: string, options?: Readonly<ImageURLOptions>): string {\n\t\treturn this.dynamicMakeURL(`/avatars/${id}/${avatarHash}`, avatarHash, options);\n\t}\n\n\t/**\n\t * Generates a user avatar decoration URL.\n\t *\n\t * @param userId - The id of the user\n\t * @param userAvatarDecoration - The hash provided by Discord for this avatar decoration\n\t * @param options - Optional options for the avatar decoration\n\t */\n\tpublic avatarDecoration(\n\t\tuserId: string,\n\t\tuserAvatarDecoration: string,\n\t\toptions?: Readonly<BaseImageURLOptions>,\n\t): string {\n\t\treturn this.makeURL(`/avatar-decorations/${userId}/${userAvatarDecoration}`, options);\n\t}\n\n\t/**\n\t * Generates a banner URL, e.g. for a user or a guild.\n\t *\n\t * @param id - The id that has the banner splash\n\t * @param bannerHash - The hash provided by Discord for this banner\n\t * @param options - Optional options for the banner\n\t */\n\tpublic banner(id: string, bannerHash: string, options?: Readonly<ImageURLOptions>): string {\n\t\treturn this.dynamicMakeURL(`/banners/${id}/${bannerHash}`, bannerHash, options);\n\t}\n\n\t/**\n\t * Generates an icon URL for a channel, e.g. a group DM.\n\t *\n\t * @param channelId - The channel id that has the icon\n\t * @param iconHash - The hash provided by Discord for this channel\n\t * @param options - Optional options for the icon\n\t */\n\tpublic channelIcon(channelId: string, iconHash: string, options?: Readonly<BaseImageURLOptions>): string {\n\t\treturn this.makeURL(`/channel-icons/${channelId}/${iconHash}`, options);\n\t}\n\n\t/**\n\t * Generates a default avatar URL\n\t *\n\t * @param index - The default avatar index\n\t * @remarks\n\t * To calculate the index for a user do `(userId >> 22) % 6`,\n\t * or `discriminator % 5` if they're using the legacy username system.\n\t */\n\tpublic defaultAvatar(index: number): string {\n\t\treturn this.makeURL(`/embed/avatars/${index}`, { extension: 'png' });\n\t}\n\n\t/**\n\t * Generates a discovery splash URL for a guild's discovery splash.\n\t *\n\t * @param guildId - The guild id that has the discovery splash\n\t * @param splashHash - The hash provided by Discord for this splash\n\t * @param options - Optional options for the splash\n\t */\n\tpublic discoverySplash(guildId: string, splashHash: string, options?: Readonly<BaseImageURLOptions>): string {\n\t\treturn this.makeURL(`/discovery-splashes/${guildId}/${splashHash}`, options);\n\t}\n\n\t/**\n\t * Generates an emoji's URL for an emoji.\n\t *\n\t * @param emojiId - The emoji id\n\t * @param extension - The extension of the emoji\n\t */\n\tpublic emoji(emojiId: string, extension?: ImageExtension): string {\n\t\treturn this.makeURL(`/emojis/${emojiId}`, { extension });\n\t}\n\n\t/**\n\t * Generates a guild member avatar URL.\n\t *\n\t * @param guildId - The id of the guild\n\t * @param userId - The id of the user\n\t * @param avatarHash - The hash provided by Discord for this avatar\n\t * @param options - Optional options for the avatar\n\t */\n\tpublic guildMemberAvatar(\n\t\tguildId: string,\n\t\tuserId: string,\n\t\tavatarHash: string,\n\t\toptions?: Readonly<ImageURLOptions>,\n\t): string {\n\t\treturn this.dynamicMakeURL(`/guilds/${guildId}/users/${userId}/avatars/${avatarHash}`, avatarHash, options);\n\t}\n\n\t/**\n\t * Generates a guild member banner URL.\n\t *\n\t * @param guildId - The id of the guild\n\t * @param userId - The id of the user\n\t * @param bannerHash - The hash provided by Discord for this banner\n\t * @param options - Optional options for the banner\n\t */\n\tpublic guildMemberBanner(\n\t\tguildId: string,\n\t\tuserId: string,\n\t\tbannerHash: string,\n\t\toptions?: Readonly<ImageURLOptions>,\n\t): string {\n\t\treturn this.dynamicMakeURL(`/guilds/${guildId}/users/${userId}/banner`, bannerHash, options);\n\t}\n\n\t/**\n\t * Generates an icon URL, e.g. for a guild.\n\t *\n\t * @param id - The id that has the icon splash\n\t * @param iconHash - The hash provided by Discord for this icon\n\t * @param options - Optional options for the icon\n\t */\n\tpublic icon(id: string, iconHash: string, options?: Readonly<ImageURLOptions>): string {\n\t\treturn this.dynamicMakeURL(`/icons/${id}/${iconHash}`, iconHash, options);\n\t}\n\n\t/**\n\t * Generates a URL for the icon of a role\n\t *\n\t * @param roleId - The id of the role that has the icon\n\t * @param roleIconHash - The hash provided by Discord for this role icon\n\t * @param options - Optional options for the role icon\n\t */\n\tpublic roleIcon(roleId: string, roleIconHash: string, options?: Readonly<BaseImageURLOptions>): string {\n\t\treturn this.makeURL(`/role-icons/${roleId}/${roleIconHash}`, options);\n\t}\n\n\t/**\n\t * Generates a guild invite splash URL for a guild's invite splash.\n\t *\n\t * @param guildId - The guild id that has the invite splash\n\t * @param splashHash - The hash provided by Discord for this splash\n\t * @param options - Optional options for the splash\n\t */\n\tpublic splash(guildId: string, splashHash: string, options?: Readonly<BaseImageURLOptions>): string {\n\t\treturn this.makeURL(`/splashes/${guildId}/${splashHash}`, options);\n\t}\n\n\t/**\n\t * Generates a sticker URL.\n\t *\n\t * @param stickerId - The sticker id\n\t * @param extension - The extension of the sticker\n\t * @privateRemarks\n\t * Stickers cannot have a `.webp` extension, so we default to a `.png`\n\t */\n\tpublic sticker(stickerId: string, extension: StickerExtension = 'png'): string {\n\t\treturn this.makeURL(`/stickers/${stickerId}`, { allowedExtensions: ALLOWED_STICKER_EXTENSIONS, extension });\n\t}\n\n\t/**\n\t * Generates a sticker pack banner URL.\n\t *\n\t * @param bannerId - The banner id\n\t * @param options - Optional options for the banner\n\t */\n\tpublic stickerPackBanner(bannerId: string, options?: Readonly<BaseImageURLOptions>): string {\n\t\treturn this.makeURL(`/app-assets/710982414301790216/store/${bannerId}`, options);\n\t}\n\n\t/**\n\t * Generates a team icon URL for a team's icon.\n\t *\n\t * @param teamId - The team id that has the icon\n\t * @param iconHash - The hash provided by Discord for this icon\n\t * @param options - Optional options for the icon\n\t */\n\tpublic teamIcon(teamId: string, iconHash: string, options?: Readonly<BaseImageURLOptions>): string {\n\t\treturn this.makeURL(`/team-icons/${teamId}/${iconHash}`, options);\n\t}\n\n\t/**\n\t * Generates a cover image for a guild scheduled event.\n\t *\n\t * @param scheduledEventId - The scheduled event id\n\t * @param coverHash - The hash provided by discord for this cover image\n\t * @param options - Optional options for the cover image\n\t */\n\tpublic guildScheduledEventCover(\n\t\tscheduledEventId: string,\n\t\tcoverHash: string,\n\t\toptions?: Readonly<BaseImageURLOptions>,\n\t): string {\n\t\treturn this.makeURL(`/guild-events/${scheduledEventId}/${coverHash}`, options);\n\t}\n\n\t/**\n\t * Constructs the URL for the resource, checking whether or not `hash` starts with `a_` if `dynamic` is set to `true`.\n\t *\n\t * @param route - The base cdn route\n\t * @param hash - The hash provided by Discord for this icon\n\t * @param options - Optional options for the link\n\t */\n\tprivate dynamicMakeURL(\n\t\troute: string,\n\t\thash: string,\n\t\t{ forceStatic = false, ...options }: Readonly<ImageURLOptions> = {},\n\t): string {\n\t\treturn this.makeURL(route, !forceStatic && hash.startsWith('a_') ? { ...options, extension: 'gif' } : options);\n\t}\n\n\t/**\n\t * Constructs the URL for the resource\n\t *\n\t * @param route - The base cdn route\n\t * @param options - The extension/size options for the link\n\t */\n\tprivate makeURL(\n\t\troute: string,\n\t\t{ allowedExtensions = ALLOWED_EXTENSIONS, extension = 'webp', size }: Readonly<MakeURLOptions> = {},\n\t): string {\n\t\t// eslint-disable-next-line no-param-reassign\n\t\textension = String(extension).toLowerCase();\n\n\t\tif (!allowedExtensions.includes(extension)) {\n\t\t\tthrow new RangeError(`Invalid extension provided: ${extension}\\nMust be one of: ${allowedExtensions.join(', ')}`);\n\t\t}\n\n\t\tif (size && !ALLOWED_SIZES.includes(size)) {\n\t\t\tthrow new RangeError(`Invalid size provided: ${size}\\nMust be one of: ${ALLOWED_SIZES.join(', ')}`);\n\t\t}\n\n\t\tconst url = new URL(`${this.base}${route}.${extension}`);\n\n\t\tif (size) {\n\t\t\turl.searchParams.set('size', String(size));\n\t\t}\n\n\t\treturn url.toString();\n\t}\n}\n","import type { InternalRequest, RawFile } from '../utils/types.js';\n\ninterface DiscordErrorFieldInformation {\n\tcode: string;\n\tmessage: string;\n}\n\ninterface DiscordErrorGroupWrapper {\n\t_errors: DiscordError[];\n}\n\ntype DiscordError = DiscordErrorFieldInformation | DiscordErrorGroupWrapper | string | { [k: string]: DiscordError };\n\nexport interface DiscordErrorData {\n\tcode: number;\n\terrors?: DiscordError;\n\tmessage: string;\n}\n\nexport interface OAuthErrorData {\n\terror: string;\n\terror_description?: string;\n}\n\nexport interface RequestBody {\n\tfiles: RawFile[] | undefined;\n\tjson: unknown | undefined;\n}\n\nfunction isErrorGroupWrapper(error: DiscordError): error is DiscordErrorGroupWrapper {\n\treturn Reflect.has(error as Record<string, unknown>, '_errors');\n}\n\nfunction isErrorResponse(error: DiscordError): error is DiscordErrorFieldInformation {\n\treturn typeof Reflect.get(error as Record<string, unknown>, 'message') === 'string';\n}\n\n/**\n * Represents an API error returned by Discord\n */\nexport class DiscordAPIError extends Error {\n\tpublic requestBody: RequestBody;\n\n\t/**\n\t * @param rawError - The error reported by Discord\n\t * @param code - The error code reported by Discord\n\t * @param status - The status code of the response\n\t * @param method - The method of the request that erred\n\t * @param url - The url of the request that erred\n\t * @param bodyData - The unparsed data for the request that errored\n\t */\n\tpublic constructor(\n\t\tpublic rawError: DiscordErrorData | OAuthErrorData,\n\t\tpublic code: number | string,\n\t\tpublic status: number,\n\t\tpublic method: string,\n\t\tpublic url: string,\n\t\tbodyData: Pick<InternalRequest, 'body' | 'files'>,\n\t) {\n\t\tsuper(DiscordAPIError.getMessage(rawError));\n\n\t\tthis.requestBody = { files: bodyData.files, json: bodyData.body };\n\t}\n\n\t/**\n\t * The name of the error\n\t */\n\tpublic override get name(): string {\n\t\treturn `${DiscordAPIError.name}[${this.code}]`;\n\t}\n\n\tprivate static getMessage(error: DiscordErrorData | OAuthErrorData) {\n\t\tlet flattened = '';\n\t\tif ('code' in error) {\n\t\t\tif (error.errors) {\n\t\t\t\tflattened = [...this.flattenDiscordError(error.errors)].join('\\n');\n\t\t\t}\n\n\t\t\treturn error.message && flattened\n\t\t\t\t? `${error.message}\\n${flattened}`\n\t\t\t\t: error.message || flattened || 'Unknown Error';\n\t\t}\n\n\t\treturn error.error_description ?? 'No Description';\n\t}\n\n\tprivate static *flattenDiscordError(obj: DiscordError, key = ''): IterableIterator<string> {\n\t\tif (isErrorResponse(obj)) {\n\t\t\treturn yield `${key.length ? `${key}[${obj.code}]` : `${obj.code}`}: ${obj.message}`.trim();\n\t\t}\n\n\t\tfor (const [otherKey, val] of Object.entries(obj)) {\n\t\t\tconst nextKey = otherKey.startsWith('_')\n\t\t\t\t? key\n\t\t\t\t: key\n\t\t\t\t? Number.isNaN(Number(otherKey))\n\t\t\t\t\t? `${key}.${otherKey}`\n\t\t\t\t\t: `${key}[${otherKey}]`\n\t\t\t\t: otherKey;\n\n\t\t\tif (typeof val === 'string') {\n\t\t\t\tyield val;\n\t\t\t} else if (isErrorGroupWrapper(val)) {\n\t\t\t\tfor (const error of val._errors) {\n\t\t\t\t\tyield* this.flattenDiscordError(error, nextKey);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tyield* this.flattenDiscordError(val, nextKey);\n\t\t\t}\n\t\t}\n\t}\n}\n","import type { InternalRequest } from '../utils/types.js';\nimport type { RequestBody } from './DiscordAPIError.js';\n\n/**\n * Represents a HTTP error\n */\nexport class HTTPError extends Error {\n\tpublic requestBody: RequestBody;\n\n\tpublic override name = HTTPError.name;\n\n\t/**\n\t * @param status - The status code of the response\n\t * @param statusText - The status text of the response\n\t * @param method - The method of the request that erred\n\t * @param url - The url of the request that erred\n\t * @param bodyData - The unparsed data for the request that errored\n\t */\n\tpublic constructor(\n\t\tpublic status: number,\n\t\tstatusText: string,\n\t\tpublic method: string,\n\t\tpublic url: string,\n\t\tbodyData: Pick<InternalRequest, 'body' | 'files'>,\n\t) {\n\t\tsuper(statusText);\n\t\tthis.requestBody = { files: bodyData.files, json: bodyData.body };\n\t}\n}\n","import type { RateLimitData } from '../utils/types.js';\n\nexport class RateLimitError extends Error implements RateLimitData {\n\tpublic timeToReset: number;\n\n\tpublic limit: number;\n\n\tpublic method: string;\n\n\tpublic hash: string;\n\n\tpublic url: string;\n\n\tpublic route: string;\n\n\tpublic majorParameter: string;\n\n\tpublic global: boolean;\n\n\tpublic constructor({ timeToReset, limit, method, hash, url, route, majorParameter, global }: RateLimitData) {\n\t\tsuper();\n\t\tthis.timeToReset = timeToReset;\n\t\tthis.limit = limit;\n\t\tthis.method = method;\n\t\tthis.hash = hash;\n\t\tthis.url = url;\n\t\tthis.route = route;\n\t\tthis.majorParameter = majorParameter;\n\t\tthis.global = global;\n\t}\n\n\t/**\n\t * The name of the error\n\t */\n\tpublic override get name(): string {\n\t\treturn `${RateLimitError.name}[${this.route}]`;\n\t}\n}\n","import { Collection } from '@discordjs/collection';\nimport { DiscordSnowflake } from '@sapphire/snowflake';\nimport { AsyncEventEmitter } from '@vladfrangu/async_event_emitter';\nimport { filetypeinfo } from 'magic-bytes.js';\nimport type { RequestInit, BodyInit, Dispatcher } from 'undici';\nimport { CDN } from './CDN.js';\nimport { BurstHandler } from './handlers/BurstHandler.js';\nimport { SequentialHandler } from './handlers/SequentialHandler.js';\nimport type { IHandler } from './interfaces/Handler.js';\nimport {\n\tBurstHandlerMajorIdKey,\n\tDefaultRestOptions,\n\tDefaultUserAgent,\n\tOverwrittenMimeTypes,\n\tRESTEvents,\n} from './utils/constants.js';\nimport { RequestMethod } from './utils/types.js';\nimport type {\n\tRESTOptions,\n\tResponseLike,\n\tRestEventsMap,\n\tHashData,\n\tInternalRequest,\n\tRouteLike,\n\tRequestHeaders,\n\tRouteData,\n\tRequestData,\n} from './utils/types.js';\nimport { isBufferLike, parseResponse } from './utils/utils.js';\n\n/**\n * Represents the class that manages handlers for endpoints\n */\nexport class REST extends AsyncEventEmitter<RestEventsMap> {\n\t/**\n\t * The {@link https://undici.nodejs.org/#/docs/api/Agent | Agent} for all requests\n\t * performed by this manager.\n\t */\n\tpublic agent: Dispatcher | null = null;\n\n\tpublic readonly cdn: CDN;\n\n\t/**\n\t * The number of requests remaining in the global bucket\n\t */\n\tpublic globalRemaining: number;\n\n\t/**\n\t * The promise used to wait out the global rate limit\n\t */\n\tpublic globalDelay: Promise<void> | null = null;\n\n\t/**\n\t * The timestamp at which the global bucket resets\n\t */\n\tpublic globalReset = -1;\n\n\t/**\n\t * API bucket hashes that are cached from provided routes\n\t */\n\tpublic readonly hashes = new Collection<string, HashData>();\n\n\t/**\n\t * Request handlers created from the bucket hash and the major parameters\n\t */\n\tpublic readonly handlers = new Collection<string, IHandler>();\n\n\t#token: string | null = null;\n\n\tprivate hashTimer!: NodeJS.Timer | number;\n\n\tprivate handlerTimer!: NodeJS.Timer | number;\n\n\tpublic readonly options: RESTOptions;\n\n\tpublic constructor(options: Partial<RESTOptions> = {}) {\n\t\tsuper();\n\t\tthis.cdn = new CDN(options.cdn ?? DefaultRestOptions.cdn);\n\t\tthis.options = { ...DefaultRestOptions, ...options };\n\t\tthis.options.offset = Math.max(0, this.options.offset);\n\t\tthis.globalRemaining = Math.max(1, this.options.globalRequestsPerSecond);\n\t\tthis.agent = options.agent ?? null;\n\n\t\t// Start sweepers\n\t\tthis.setupSweepers();\n\t}\n\n\tprivate setupSweepers() {\n\t\t// eslint-disable-next-line unicorn/consistent-function-scoping\n\t\tconst validateMaxInterval = (interval: number) => {\n\t\t\tif (interval > 14_400_000) {\n\t\t\t\tthrow new Error('Cannot set an interval greater than 4 hours');\n\t\t\t}\n\t\t};\n\n\t\tif (this.options.hashSweepInterval !== 0 && this.options.hashSweepInterval !== Number.POSITIVE_INFINITY) {\n\t\t\tvalidateMaxInterval(this.options.hashSweepInterval);\n\t\t\tthis.hashTimer = setInterval(() => {\n\t\t\t\tconst sweptHashes = new Collection<string, HashData>();\n\t\t\t\tconst currentDate = Date.now();\n\n\t\t\t\t// Begin sweeping hash based on lifetimes\n\t\t\t\tthis.hashes.sweep((val, key) => {\n\t\t\t\t\t// `-1` indicates a global hash\n\t\t\t\t\tif (val.lastAccess === -1) return false;\n\n\t\t\t\t\t// Check if lifetime has been exceeded\n\t\t\t\t\tconst shouldSweep = Math.floor(currentDate - val.lastAccess) > this.options.hashLifetime;\n\n\t\t\t\t\t// Add hash to collection of swept hashes\n\t\t\t\t\tif (shouldSweep) {\n\t\t\t\t\t\t// Add to swept hashes\n\t\t\t\t\t\tsweptHashes.set(key, val);\n\n\t\t\t\t\t\t// Emit debug information\n\t\t\t\t\t\tthis.emit(RESTEvents.Debug, `Hash ${val.value} for ${key} swept due to lifetime being exceeded`);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn shouldSweep;\n\t\t\t\t});\n\n\t\t\t\t// Fire event\n\t\t\t\tthis.emit(RESTEvents.HashSweep, sweptHashes);\n\t\t\t}, this.options.hashSweepInterval);\n\n\t\t\tthis.hashTimer.unref?.();\n\t\t}\n\n\t\tif (this.options.handlerSweepInterval !== 0 && this.options.handlerSweepInterval !== Number.POSITIVE_INFINITY) {\n\t\t\tvalidateMaxInterval(this.options.handlerSweepInterval);\n\t\t\tthis.handlerTimer = setInterval(() => {\n\t\t\t\tconst sweptHandlers = new Collection<string, IHandler>();\n\n\t\t\t\t// Begin sweeping handlers based on activity\n\t\t\t\tthis.handlers.sweep((val, key) => {\n\t\t\t\t\tconst { inactive } = val;\n\n\t\t\t\t\t// Collect inactive handlers\n\t\t\t\t\tif (inactive) {\n\t\t\t\t\t\tsweptHandlers.set(key, val);\n\t\t\t\t\t\tthis.emit(RESTEvents.Debug, `Handler ${val.id} for ${key} swept due to being inactive`);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn inactive;\n\t\t\t\t});\n\n\t\t\t\t// Fire event\n\t\t\t\tthis.emit(RESTEvents.HandlerSweep, sweptHandlers);\n\t\t\t}, this.options.handlerSweepInterval);\n\n\t\t\tthis.handlerTimer.unref?.();\n\t\t}\n\t}\n\n\t/**\n\t * Runs a get request from the api\n\t *\n\t * @param fullRoute - The full route to query\n\t * @param options - Optional request options\n\t */\n\tpublic async get(fullRoute: RouteLike, options: RequestData = {}) {\n\t\treturn this.request({ ...options, fullRoute, method: RequestMethod.Get });\n\t}\n\n\t/**\n\t * Runs a delete request from the api\n\t *\n\t * @param fullRoute - The full route to query\n\t * @param options - Optional request options\n\t */\n\tpublic async delete(fullRoute: RouteLike, options: RequestData = {}) {\n\t\treturn this.request({ ...options, fullRoute, method: RequestMethod.Delete });\n\t}\n\n\t/**\n\t * Runs a post request from the api\n\t *\n\t * @param fullRoute - The full route to query\n\t * @param options - Optional request options\n\t */\n\tpublic async post(fullRoute: RouteLike, options: RequestData = {}) {\n\t\treturn this.request({ ...options, fullRoute, method: RequestMethod.Post });\n\t}\n\n\t/**\n\t * Runs a put request from the api\n\t *\n\t * @param fullRoute - The full route to query\n\t * @param options - Optional request options\n\t */\n\tpublic async put(fullRoute: RouteLike, options: RequestData = {}) {\n\t\treturn this.request({ ...options, fullRoute, method: RequestMethod.Put });\n\t}\n\n\t/**\n\t * Runs a patch request from the api\n\t *\n\t * @param fullRoute - The full route to query\n\t * @param options - Optional request options\n\t */\n\tpublic async patch(fullRoute: RouteLike, options: RequestData = {}) {\n\t\treturn this.request({ ...options, fullRoute, method: RequestMethod.Patch });\n\t}\n\n\t/**\n\t * Runs a request from the api\n\t *\n\t * @param options - Request options\n\t */\n\tpublic async request(options: InternalRequest) {\n\t\tconst response = await this.queueRequest(options);\n\t\treturn parseResponse(response);\n\t}\n\n\t/**\n\t * Sets the default agent to use for requests performed by this manager\n\t *\n\t * @param agent - The agent to use\n\t */\n\tpublic setAgent(agent: Dispatcher) {\n\t\tthis.agent = agent;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the authorization token that should be used for requests\n\t *\n\t * @param token - The authorization token to use\n\t */\n\tpublic setToken(token: string) {\n\t\tthis.#token = token;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Queues a request to be sent\n\t *\n\t * @param request - All the information needed to make a request\n\t * @returns The response from the api request\n\t */\n\tpublic async queueRequest(request: InternalRequest): Promise<ResponseLike> {\n\t\t// Generalize the endpoint to its route data\n\t\tconst routeId = REST.generateRouteData(request.fullRoute, request.method);\n\t\t// Get the bucket hash for the generic route, or point to a global route otherwise\n\t\tconst hash = this.hashes.get(`${request.method}:${routeId.bucketRoute}`) ?? {\n\t\t\tvalue: `Global(${request.method}:${routeId.bucketRoute})`,\n\t\t\tlastAccess: -1,\n\t\t};\n\n\t\t// Get the request handler for the obtained hash, with its major parameter\n\t\tconst handler =\n\t\t\tthis.handlers.get(`${hash.value}:${routeId.majorParameter}`) ??\n\t\t\tthis.createHandler(hash.value, routeId.majorParameter);\n\n\t\t// Resolve the request into usable fetch options\n\t\tconst { url, fetchOptions } = await this.resolveRequest(request);\n\n\t\t// Queue the request\n\t\treturn handler.queueRequest(routeId, url, fetchOptions, {\n\t\t\tbody: request.body,\n\t\t\tfiles: request.files,\n\t\t\tauth: request.auth !== false,\n\t\t\tsignal: request.signal,\n\t\t});\n\t}\n\n\t/**\n\t * Creates a new rate limit handler from a hash, based on the hash and the major parameter\n\t *\n\t * @param hash - The hash for the route\n\t * @param majorParameter - The major parameter for this handler\n\t * @internal\n\t */\n\tprivate createHandler(hash: string, majorParameter: string) {\n\t\t// Create the async request queue to handle requests\n\t\tconst queue =\n\t\t\tmajorParameter === BurstHandlerMajorIdKey\n\t\t\t\t? new BurstHandler(this, hash, majorParameter)\n\t\t\t\t: new SequentialHandler(this, hash, majorParameter);\n\t\t// Save the queue based on its id\n\t\tthis.handlers.set(queue.id, queue);\n\n\t\treturn queue;\n\t}\n\n\t/**\n\t * Formats the request data to a usable format for fetch\n\t *\n\t * @param request - The request data\n\t */\n\tprivate async resolveRequest(request: InternalRequest): Promise<{ fetchOptions: RequestInit; url: string }> {\n\t\tconst { options } = this;\n\n\t\tlet query = '';\n\n\t\t// If a query option is passed, use it\n\t\tif (request.query) {\n\t\t\tconst resolvedQuery = request.query.toString();\n\t\t\tif (resolvedQuery !== '') {\n\t\t\t\tquery = `?${resolvedQuery}`;\n\t\t\t}\n\t\t}\n\n\t\t// Create the required headers\n\t\tconst headers: RequestHeaders = {\n\t\t\t...this.options.headers,\n\t\t\t'User-Agent': `${DefaultUserAgent} ${options.userAgentAppendix}`.trim(),\n\t\t};\n\n\t\t// If this request requires authorization (allowing non-\"authorized\" requests for webhooks)\n\t\tif (request.auth !== false) {\n\t\t\t// If we haven't received a token, throw an error\n\t\t\tif (!this.#token) {\n\t\t\t\tthrow new Error('Expected token to be set for this request, but none was present');\n\t\t\t}\n\n\t\t\theaders.Authorization = `${request.authPrefix ?? this.options.authPrefix} ${this.#token}`;\n\t\t}\n\n\t\t// If a reason was set, set it's appropriate header\n\t\tif (request.reason?.length) {\n\t\t\theaders['X-Audit-Log-Reason'] = encodeURIComponent(request.reason);\n\t\t}\n\n\t\t// Format the full request URL (api base, optional version, endpoint, optional querystring)\n\t\tconst url = `${options.api}${request.versioned === false ? '' : `/v${options.version}`}${\n\t\t\trequest.fullRoute\n\t\t}${query}`;\n\n\t\tlet finalBody: RequestInit['body'];\n\t\tlet additionalHeaders: Record<string, string> = {};\n\n\t\tif (request.files?.length) {\n\t\t\tconst formData = new FormData();\n\n\t\t\t// Attach all files to the request\n\t\t\tfor (const [index, file] of request.files.entries()) {\n\t\t\t\tconst fileKey = file.key ?? `files[${index}]`;\n\n\t\t\t\t// https://developer.mozilla.org/en-US/docs/Web/API/FormData/append#parameters\n\t\t\t\t// FormData.append only accepts a string or Blob.\n\t\t\t\t// https://developer.mozilla.org/en-US/docs/Web/API/Blob/Blob#parameters\n\t\t\t\t// The Blob constructor accepts TypedArray/ArrayBuffer, strings, and Blobs.\n\t\t\t\tif (isBufferLike(file.data)) {\n\t\t\t\t\t// Try to infer the content type from the buffer if one isn't passed\n\t\t\t\t\tlet contentType = file.contentType;\n\n\t\t\t\t\tif (!contentType) {\n\t\t\t\t\t\tconst [parsedType] = filetypeinfo(file.data);\n\n\t\t\t\t\t\tif (parsedType) {\n\t\t\t\t\t\t\tcontentType =\n\t\t\t\t\t\t\t\tOverwrittenMimeTypes[parsedType.mime as keyof typeof OverwrittenMimeTypes] ??\n\t\t\t\t\t\t\t\tparsedType.mime ??\n\t\t\t\t\t\t\t\t'application/octet-stream';\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tformData.append(fileKey, new Blob([file.data], { type: contentType }), file.name);\n\t\t\t\t} else {\n\t\t\t\t\tformData.append(fileKey, new Blob([`${file.data}`], { type: file.contentType }), file.name);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If a JSON body was added as well, attach it to the form data, using payload_json unless otherwise specified\n\t\t\t// eslint-disable-next-line no-eq-null, eqeqeq\n\t\t\tif (request.body != null) {\n\t\t\t\tif (request.appendToFormData) {\n\t\t\t\t\tfor (const [key, value] of Object.entries(request.body as Record<string, unknown>)) {\n\t\t\t\t\t\tformData.append(key, value);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tformData.append('payload_json', JSON.stringify(request.body));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Set the final body to the form data\n\t\t\tfinalBody = formData;\n\n\t\t\t// eslint-disable-next-line no-eq-null, eqeqeq\n\t\t} else if (request.body != null) {\n\t\t\tif (request.passThroughBody) {\n\t\t\t\tfinalBody = request.body as BodyInit;\n\t\t\t} else {\n\t\t\t\t// Stringify the JSON data\n\t\t\t\tfinalBody = JSON.stringify(request.body);\n\t\t\t\t// Set the additional headers to specify the content-type\n\t\t\t\tadditionalHeaders = { 'Content-Type': 'application/json' };\n\t\t\t}\n\t\t}\n\n\t\tconst method = request.method.toUpperCase();\n\n\t\t// The non null assertions in the following block are due to exactOptionalPropertyTypes, they have been tested to work with undefined\n\t\tconst fetchOptions: RequestInit = {\n\t\t\t// Set body to null on get / head requests. This does not follow fetch spec (likely because it causes subtle bugs) but is aligned with what request was doing\n\t\t\tbody: ['GET', 'HEAD'].includes(method) ? null : finalBody!,\n\t\t\theaders: { ...request.headers, ...additionalHeaders, ...headers } as Record<string, string>,\n\t\t\tmethod,\n\t\t\t// Prioritize setting an agent per request, use the agent for this instance otherwise.\n\t\t\tdispatcher: request.dispatcher ?? this.agent ?? undefined!,\n\t\t};\n\n\t\treturn { url, fetchOptions };\n\t}\n\n\t/**\n\t * Stops the hash sweeping interval\n\t */\n\tpublic clearHashSweeper() {\n\t\tclearInterval(this.hashTimer);\n\t}\n\n\t/**\n\t * Stops the request handler sweeping interval\n\t */\n\tpublic clearHandlerSweeper() {\n\t\tclearInterval(this.handlerTimer);\n\t}\n\n\t/**\n\t * Generates route data for an endpoint:method\n\t *\n\t * @param endpoint - The raw endpoint to generalize\n\t * @param method - The HTTP method this endpoint is called without\n\t * @internal\n\t */\n\tprivate static generateRouteData(endpoint: RouteLike, method: RequestMethod): RouteData {\n\t\tif (endpoint.startsWith('/interactions/') && endpoint.endsWith('/callback')) {\n\t\t\treturn {\n\t\t\t\tmajorParameter: BurstHandlerMajorIdKey,\n\t\t\t\tbucketRoute: '/interactions/:id/:token/callback',\n\t\t\t\toriginal: endpoint,\n\t\t\t};\n\t\t}\n\n\t\tconst majorIdMatch = /^\\/(?:channels|guilds|webhooks)\\/(\\d{17,19})/.exec(endpoint);\n\n\t\t// Get the major id for this route - global otherwise\n\t\tconst majorId = majorIdMatch?.[1] ?? 'global';\n\n\t\tconst baseRoute = endpoint\n\t\t\t// Strip out all ids\n\t\t\t.replaceAll(/\\d{17,19}/g, ':id')\n\t\t\t// Strip out reaction as they fall under the same bucket\n\t\t\t.replace(/\\/reactions\\/(.*)/, '/reactions/:reaction');\n\n\t\tlet exceptions = '';\n\n\t\t// Hard-Code Old Message Deletion Exception (2 week+ old messages are a different bucket)\n\t\t// https://github.com/discord/discord-api-docs/issues/1295\n\t\tif (method === RequestMethod.Delete && baseRoute === '/channels/:id/messages/:id') {\n\t\t\tconst id = /\\d{17,19}$/.exec(endpoint)![0]!;\n\t\t\tconst timestamp = DiscordSnowflake.timestampFrom(id);\n\t\t\tif (Date.now() - timestamp > 1_000 * 60 * 60 * 24 * 14) {\n\t\t\t\texceptions += '/Delete Old Message';\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tmajorParameter: majorId,\n\t\t\tbucketRoute: baseRoute + exceptions,\n\t\t\toriginal: endpoint,\n\t\t};\n\t}\n}\n","import type { Readable } from 'node:stream';\nimport type { ReadableStream } from 'node:stream/web';\nimport type { Collection } from '@discordjs/collection';\nimport type { Agent, Dispatcher, RequestInit, BodyInit, Response } from 'undici';\nimport type { IHandler } from '../interfaces/Handler.js';\n\nexport interface RestEvents {\n\thandlerSweep: [sweptHandlers: Collection<string, IHandler>];\n\thashSweep: [sweptHashes: Collection<string, HashData>];\n\tinvalidRequestWarning: [invalidRequestInfo: InvalidRequestWarningData];\n\trateLimited: [rateLimitInfo: RateLimitData];\n\tresponse: [request: APIRequest, response: ResponseLike];\n\trestDebug: [info: string];\n}\n\nexport type RestEventsMap = {\n\t[K in keyof RestEvents]: RestEvents[K];\n};\n\n/**\n * Options to be passed when creating the REST instance\n */\nexport interface RESTOptions {\n\t/**\n\t * The agent to set globally\n\t */\n\tagent: Dispatcher | null;\n\t/**\n\t * The base api path, without version\n\t *\n\t * @defaultValue `'https://discord.com/api'`\n\t */\n\tapi: string;\n\t/**\n\t * The authorization prefix to use for requests, useful if you want to use\n\t * bearer tokens\n\t *\n\t * @defaultValue `'Bot'`\n\t */\n\tauthPrefix: 'Bearer' | 'Bot';\n\t/**\n\t * The cdn path\n\t *\n\t * @defaultValue `'https://cdn.discordapp.com'`\n\t */\n\tcdn: string;\n\t/**\n\t * How many requests to allow sending per second (Infinity for unlimited, 50 for the standard global limit used by Discord)\n\t *\n\t * @defaultValue `50`\n\t */\n\tglobalRequestsPerSecond: number;\n\t/**\n\t * The amount of time in milliseconds that passes between each hash sweep. (defaults to 1h)\n\t *\n\t * @defaultValue `3_600_000`\n\t */\n\thandlerSweepInterval: number;\n\t/**\n\t * The maximum amount of time a hash can exist in milliseconds without being hit with a request (defaults to 24h)\n\t *\n\t * @defaultValue `86_400_000`\n\t */\n\thashLifetime: number;\n\t/**\n\t * The amount of time in milliseconds that passes between each hash sweep. (defaults to 4h)\n\t *\n\t * @defaultValue `14_400_000`\n\t */\n\thashSweepInterval: number;\n\t/**\n\t * Additional headers to send for all API requests\n\t *\n\t * @defaultValue `{}`\n\t */\n\theaders: Record<string, string>;\n\t/**\n\t * The number of invalid REST requests (those that return 401, 403, or 429) in a 10 minute window between emitted warnings (0 for no warnings).\n\t * That is, if set to 500, warnings will be emitted at invalid request number 500, 1000, 1500, and so on.\n\t *\n\t * @defaultValue `0`\n\t */\n\tinvalidRequestWarningInterval: number;\n\t/**\n\t * The method called to perform the actual HTTP request given a url and web `fetch` options\n\t * For example, to use global fetch, simply provide `makeRequest: fetch`\n\t */\n\tmakeRequest(url: string, init: RequestInit): Promise<ResponseLike>;\n\t/**\n\t * The extra offset to add to rate limits in milliseconds\n\t *\n\t * @defaultValue `50`\n\t */\n\toffset: number;\n\t/**\n\t * Determines how rate limiting and pre-emptive throttling should be handled.\n\t * When an array of strings, each element is treated as a prefix for the request route\n\t * (e.g. `/channels` to match any route starting with `/channels` such as `/channels/:id/messages`)\n\t * for which to throw {@link RateLimitError}s. All other request routes will be queued normally\n\t *\n\t * @defaultValue `null`\n\t */\n\trejectOnRateLimit: RateLimitQueueFilter | string[] | null;\n\t/**\n\t * The number of retries for errors with the 500 code, or errors\n\t * that timeout\n\t *\n\t * @defaultValue `3`\n\t */\n\tretries: number;\n\t/**\n\t * The time to wait in milliseconds before a request is aborted\n\t *\n\t * @defaultValue `15_000`\n\t */\n\ttimeout: number;\n\t/**\n\t * Extra information to add to the user agent\n\t *\n\t * @defaultValue DefaultUserAgentAppendix\n\t */\n\tuserAgentAppendix: string;\n\t/**\n\t * The version of the API to use\n\t *\n\t * @defaultValue `'10'`\n\t */\n\tversion: string;\n}\n\n/**\n * Data emitted on `RESTEvents.RateLimited`\n */\nexport interface RateLimitData {\n\t/**\n\t * Whether the rate limit that was reached was the global limit\n\t */\n\tglobal: boolean;\n\t/**\n\t * The bucket hash for this request\n\t */\n\thash: string;\n\t/**\n\t * The amount of requests we can perform before locking requests\n\t */\n\tlimit: number;\n\t/**\n\t * The major parameter of the route\n\t *\n\t * For example, in `/channels/x`, this will be `x`.\n\t * If there is no major parameter (e.g: `/bot/gateway`) this will be `global`.\n\t */\n\tmajorParameter: string;\n\t/**\n\t * The HTTP method being performed\n\t */\n\tmethod: string;\n\t/**\n\t * The route being hit in this request\n\t */\n\troute: string;\n\t/**\n\t * The time, in milliseconds, until the request-lock is reset\n\t */\n\ttimeToReset: number;\n\t/**\n\t * The full URL for this request\n\t */\n\turl: string;\n}\n\n/**\n * A function that determines whether the rate limit hit should throw an Error\n */\nexport type RateLimitQueueFilter = (rateLimitData: RateLimitData) => Promise<boolean> | boolean;\n\nexport interface APIRequest {\n\t/**\n\t * The data that was used to form the body of this request\n\t */\n\tdata: HandlerRequestData;\n\t/**\n\t * The HTTP method used in this request\n\t */\n\tmethod: string;\n\t/**\n\t * Additional HTTP options for this request\n\t */\n\toptions: RequestInit;\n\t/**\n\t * The full path used to make the request\n\t */\n\tpath: RouteLike;\n\t/**\n\t * The number of times this request has been attempted\n\t */\n\tretries: number;\n\t/**\n\t * The API route identifying the ratelimit for this request\n\t */\n\troute: string;\n}\n\nexport interface ResponseLike\n\textends Pick<Response, 'arrayBuffer' | 'bodyUsed' | 'headers' | 'json' | 'ok' | 'status' | 'statusText' | 'text'> {\n\tbody: Readable | ReadableStream | null;\n}\n\nexport interface InvalidRequestWarningData {\n\t/**\n\t * Number of invalid requests that have been made in the window\n\t */\n\tcount: number;\n\t/**\n\t * Time in milliseconds remaining before the count resets\n\t */\n\tremainingTime: number;\n}\n\n/**\n * Represents a file to be added to the request\n */\nexport interface RawFile {\n\t/**\n\t * Content-Type of the file\n\t */\n\tcontentType?: string;\n\t/**\n\t * The actual data for the file\n\t */\n\tdata: Buffer | Uint8Array | boolean | number | string;\n\t/**\n\t * An explicit key to use for key of the formdata field for this file.\n\t * When not provided, the index of the file in the files array is used in the form `files[${index}]`.\n\t * If you wish to alter the placeholder snowflake, you must provide this property in the same form (`files[${placeholder}]`)\n\t */\n\tkey?: string;\n\t/**\n\t * The name of the file\n\t */\n\tname: string;\n}\n\n/**\n * Represents possible data to be given to an endpoint\n */\nexport interface RequestData {\n\t/**\n\t * Whether to append JSON data to form data instead of `payload_json` when sending files\n\t */\n\tappendToFormData?: boolean;\n\t/**\n\t * If this request needs the `Authorization` header\n\t *\n\t * @defaultValue `true`\n\t */\n\tauth?: boolean;\n\t/**\n\t * The authorization prefix to use for this request, useful if you use this with bearer tokens\n\t *\n\t * @defaultValue `'Bot'`\n\t */\n\tauthPrefix?: 'Bearer' | 'Bot';\n\t/**\n\t * The body to send to this request.\n\t * If providing as BodyInit, set `passThroughBody: true`\n\t */\n\tbody?: BodyInit | unknown;\n\t/**\n\t * The {@link https://undici.nodejs.org/#/docs/api/Agent | Agent} to use for the request.\n\t */\n\tdispatcher?: Agent;\n\t/**\n\t * Files to be attached to this request\n\t */\n\tfiles?: RawFile[] | undefined;\n\t/**\n\t * Additional headers to add to this request\n\t */\n\theaders?: Record<string, string>;\n\t/**\n\t * Whether to pass-through the body property directly to `fetch()`.\n\t * <warn>This only applies when files is NOT present</warn>\n\t */\n\tpassThroughBody?: boolean;\n\t/**\n\t * Query string parameters to append to the called endpoint\n\t */\n\tquery?: URLSearchParams;\n\t/**\n\t * Reason to show in the audit logs\n\t */\n\treason?: string | undefined;\n\t/**\n\t * The signal to abort the queue entry or the REST call, where applicable\n\t */\n\tsignal?: AbortSignal | undefined;\n\t/**\n\t * If this request should be versioned\n\t *\n\t * @defaultValue `true`\n\t */\n\tversioned?: boolean;\n}\n\n/**\n * Possible headers for an API call\n */\nexport interface RequestHeaders {\n\tAuthorization?: string;\n\t'User-Agent': string;\n\t'X-Audit-Log-Reason'?: string;\n}\n\n/**\n * Possible API methods to be used when doing requests\n */\nexport enum RequestMethod {\n\tDelete = 'DELETE',\n\tGet = 'GET',\n\tPatch = 'PATCH',\n\tPost = 'POST',\n\tPut = 'PUT',\n}\n\nexport type RouteLike = `/${string}`;\n\n/**\n * Internal request options\n *\n * @internal\n */\nexport interface InternalRequest extends RequestData {\n\tfullRoute: RouteLike;\n\tmethod: RequestMethod;\n}\n\nexport type HandlerRequestData = Pick<InternalRequest, 'auth' | 'body' | 'files' | 'signal'>;\n\n/**\n * Parsed route data for an endpoint\n *\n * @internal\n */\nexport interface RouteData {\n\tbucketRoute: string;\n\tmajorParameter: string;\n\toriginal: RouteLike;\n}\n\n/**\n * Represents a hash and its associated fields\n *\n * @internal\n */\nexport interface HashData {\n\tlastAccess: number;\n\tvalue: string;\n}\n","import type { RESTPatchAPIChannelJSONBody, Snowflake } from 'discord-api-types/v10';\nimport type { REST } from '../REST.js';\nimport { RateLimitError } from '../errors/RateLimitError.js';\nimport { RequestMethod, type RateLimitData, type ResponseLike } from './types.js';\n\nfunction serializeSearchParam(value: unknown): string | null {\n\tswitch (typeof value) {\n\t\tcase 'string':\n\t\t\treturn value;\n\t\tcase 'number':\n\t\tcase 'bigint':\n\t\tcase 'boolean':\n\t\t\treturn value.toString();\n\t\tcase 'object':\n\t\t\tif (value === null) return null;\n\t\t\tif (value instanceof Date) {\n\t\t\t\treturn Number.isNaN(value.getTime()) ? null : value.toISOString();\n\t\t\t}\n\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-base-to-string\n\t\t\tif (typeof value.toString === 'function' && value.toString !== Object.prototype.toString) return value.toString();\n\t\t\treturn null;\n\t\tdefault:\n\t\t\treturn null;\n\t}\n}\n\n/**\n * Creates and populates an URLSearchParams instance from an object, stripping\n * out null and undefined values, while also coercing non-strings to strings.\n *\n * @param options - The options to use\n * @returns A populated URLSearchParams instance\n */\nexport function makeURLSearchParams<T extends object>(options?: Readonly<T>) {\n\tconst params = new URLSearchParams();\n\tif (!options) return params;\n\n\tfor (const [key, value] of Object.entries(options)) {\n\t\tconst serialized = serializeSearchParam(value);\n\t\tif (serialized !== null) params.append(key, serialized);\n\t}\n\n\treturn params;\n}\n\n/**\n * Converts the response to usable data\n *\n * @param res - The fetch response\n */\nexport async function parseResponse(res: ResponseLike): Promise<unknown> {\n\tif (res.headers.get('Content-Type')?.startsWith('application/json')) {\n\t\treturn res.json();\n\t}\n\n\treturn res.arrayBuffer();\n}\n\n/**\n * Check whether a request falls under a sublimit\n *\n * @param bucketRoute - The buckets route identifier\n * @param body - The options provided as JSON data\n * @param method - The HTTP method that will be used to make the request\n * @returns Whether the request falls under a sublimit\n */\nexport function hasSublimit(bucketRoute: string, body?: unknown, method?: string): boolean {\n\t// TODO: Update for new sublimits\n\t// Currently known sublimits:\n\t// Editing channel `name` or `topic`\n\tif (bucketRoute === '/channels/:id') {\n\t\tif (typeof body !== 'object' || body === null) return false;\n\t\t// This should never be a POST body, but just in case\n\t\tif (method !== RequestMethod.Patch) return false;\n\t\tconst castedBody = body as RESTPatchAPIChannelJSONBody;\n\t\treturn ['name', 'topic'].some((key) => Reflect.has(castedBody, key));\n\t}\n\n\t// If we are checking if a request has a sublimit on a route not checked above, sublimit all requests to avoid a flood of 429s\n\treturn true;\n}\n\n/**\n * Check whether an error indicates that a retry can be attempted\n *\n * @param error - The error thrown by the network request\n * @returns Whether the error indicates a retry should be attempted\n */\nexport function shouldRetry(error: Error | NodeJS.ErrnoException) {\n\t// Retry for possible timed out requests\n\tif (error.name === 'AbortError') return true;\n\t// Downlevel ECONNRESET to retry as it may be recoverable\n\treturn ('code' in error && error.code === 'ECONNRESET') || error.message.includes('ECONNRESET');\n}\n\n/**\n * Determines whether the request should be queued or whether a RateLimitError should be thrown\n *\n * @internal\n */\nexport async function onRateLimit(manager: REST, rateLimitData: RateLimitData) {\n\tconst { options } = manager;\n\tif (!options.rejectOnRateLimit) return;\n\n\tconst shouldThrow =\n\t\ttypeof options.rejectOnRateLimit === 'function'\n\t\t\t? await options.rejectOnRateLimit(rateLimitData)\n\t\t\t: options.rejectOnRateLimit.some((route) => rateLimitData.route.startsWith(route.toLowerCase()));\n\tif (shouldThrow) {\n\t\tthrow new RateLimitError(rateLimitData);\n\t}\n}\n\n/**\n * Calculates the default avatar index for a given user id.\n *\n * @param userId - The user id to calculate the default avatar index for\n */\nexport function calculateUserDefaultAvatarIndex(userId: Snowflake) {\n\treturn Number(BigInt(userId) >> 22n) % 6;\n}\n\n/**\n * Sleeps for a given amount of time.\n *\n * @param ms - The amount of time (in milliseconds) to sleep for\n */\nexport async function sleep(ms: number): Promise<void> {\n\treturn new Promise<void>((resolve) => {\n\t\tsetTimeout(() => resolve(), ms);\n\t});\n}\n\n/**\n * Verifies that a value is a buffer-like object.\n *\n * @param value - The value to check\n */\nexport function isBufferLike(value: unknown): value is ArrayBuffer | Buffer | Uint8Array | Uint8ClampedArray {\n\treturn value instanceof ArrayBuffer || value instanceof Uint8Array || value instanceof Uint8ClampedArray;\n}\n","import type { RequestInit } from 'undici';\nimport type { REST } from '../REST.js';\nimport type { DiscordErrorData, OAuthErrorData } from '../errors/DiscordAPIError.js';\nimport { DiscordAPIError } from '../errors/DiscordAPIError.js';\nimport { HTTPError } from '../errors/HTTPError.js';\nimport { RESTEvents } from '../utils/constants.js';\nimport type { ResponseLike, HandlerRequestData, RouteData } from '../utils/types.js';\nimport { parseResponse, shouldRetry } from '../utils/utils.js';\n\n/**\n * Invalid request limiting is done on a per-IP basis, not a per-token basis.\n * The best we can do is track invalid counts process-wide (on the theory that\n * users could have multiple bots run from one process) rather than per-bot.\n * Therefore, store these at file scope here rather than in the client's\n * RESTManager object.\n */\nlet invalidCount = 0;\nlet invalidCountResetTime: number | null = null;\n\n/**\n * Increment the invalid request count and emit warning if necessary\n *\n * @internal\n */\nexport function incrementInvalidCount(manager: REST) {\n\tif (!invalidCountResetTime || invalidCountResetTime < Date.now()) {\n\t\tinvalidCountResetTime = Date.now() + 1_000 * 60 * 10;\n\t\tinvalidCount = 0;\n\t}\n\n\tinvalidCount++;\n\n\tconst emitInvalid =\n\t\tmanager.options.invalidRequestWarningInterval > 0 &&\n\t\tinvalidCount % manager.options.invalidRequestWarningInterval === 0;\n\tif (emitInvalid) {\n\t\t// Let library users know periodically about invalid requests\n\t\tmanager.emit(RESTEvents.InvalidRequestWarning, {\n\t\t\tcount: invalidCount,\n\t\t\tremainingTime: invalidCountResetTime - Date.now(),\n\t\t});\n\t}\n}\n\n/**\n * Performs the actual network request for a request handler\n *\n * @param manager - The manager that holds options and emits informational events\n * @param routeId - The generalized api route with literal ids for major parameters\n * @param url - The fully resolved url to make the request to\n * @param options - The fetch options needed to make the request\n * @param requestData - Extra data from the user's request needed for errors and additional processing\n * @param retries - The number of retries this request has already attempted (recursion occurs on the handler)\n * @returns The respond from the network or `null` when the request should be retried\n * @internal\n */\nexport async function makeNetworkRequest(\n\tmanager: REST,\n\trouteId: RouteData,\n\turl: string,\n\toptions: RequestInit,\n\trequestData: HandlerRequestData,\n\tretries: number,\n) {\n\tconst controller = new AbortController();\n\tconst timeout = setTimeout(() => controller.abort(), manager.options.timeout);\n\tif (requestData.signal) {\n\t\t// If the user signal was aborted, abort the controller, else abort the local signal.\n\t\t// The reason why we don't re-use the user's signal, is because users may use the same signal for multiple\n\t\t// requests, and we do not want to cause unexpected side-effects.\n\t\tif (requestData.signal.aborted) controller.abort();\n\t\telse requestData.signal.addEventListener('abort', () => controller.abort());\n\t}\n\n\tlet res: ResponseLike;\n\ttry {\n\t\tres = await manager.options.makeRequest(url, { ...options, signal: controller.signal });\n\t} catch (error: unknown) {\n\t\tif (!(error instanceof Error)) throw error;\n\t\t// Retry the specified number of times if needed\n\t\tif (shouldRetry(error) && retries !== manager.options.retries) {\n\t\t\t// Retry is handled by the handler upon receiving null\n\t\t\treturn null;\n\t\t}\n\n\t\tthrow error;\n\t} finally {\n\t\tclearTimeout(timeout);\n\t}\n\n\tif (manager.listenerCount(RESTEvents.Response)) {\n\t\tmanager.emit(\n\t\t\tRESTEvents.Response,\n\t\t\t{\n\t\t\t\tmethod: options.method ?? 'get',\n\t\t\t\tpath: routeId.original,\n\t\t\t\troute: routeId.bucketRoute,\n\t\t\t\toptions,\n\t\t\t\tdata: requestData,\n\t\t\t\tretries,\n\t\t\t},\n\t\t\tres instanceof Response ? res.clone() : { ...res },\n\t\t);\n\t}\n\n\treturn res;\n}\n\n/**\n * Handles 5xx and 4xx errors (not 429's) conventionally. 429's should be handled before calling this function\n *\n * @param manager - The manager that holds options and emits informational events\n * @param res - The response received from {@link makeNetworkRequest}\n * @param method - The method used to make the request\n * @param url - The fully resolved url to make the request to\n * @param requestData - Extra data from the user's request needed for errors and additional processing\n * @param retries - The number of retries this request has already attempted (recursion occurs on the handler)\n * @returns - The response if the status code is not handled or null to request a retry\n */\nexport async function handleErrors(\n\tmanager: REST,\n\tres: ResponseLike,\n\tmethod: string,\n\turl: string,\n\trequestData: HandlerRequestData,\n\tretries: number,\n) {\n\tconst status = res.status;\n\tif (status >= 500 && status < 600) {\n\t\t// Retry the specified number of times for possible server side issues\n\t\tif (retries !== manager.options.retries) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// We are out of retries, throw an error\n\t\tthrow new HTTPError(status, res.statusText, method, url, requestData);\n\t} else {\n\t\t// Handle possible malformed requests\n\t\tif (status >= 400 && status < 500) {\n\t\t\t// If we receive this status code, it means the token we had is no longer valid.\n\t\t\tif (status === 401 && requestData.auth) {\n\t\t\t\tmanager.setToken(null!);\n\t\t\t}\n\n\t\t\t// The request will not succeed for some reason, parse the error returned from the api\n\t\t\tconst data = (await parseResponse(res)) as DiscordErrorData | OAuthErrorData;\n\t\t\t// throw the API error\n\t\t\tthrow new DiscordAPIError(data, 'code' in data ? data.code : data.error, status, method, url, requestData);\n\t\t}\n\n\t\treturn res;\n\t}\n}\n","import type { RequestInit } from 'undici';\nimport type { REST } from '../REST.js';\nimport type { IHandler } from '../interfaces/Handler.js';\nimport { RESTEvents } from '../utils/constants.js';\nimport type { ResponseLike, HandlerRequestData, RouteData } from '../utils/types.js';\nimport { onRateLimit, sleep } from '../utils/utils.js';\nimport { handleErrors, incrementInvalidCount, makeNetworkRequest } from './Shared.js';\n\n/**\n * The structure used to handle burst requests for a given bucket.\n * Burst requests have no ratelimit handling but allow for pre- and post-processing\n * of data in the same manner as sequentially queued requests.\n *\n * @remarks\n * This queue may still emit a rate limit error if an unexpected 429 is hit\n */\nexport class BurstHandler implements IHandler {\n\t/**\n\t * {@inheritdoc IHandler.id}\n\t */\n\tpublic readonly id: string;\n\n\t/**\n\t * {@inheritDoc IHandler.inactive}\n\t */\n\tpublic inactive = false;\n\n\t/**\n\t * @param manager - The request manager\n\t * @param hash - The hash that this RequestHandler handles\n\t * @param majorParameter - The major parameter for this handler\n\t */\n\tpublic constructor(\n\t\tprivate readonly manager: REST,\n\t\tprivate readonly hash: string,\n\t\tprivate readonly majorParameter: string,\n\t) {\n\t\tthis.id = `${hash}:${majorParameter}`;\n\t}\n\n\t/**\n\t * Emits a debug message\n\t *\n\t * @param message - The message to debug\n\t */\n\tprivate debug(message: string) {\n\t\tthis.manager.emit(RESTEvents.Debug, `[REST ${this.id}] ${message}`);\n\t}\n\n\t/**\n\t * {@inheritDoc IHandler.queueRequest}\n\t */\n\tpublic async queueRequest(\n\t\trouteId: RouteData,\n\t\turl: string,\n\t\toptions: RequestInit,\n\t\trequestData: HandlerRequestData,\n\t): Promise<ResponseLike> {\n\t\treturn this.runRequest(routeId, url, options, requestData);\n\t}\n\n\t/**\n\t * The method that actually makes the request to the API, and updates info about the bucket accordingly\n\t *\n\t * @param routeId - The generalized API route with literal ids for major parameters\n\t * @param url - The fully resolved URL to make the request to\n\t * @param options - The fetch options needed to make the request\n\t * @param requestData - Extra data from the user's request needed for errors and additional processing\n\t * @param retries - The number of retries this request has already attempted (recursion)\n\t */\n\tprivate async runRequest(\n\t\trouteId: RouteData,\n\t\turl: string,\n\t\toptions: RequestInit,\n\t\trequestData: HandlerRequestData,\n\t\tretries = 0,\n\t): Promise<ResponseLike> {\n\t\tconst method = options.method ?? 'get';\n\n\t\tconst res = await makeNetworkRequest(this.manager, routeId, url, options, requestData, retries);\n\n\t\t// Retry requested\n\t\tif (res === null) {\n\t\t\t// eslint-disable-next-line no-param-reassign\n\t\t\treturn this.runRequest(routeId, url, options, requestData, ++retries);\n\t\t}\n\n\t\tconst status = res.status;\n\t\tlet retryAfter = 0;\n\t\tconst retry = res.headers.get('Retry-After');\n\n\t\t// Amount of time in milliseconds until we should retry if rate limited (globally or otherwise)\n\t\tif (retry) retryAfter = Number(retry) * 1_000 + this.manager.options.offset;\n\n\t\t// Count the invalid requests\n\t\tif (status === 401 || status === 403 || status === 429) {\n\t\t\tincrementInvalidCount(this.manager);\n\t\t}\n\n\t\tif (status >= 200 && status < 300) {\n\t\t\treturn res;\n\t\t} else if (status === 429) {\n\t\t\t// Unexpected ratelimit\n\t\t\tconst isGlobal = res.headers.has('X-RateLimit-Global');\n\t\t\tawait onRateLimit(this.manager, {\n\t\t\t\ttimeToReset: retryAfter,\n\t\t\t\tlimit: Number.POSITIVE_INFINITY,\n\t\t\t\tmethod,\n\t\t\t\thash: this.hash,\n\t\t\t\turl,\n\t\t\t\troute: routeId.bucketRoute,\n\t\t\t\tmajorParameter: this.majorParameter,\n\t\t\t\tglobal: isGlobal,\n\t\t\t});\n\t\t\tthis.debug(\n\t\t\t\t[\n\t\t\t\t\t'Encountered unexpected 429 rate limit',\n\t\t\t\t\t` Global : ${isGlobal}`,\n\t\t\t\t\t` Method : ${method}`,\n\t\t\t\t\t` URL : ${url}`,\n\t\t\t\t\t` Bucket : ${routeId.bucketRoute}`,\n\t\t\t\t\t` Major parameter: ${routeId.majorParameter}`,\n\t\t\t\t\t` Hash : ${this.hash}`,\n\t\t\t\t\t` Limit : ${Number.POSITIVE_INFINITY}`,\n\t\t\t\t\t` Retry After : ${retryAfter}ms`,\n\t\t\t\t\t` Sublimit : None`,\n\t\t\t\t].join('\\n'),\n\t\t\t);\n\n\t\t\t// We are bypassing all other limits, but an encountered limit should be respected (it's probably a non-punished rate limit anyways)\n\t\t\tawait sleep(retryAfter);\n\n\t\t\t// Since this is not a server side issue, the next request should pass, so we don't bump the retries counter\n\t\t\treturn this.runRequest(routeId, url, options, requestData, retries);\n\t\t} else {\n\t\t\tconst handled = await handleErrors(this.manager, res, method, url, requestData, retries);\n\t\t\tif (handled === null) {\n\t\t\t\t// eslint-disable-next-line no-param-reassign\n\t\t\t\treturn this.runRequest(routeId, url, options, requestData, ++retries);\n\t\t\t}\n\n\t\t\treturn handled;\n\t\t}\n\t}\n}\n","import { AsyncQueue } from '@sapphire/async-queue';\nimport type { RequestInit } from 'undici';\nimport type { REST } from '../REST.js';\nimport type { IHandler } from '../interfaces/Handler.js';\nimport { RESTEvents } from '../utils/constants.js';\nimport type { RateLimitData, ResponseLike, HandlerRequestData, RouteData } from '../utils/types.js';\nimport { hasSublimit, onRateLimit, sleep } from '../utils/utils.js';\nimport { handleErrors, incrementInvalidCount, makeNetworkRequest } from './Shared.js';\n\nconst enum QueueType {\n\tStandard,\n\tSublimit,\n}\n\n/**\n * The structure used to handle sequential requests for a given bucket\n */\nexport class SequentialHandler implements IHandler {\n\t/**\n\t * {@inheritDoc IHandler.id}\n\t */\n\tpublic readonly id: string;\n\n\t/**\n\t * The time this rate limit bucket will reset\n\t */\n\tprivate reset = -1;\n\n\t/**\n\t * The remaining requests that can be made before we are rate limited\n\t */\n\tprivate remaining = 1;\n\n\t/**\n\t * The total number of requests that can be made before we are rate limited\n\t */\n\tprivate limit = Number.POSITIVE_INFINITY;\n\n\t/**\n\t * The interface used to sequence async requests sequentially\n\t */\n\t#asyncQueue = new AsyncQueue();\n\n\t/**\n\t * The interface used to sequence sublimited async requests sequentially\n\t */\n\t#sublimitedQueue: AsyncQueue | null = null;\n\n\t/**\n\t * A promise wrapper for when the sublimited queue is finished being processed or null when not being processed\n\t */\n\t#sublimitPromise: { promise: Promise<void>; resolve(): void } | null = null;\n\n\t/**\n\t * Whether the sublimit queue needs to be shifted in the finally block\n\t */\n\t#shiftSublimit = false;\n\n\t/**\n\t * @param manager - The request manager\n\t * @param hash - The hash that this RequestHandler handles\n\t * @param majorParameter - The major parameter for this handler\n\t */\n\tpublic constructor(\n\t\tprivate readonly manager: REST,\n\t\tprivate readonly hash: string,\n\t\tprivate readonly majorParameter: string,\n\t) {\n\t\tthis.id = `${hash}:${majorParameter}`;\n\t}\n\n\t/**\n\t * {@inheritDoc IHandler.inactive}\n\t */\n\tpublic get inactive(): boolean {\n\t\treturn (\n\t\t\tthis.#asyncQueue.remaining === 0 &&\n\t\t\t(this.#sublimitedQueue === null || this.#sublimitedQueue.remaining === 0) &&\n\t\t\t!this.limited\n\t\t);\n\t}\n\n\t/**\n\t * If the rate limit bucket is currently limited by the global limit\n\t */\n\tprivate get globalLimited(): boolean {\n\t\treturn this.manager.globalRemaining <= 0 && Date.now() < this.manager.globalReset;\n\t}\n\n\t/**\n\t * If the rate limit bucket is currently limited by its limit\n\t */\n\tprivate get localLimited(): boolean {\n\t\treturn this.remaining <= 0 && Date.now() < this.reset;\n\t}\n\n\t/**\n\t * If the rate limit bucket is currently limited\n\t */\n\tprivate get limited(): boolean {\n\t\treturn this.globalLimited || this.localLimited;\n\t}\n\n\t/**\n\t * The time until queued requests can continue\n\t */\n\tprivate get timeToReset(): number {\n\t\treturn this.reset + this.manager.options.offset - Date.now();\n\t}\n\n\t/**\n\t * Emits a debug message\n\t *\n\t * @param message - The message to debug\n\t */\n\tprivate debug(message: string) {\n\t\tthis.manager.emit(RESTEvents.Debug, `[REST ${this.id}] ${message}`);\n\t}\n\n\t/**\n\t * Delay all requests for the specified amount of time, handling global rate limits\n\t *\n\t * @param time - The amount of time to delay all requests for\n\t */\n\tprivate async globalDelayFor(time: number): Promise<void> {\n\t\tawait sleep(time);\n\t\tthis.manager.globalDelay = null;\n\t}\n\n\t/**\n\t * {@inheritDoc IHandler.queueRequest}\n\t */\n\tpublic async queueRequest(\n\t\trouteId: RouteData,\n\t\turl: string,\n\t\toptions: RequestInit,\n\t\trequestData: HandlerRequestData,\n\t): Promise<ResponseLike> {\n\t\tlet queue = this.#asyncQueue;\n\t\tlet queueType = QueueType.Standard;\n\t\t// Separate sublimited requests when already sublimited\n\t\tif (this.#sublimitedQueue && hasSublimit(routeId.bucketRoute, requestData.body, options.method)) {\n\t\t\tqueue = this.#sublimitedQueue!;\n\t\t\tqueueType = QueueType.Sublimit;\n\t\t}\n\n\t\t// Wait for any previous requests to be completed before this one is run\n\t\tawait queue.wait({ signal: requestData.signal });\n\t\t// This set handles retroactively sublimiting requests\n\t\tif (queueType === QueueType.Standard) {\n\t\t\tif (this.#sublimitedQueue && hasSublimit(routeId.bucketRoute, requestData.body, options.method)) {\n\t\t\t\t/**\n\t\t\t\t * Remove the request from the standard queue, it should never be possible to get here while processing the\n\t\t\t\t * sublimit queue so there is no need to worry about shifting the wrong request\n\t\t\t\t */\n\t\t\t\tqueue = this.#sublimitedQueue!;\n\t\t\t\tconst wait = queue.wait();\n\t\t\t\tthis.#asyncQueue.shift();\n\t\t\t\tawait wait;\n\t\t\t} else if (this.#sublimitPromise) {\n\t\t\t\t// Stall requests while the sublimit queue gets processed\n\t\t\t\tawait this.#sublimitPromise.promise;\n\t\t\t}\n\t\t}\n\n\t\ttry {\n\t\t\t// Make the request, and return the results\n\t\t\treturn await this.runRequest(routeId, url, options, requestData);\n\t\t} finally {\n\t\t\t// Allow the next request to fire\n\t\t\tqueue.shift();\n\t\t\tif (this.#shiftSublimit) {\n\t\t\t\tthis.#shiftSublimit = false;\n\t\t\t\tthis.#sublimitedQueue?.shift();\n\t\t\t}\n\n\t\t\t// If this request is the last request in a sublimit\n\t\t\tif (this.#sublimitedQueue?.remaining === 0) {\n\t\t\t\tthis.#sublimitPromise?.resolve();\n\t\t\t\tthis.#sublimitedQueue = null;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * The method that actually makes the request to the api, and updates info about the bucket accordingly\n\t *\n\t * @param routeId - The generalized api route with literal ids for major parameters\n\t * @param url - The fully resolved url to make the request to\n\t * @param options - The fetch options needed to make the request\n\t * @param requestData - Extra data from the user's request needed for errors and additional processing\n\t * @param retries - The number of retries this request has already attempted (recursion)\n\t */\n\tprivate async runRequest(\n\t\trouteId: RouteData,\n\t\turl: string,\n\t\toptions: RequestInit,\n\t\trequestData: HandlerRequestData,\n\t\tretries = 0,\n\t): Promise<ResponseLike> {\n\t\t/*\n\t\t * After calculations have been done, pre-emptively stop further requests\n\t\t * Potentially loop until this task can run if e.g. the global rate limit is hit twice\n\t\t */\n\t\twhile (this.limited) {\n\t\t\tconst isGlobal = this.globalLimited;\n\t\t\tlet limit: number;\n\t\t\tlet timeout: number;\n\t\t\tlet delay: Promise<void>;\n\n\t\t\tif (isGlobal) {\n\t\t\t\t// Set RateLimitData based on the global limit\n\t\t\t\tlimit = this.manager.options.globalRequestsPerSecond;\n\t\t\t\ttimeout = this.manager.globalReset + this.manager.options.offset - Date.now();\n\t\t\t\t// If this is the first task to reach the global timeout, set the global delay\n\t\t\t\tif (!this.manager.globalDelay) {\n\t\t\t\t\t// The global delay function clears the global delay state when it is resolved\n\t\t\t\t\tthis.manager.globalDelay = this.globalDelayFor(timeout);\n\t\t\t\t}\n\n\t\t\t\tdelay = this.manager.globalDelay;\n\t\t\t} else {\n\t\t\t\t// Set RateLimitData based on the route-specific limit\n\t\t\t\tlimit = this.limit;\n\t\t\t\ttimeout = this.timeToReset;\n\t\t\t\tdelay = sleep(timeout);\n\t\t\t}\n\n\t\t\tconst rateLimitData: RateLimitData = {\n\t\t\t\ttimeToReset: timeout,\n\t\t\t\tlimit,\n\t\t\t\tmethod: options.method ?? 'get',\n\t\t\t\thash: this.hash,\n\t\t\t\turl,\n\t\t\t\troute: routeId.bucketRoute,\n\t\t\t\tmajorParameter: this.majorParameter,\n\t\t\t\tglobal: isGlobal,\n\t\t\t};\n\t\t\t// Let library users know they have hit a rate limit\n\t\t\tthis.manager.emit(RESTEvents.RateLimited, rateLimitData);\n\t\t\t// Determine whether a RateLimitError should be thrown\n\t\t\tawait onRateLimit(this.manager, rateLimitData);\n\t\t\t// When not erroring, emit debug for what is happening\n\t\t\tif (isGlobal) {\n\t\t\t\tthis.debug(`Global rate limit hit, blocking all requests for ${timeout}ms`);\n\t\t\t} else {\n\t\t\t\tthis.debug(`Waiting ${timeout}ms for rate limit to pass`);\n\t\t\t}\n\n\t\t\t// Wait the remaining time left before the rate limit resets\n\t\t\tawait delay;\n\t\t}\n\n\t\t// As the request goes out, update the global usage information\n\t\tif (!this.manager.globalReset || this.manager.globalReset < Date.now()) {\n\t\t\tthis.manager.globalReset = Date.now() + 1_000;\n\t\t\tthis.manager.globalRemaining = this.manager.options.globalRequestsPerSecond;\n\t\t}\n\n\t\tthis.manager.globalRemaining--;\n\n\t\tconst method = options.method ?? 'get';\n\n\t\tconst res = await makeNetworkRequest(this.manager, routeId, url, options, requestData, retries);\n\n\t\t// Retry requested\n\t\tif (res === null) {\n\t\t\t// eslint-disable-next-line no-param-reassign\n\t\t\treturn this.runRequest(routeId, url, options, requestData, ++retries);\n\t\t}\n\n\t\tconst status = res.status;\n\t\tlet retryAfter = 0;\n\n\t\tconst limit = res.headers.get('X-RateLimit-Limit');\n\t\tconst remaining = res.headers.get('X-RateLimit-Remaining');\n\t\tconst reset = res.headers.get('X-RateLimit-Reset-After');\n\t\tconst hash = res.headers.get('X-RateLimit-Bucket');\n\t\tconst retry = res.headers.get('Retry-After');\n\n\t\t// Update the total number of requests that can be made before the rate limit resets\n\t\tthis.limit = limit ? Number(limit) : Number.POSITIVE_INFINITY;\n\t\t// Update the number of remaining requests that can be made before the rate limit resets\n\t\tthis.remaining = remaining ? Number(remaining) : 1;\n\t\t// Update the time when this rate limit resets (reset-after is in seconds)\n\t\tthis.reset = reset ? Number(reset) * 1_000 + Date.now() + this.manager.options.offset : Date.now();\n\n\t\t// Amount of time in milliseconds until we should retry if rate limited (globally or otherwise)\n\t\tif (retry) retryAfter = Number(retry) * 1_000 + this.manager.options.offset;\n\n\t\t// Handle buckets via the hash header retroactively\n\t\tif (hash && hash !== this.hash) {\n\t\t\t// Let library users know when rate limit buckets have been updated\n\t\t\tthis.debug(['Received bucket hash update', ` Old Hash : ${this.hash}`, ` New Hash : ${hash}`].join('\\n'));\n\t\t\t// This queue will eventually be eliminated via attrition\n\t\t\tthis.manager.hashes.set(`${method}:${routeId.bucketRoute}`, { value: hash, lastAccess: Date.now() });\n\t\t} else if (hash) {\n\t\t\t// Handle the case where hash value doesn't change\n\t\t\t// Fetch the hash data from the manager\n\t\t\tconst hashData = this.manager.hashes.get(`${method}:${routeId.bucketRoute}`);\n\n\t\t\t// When fetched, update the last access of the hash\n\t\t\tif (hashData) {\n\t\t\t\thashData.lastAccess = Date.now();\n\t\t\t}\n\t\t}\n\n\t\t// Handle retryAfter, which means we have actually hit a rate limit\n\t\tlet sublimitTimeout: number | null = null;\n\t\tif (retryAfter > 0) {\n\t\t\tif (res.headers.has('X-RateLimit-Global')) {\n\t\t\t\tthis.manager.globalRemaining = 0;\n\t\t\t\tthis.manager.globalReset = Date.now() + retryAfter;\n\t\t\t} else if (!this.localLimited) {\n\t\t\t\t/*\n\t\t\t\t * This is a sublimit (e.g. 2 channel name changes/10 minutes) since the headers don't indicate a\n\t\t\t\t * route-wide rate limit. Don't update remaining or reset to avoid rate limiting the whole\n\t\t\t\t * endpoint, just set a reset time on the request itself to avoid retrying too soon.\n\t\t\t\t */\n\t\t\t\tsublimitTimeout = retryAfter;\n\t\t\t}\n\t\t}\n\n\t\t// Count the invalid requests\n\t\tif (status === 401 || status === 403 || status === 429) {\n\t\t\tincrementInvalidCount(this.manager);\n\t\t}\n\n\t\tif (res.ok) {\n\t\t\treturn res;\n\t\t} else if (status === 429) {\n\t\t\t// A rate limit was hit - this may happen if the route isn't associated with an official bucket hash yet, or when first globally rate limited\n\t\t\tconst isGlobal = this.globalLimited;\n\t\t\tlet limit: number;\n\t\t\tlet timeout: number;\n\n\t\t\tif (isGlobal) {\n\t\t\t\t// Set RateLimitData based on the global limit\n\t\t\t\tlimit = this.manager.options.globalRequestsPerSecond;\n\t\t\t\ttimeout = this.manager.globalReset + this.manager.options.offset - Date.now();\n\t\t\t} else {\n\t\t\t\t// Set RateLimitData based on the route-specific limit\n\t\t\t\tlimit = this.limit;\n\t\t\t\ttimeout = this.timeToReset;\n\t\t\t}\n\n\t\t\tawait onRateLimit(this.manager, {\n\t\t\t\ttimeToReset: timeout,\n\t\t\t\tlimit,\n\t\t\t\tmethod,\n\t\t\t\thash: this.hash,\n\t\t\t\turl,\n\t\t\t\troute: routeId.bucketRoute,\n\t\t\t\tmajorParameter: this.majorParameter,\n\t\t\t\tglobal: isGlobal,\n\t\t\t});\n\t\t\tthis.debug(\n\t\t\t\t[\n\t\t\t\t\t'Encountered unexpected 429 rate limit',\n\t\t\t\t\t` Global : ${isGlobal.toString()}`,\n\t\t\t\t\t` Method : ${method}`,\n\t\t\t\t\t` URL : ${url}`,\n\t\t\t\t\t` Bucket : ${routeId.bucketRoute}`,\n\t\t\t\t\t` Major parameter: ${routeId.majorParameter}`,\n\t\t\t\t\t` Hash : ${this.hash}`,\n\t\t\t\t\t` Limit : ${limit}`,\n\t\t\t\t\t` Retry After : ${retryAfter}ms`,\n\t\t\t\t\t` Sublimit : ${sublimitTimeout ? `${sublimitTimeout}ms` : 'None'}`,\n\t\t\t\t].join('\\n'),\n\t\t\t);\n\t\t\t// If caused by a sublimit, wait it out here so other requests on the route can be handled\n\t\t\tif (sublimitTimeout) {\n\t\t\t\t// Normally the sublimit queue will not exist, however, if a sublimit is hit while in the sublimit queue, it will\n\t\t\t\tconst firstSublimit = !this.#sublimitedQueue;\n\t\t\t\tif (firstSublimit) {\n\t\t\t\t\tthis.#sublimitedQueue = new AsyncQueue();\n\t\t\t\t\tvoid this.#sublimitedQueue.wait();\n\t\t\t\t\tthis.#asyncQueue.shift();\n\t\t\t\t}\n\n\t\t\t\tthis.#sublimitPromise?.resolve();\n\t\t\t\tthis.#sublimitPromise = null;\n\t\t\t\tawait sleep(sublimitTimeout);\n\t\t\t\tlet resolve: () => void;\n\t\t\t\t// eslint-disable-next-line promise/param-names, no-promise-executor-return\n\t\t\t\tconst promise = new Promise<void>((res) => (resolve = res));\n\t\t\t\tthis.#sublimitPromise = { promise, resolve: resolve! };\n\t\t\t\tif (firstSublimit) {\n\t\t\t\t\t// Re-queue this request so it can be shifted by the finally\n\t\t\t\t\tawait this.#asyncQueue.wait();\n\t\t\t\t\tthis.#shiftSublimit = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Since this is not a server side issue, the next request should pass, so we don't bump the retries counter\n\t\t\treturn this.runRequest(routeId, url, options, requestData, retries);\n\t\t} else {\n\t\t\tconst handled = await handleErrors(this.manager, res, method, url, requestData, retries);\n\t\t\tif (handled === null) {\n\t\t\t\t// eslint-disable-next-line no-param-reassign\n\t\t\t\treturn this.runRequest(routeId, url, options, requestData, ++retries);\n\t\t\t}\n\n\t\t\treturn handled;\n\t\t}\n\t}\n}\n","export * from './lib/CDN.js';\nexport * from './lib/errors/DiscordAPIError.js';\nexport * from './lib/errors/HTTPError.js';\nexport * from './lib/errors/RateLimitError.js';\nexport * from './lib/REST.js';\nexport * from './lib/utils/constants.js';\nexport * from './lib/utils/types.js';\nexport { calculateUserDefaultAvatarIndex, makeURLSearchParams, parseResponse } from './lib/utils/utils.js';\n\n/**\n * The {@link https://github.com/discordjs/discord.js/blob/main/packages/rest/#readme | @discordjs/rest} version\n * that you are currently using.\n */\n// This needs to explicitly be `string` so it is not typed as a \"const string\" that gets injected by esbuild\nexport const version = '2.0.1' as string;\n"],"mappings":"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","names":["Blob","FormData","URLSearchParams","URLSearchParams","RESTEvents","RequestMethod","limit","res","request","FormData","Blob"]}
\ No newline at end of file diff --git a/node_modules/@discordjs/rest/dist/strategies/undiciRequest.d.mts b/node_modules/@discordjs/rest/dist/strategies/undiciRequest.d.mts new file mode 100644 index 0000000..4e38977 --- /dev/null +++ b/node_modules/@discordjs/rest/dist/strategies/undiciRequest.d.mts @@ -0,0 +1,11 @@ +import { request, RequestInit } from 'undici'; +import { R as ResponseLike } from '../types-65527f29.js'; +import 'node:stream'; +import 'node:stream/web'; +import '@discordjs/collection'; + +type RequestOptions = Exclude<Parameters<typeof request>[1], undefined>; +declare function makeRequest(url: string, init: RequestInit): Promise<ResponseLike>; +declare function resolveBody(body: RequestInit['body']): Promise<Exclude<RequestOptions['body'], undefined>>; + +export { RequestOptions, makeRequest, resolveBody }; diff --git a/node_modules/@discordjs/rest/dist/strategies/undiciRequest.d.ts b/node_modules/@discordjs/rest/dist/strategies/undiciRequest.d.ts new file mode 100644 index 0000000..4e38977 --- /dev/null +++ b/node_modules/@discordjs/rest/dist/strategies/undiciRequest.d.ts @@ -0,0 +1,11 @@ +import { request, RequestInit } from 'undici'; +import { R as ResponseLike } from '../types-65527f29.js'; +import 'node:stream'; +import 'node:stream/web'; +import '@discordjs/collection'; + +type RequestOptions = Exclude<Parameters<typeof request>[1], undefined>; +declare function makeRequest(url: string, init: RequestInit): Promise<ResponseLike>; +declare function resolveBody(body: RequestInit['body']): Promise<Exclude<RequestOptions['body'], undefined>>; + +export { RequestOptions, makeRequest, resolveBody }; diff --git a/node_modules/@discordjs/rest/dist/strategies/undiciRequest.js b/node_modules/@discordjs/rest/dist/strategies/undiciRequest.js new file mode 100644 index 0000000..640fe1d --- /dev/null +++ b/node_modules/@discordjs/rest/dist/strategies/undiciRequest.js @@ -0,0 +1,94 @@ +"use strict"; +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); + +// src/strategies/undiciRequest.ts +var undiciRequest_exports = {}; +__export(undiciRequest_exports, { + makeRequest: () => makeRequest, + resolveBody: () => resolveBody +}); +module.exports = __toCommonJS(undiciRequest_exports); +var import_node_http = require("http"); +var import_node_url = require("url"); +var import_node_util = require("util"); +var import_undici = require("undici"); +async function makeRequest(url, init) { + const options = { + ...init, + body: await resolveBody(init.body) + }; + const res = await (0, import_undici.request)(url, options); + return { + body: res.body, + async arrayBuffer() { + return res.body.arrayBuffer(); + }, + async json() { + return res.body.json(); + }, + async text() { + return res.body.text(); + }, + get bodyUsed() { + return res.body.bodyUsed; + }, + headers: new import_undici.Headers(res.headers), + status: res.statusCode, + statusText: import_node_http.STATUS_CODES[res.statusCode], + ok: res.statusCode >= 200 && res.statusCode < 300 + }; +} +__name(makeRequest, "makeRequest"); +async function resolveBody(body) { + if (body == null) { + return null; + } else if (typeof body === "string") { + return body; + } else if (import_node_util.types.isUint8Array(body)) { + return body; + } else if (import_node_util.types.isArrayBuffer(body)) { + return new Uint8Array(body); + } else if (body instanceof import_node_url.URLSearchParams) { + return body.toString(); + } else if (body instanceof DataView) { + return new Uint8Array(body.buffer); + } else if (body instanceof Blob) { + return new Uint8Array(await body.arrayBuffer()); + } else if (body instanceof FormData) { + return body; + } else if (body[Symbol.iterator]) { + const chunks = [...body]; + return Buffer.concat(chunks); + } else if (body[Symbol.asyncIterator]) { + const chunks = []; + for await (const chunk of body) { + chunks.push(chunk); + } + return Buffer.concat(chunks); + } + throw new TypeError(`Unable to resolve body.`); +} +__name(resolveBody, "resolveBody"); +// Annotate the CommonJS export names for ESM import in node: +0 && (module.exports = { + makeRequest, + resolveBody +}); +//# sourceMappingURL=undiciRequest.js.map
\ No newline at end of file diff --git a/node_modules/@discordjs/rest/dist/strategies/undiciRequest.js.map b/node_modules/@discordjs/rest/dist/strategies/undiciRequest.js.map new file mode 100644 index 0000000..e3c49ee --- /dev/null +++ b/node_modules/@discordjs/rest/dist/strategies/undiciRequest.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/strategies/undiciRequest.ts"],"sourcesContent":["import { STATUS_CODES } from 'node:http';\nimport { URLSearchParams } from 'node:url';\nimport { types } from 'node:util';\nimport { type RequestInit, request, Headers } from 'undici';\nimport type { ResponseLike } from '../shared.js';\n\nexport type RequestOptions = Exclude<Parameters<typeof request>[1], undefined>;\n\nexport async function makeRequest(url: string, init: RequestInit): Promise<ResponseLike> {\n\t// The cast is necessary because `headers` and `method` are narrower types in `undici.request`\n\t// our request path guarantees they are of acceptable type for `undici.request`\n\tconst options = {\n\t\t...init,\n\t\tbody: await resolveBody(init.body),\n\t} as RequestOptions;\n\tconst res = await request(url, options);\n\treturn {\n\t\tbody: res.body,\n\t\tasync arrayBuffer() {\n\t\t\treturn res.body.arrayBuffer();\n\t\t},\n\t\tasync json() {\n\t\t\treturn res.body.json();\n\t\t},\n\t\tasync text() {\n\t\t\treturn res.body.text();\n\t\t},\n\t\tget bodyUsed() {\n\t\t\treturn res.body.bodyUsed;\n\t\t},\n\t\theaders: new Headers(res.headers as Record<string, string[] | string>),\n\t\tstatus: res.statusCode,\n\t\tstatusText: STATUS_CODES[res.statusCode]!,\n\t\tok: res.statusCode >= 200 && res.statusCode < 300,\n\t};\n}\n\nexport async function resolveBody(body: RequestInit['body']): Promise<Exclude<RequestOptions['body'], undefined>> {\n\t// eslint-disable-next-line no-eq-null, eqeqeq\n\tif (body == null) {\n\t\treturn null;\n\t} else if (typeof body === 'string') {\n\t\treturn body;\n\t} else if (types.isUint8Array(body)) {\n\t\treturn body;\n\t} else if (types.isArrayBuffer(body)) {\n\t\treturn new Uint8Array(body);\n\t} else if (body instanceof URLSearchParams) {\n\t\treturn body.toString();\n\t} else if (body instanceof DataView) {\n\t\treturn new Uint8Array(body.buffer);\n\t} else if (body instanceof Blob) {\n\t\treturn new Uint8Array(await body.arrayBuffer());\n\t} else if (body instanceof FormData) {\n\t\treturn body;\n\t} else if ((body as Iterable<Uint8Array>)[Symbol.iterator]) {\n\t\tconst chunks = [...(body as Iterable<Uint8Array>)];\n\n\t\treturn Buffer.concat(chunks);\n\t} else if ((body as AsyncIterable<Uint8Array>)[Symbol.asyncIterator]) {\n\t\tconst chunks: Uint8Array[] = [];\n\n\t\tfor await (const chunk of body as AsyncIterable<Uint8Array>) {\n\t\t\tchunks.push(chunk);\n\t\t}\n\n\t\treturn Buffer.concat(chunks);\n\t}\n\n\tthrow new TypeError(`Unable to resolve body.`);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,uBAA6B;AAC7B,sBAAgC;AAChC,uBAAsB;AACtB,oBAAmD;AAKnD,eAAsB,YAAY,KAAa,MAA0C;AAGxF,QAAM,UAAU;AAAA,IACf,GAAG;AAAA,IACH,MAAM,MAAM,YAAY,KAAK,IAAI;AAAA,EAClC;AACA,QAAM,MAAM,UAAM,uBAAQ,KAAK,OAAO;AACtC,SAAO;AAAA,IACN,MAAM,IAAI;AAAA,IACV,MAAM,cAAc;AACnB,aAAO,IAAI,KAAK,YAAY;AAAA,IAC7B;AAAA,IACA,MAAM,OAAO;AACZ,aAAO,IAAI,KAAK,KAAK;AAAA,IACtB;AAAA,IACA,MAAM,OAAO;AACZ,aAAO,IAAI,KAAK,KAAK;AAAA,IACtB;AAAA,IACA,IAAI,WAAW;AACd,aAAO,IAAI,KAAK;AAAA,IACjB;AAAA,IACA,SAAS,IAAI,sBAAQ,IAAI,OAA4C;AAAA,IACrE,QAAQ,IAAI;AAAA,IACZ,YAAY,8BAAa,IAAI,UAAU;AAAA,IACvC,IAAI,IAAI,cAAc,OAAO,IAAI,aAAa;AAAA,EAC/C;AACD;AA3BsB;AA6BtB,eAAsB,YAAY,MAAgF;AAEjH,MAAI,QAAQ,MAAM;AACjB,WAAO;AAAA,EACR,WAAW,OAAO,SAAS,UAAU;AACpC,WAAO;AAAA,EACR,WAAW,uBAAM,aAAa,IAAI,GAAG;AACpC,WAAO;AAAA,EACR,WAAW,uBAAM,cAAc,IAAI,GAAG;AACrC,WAAO,IAAI,WAAW,IAAI;AAAA,EAC3B,WAAW,gBAAgB,iCAAiB;AAC3C,WAAO,KAAK,SAAS;AAAA,EACtB,WAAW,gBAAgB,UAAU;AACpC,WAAO,IAAI,WAAW,KAAK,MAAM;AAAA,EAClC,WAAW,gBAAgB,MAAM;AAChC,WAAO,IAAI,WAAW,MAAM,KAAK,YAAY,CAAC;AAAA,EAC/C,WAAW,gBAAgB,UAAU;AACpC,WAAO;AAAA,EACR,WAAY,KAA8B,OAAO,QAAQ,GAAG;AAC3D,UAAM,SAAS,CAAC,GAAI,IAA6B;AAEjD,WAAO,OAAO,OAAO,MAAM;AAAA,EAC5B,WAAY,KAAmC,OAAO,aAAa,GAAG;AACrE,UAAM,SAAuB,CAAC;AAE9B,qBAAiB,SAAS,MAAmC;AAC5D,aAAO,KAAK,KAAK;AAAA,IAClB;AAEA,WAAO,OAAO,OAAO,MAAM;AAAA,EAC5B;AAEA,QAAM,IAAI,UAAU,yBAAyB;AAC9C;AAjCsB;","names":[]}
\ No newline at end of file diff --git a/node_modules/@discordjs/rest/dist/strategies/undiciRequest.mjs b/node_modules/@discordjs/rest/dist/strategies/undiciRequest.mjs new file mode 100644 index 0000000..0e6ce0a --- /dev/null +++ b/node_modules/@discordjs/rest/dist/strategies/undiciRequest.mjs @@ -0,0 +1,70 @@ +var __defProp = Object.defineProperty; +var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); + +// src/strategies/undiciRequest.ts +import { STATUS_CODES } from "node:http"; +import { URLSearchParams } from "node:url"; +import { types } from "node:util"; +import { request, Headers } from "undici"; +async function makeRequest(url, init) { + const options = { + ...init, + body: await resolveBody(init.body) + }; + const res = await request(url, options); + return { + body: res.body, + async arrayBuffer() { + return res.body.arrayBuffer(); + }, + async json() { + return res.body.json(); + }, + async text() { + return res.body.text(); + }, + get bodyUsed() { + return res.body.bodyUsed; + }, + headers: new Headers(res.headers), + status: res.statusCode, + statusText: STATUS_CODES[res.statusCode], + ok: res.statusCode >= 200 && res.statusCode < 300 + }; +} +__name(makeRequest, "makeRequest"); +async function resolveBody(body) { + if (body == null) { + return null; + } else if (typeof body === "string") { + return body; + } else if (types.isUint8Array(body)) { + return body; + } else if (types.isArrayBuffer(body)) { + return new Uint8Array(body); + } else if (body instanceof URLSearchParams) { + return body.toString(); + } else if (body instanceof DataView) { + return new Uint8Array(body.buffer); + } else if (body instanceof Blob) { + return new Uint8Array(await body.arrayBuffer()); + } else if (body instanceof FormData) { + return body; + } else if (body[Symbol.iterator]) { + const chunks = [...body]; + return Buffer.concat(chunks); + } else if (body[Symbol.asyncIterator]) { + const chunks = []; + for await (const chunk of body) { + chunks.push(chunk); + } + return Buffer.concat(chunks); + } + throw new TypeError(`Unable to resolve body.`); +} +__name(resolveBody, "resolveBody"); +export { + makeRequest, + resolveBody +}; +//# sourceMappingURL=undiciRequest.mjs.map
\ No newline at end of file diff --git a/node_modules/@discordjs/rest/dist/strategies/undiciRequest.mjs.map b/node_modules/@discordjs/rest/dist/strategies/undiciRequest.mjs.map new file mode 100644 index 0000000..e238a9c --- /dev/null +++ b/node_modules/@discordjs/rest/dist/strategies/undiciRequest.mjs.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/strategies/undiciRequest.ts"],"sourcesContent":["import { STATUS_CODES } from 'node:http';\nimport { URLSearchParams } from 'node:url';\nimport { types } from 'node:util';\nimport { type RequestInit, request, Headers } from 'undici';\nimport type { ResponseLike } from '../shared.js';\n\nexport type RequestOptions = Exclude<Parameters<typeof request>[1], undefined>;\n\nexport async function makeRequest(url: string, init: RequestInit): Promise<ResponseLike> {\n\t// The cast is necessary because `headers` and `method` are narrower types in `undici.request`\n\t// our request path guarantees they are of acceptable type for `undici.request`\n\tconst options = {\n\t\t...init,\n\t\tbody: await resolveBody(init.body),\n\t} as RequestOptions;\n\tconst res = await request(url, options);\n\treturn {\n\t\tbody: res.body,\n\t\tasync arrayBuffer() {\n\t\t\treturn res.body.arrayBuffer();\n\t\t},\n\t\tasync json() {\n\t\t\treturn res.body.json();\n\t\t},\n\t\tasync text() {\n\t\t\treturn res.body.text();\n\t\t},\n\t\tget bodyUsed() {\n\t\t\treturn res.body.bodyUsed;\n\t\t},\n\t\theaders: new Headers(res.headers as Record<string, string[] | string>),\n\t\tstatus: res.statusCode,\n\t\tstatusText: STATUS_CODES[res.statusCode]!,\n\t\tok: res.statusCode >= 200 && res.statusCode < 300,\n\t};\n}\n\nexport async function resolveBody(body: RequestInit['body']): Promise<Exclude<RequestOptions['body'], undefined>> {\n\t// eslint-disable-next-line no-eq-null, eqeqeq\n\tif (body == null) {\n\t\treturn null;\n\t} else if (typeof body === 'string') {\n\t\treturn body;\n\t} else if (types.isUint8Array(body)) {\n\t\treturn body;\n\t} else if (types.isArrayBuffer(body)) {\n\t\treturn new Uint8Array(body);\n\t} else if (body instanceof URLSearchParams) {\n\t\treturn body.toString();\n\t} else if (body instanceof DataView) {\n\t\treturn new Uint8Array(body.buffer);\n\t} else if (body instanceof Blob) {\n\t\treturn new Uint8Array(await body.arrayBuffer());\n\t} else if (body instanceof FormData) {\n\t\treturn body;\n\t} else if ((body as Iterable<Uint8Array>)[Symbol.iterator]) {\n\t\tconst chunks = [...(body as Iterable<Uint8Array>)];\n\n\t\treturn Buffer.concat(chunks);\n\t} else if ((body as AsyncIterable<Uint8Array>)[Symbol.asyncIterator]) {\n\t\tconst chunks: Uint8Array[] = [];\n\n\t\tfor await (const chunk of body as AsyncIterable<Uint8Array>) {\n\t\t\tchunks.push(chunk);\n\t\t}\n\n\t\treturn Buffer.concat(chunks);\n\t}\n\n\tthrow new TypeError(`Unable to resolve body.`);\n}\n"],"mappings":";;;;AAAA,SAAS,oBAAoB;AAC7B,SAAS,uBAAuB;AAChC,SAAS,aAAa;AACtB,SAA2B,SAAS,eAAe;AAKnD,eAAsB,YAAY,KAAa,MAA0C;AAGxF,QAAM,UAAU;AAAA,IACf,GAAG;AAAA,IACH,MAAM,MAAM,YAAY,KAAK,IAAI;AAAA,EAClC;AACA,QAAM,MAAM,MAAM,QAAQ,KAAK,OAAO;AACtC,SAAO;AAAA,IACN,MAAM,IAAI;AAAA,IACV,MAAM,cAAc;AACnB,aAAO,IAAI,KAAK,YAAY;AAAA,IAC7B;AAAA,IACA,MAAM,OAAO;AACZ,aAAO,IAAI,KAAK,KAAK;AAAA,IACtB;AAAA,IACA,MAAM,OAAO;AACZ,aAAO,IAAI,KAAK,KAAK;AAAA,IACtB;AAAA,IACA,IAAI,WAAW;AACd,aAAO,IAAI,KAAK;AAAA,IACjB;AAAA,IACA,SAAS,IAAI,QAAQ,IAAI,OAA4C;AAAA,IACrE,QAAQ,IAAI;AAAA,IACZ,YAAY,aAAa,IAAI,UAAU;AAAA,IACvC,IAAI,IAAI,cAAc,OAAO,IAAI,aAAa;AAAA,EAC/C;AACD;AA3BsB;AA6BtB,eAAsB,YAAY,MAAgF;AAEjH,MAAI,QAAQ,MAAM;AACjB,WAAO;AAAA,EACR,WAAW,OAAO,SAAS,UAAU;AACpC,WAAO;AAAA,EACR,WAAW,MAAM,aAAa,IAAI,GAAG;AACpC,WAAO;AAAA,EACR,WAAW,MAAM,cAAc,IAAI,GAAG;AACrC,WAAO,IAAI,WAAW,IAAI;AAAA,EAC3B,WAAW,gBAAgB,iBAAiB;AAC3C,WAAO,KAAK,SAAS;AAAA,EACtB,WAAW,gBAAgB,UAAU;AACpC,WAAO,IAAI,WAAW,KAAK,MAAM;AAAA,EAClC,WAAW,gBAAgB,MAAM;AAChC,WAAO,IAAI,WAAW,MAAM,KAAK,YAAY,CAAC;AAAA,EAC/C,WAAW,gBAAgB,UAAU;AACpC,WAAO;AAAA,EACR,WAAY,KAA8B,OAAO,QAAQ,GAAG;AAC3D,UAAM,SAAS,CAAC,GAAI,IAA6B;AAEjD,WAAO,OAAO,OAAO,MAAM;AAAA,EAC5B,WAAY,KAAmC,OAAO,aAAa,GAAG;AACrE,UAAM,SAAuB,CAAC;AAE9B,qBAAiB,SAAS,MAAmC;AAC5D,aAAO,KAAK,KAAK;AAAA,IAClB;AAEA,WAAO,OAAO,OAAO,MAAM;AAAA,EAC5B;AAEA,QAAM,IAAI,UAAU,yBAAyB;AAC9C;AAjCsB;","names":[]}
\ No newline at end of file diff --git a/node_modules/@discordjs/rest/dist/types-65527f29.d.ts b/node_modules/@discordjs/rest/dist/types-65527f29.d.ts new file mode 100644 index 0000000..16c9e8b --- /dev/null +++ b/node_modules/@discordjs/rest/dist/types-65527f29.d.ts @@ -0,0 +1,363 @@ +import { Readable } from 'node:stream'; +import { ReadableStream } from 'node:stream/web'; +import { Collection } from '@discordjs/collection'; +import { RequestInit, Dispatcher, Response, BodyInit, Agent } from 'undici'; + +interface IHandler { + /** + * The unique id of the handler + */ + readonly id: string; + /** + * If the bucket is currently inactive (no pending requests) + */ + get inactive(): boolean; + /** + * Queues a request to be sent + * + * @param routeId - The generalized api route with literal ids for major parameters + * @param url - The url to do the request on + * @param options - All the information needed to make a request + * @param requestData - Extra data from the user's request needed for errors and additional processing + */ + queueRequest(routeId: RouteData, url: string, options: RequestInit, requestData: HandlerRequestData): Promise<ResponseLike>; +} + +interface RestEvents { + handlerSweep: [sweptHandlers: Collection<string, IHandler>]; + hashSweep: [sweptHashes: Collection<string, HashData>]; + invalidRequestWarning: [invalidRequestInfo: InvalidRequestWarningData]; + rateLimited: [rateLimitInfo: RateLimitData]; + response: [request: APIRequest, response: ResponseLike]; + restDebug: [info: string]; +} +type RestEventsMap = { + [K in keyof RestEvents]: RestEvents[K]; +}; +/** + * Options to be passed when creating the REST instance + */ +interface RESTOptions { + /** + * The agent to set globally + */ + agent: Dispatcher | null; + /** + * The base api path, without version + * + * @defaultValue `'https://discord.com/api'` + */ + api: string; + /** + * The authorization prefix to use for requests, useful if you want to use + * bearer tokens + * + * @defaultValue `'Bot'` + */ + authPrefix: 'Bearer' | 'Bot'; + /** + * The cdn path + * + * @defaultValue `'https://cdn.discordapp.com'` + */ + cdn: string; + /** + * How many requests to allow sending per second (Infinity for unlimited, 50 for the standard global limit used by Discord) + * + * @defaultValue `50` + */ + globalRequestsPerSecond: number; + /** + * The amount of time in milliseconds that passes between each hash sweep. (defaults to 1h) + * + * @defaultValue `3_600_000` + */ + handlerSweepInterval: number; + /** + * The maximum amount of time a hash can exist in milliseconds without being hit with a request (defaults to 24h) + * + * @defaultValue `86_400_000` + */ + hashLifetime: number; + /** + * The amount of time in milliseconds that passes between each hash sweep. (defaults to 4h) + * + * @defaultValue `14_400_000` + */ + hashSweepInterval: number; + /** + * Additional headers to send for all API requests + * + * @defaultValue `{}` + */ + headers: Record<string, string>; + /** + * The number of invalid REST requests (those that return 401, 403, or 429) in a 10 minute window between emitted warnings (0 for no warnings). + * That is, if set to 500, warnings will be emitted at invalid request number 500, 1000, 1500, and so on. + * + * @defaultValue `0` + */ + invalidRequestWarningInterval: number; + /** + * The method called to perform the actual HTTP request given a url and web `fetch` options + * For example, to use global fetch, simply provide `makeRequest: fetch` + */ + makeRequest(url: string, init: RequestInit): Promise<ResponseLike>; + /** + * The extra offset to add to rate limits in milliseconds + * + * @defaultValue `50` + */ + offset: number; + /** + * Determines how rate limiting and pre-emptive throttling should be handled. + * When an array of strings, each element is treated as a prefix for the request route + * (e.g. `/channels` to match any route starting with `/channels` such as `/channels/:id/messages`) + * for which to throw {@link RateLimitError}s. All other request routes will be queued normally + * + * @defaultValue `null` + */ + rejectOnRateLimit: RateLimitQueueFilter | string[] | null; + /** + * The number of retries for errors with the 500 code, or errors + * that timeout + * + * @defaultValue `3` + */ + retries: number; + /** + * The time to wait in milliseconds before a request is aborted + * + * @defaultValue `15_000` + */ + timeout: number; + /** + * Extra information to add to the user agent + * + * @defaultValue DefaultUserAgentAppendix + */ + userAgentAppendix: string; + /** + * The version of the API to use + * + * @defaultValue `'10'` + */ + version: string; +} +/** + * Data emitted on `RESTEvents.RateLimited` + */ +interface RateLimitData { + /** + * Whether the rate limit that was reached was the global limit + */ + global: boolean; + /** + * The bucket hash for this request + */ + hash: string; + /** + * The amount of requests we can perform before locking requests + */ + limit: number; + /** + * The major parameter of the route + * + * For example, in `/channels/x`, this will be `x`. + * If there is no major parameter (e.g: `/bot/gateway`) this will be `global`. + */ + majorParameter: string; + /** + * The HTTP method being performed + */ + method: string; + /** + * The route being hit in this request + */ + route: string; + /** + * The time, in milliseconds, until the request-lock is reset + */ + timeToReset: number; + /** + * The full URL for this request + */ + url: string; +} +/** + * A function that determines whether the rate limit hit should throw an Error + */ +type RateLimitQueueFilter = (rateLimitData: RateLimitData) => Promise<boolean> | boolean; +interface APIRequest { + /** + * The data that was used to form the body of this request + */ + data: HandlerRequestData; + /** + * The HTTP method used in this request + */ + method: string; + /** + * Additional HTTP options for this request + */ + options: RequestInit; + /** + * The full path used to make the request + */ + path: RouteLike; + /** + * The number of times this request has been attempted + */ + retries: number; + /** + * The API route identifying the ratelimit for this request + */ + route: string; +} +interface ResponseLike extends Pick<Response, 'arrayBuffer' | 'bodyUsed' | 'headers' | 'json' | 'ok' | 'status' | 'statusText' | 'text'> { + body: Readable | ReadableStream | null; +} +interface InvalidRequestWarningData { + /** + * Number of invalid requests that have been made in the window + */ + count: number; + /** + * Time in milliseconds remaining before the count resets + */ + remainingTime: number; +} +/** + * Represents a file to be added to the request + */ +interface RawFile { + /** + * Content-Type of the file + */ + contentType?: string; + /** + * The actual data for the file + */ + data: Buffer | Uint8Array | boolean | number | string; + /** + * An explicit key to use for key of the formdata field for this file. + * When not provided, the index of the file in the files array is used in the form `files[${index}]`. + * If you wish to alter the placeholder snowflake, you must provide this property in the same form (`files[${placeholder}]`) + */ + key?: string; + /** + * The name of the file + */ + name: string; +} +/** + * Represents possible data to be given to an endpoint + */ +interface RequestData { + /** + * Whether to append JSON data to form data instead of `payload_json` when sending files + */ + appendToFormData?: boolean; + /** + * If this request needs the `Authorization` header + * + * @defaultValue `true` + */ + auth?: boolean; + /** + * The authorization prefix to use for this request, useful if you use this with bearer tokens + * + * @defaultValue `'Bot'` + */ + authPrefix?: 'Bearer' | 'Bot'; + /** + * The body to send to this request. + * If providing as BodyInit, set `passThroughBody: true` + */ + body?: BodyInit | unknown; + /** + * The {@link https://undici.nodejs.org/#/docs/api/Agent | Agent} to use for the request. + */ + dispatcher?: Agent; + /** + * Files to be attached to this request + */ + files?: RawFile[] | undefined; + /** + * Additional headers to add to this request + */ + headers?: Record<string, string>; + /** + * Whether to pass-through the body property directly to `fetch()`. + * <warn>This only applies when files is NOT present</warn> + */ + passThroughBody?: boolean; + /** + * Query string parameters to append to the called endpoint + */ + query?: URLSearchParams; + /** + * Reason to show in the audit logs + */ + reason?: string | undefined; + /** + * The signal to abort the queue entry or the REST call, where applicable + */ + signal?: AbortSignal | undefined; + /** + * If this request should be versioned + * + * @defaultValue `true` + */ + versioned?: boolean; +} +/** + * Possible headers for an API call + */ +interface RequestHeaders { + Authorization?: string; + 'User-Agent': string; + 'X-Audit-Log-Reason'?: string; +} +/** + * Possible API methods to be used when doing requests + */ +declare enum RequestMethod { + Delete = "DELETE", + Get = "GET", + Patch = "PATCH", + Post = "POST", + Put = "PUT" +} +type RouteLike = `/${string}`; +/** + * Internal request options + * + * @internal + */ +interface InternalRequest extends RequestData { + fullRoute: RouteLike; + method: RequestMethod; +} +type HandlerRequestData = Pick<InternalRequest, 'auth' | 'body' | 'files' | 'signal'>; +/** + * Parsed route data for an endpoint + * + * @internal + */ +interface RouteData { + bucketRoute: string; + majorParameter: string; + original: RouteLike; +} +/** + * Represents a hash and its associated fields + * + * @internal + */ +interface HashData { + lastAccess: number; + value: string; +} + +export { APIRequest as A, HashData as H, InternalRequest as I, ResponseLike as R, RawFile as a, RateLimitData as b, RestEventsMap as c, IHandler as d, RESTOptions as e, RouteLike as f, RequestData as g, RestEvents as h, RateLimitQueueFilter as i, InvalidRequestWarningData as j, RequestHeaders as k, RequestMethod as l, HandlerRequestData as m, RouteData as n }; diff --git a/node_modules/@discordjs/rest/dist/web.d.mts b/node_modules/@discordjs/rest/dist/web.d.mts new file mode 100644 index 0000000..4a4ce8a --- /dev/null +++ b/node_modules/@discordjs/rest/dist/web.d.mts @@ -0,0 +1,9 @@ +export { ALLOWED_EXTENSIONS, ALLOWED_SIZES, ALLOWED_STICKER_EXTENSIONS, BaseImageURLOptions, BurstHandlerMajorIdKey, CDN, DefaultRestOptions, DefaultUserAgent, DefaultUserAgentAppendix, DiscordAPIError, DiscordErrorData, HTTPError, ImageExtension, ImageSize, ImageURLOptions, MakeURLOptions, OAuthErrorData, OverwrittenMimeTypes, REST, RESTEvents, RateLimitError, RequestBody, StickerExtension, calculateUserDefaultAvatarIndex, makeURLSearchParams, parseResponse, version } from './index.mjs'; +export { A as APIRequest, m as HandlerRequestData, H as HashData, I as InternalRequest, j as InvalidRequestWarningData, e as RESTOptions, b as RateLimitData, i as RateLimitQueueFilter, a as RawFile, g as RequestData, k as RequestHeaders, l as RequestMethod, R as ResponseLike, h as RestEvents, c as RestEventsMap, n as RouteData, f as RouteLike } from './types-65527f29.js'; +import 'url'; +import 'discord-api-types/v10'; +import 'undici'; +import '@discordjs/collection'; +import '@vladfrangu/async_event_emitter'; +import 'node:stream'; +import 'node:stream/web'; diff --git a/node_modules/@discordjs/rest/dist/web.d.ts b/node_modules/@discordjs/rest/dist/web.d.ts new file mode 100644 index 0000000..98e05e9 --- /dev/null +++ b/node_modules/@discordjs/rest/dist/web.d.ts @@ -0,0 +1,9 @@ +export { ALLOWED_EXTENSIONS, ALLOWED_SIZES, ALLOWED_STICKER_EXTENSIONS, BaseImageURLOptions, BurstHandlerMajorIdKey, CDN, DefaultRestOptions, DefaultUserAgent, DefaultUserAgentAppendix, DiscordAPIError, DiscordErrorData, HTTPError, ImageExtension, ImageSize, ImageURLOptions, MakeURLOptions, OAuthErrorData, OverwrittenMimeTypes, REST, RESTEvents, RateLimitError, RequestBody, StickerExtension, calculateUserDefaultAvatarIndex, makeURLSearchParams, parseResponse, version } from './index.js'; +export { A as APIRequest, m as HandlerRequestData, H as HashData, I as InternalRequest, j as InvalidRequestWarningData, e as RESTOptions, b as RateLimitData, i as RateLimitQueueFilter, a as RawFile, g as RequestData, k as RequestHeaders, l as RequestMethod, R as ResponseLike, h as RestEvents, c as RestEventsMap, n as RouteData, f as RouteLike } from './types-65527f29.js'; +import 'url'; +import 'discord-api-types/v10'; +import 'undici'; +import '@discordjs/collection'; +import '@vladfrangu/async_event_emitter'; +import 'node:stream'; +import 'node:stream/web'; diff --git a/node_modules/@discordjs/rest/dist/web.js b/node_modules/@discordjs/rest/dist/web.js new file mode 100644 index 0000000..191975b --- /dev/null +++ b/node_modules/@discordjs/rest/dist/web.js @@ -0,0 +1,1355 @@ +"use strict"; +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); + +// src/web.ts +var web_exports = {}; +__export(web_exports, { + ALLOWED_EXTENSIONS: () => ALLOWED_EXTENSIONS, + ALLOWED_SIZES: () => ALLOWED_SIZES, + ALLOWED_STICKER_EXTENSIONS: () => ALLOWED_STICKER_EXTENSIONS, + BurstHandlerMajorIdKey: () => BurstHandlerMajorIdKey, + CDN: () => CDN, + DefaultRestOptions: () => DefaultRestOptions, + DefaultUserAgent: () => DefaultUserAgent, + DefaultUserAgentAppendix: () => DefaultUserAgentAppendix, + DiscordAPIError: () => DiscordAPIError, + HTTPError: () => HTTPError, + OverwrittenMimeTypes: () => OverwrittenMimeTypes, + REST: () => REST, + RESTEvents: () => RESTEvents, + RateLimitError: () => RateLimitError, + RequestMethod: () => RequestMethod, + calculateUserDefaultAvatarIndex: () => calculateUserDefaultAvatarIndex, + makeURLSearchParams: () => makeURLSearchParams, + parseResponse: () => parseResponse, + version: () => version +}); +module.exports = __toCommonJS(web_exports); + +// src/environment.ts +var defaultStrategy; +function setDefaultStrategy(newStrategy) { + defaultStrategy = newStrategy; +} +__name(setDefaultStrategy, "setDefaultStrategy"); +function getDefaultStrategy() { + return defaultStrategy; +} +__name(getDefaultStrategy, "getDefaultStrategy"); + +// src/lib/utils/constants.ts +var import_util = require("@discordjs/util"); +var import_v10 = require("discord-api-types/v10"); +var DefaultUserAgent = `DiscordBot (https://discord.js.org, 2.0.1)`; +var DefaultUserAgentAppendix = (0, import_util.getUserAgentAppendix)(); +var DefaultRestOptions = { + agent: null, + api: "https://discord.com/api", + authPrefix: "Bot", + cdn: "https://cdn.discordapp.com", + headers: {}, + invalidRequestWarningInterval: 0, + globalRequestsPerSecond: 50, + offset: 50, + rejectOnRateLimit: null, + retries: 3, + timeout: 15e3, + userAgentAppendix: DefaultUserAgentAppendix, + version: import_v10.APIVersion, + hashSweepInterval: 144e5, + // 4 Hours + hashLifetime: 864e5, + // 24 Hours + handlerSweepInterval: 36e5, + // 1 Hour + async makeRequest(...args) { + return getDefaultStrategy()(...args); + } +}; +var RESTEvents = /* @__PURE__ */ ((RESTEvents2) => { + RESTEvents2["Debug"] = "restDebug"; + RESTEvents2["HandlerSweep"] = "handlerSweep"; + RESTEvents2["HashSweep"] = "hashSweep"; + RESTEvents2["InvalidRequestWarning"] = "invalidRequestWarning"; + RESTEvents2["RateLimited"] = "rateLimited"; + RESTEvents2["Response"] = "response"; + return RESTEvents2; +})(RESTEvents || {}); +var ALLOWED_EXTENSIONS = ["webp", "png", "jpg", "jpeg", "gif"]; +var ALLOWED_STICKER_EXTENSIONS = ["png", "json", "gif"]; +var ALLOWED_SIZES = [16, 32, 64, 128, 256, 512, 1024, 2048, 4096]; +var OverwrittenMimeTypes = { + // https://github.com/discordjs/discord.js/issues/8557 + "image/apng": "image/png" +}; +var BurstHandlerMajorIdKey = "burst"; + +// src/lib/CDN.ts +var CDN = class { + constructor(base = DefaultRestOptions.cdn) { + this.base = base; + } + static { + __name(this, "CDN"); + } + /** + * Generates an app asset URL for a client's asset. + * + * @param clientId - The client id that has the asset + * @param assetHash - The hash provided by Discord for this asset + * @param options - Optional options for the asset + */ + appAsset(clientId, assetHash, options) { + return this.makeURL(`/app-assets/${clientId}/${assetHash}`, options); + } + /** + * Generates an app icon URL for a client's icon. + * + * @param clientId - The client id that has the icon + * @param iconHash - The hash provided by Discord for this icon + * @param options - Optional options for the icon + */ + appIcon(clientId, iconHash, options) { + return this.makeURL(`/app-icons/${clientId}/${iconHash}`, options); + } + /** + * Generates an avatar URL, e.g. for a user or a webhook. + * + * @param id - The id that has the icon + * @param avatarHash - The hash provided by Discord for this avatar + * @param options - Optional options for the avatar + */ + avatar(id, avatarHash, options) { + return this.dynamicMakeURL(`/avatars/${id}/${avatarHash}`, avatarHash, options); + } + /** + * Generates a user avatar decoration URL. + * + * @param userId - The id of the user + * @param userAvatarDecoration - The hash provided by Discord for this avatar decoration + * @param options - Optional options for the avatar decoration + */ + avatarDecoration(userId, userAvatarDecoration, options) { + return this.makeURL(`/avatar-decorations/${userId}/${userAvatarDecoration}`, options); + } + /** + * Generates a banner URL, e.g. for a user or a guild. + * + * @param id - The id that has the banner splash + * @param bannerHash - The hash provided by Discord for this banner + * @param options - Optional options for the banner + */ + banner(id, bannerHash, options) { + return this.dynamicMakeURL(`/banners/${id}/${bannerHash}`, bannerHash, options); + } + /** + * Generates an icon URL for a channel, e.g. a group DM. + * + * @param channelId - The channel id that has the icon + * @param iconHash - The hash provided by Discord for this channel + * @param options - Optional options for the icon + */ + channelIcon(channelId, iconHash, options) { + return this.makeURL(`/channel-icons/${channelId}/${iconHash}`, options); + } + /** + * Generates a default avatar URL + * + * @param index - The default avatar index + * @remarks + * To calculate the index for a user do `(userId >> 22) % 6`, + * or `discriminator % 5` if they're using the legacy username system. + */ + defaultAvatar(index) { + return this.makeURL(`/embed/avatars/${index}`, { extension: "png" }); + } + /** + * Generates a discovery splash URL for a guild's discovery splash. + * + * @param guildId - The guild id that has the discovery splash + * @param splashHash - The hash provided by Discord for this splash + * @param options - Optional options for the splash + */ + discoverySplash(guildId, splashHash, options) { + return this.makeURL(`/discovery-splashes/${guildId}/${splashHash}`, options); + } + /** + * Generates an emoji's URL for an emoji. + * + * @param emojiId - The emoji id + * @param extension - The extension of the emoji + */ + emoji(emojiId, extension) { + return this.makeURL(`/emojis/${emojiId}`, { extension }); + } + /** + * Generates a guild member avatar URL. + * + * @param guildId - The id of the guild + * @param userId - The id of the user + * @param avatarHash - The hash provided by Discord for this avatar + * @param options - Optional options for the avatar + */ + guildMemberAvatar(guildId, userId, avatarHash, options) { + return this.dynamicMakeURL(`/guilds/${guildId}/users/${userId}/avatars/${avatarHash}`, avatarHash, options); + } + /** + * Generates a guild member banner URL. + * + * @param guildId - The id of the guild + * @param userId - The id of the user + * @param bannerHash - The hash provided by Discord for this banner + * @param options - Optional options for the banner + */ + guildMemberBanner(guildId, userId, bannerHash, options) { + return this.dynamicMakeURL(`/guilds/${guildId}/users/${userId}/banner`, bannerHash, options); + } + /** + * Generates an icon URL, e.g. for a guild. + * + * @param id - The id that has the icon splash + * @param iconHash - The hash provided by Discord for this icon + * @param options - Optional options for the icon + */ + icon(id, iconHash, options) { + return this.dynamicMakeURL(`/icons/${id}/${iconHash}`, iconHash, options); + } + /** + * Generates a URL for the icon of a role + * + * @param roleId - The id of the role that has the icon + * @param roleIconHash - The hash provided by Discord for this role icon + * @param options - Optional options for the role icon + */ + roleIcon(roleId, roleIconHash, options) { + return this.makeURL(`/role-icons/${roleId}/${roleIconHash}`, options); + } + /** + * Generates a guild invite splash URL for a guild's invite splash. + * + * @param guildId - The guild id that has the invite splash + * @param splashHash - The hash provided by Discord for this splash + * @param options - Optional options for the splash + */ + splash(guildId, splashHash, options) { + return this.makeURL(`/splashes/${guildId}/${splashHash}`, options); + } + /** + * Generates a sticker URL. + * + * @param stickerId - The sticker id + * @param extension - The extension of the sticker + * @privateRemarks + * Stickers cannot have a `.webp` extension, so we default to a `.png` + */ + sticker(stickerId, extension = "png") { + return this.makeURL(`/stickers/${stickerId}`, { allowedExtensions: ALLOWED_STICKER_EXTENSIONS, extension }); + } + /** + * Generates a sticker pack banner URL. + * + * @param bannerId - The banner id + * @param options - Optional options for the banner + */ + stickerPackBanner(bannerId, options) { + return this.makeURL(`/app-assets/710982414301790216/store/${bannerId}`, options); + } + /** + * Generates a team icon URL for a team's icon. + * + * @param teamId - The team id that has the icon + * @param iconHash - The hash provided by Discord for this icon + * @param options - Optional options for the icon + */ + teamIcon(teamId, iconHash, options) { + return this.makeURL(`/team-icons/${teamId}/${iconHash}`, options); + } + /** + * Generates a cover image for a guild scheduled event. + * + * @param scheduledEventId - The scheduled event id + * @param coverHash - The hash provided by discord for this cover image + * @param options - Optional options for the cover image + */ + guildScheduledEventCover(scheduledEventId, coverHash, options) { + return this.makeURL(`/guild-events/${scheduledEventId}/${coverHash}`, options); + } + /** + * Constructs the URL for the resource, checking whether or not `hash` starts with `a_` if `dynamic` is set to `true`. + * + * @param route - The base cdn route + * @param hash - The hash provided by Discord for this icon + * @param options - Optional options for the link + */ + dynamicMakeURL(route, hash, { forceStatic = false, ...options } = {}) { + return this.makeURL(route, !forceStatic && hash.startsWith("a_") ? { ...options, extension: "gif" } : options); + } + /** + * Constructs the URL for the resource + * + * @param route - The base cdn route + * @param options - The extension/size options for the link + */ + makeURL(route, { allowedExtensions = ALLOWED_EXTENSIONS, extension = "webp", size } = {}) { + extension = String(extension).toLowerCase(); + if (!allowedExtensions.includes(extension)) { + throw new RangeError(`Invalid extension provided: ${extension} +Must be one of: ${allowedExtensions.join(", ")}`); + } + if (size && !ALLOWED_SIZES.includes(size)) { + throw new RangeError(`Invalid size provided: ${size} +Must be one of: ${ALLOWED_SIZES.join(", ")}`); + } + const url = new URL(`${this.base}${route}.${extension}`); + if (size) { + url.searchParams.set("size", String(size)); + } + return url.toString(); + } +}; + +// src/lib/errors/DiscordAPIError.ts +function isErrorGroupWrapper(error) { + return Reflect.has(error, "_errors"); +} +__name(isErrorGroupWrapper, "isErrorGroupWrapper"); +function isErrorResponse(error) { + return typeof Reflect.get(error, "message") === "string"; +} +__name(isErrorResponse, "isErrorResponse"); +var DiscordAPIError = class _DiscordAPIError extends Error { + /** + * @param rawError - The error reported by Discord + * @param code - The error code reported by Discord + * @param status - The status code of the response + * @param method - The method of the request that erred + * @param url - The url of the request that erred + * @param bodyData - The unparsed data for the request that errored + */ + constructor(rawError, code, status, method, url, bodyData) { + super(_DiscordAPIError.getMessage(rawError)); + this.rawError = rawError; + this.code = code; + this.status = status; + this.method = method; + this.url = url; + this.requestBody = { files: bodyData.files, json: bodyData.body }; + } + static { + __name(this, "DiscordAPIError"); + } + requestBody; + /** + * The name of the error + */ + get name() { + return `${_DiscordAPIError.name}[${this.code}]`; + } + static getMessage(error) { + let flattened = ""; + if ("code" in error) { + if (error.errors) { + flattened = [...this.flattenDiscordError(error.errors)].join("\n"); + } + return error.message && flattened ? `${error.message} +${flattened}` : error.message || flattened || "Unknown Error"; + } + return error.error_description ?? "No Description"; + } + static *flattenDiscordError(obj, key = "") { + if (isErrorResponse(obj)) { + return yield `${key.length ? `${key}[${obj.code}]` : `${obj.code}`}: ${obj.message}`.trim(); + } + for (const [otherKey, val] of Object.entries(obj)) { + const nextKey = otherKey.startsWith("_") ? key : key ? Number.isNaN(Number(otherKey)) ? `${key}.${otherKey}` : `${key}[${otherKey}]` : otherKey; + if (typeof val === "string") { + yield val; + } else if (isErrorGroupWrapper(val)) { + for (const error of val._errors) { + yield* this.flattenDiscordError(error, nextKey); + } + } else { + yield* this.flattenDiscordError(val, nextKey); + } + } + } +}; + +// src/lib/errors/HTTPError.ts +var HTTPError = class _HTTPError extends Error { + /** + * @param status - The status code of the response + * @param statusText - The status text of the response + * @param method - The method of the request that erred + * @param url - The url of the request that erred + * @param bodyData - The unparsed data for the request that errored + */ + constructor(status, statusText, method, url, bodyData) { + super(statusText); + this.status = status; + this.method = method; + this.url = url; + this.requestBody = { files: bodyData.files, json: bodyData.body }; + } + static { + __name(this, "HTTPError"); + } + requestBody; + name = _HTTPError.name; +}; + +// src/lib/errors/RateLimitError.ts +var RateLimitError = class _RateLimitError extends Error { + static { + __name(this, "RateLimitError"); + } + timeToReset; + limit; + method; + hash; + url; + route; + majorParameter; + global; + constructor({ timeToReset, limit, method, hash, url, route, majorParameter, global }) { + super(); + this.timeToReset = timeToReset; + this.limit = limit; + this.method = method; + this.hash = hash; + this.url = url; + this.route = route; + this.majorParameter = majorParameter; + this.global = global; + } + /** + * The name of the error + */ + get name() { + return `${_RateLimitError.name}[${this.route}]`; + } +}; + +// src/lib/REST.ts +var import_collection = require("@discordjs/collection"); +var import_snowflake = require("@sapphire/snowflake"); +var import_async_event_emitter = require("@vladfrangu/async_event_emitter"); +var import_magic_bytes = require("magic-bytes.js"); + +// src/lib/utils/types.ts +var RequestMethod = /* @__PURE__ */ ((RequestMethod2) => { + RequestMethod2["Delete"] = "DELETE"; + RequestMethod2["Get"] = "GET"; + RequestMethod2["Patch"] = "PATCH"; + RequestMethod2["Post"] = "POST"; + RequestMethod2["Put"] = "PUT"; + return RequestMethod2; +})(RequestMethod || {}); + +// src/lib/utils/utils.ts +function serializeSearchParam(value) { + switch (typeof value) { + case "string": + return value; + case "number": + case "bigint": + case "boolean": + return value.toString(); + case "object": + if (value === null) + return null; + if (value instanceof Date) { + return Number.isNaN(value.getTime()) ? null : value.toISOString(); + } + if (typeof value.toString === "function" && value.toString !== Object.prototype.toString) + return value.toString(); + return null; + default: + return null; + } +} +__name(serializeSearchParam, "serializeSearchParam"); +function makeURLSearchParams(options) { + const params = new URLSearchParams(); + if (!options) + return params; + for (const [key, value] of Object.entries(options)) { + const serialized = serializeSearchParam(value); + if (serialized !== null) + params.append(key, serialized); + } + return params; +} +__name(makeURLSearchParams, "makeURLSearchParams"); +async function parseResponse(res) { + if (res.headers.get("Content-Type")?.startsWith("application/json")) { + return res.json(); + } + return res.arrayBuffer(); +} +__name(parseResponse, "parseResponse"); +function hasSublimit(bucketRoute, body, method) { + if (bucketRoute === "/channels/:id") { + if (typeof body !== "object" || body === null) + return false; + if (method !== "PATCH" /* Patch */) + return false; + const castedBody = body; + return ["name", "topic"].some((key) => Reflect.has(castedBody, key)); + } + return true; +} +__name(hasSublimit, "hasSublimit"); +function shouldRetry(error) { + if (error.name === "AbortError") + return true; + return "code" in error && error.code === "ECONNRESET" || error.message.includes("ECONNRESET"); +} +__name(shouldRetry, "shouldRetry"); +async function onRateLimit(manager, rateLimitData) { + const { options } = manager; + if (!options.rejectOnRateLimit) + return; + const shouldThrow = typeof options.rejectOnRateLimit === "function" ? await options.rejectOnRateLimit(rateLimitData) : options.rejectOnRateLimit.some((route) => rateLimitData.route.startsWith(route.toLowerCase())); + if (shouldThrow) { + throw new RateLimitError(rateLimitData); + } +} +__name(onRateLimit, "onRateLimit"); +function calculateUserDefaultAvatarIndex(userId) { + return Number(BigInt(userId) >> 22n) % 6; +} +__name(calculateUserDefaultAvatarIndex, "calculateUserDefaultAvatarIndex"); +async function sleep(ms) { + return new Promise((resolve) => { + setTimeout(() => resolve(), ms); + }); +} +__name(sleep, "sleep"); +function isBufferLike(value) { + return value instanceof ArrayBuffer || value instanceof Uint8Array || value instanceof Uint8ClampedArray; +} +__name(isBufferLike, "isBufferLike"); + +// src/lib/handlers/Shared.ts +var invalidCount = 0; +var invalidCountResetTime = null; +function incrementInvalidCount(manager) { + if (!invalidCountResetTime || invalidCountResetTime < Date.now()) { + invalidCountResetTime = Date.now() + 1e3 * 60 * 10; + invalidCount = 0; + } + invalidCount++; + const emitInvalid = manager.options.invalidRequestWarningInterval > 0 && invalidCount % manager.options.invalidRequestWarningInterval === 0; + if (emitInvalid) { + manager.emit("invalidRequestWarning" /* InvalidRequestWarning */, { + count: invalidCount, + remainingTime: invalidCountResetTime - Date.now() + }); + } +} +__name(incrementInvalidCount, "incrementInvalidCount"); +async function makeNetworkRequest(manager, routeId, url, options, requestData, retries) { + const controller = new AbortController(); + const timeout = setTimeout(() => controller.abort(), manager.options.timeout); + if (requestData.signal) { + if (requestData.signal.aborted) + controller.abort(); + else + requestData.signal.addEventListener("abort", () => controller.abort()); + } + let res; + try { + res = await manager.options.makeRequest(url, { ...options, signal: controller.signal }); + } catch (error) { + if (!(error instanceof Error)) + throw error; + if (shouldRetry(error) && retries !== manager.options.retries) { + return null; + } + throw error; + } finally { + clearTimeout(timeout); + } + if (manager.listenerCount("response" /* Response */)) { + manager.emit( + "response" /* Response */, + { + method: options.method ?? "get", + path: routeId.original, + route: routeId.bucketRoute, + options, + data: requestData, + retries + }, + res instanceof Response ? res.clone() : { ...res } + ); + } + return res; +} +__name(makeNetworkRequest, "makeNetworkRequest"); +async function handleErrors(manager, res, method, url, requestData, retries) { + const status = res.status; + if (status >= 500 && status < 600) { + if (retries !== manager.options.retries) { + return null; + } + throw new HTTPError(status, res.statusText, method, url, requestData); + } else { + if (status >= 400 && status < 500) { + if (status === 401 && requestData.auth) { + manager.setToken(null); + } + const data = await parseResponse(res); + throw new DiscordAPIError(data, "code" in data ? data.code : data.error, status, method, url, requestData); + } + return res; + } +} +__name(handleErrors, "handleErrors"); + +// src/lib/handlers/BurstHandler.ts +var BurstHandler = class { + /** + * @param manager - The request manager + * @param hash - The hash that this RequestHandler handles + * @param majorParameter - The major parameter for this handler + */ + constructor(manager, hash, majorParameter) { + this.manager = manager; + this.hash = hash; + this.majorParameter = majorParameter; + this.id = `${hash}:${majorParameter}`; + } + static { + __name(this, "BurstHandler"); + } + /** + * {@inheritdoc IHandler.id} + */ + id; + /** + * {@inheritDoc IHandler.inactive} + */ + inactive = false; + /** + * Emits a debug message + * + * @param message - The message to debug + */ + debug(message) { + this.manager.emit("restDebug" /* Debug */, `[REST ${this.id}] ${message}`); + } + /** + * {@inheritDoc IHandler.queueRequest} + */ + async queueRequest(routeId, url, options, requestData) { + return this.runRequest(routeId, url, options, requestData); + } + /** + * The method that actually makes the request to the API, and updates info about the bucket accordingly + * + * @param routeId - The generalized API route with literal ids for major parameters + * @param url - The fully resolved URL to make the request to + * @param options - The fetch options needed to make the request + * @param requestData - Extra data from the user's request needed for errors and additional processing + * @param retries - The number of retries this request has already attempted (recursion) + */ + async runRequest(routeId, url, options, requestData, retries = 0) { + const method = options.method ?? "get"; + const res = await makeNetworkRequest(this.manager, routeId, url, options, requestData, retries); + if (res === null) { + return this.runRequest(routeId, url, options, requestData, ++retries); + } + const status = res.status; + let retryAfter = 0; + const retry = res.headers.get("Retry-After"); + if (retry) + retryAfter = Number(retry) * 1e3 + this.manager.options.offset; + if (status === 401 || status === 403 || status === 429) { + incrementInvalidCount(this.manager); + } + if (status >= 200 && status < 300) { + return res; + } else if (status === 429) { + const isGlobal = res.headers.has("X-RateLimit-Global"); + await onRateLimit(this.manager, { + timeToReset: retryAfter, + limit: Number.POSITIVE_INFINITY, + method, + hash: this.hash, + url, + route: routeId.bucketRoute, + majorParameter: this.majorParameter, + global: isGlobal + }); + this.debug( + [ + "Encountered unexpected 429 rate limit", + ` Global : ${isGlobal}`, + ` Method : ${method}`, + ` URL : ${url}`, + ` Bucket : ${routeId.bucketRoute}`, + ` Major parameter: ${routeId.majorParameter}`, + ` Hash : ${this.hash}`, + ` Limit : ${Number.POSITIVE_INFINITY}`, + ` Retry After : ${retryAfter}ms`, + ` Sublimit : None` + ].join("\n") + ); + await sleep(retryAfter); + return this.runRequest(routeId, url, options, requestData, retries); + } else { + const handled = await handleErrors(this.manager, res, method, url, requestData, retries); + if (handled === null) { + return this.runRequest(routeId, url, options, requestData, ++retries); + } + return handled; + } + } +}; + +// src/lib/handlers/SequentialHandler.ts +var import_async_queue = require("@sapphire/async-queue"); +var SequentialHandler = class { + /** + * @param manager - The request manager + * @param hash - The hash that this RequestHandler handles + * @param majorParameter - The major parameter for this handler + */ + constructor(manager, hash, majorParameter) { + this.manager = manager; + this.hash = hash; + this.majorParameter = majorParameter; + this.id = `${hash}:${majorParameter}`; + } + static { + __name(this, "SequentialHandler"); + } + /** + * {@inheritDoc IHandler.id} + */ + id; + /** + * The time this rate limit bucket will reset + */ + reset = -1; + /** + * The remaining requests that can be made before we are rate limited + */ + remaining = 1; + /** + * The total number of requests that can be made before we are rate limited + */ + limit = Number.POSITIVE_INFINITY; + /** + * The interface used to sequence async requests sequentially + */ + #asyncQueue = new import_async_queue.AsyncQueue(); + /** + * The interface used to sequence sublimited async requests sequentially + */ + #sublimitedQueue = null; + /** + * A promise wrapper for when the sublimited queue is finished being processed or null when not being processed + */ + #sublimitPromise = null; + /** + * Whether the sublimit queue needs to be shifted in the finally block + */ + #shiftSublimit = false; + /** + * {@inheritDoc IHandler.inactive} + */ + get inactive() { + return this.#asyncQueue.remaining === 0 && (this.#sublimitedQueue === null || this.#sublimitedQueue.remaining === 0) && !this.limited; + } + /** + * If the rate limit bucket is currently limited by the global limit + */ + get globalLimited() { + return this.manager.globalRemaining <= 0 && Date.now() < this.manager.globalReset; + } + /** + * If the rate limit bucket is currently limited by its limit + */ + get localLimited() { + return this.remaining <= 0 && Date.now() < this.reset; + } + /** + * If the rate limit bucket is currently limited + */ + get limited() { + return this.globalLimited || this.localLimited; + } + /** + * The time until queued requests can continue + */ + get timeToReset() { + return this.reset + this.manager.options.offset - Date.now(); + } + /** + * Emits a debug message + * + * @param message - The message to debug + */ + debug(message) { + this.manager.emit("restDebug" /* Debug */, `[REST ${this.id}] ${message}`); + } + /** + * Delay all requests for the specified amount of time, handling global rate limits + * + * @param time - The amount of time to delay all requests for + */ + async globalDelayFor(time) { + await sleep(time); + this.manager.globalDelay = null; + } + /** + * {@inheritDoc IHandler.queueRequest} + */ + async queueRequest(routeId, url, options, requestData) { + let queue = this.#asyncQueue; + let queueType = 0 /* Standard */; + if (this.#sublimitedQueue && hasSublimit(routeId.bucketRoute, requestData.body, options.method)) { + queue = this.#sublimitedQueue; + queueType = 1 /* Sublimit */; + } + await queue.wait({ signal: requestData.signal }); + if (queueType === 0 /* Standard */) { + if (this.#sublimitedQueue && hasSublimit(routeId.bucketRoute, requestData.body, options.method)) { + queue = this.#sublimitedQueue; + const wait = queue.wait(); + this.#asyncQueue.shift(); + await wait; + } else if (this.#sublimitPromise) { + await this.#sublimitPromise.promise; + } + } + try { + return await this.runRequest(routeId, url, options, requestData); + } finally { + queue.shift(); + if (this.#shiftSublimit) { + this.#shiftSublimit = false; + this.#sublimitedQueue?.shift(); + } + if (this.#sublimitedQueue?.remaining === 0) { + this.#sublimitPromise?.resolve(); + this.#sublimitedQueue = null; + } + } + } + /** + * The method that actually makes the request to the api, and updates info about the bucket accordingly + * + * @param routeId - The generalized api route with literal ids for major parameters + * @param url - The fully resolved url to make the request to + * @param options - The fetch options needed to make the request + * @param requestData - Extra data from the user's request needed for errors and additional processing + * @param retries - The number of retries this request has already attempted (recursion) + */ + async runRequest(routeId, url, options, requestData, retries = 0) { + while (this.limited) { + const isGlobal = this.globalLimited; + let limit2; + let timeout; + let delay; + if (isGlobal) { + limit2 = this.manager.options.globalRequestsPerSecond; + timeout = this.manager.globalReset + this.manager.options.offset - Date.now(); + if (!this.manager.globalDelay) { + this.manager.globalDelay = this.globalDelayFor(timeout); + } + delay = this.manager.globalDelay; + } else { + limit2 = this.limit; + timeout = this.timeToReset; + delay = sleep(timeout); + } + const rateLimitData = { + timeToReset: timeout, + limit: limit2, + method: options.method ?? "get", + hash: this.hash, + url, + route: routeId.bucketRoute, + majorParameter: this.majorParameter, + global: isGlobal + }; + this.manager.emit("rateLimited" /* RateLimited */, rateLimitData); + await onRateLimit(this.manager, rateLimitData); + if (isGlobal) { + this.debug(`Global rate limit hit, blocking all requests for ${timeout}ms`); + } else { + this.debug(`Waiting ${timeout}ms for rate limit to pass`); + } + await delay; + } + if (!this.manager.globalReset || this.manager.globalReset < Date.now()) { + this.manager.globalReset = Date.now() + 1e3; + this.manager.globalRemaining = this.manager.options.globalRequestsPerSecond; + } + this.manager.globalRemaining--; + const method = options.method ?? "get"; + const res = await makeNetworkRequest(this.manager, routeId, url, options, requestData, retries); + if (res === null) { + return this.runRequest(routeId, url, options, requestData, ++retries); + } + const status = res.status; + let retryAfter = 0; + const limit = res.headers.get("X-RateLimit-Limit"); + const remaining = res.headers.get("X-RateLimit-Remaining"); + const reset = res.headers.get("X-RateLimit-Reset-After"); + const hash = res.headers.get("X-RateLimit-Bucket"); + const retry = res.headers.get("Retry-After"); + this.limit = limit ? Number(limit) : Number.POSITIVE_INFINITY; + this.remaining = remaining ? Number(remaining) : 1; + this.reset = reset ? Number(reset) * 1e3 + Date.now() + this.manager.options.offset : Date.now(); + if (retry) + retryAfter = Number(retry) * 1e3 + this.manager.options.offset; + if (hash && hash !== this.hash) { + this.debug(["Received bucket hash update", ` Old Hash : ${this.hash}`, ` New Hash : ${hash}`].join("\n")); + this.manager.hashes.set(`${method}:${routeId.bucketRoute}`, { value: hash, lastAccess: Date.now() }); + } else if (hash) { + const hashData = this.manager.hashes.get(`${method}:${routeId.bucketRoute}`); + if (hashData) { + hashData.lastAccess = Date.now(); + } + } + let sublimitTimeout = null; + if (retryAfter > 0) { + if (res.headers.has("X-RateLimit-Global")) { + this.manager.globalRemaining = 0; + this.manager.globalReset = Date.now() + retryAfter; + } else if (!this.localLimited) { + sublimitTimeout = retryAfter; + } + } + if (status === 401 || status === 403 || status === 429) { + incrementInvalidCount(this.manager); + } + if (res.ok) { + return res; + } else if (status === 429) { + const isGlobal = this.globalLimited; + let limit2; + let timeout; + if (isGlobal) { + limit2 = this.manager.options.globalRequestsPerSecond; + timeout = this.manager.globalReset + this.manager.options.offset - Date.now(); + } else { + limit2 = this.limit; + timeout = this.timeToReset; + } + await onRateLimit(this.manager, { + timeToReset: timeout, + limit: limit2, + method, + hash: this.hash, + url, + route: routeId.bucketRoute, + majorParameter: this.majorParameter, + global: isGlobal + }); + this.debug( + [ + "Encountered unexpected 429 rate limit", + ` Global : ${isGlobal.toString()}`, + ` Method : ${method}`, + ` URL : ${url}`, + ` Bucket : ${routeId.bucketRoute}`, + ` Major parameter: ${routeId.majorParameter}`, + ` Hash : ${this.hash}`, + ` Limit : ${limit2}`, + ` Retry After : ${retryAfter}ms`, + ` Sublimit : ${sublimitTimeout ? `${sublimitTimeout}ms` : "None"}` + ].join("\n") + ); + if (sublimitTimeout) { + const firstSublimit = !this.#sublimitedQueue; + if (firstSublimit) { + this.#sublimitedQueue = new import_async_queue.AsyncQueue(); + void this.#sublimitedQueue.wait(); + this.#asyncQueue.shift(); + } + this.#sublimitPromise?.resolve(); + this.#sublimitPromise = null; + await sleep(sublimitTimeout); + let resolve; + const promise = new Promise((res2) => resolve = res2); + this.#sublimitPromise = { promise, resolve }; + if (firstSublimit) { + await this.#asyncQueue.wait(); + this.#shiftSublimit = true; + } + } + return this.runRequest(routeId, url, options, requestData, retries); + } else { + const handled = await handleErrors(this.manager, res, method, url, requestData, retries); + if (handled === null) { + return this.runRequest(routeId, url, options, requestData, ++retries); + } + return handled; + } + } +}; + +// src/lib/REST.ts +var REST = class _REST extends import_async_event_emitter.AsyncEventEmitter { + static { + __name(this, "REST"); + } + /** + * The {@link https://undici.nodejs.org/#/docs/api/Agent | Agent} for all requests + * performed by this manager. + */ + agent = null; + cdn; + /** + * The number of requests remaining in the global bucket + */ + globalRemaining; + /** + * The promise used to wait out the global rate limit + */ + globalDelay = null; + /** + * The timestamp at which the global bucket resets + */ + globalReset = -1; + /** + * API bucket hashes that are cached from provided routes + */ + hashes = new import_collection.Collection(); + /** + * Request handlers created from the bucket hash and the major parameters + */ + handlers = new import_collection.Collection(); + #token = null; + hashTimer; + handlerTimer; + options; + constructor(options = {}) { + super(); + this.cdn = new CDN(options.cdn ?? DefaultRestOptions.cdn); + this.options = { ...DefaultRestOptions, ...options }; + this.options.offset = Math.max(0, this.options.offset); + this.globalRemaining = Math.max(1, this.options.globalRequestsPerSecond); + this.agent = options.agent ?? null; + this.setupSweepers(); + } + setupSweepers() { + const validateMaxInterval = /* @__PURE__ */ __name((interval) => { + if (interval > 144e5) { + throw new Error("Cannot set an interval greater than 4 hours"); + } + }, "validateMaxInterval"); + if (this.options.hashSweepInterval !== 0 && this.options.hashSweepInterval !== Number.POSITIVE_INFINITY) { + validateMaxInterval(this.options.hashSweepInterval); + this.hashTimer = setInterval(() => { + const sweptHashes = new import_collection.Collection(); + const currentDate = Date.now(); + this.hashes.sweep((val, key) => { + if (val.lastAccess === -1) + return false; + const shouldSweep = Math.floor(currentDate - val.lastAccess) > this.options.hashLifetime; + if (shouldSweep) { + sweptHashes.set(key, val); + this.emit("restDebug" /* Debug */, `Hash ${val.value} for ${key} swept due to lifetime being exceeded`); + } + return shouldSweep; + }); + this.emit("hashSweep" /* HashSweep */, sweptHashes); + }, this.options.hashSweepInterval); + this.hashTimer.unref?.(); + } + if (this.options.handlerSweepInterval !== 0 && this.options.handlerSweepInterval !== Number.POSITIVE_INFINITY) { + validateMaxInterval(this.options.handlerSweepInterval); + this.handlerTimer = setInterval(() => { + const sweptHandlers = new import_collection.Collection(); + this.handlers.sweep((val, key) => { + const { inactive } = val; + if (inactive) { + sweptHandlers.set(key, val); + this.emit("restDebug" /* Debug */, `Handler ${val.id} for ${key} swept due to being inactive`); + } + return inactive; + }); + this.emit("handlerSweep" /* HandlerSweep */, sweptHandlers); + }, this.options.handlerSweepInterval); + this.handlerTimer.unref?.(); + } + } + /** + * Runs a get request from the api + * + * @param fullRoute - The full route to query + * @param options - Optional request options + */ + async get(fullRoute, options = {}) { + return this.request({ ...options, fullRoute, method: "GET" /* Get */ }); + } + /** + * Runs a delete request from the api + * + * @param fullRoute - The full route to query + * @param options - Optional request options + */ + async delete(fullRoute, options = {}) { + return this.request({ ...options, fullRoute, method: "DELETE" /* Delete */ }); + } + /** + * Runs a post request from the api + * + * @param fullRoute - The full route to query + * @param options - Optional request options + */ + async post(fullRoute, options = {}) { + return this.request({ ...options, fullRoute, method: "POST" /* Post */ }); + } + /** + * Runs a put request from the api + * + * @param fullRoute - The full route to query + * @param options - Optional request options + */ + async put(fullRoute, options = {}) { + return this.request({ ...options, fullRoute, method: "PUT" /* Put */ }); + } + /** + * Runs a patch request from the api + * + * @param fullRoute - The full route to query + * @param options - Optional request options + */ + async patch(fullRoute, options = {}) { + return this.request({ ...options, fullRoute, method: "PATCH" /* Patch */ }); + } + /** + * Runs a request from the api + * + * @param options - Request options + */ + async request(options) { + const response = await this.queueRequest(options); + return parseResponse(response); + } + /** + * Sets the default agent to use for requests performed by this manager + * + * @param agent - The agent to use + */ + setAgent(agent) { + this.agent = agent; + return this; + } + /** + * Sets the authorization token that should be used for requests + * + * @param token - The authorization token to use + */ + setToken(token) { + this.#token = token; + return this; + } + /** + * Queues a request to be sent + * + * @param request - All the information needed to make a request + * @returns The response from the api request + */ + async queueRequest(request) { + const routeId = _REST.generateRouteData(request.fullRoute, request.method); + const hash = this.hashes.get(`${request.method}:${routeId.bucketRoute}`) ?? { + value: `Global(${request.method}:${routeId.bucketRoute})`, + lastAccess: -1 + }; + const handler = this.handlers.get(`${hash.value}:${routeId.majorParameter}`) ?? this.createHandler(hash.value, routeId.majorParameter); + const { url, fetchOptions } = await this.resolveRequest(request); + return handler.queueRequest(routeId, url, fetchOptions, { + body: request.body, + files: request.files, + auth: request.auth !== false, + signal: request.signal + }); + } + /** + * Creates a new rate limit handler from a hash, based on the hash and the major parameter + * + * @param hash - The hash for the route + * @param majorParameter - The major parameter for this handler + * @internal + */ + createHandler(hash, majorParameter) { + const queue = majorParameter === BurstHandlerMajorIdKey ? new BurstHandler(this, hash, majorParameter) : new SequentialHandler(this, hash, majorParameter); + this.handlers.set(queue.id, queue); + return queue; + } + /** + * Formats the request data to a usable format for fetch + * + * @param request - The request data + */ + async resolveRequest(request) { + const { options } = this; + let query = ""; + if (request.query) { + const resolvedQuery = request.query.toString(); + if (resolvedQuery !== "") { + query = `?${resolvedQuery}`; + } + } + const headers = { + ...this.options.headers, + "User-Agent": `${DefaultUserAgent} ${options.userAgentAppendix}`.trim() + }; + if (request.auth !== false) { + if (!this.#token) { + throw new Error("Expected token to be set for this request, but none was present"); + } + headers.Authorization = `${request.authPrefix ?? this.options.authPrefix} ${this.#token}`; + } + if (request.reason?.length) { + headers["X-Audit-Log-Reason"] = encodeURIComponent(request.reason); + } + const url = `${options.api}${request.versioned === false ? "" : `/v${options.version}`}${request.fullRoute}${query}`; + let finalBody; + let additionalHeaders = {}; + if (request.files?.length) { + const formData = new FormData(); + for (const [index, file] of request.files.entries()) { + const fileKey = file.key ?? `files[${index}]`; + if (isBufferLike(file.data)) { + let contentType = file.contentType; + if (!contentType) { + const [parsedType] = (0, import_magic_bytes.filetypeinfo)(file.data); + if (parsedType) { + contentType = OverwrittenMimeTypes[parsedType.mime] ?? parsedType.mime ?? "application/octet-stream"; + } + } + formData.append(fileKey, new Blob([file.data], { type: contentType }), file.name); + } else { + formData.append(fileKey, new Blob([`${file.data}`], { type: file.contentType }), file.name); + } + } + if (request.body != null) { + if (request.appendToFormData) { + for (const [key, value] of Object.entries(request.body)) { + formData.append(key, value); + } + } else { + formData.append("payload_json", JSON.stringify(request.body)); + } + } + finalBody = formData; + } else if (request.body != null) { + if (request.passThroughBody) { + finalBody = request.body; + } else { + finalBody = JSON.stringify(request.body); + additionalHeaders = { "Content-Type": "application/json" }; + } + } + const method = request.method.toUpperCase(); + const fetchOptions = { + // Set body to null on get / head requests. This does not follow fetch spec (likely because it causes subtle bugs) but is aligned with what request was doing + body: ["GET", "HEAD"].includes(method) ? null : finalBody, + headers: { ...request.headers, ...additionalHeaders, ...headers }, + method, + // Prioritize setting an agent per request, use the agent for this instance otherwise. + dispatcher: request.dispatcher ?? this.agent ?? void 0 + }; + return { url, fetchOptions }; + } + /** + * Stops the hash sweeping interval + */ + clearHashSweeper() { + clearInterval(this.hashTimer); + } + /** + * Stops the request handler sweeping interval + */ + clearHandlerSweeper() { + clearInterval(this.handlerTimer); + } + /** + * Generates route data for an endpoint:method + * + * @param endpoint - The raw endpoint to generalize + * @param method - The HTTP method this endpoint is called without + * @internal + */ + static generateRouteData(endpoint, method) { + if (endpoint.startsWith("/interactions/") && endpoint.endsWith("/callback")) { + return { + majorParameter: BurstHandlerMajorIdKey, + bucketRoute: "/interactions/:id/:token/callback", + original: endpoint + }; + } + const majorIdMatch = /^\/(?:channels|guilds|webhooks)\/(\d{17,19})/.exec(endpoint); + const majorId = majorIdMatch?.[1] ?? "global"; + const baseRoute = endpoint.replaceAll(/\d{17,19}/g, ":id").replace(/\/reactions\/(.*)/, "/reactions/:reaction"); + let exceptions = ""; + if (method === "DELETE" /* Delete */ && baseRoute === "/channels/:id/messages/:id") { + const id = /\d{17,19}$/.exec(endpoint)[0]; + const timestamp = import_snowflake.DiscordSnowflake.timestampFrom(id); + if (Date.now() - timestamp > 1e3 * 60 * 60 * 24 * 14) { + exceptions += "/Delete Old Message"; + } + } + return { + majorParameter: majorId, + bucketRoute: baseRoute + exceptions, + original: endpoint + }; + } +}; + +// src/shared.ts +var version = "2.0.1"; + +// src/web.ts +setDefaultStrategy(fetch); +// Annotate the CommonJS export names for ESM import in node: +0 && (module.exports = { + ALLOWED_EXTENSIONS, + ALLOWED_SIZES, + ALLOWED_STICKER_EXTENSIONS, + BurstHandlerMajorIdKey, + CDN, + DefaultRestOptions, + DefaultUserAgent, + DefaultUserAgentAppendix, + DiscordAPIError, + HTTPError, + OverwrittenMimeTypes, + REST, + RESTEvents, + RateLimitError, + RequestMethod, + calculateUserDefaultAvatarIndex, + makeURLSearchParams, + parseResponse, + version +}); +//# sourceMappingURL=web.js.map
\ No newline at end of file diff --git a/node_modules/@discordjs/rest/dist/web.js.map b/node_modules/@discordjs/rest/dist/web.js.map new file mode 100644 index 0000000..69abc89 --- /dev/null +++ b/node_modules/@discordjs/rest/dist/web.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../src/web.ts","../src/environment.ts","../src/lib/utils/constants.ts","../src/lib/CDN.ts","../src/lib/errors/DiscordAPIError.ts","../src/lib/errors/HTTPError.ts","../src/lib/errors/RateLimitError.ts","../src/lib/REST.ts","../src/lib/utils/types.ts","../src/lib/utils/utils.ts","../src/lib/handlers/Shared.ts","../src/lib/handlers/BurstHandler.ts","../src/lib/handlers/SequentialHandler.ts","../src/shared.ts"],"sourcesContent":["import { setDefaultStrategy } from './environment.js';\n\nsetDefaultStrategy(fetch);\n\nexport * from './shared.js';\n","import type { RESTOptions } from './shared.js';\n\nlet defaultStrategy: RESTOptions['makeRequest'];\n\nexport function setDefaultStrategy(newStrategy: RESTOptions['makeRequest']) {\n\tdefaultStrategy = newStrategy;\n}\n\nexport function getDefaultStrategy() {\n\treturn defaultStrategy;\n}\n","import { getUserAgentAppendix } from '@discordjs/util';\nimport { APIVersion } from 'discord-api-types/v10';\nimport { getDefaultStrategy } from '../../environment.js';\nimport type { RESTOptions, ResponseLike } from './types.js';\n\nexport const DefaultUserAgent =\n\t`DiscordBot (https://discord.js.org, 2.0.1)` as `DiscordBot (https://discord.js.org, ${string})`;\n\n/**\n * The default string to append onto the user agent.\n */\nexport const DefaultUserAgentAppendix = getUserAgentAppendix();\n\nexport const DefaultRestOptions = {\n\tagent: null,\n\tapi: 'https://discord.com/api',\n\tauthPrefix: 'Bot',\n\tcdn: 'https://cdn.discordapp.com',\n\theaders: {},\n\tinvalidRequestWarningInterval: 0,\n\tglobalRequestsPerSecond: 50,\n\toffset: 50,\n\trejectOnRateLimit: null,\n\tretries: 3,\n\ttimeout: 15_000,\n\tuserAgentAppendix: DefaultUserAgentAppendix,\n\tversion: APIVersion,\n\thashSweepInterval: 14_400_000, // 4 Hours\n\thashLifetime: 86_400_000, // 24 Hours\n\thandlerSweepInterval: 3_600_000, // 1 Hour\n\tasync makeRequest(...args): Promise<ResponseLike> {\n\t\treturn getDefaultStrategy()(...args);\n\t},\n} as const satisfies Required<RESTOptions>;\n\n/**\n * The events that the REST manager emits\n */\nexport enum RESTEvents {\n\tDebug = 'restDebug',\n\tHandlerSweep = 'handlerSweep',\n\tHashSweep = 'hashSweep',\n\tInvalidRequestWarning = 'invalidRequestWarning',\n\tRateLimited = 'rateLimited',\n\tResponse = 'response',\n}\n\nexport const ALLOWED_EXTENSIONS = ['webp', 'png', 'jpg', 'jpeg', 'gif'] as const satisfies readonly string[];\nexport const ALLOWED_STICKER_EXTENSIONS = ['png', 'json', 'gif'] as const satisfies readonly string[];\nexport const ALLOWED_SIZES = [16, 32, 64, 128, 256, 512, 1_024, 2_048, 4_096] as const satisfies readonly number[];\n\nexport type ImageExtension = (typeof ALLOWED_EXTENSIONS)[number];\nexport type StickerExtension = (typeof ALLOWED_STICKER_EXTENSIONS)[number];\nexport type ImageSize = (typeof ALLOWED_SIZES)[number];\n\nexport const OverwrittenMimeTypes = {\n\t// https://github.com/discordjs/discord.js/issues/8557\n\t'image/apng': 'image/png',\n} as const satisfies Readonly<Record<string, string>>;\n\nexport const BurstHandlerMajorIdKey = 'burst';\n","/* eslint-disable jsdoc/check-param-names */\nimport {\n\tALLOWED_EXTENSIONS,\n\tALLOWED_SIZES,\n\tALLOWED_STICKER_EXTENSIONS,\n\tDefaultRestOptions,\n\ttype ImageExtension,\n\ttype ImageSize,\n\ttype StickerExtension,\n} from './utils/constants.js';\n\n/**\n * The options used for image URLs\n */\nexport interface BaseImageURLOptions {\n\t/**\n\t * The extension to use for the image URL\n\t *\n\t * @defaultValue `'webp'`\n\t */\n\textension?: ImageExtension;\n\t/**\n\t * The size specified in the image URL\n\t */\n\tsize?: ImageSize;\n}\n\n/**\n * The options used for image URLs with animated content\n */\nexport interface ImageURLOptions extends BaseImageURLOptions {\n\t/**\n\t * Whether or not to prefer the static version of an image asset.\n\t */\n\tforceStatic?: boolean;\n}\n\n/**\n * The options to use when making a CDN URL\n */\nexport interface MakeURLOptions {\n\t/**\n\t * The allowed extensions that can be used\n\t */\n\tallowedExtensions?: readonly string[];\n\t/**\n\t * The extension to use for the image URL\n\t *\n\t * @defaultValue `'webp'`\n\t */\n\textension?: string | undefined;\n\t/**\n\t * The size specified in the image URL\n\t */\n\tsize?: ImageSize;\n}\n\n/**\n * The CDN link builder\n */\nexport class CDN {\n\tpublic constructor(private readonly base: string = DefaultRestOptions.cdn) {}\n\n\t/**\n\t * Generates an app asset URL for a client's asset.\n\t *\n\t * @param clientId - The client id that has the asset\n\t * @param assetHash - The hash provided by Discord for this asset\n\t * @param options - Optional options for the asset\n\t */\n\tpublic appAsset(clientId: string, assetHash: string, options?: Readonly<BaseImageURLOptions>): string {\n\t\treturn this.makeURL(`/app-assets/${clientId}/${assetHash}`, options);\n\t}\n\n\t/**\n\t * Generates an app icon URL for a client's icon.\n\t *\n\t * @param clientId - The client id that has the icon\n\t * @param iconHash - The hash provided by Discord for this icon\n\t * @param options - Optional options for the icon\n\t */\n\tpublic appIcon(clientId: string, iconHash: string, options?: Readonly<BaseImageURLOptions>): string {\n\t\treturn this.makeURL(`/app-icons/${clientId}/${iconHash}`, options);\n\t}\n\n\t/**\n\t * Generates an avatar URL, e.g. for a user or a webhook.\n\t *\n\t * @param id - The id that has the icon\n\t * @param avatarHash - The hash provided by Discord for this avatar\n\t * @param options - Optional options for the avatar\n\t */\n\tpublic avatar(id: string, avatarHash: string, options?: Readonly<ImageURLOptions>): string {\n\t\treturn this.dynamicMakeURL(`/avatars/${id}/${avatarHash}`, avatarHash, options);\n\t}\n\n\t/**\n\t * Generates a user avatar decoration URL.\n\t *\n\t * @param userId - The id of the user\n\t * @param userAvatarDecoration - The hash provided by Discord for this avatar decoration\n\t * @param options - Optional options for the avatar decoration\n\t */\n\tpublic avatarDecoration(\n\t\tuserId: string,\n\t\tuserAvatarDecoration: string,\n\t\toptions?: Readonly<BaseImageURLOptions>,\n\t): string {\n\t\treturn this.makeURL(`/avatar-decorations/${userId}/${userAvatarDecoration}`, options);\n\t}\n\n\t/**\n\t * Generates a banner URL, e.g. for a user or a guild.\n\t *\n\t * @param id - The id that has the banner splash\n\t * @param bannerHash - The hash provided by Discord for this banner\n\t * @param options - Optional options for the banner\n\t */\n\tpublic banner(id: string, bannerHash: string, options?: Readonly<ImageURLOptions>): string {\n\t\treturn this.dynamicMakeURL(`/banners/${id}/${bannerHash}`, bannerHash, options);\n\t}\n\n\t/**\n\t * Generates an icon URL for a channel, e.g. a group DM.\n\t *\n\t * @param channelId - The channel id that has the icon\n\t * @param iconHash - The hash provided by Discord for this channel\n\t * @param options - Optional options for the icon\n\t */\n\tpublic channelIcon(channelId: string, iconHash: string, options?: Readonly<BaseImageURLOptions>): string {\n\t\treturn this.makeURL(`/channel-icons/${channelId}/${iconHash}`, options);\n\t}\n\n\t/**\n\t * Generates a default avatar URL\n\t *\n\t * @param index - The default avatar index\n\t * @remarks\n\t * To calculate the index for a user do `(userId >> 22) % 6`,\n\t * or `discriminator % 5` if they're using the legacy username system.\n\t */\n\tpublic defaultAvatar(index: number): string {\n\t\treturn this.makeURL(`/embed/avatars/${index}`, { extension: 'png' });\n\t}\n\n\t/**\n\t * Generates a discovery splash URL for a guild's discovery splash.\n\t *\n\t * @param guildId - The guild id that has the discovery splash\n\t * @param splashHash - The hash provided by Discord for this splash\n\t * @param options - Optional options for the splash\n\t */\n\tpublic discoverySplash(guildId: string, splashHash: string, options?: Readonly<BaseImageURLOptions>): string {\n\t\treturn this.makeURL(`/discovery-splashes/${guildId}/${splashHash}`, options);\n\t}\n\n\t/**\n\t * Generates an emoji's URL for an emoji.\n\t *\n\t * @param emojiId - The emoji id\n\t * @param extension - The extension of the emoji\n\t */\n\tpublic emoji(emojiId: string, extension?: ImageExtension): string {\n\t\treturn this.makeURL(`/emojis/${emojiId}`, { extension });\n\t}\n\n\t/**\n\t * Generates a guild member avatar URL.\n\t *\n\t * @param guildId - The id of the guild\n\t * @param userId - The id of the user\n\t * @param avatarHash - The hash provided by Discord for this avatar\n\t * @param options - Optional options for the avatar\n\t */\n\tpublic guildMemberAvatar(\n\t\tguildId: string,\n\t\tuserId: string,\n\t\tavatarHash: string,\n\t\toptions?: Readonly<ImageURLOptions>,\n\t): string {\n\t\treturn this.dynamicMakeURL(`/guilds/${guildId}/users/${userId}/avatars/${avatarHash}`, avatarHash, options);\n\t}\n\n\t/**\n\t * Generates a guild member banner URL.\n\t *\n\t * @param guildId - The id of the guild\n\t * @param userId - The id of the user\n\t * @param bannerHash - The hash provided by Discord for this banner\n\t * @param options - Optional options for the banner\n\t */\n\tpublic guildMemberBanner(\n\t\tguildId: string,\n\t\tuserId: string,\n\t\tbannerHash: string,\n\t\toptions?: Readonly<ImageURLOptions>,\n\t): string {\n\t\treturn this.dynamicMakeURL(`/guilds/${guildId}/users/${userId}/banner`, bannerHash, options);\n\t}\n\n\t/**\n\t * Generates an icon URL, e.g. for a guild.\n\t *\n\t * @param id - The id that has the icon splash\n\t * @param iconHash - The hash provided by Discord for this icon\n\t * @param options - Optional options for the icon\n\t */\n\tpublic icon(id: string, iconHash: string, options?: Readonly<ImageURLOptions>): string {\n\t\treturn this.dynamicMakeURL(`/icons/${id}/${iconHash}`, iconHash, options);\n\t}\n\n\t/**\n\t * Generates a URL for the icon of a role\n\t *\n\t * @param roleId - The id of the role that has the icon\n\t * @param roleIconHash - The hash provided by Discord for this role icon\n\t * @param options - Optional options for the role icon\n\t */\n\tpublic roleIcon(roleId: string, roleIconHash: string, options?: Readonly<BaseImageURLOptions>): string {\n\t\treturn this.makeURL(`/role-icons/${roleId}/${roleIconHash}`, options);\n\t}\n\n\t/**\n\t * Generates a guild invite splash URL for a guild's invite splash.\n\t *\n\t * @param guildId - The guild id that has the invite splash\n\t * @param splashHash - The hash provided by Discord for this splash\n\t * @param options - Optional options for the splash\n\t */\n\tpublic splash(guildId: string, splashHash: string, options?: Readonly<BaseImageURLOptions>): string {\n\t\treturn this.makeURL(`/splashes/${guildId}/${splashHash}`, options);\n\t}\n\n\t/**\n\t * Generates a sticker URL.\n\t *\n\t * @param stickerId - The sticker id\n\t * @param extension - The extension of the sticker\n\t * @privateRemarks\n\t * Stickers cannot have a `.webp` extension, so we default to a `.png`\n\t */\n\tpublic sticker(stickerId: string, extension: StickerExtension = 'png'): string {\n\t\treturn this.makeURL(`/stickers/${stickerId}`, { allowedExtensions: ALLOWED_STICKER_EXTENSIONS, extension });\n\t}\n\n\t/**\n\t * Generates a sticker pack banner URL.\n\t *\n\t * @param bannerId - The banner id\n\t * @param options - Optional options for the banner\n\t */\n\tpublic stickerPackBanner(bannerId: string, options?: Readonly<BaseImageURLOptions>): string {\n\t\treturn this.makeURL(`/app-assets/710982414301790216/store/${bannerId}`, options);\n\t}\n\n\t/**\n\t * Generates a team icon URL for a team's icon.\n\t *\n\t * @param teamId - The team id that has the icon\n\t * @param iconHash - The hash provided by Discord for this icon\n\t * @param options - Optional options for the icon\n\t */\n\tpublic teamIcon(teamId: string, iconHash: string, options?: Readonly<BaseImageURLOptions>): string {\n\t\treturn this.makeURL(`/team-icons/${teamId}/${iconHash}`, options);\n\t}\n\n\t/**\n\t * Generates a cover image for a guild scheduled event.\n\t *\n\t * @param scheduledEventId - The scheduled event id\n\t * @param coverHash - The hash provided by discord for this cover image\n\t * @param options - Optional options for the cover image\n\t */\n\tpublic guildScheduledEventCover(\n\t\tscheduledEventId: string,\n\t\tcoverHash: string,\n\t\toptions?: Readonly<BaseImageURLOptions>,\n\t): string {\n\t\treturn this.makeURL(`/guild-events/${scheduledEventId}/${coverHash}`, options);\n\t}\n\n\t/**\n\t * Constructs the URL for the resource, checking whether or not `hash` starts with `a_` if `dynamic` is set to `true`.\n\t *\n\t * @param route - The base cdn route\n\t * @param hash - The hash provided by Discord for this icon\n\t * @param options - Optional options for the link\n\t */\n\tprivate dynamicMakeURL(\n\t\troute: string,\n\t\thash: string,\n\t\t{ forceStatic = false, ...options }: Readonly<ImageURLOptions> = {},\n\t): string {\n\t\treturn this.makeURL(route, !forceStatic && hash.startsWith('a_') ? { ...options, extension: 'gif' } : options);\n\t}\n\n\t/**\n\t * Constructs the URL for the resource\n\t *\n\t * @param route - The base cdn route\n\t * @param options - The extension/size options for the link\n\t */\n\tprivate makeURL(\n\t\troute: string,\n\t\t{ allowedExtensions = ALLOWED_EXTENSIONS, extension = 'webp', size }: Readonly<MakeURLOptions> = {},\n\t): string {\n\t\t// eslint-disable-next-line no-param-reassign\n\t\textension = String(extension).toLowerCase();\n\n\t\tif (!allowedExtensions.includes(extension)) {\n\t\t\tthrow new RangeError(`Invalid extension provided: ${extension}\\nMust be one of: ${allowedExtensions.join(', ')}`);\n\t\t}\n\n\t\tif (size && !ALLOWED_SIZES.includes(size)) {\n\t\t\tthrow new RangeError(`Invalid size provided: ${size}\\nMust be one of: ${ALLOWED_SIZES.join(', ')}`);\n\t\t}\n\n\t\tconst url = new URL(`${this.base}${route}.${extension}`);\n\n\t\tif (size) {\n\t\t\turl.searchParams.set('size', String(size));\n\t\t}\n\n\t\treturn url.toString();\n\t}\n}\n","import type { InternalRequest, RawFile } from '../utils/types.js';\n\ninterface DiscordErrorFieldInformation {\n\tcode: string;\n\tmessage: string;\n}\n\ninterface DiscordErrorGroupWrapper {\n\t_errors: DiscordError[];\n}\n\ntype DiscordError = DiscordErrorFieldInformation | DiscordErrorGroupWrapper | string | { [k: string]: DiscordError };\n\nexport interface DiscordErrorData {\n\tcode: number;\n\terrors?: DiscordError;\n\tmessage: string;\n}\n\nexport interface OAuthErrorData {\n\terror: string;\n\terror_description?: string;\n}\n\nexport interface RequestBody {\n\tfiles: RawFile[] | undefined;\n\tjson: unknown | undefined;\n}\n\nfunction isErrorGroupWrapper(error: DiscordError): error is DiscordErrorGroupWrapper {\n\treturn Reflect.has(error as Record<string, unknown>, '_errors');\n}\n\nfunction isErrorResponse(error: DiscordError): error is DiscordErrorFieldInformation {\n\treturn typeof Reflect.get(error as Record<string, unknown>, 'message') === 'string';\n}\n\n/**\n * Represents an API error returned by Discord\n */\nexport class DiscordAPIError extends Error {\n\tpublic requestBody: RequestBody;\n\n\t/**\n\t * @param rawError - The error reported by Discord\n\t * @param code - The error code reported by Discord\n\t * @param status - The status code of the response\n\t * @param method - The method of the request that erred\n\t * @param url - The url of the request that erred\n\t * @param bodyData - The unparsed data for the request that errored\n\t */\n\tpublic constructor(\n\t\tpublic rawError: DiscordErrorData | OAuthErrorData,\n\t\tpublic code: number | string,\n\t\tpublic status: number,\n\t\tpublic method: string,\n\t\tpublic url: string,\n\t\tbodyData: Pick<InternalRequest, 'body' | 'files'>,\n\t) {\n\t\tsuper(DiscordAPIError.getMessage(rawError));\n\n\t\tthis.requestBody = { files: bodyData.files, json: bodyData.body };\n\t}\n\n\t/**\n\t * The name of the error\n\t */\n\tpublic override get name(): string {\n\t\treturn `${DiscordAPIError.name}[${this.code}]`;\n\t}\n\n\tprivate static getMessage(error: DiscordErrorData | OAuthErrorData) {\n\t\tlet flattened = '';\n\t\tif ('code' in error) {\n\t\t\tif (error.errors) {\n\t\t\t\tflattened = [...this.flattenDiscordError(error.errors)].join('\\n');\n\t\t\t}\n\n\t\t\treturn error.message && flattened\n\t\t\t\t? `${error.message}\\n${flattened}`\n\t\t\t\t: error.message || flattened || 'Unknown Error';\n\t\t}\n\n\t\treturn error.error_description ?? 'No Description';\n\t}\n\n\tprivate static *flattenDiscordError(obj: DiscordError, key = ''): IterableIterator<string> {\n\t\tif (isErrorResponse(obj)) {\n\t\t\treturn yield `${key.length ? `${key}[${obj.code}]` : `${obj.code}`}: ${obj.message}`.trim();\n\t\t}\n\n\t\tfor (const [otherKey, val] of Object.entries(obj)) {\n\t\t\tconst nextKey = otherKey.startsWith('_')\n\t\t\t\t? key\n\t\t\t\t: key\n\t\t\t\t? Number.isNaN(Number(otherKey))\n\t\t\t\t\t? `${key}.${otherKey}`\n\t\t\t\t\t: `${key}[${otherKey}]`\n\t\t\t\t: otherKey;\n\n\t\t\tif (typeof val === 'string') {\n\t\t\t\tyield val;\n\t\t\t} else if (isErrorGroupWrapper(val)) {\n\t\t\t\tfor (const error of val._errors) {\n\t\t\t\t\tyield* this.flattenDiscordError(error, nextKey);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tyield* this.flattenDiscordError(val, nextKey);\n\t\t\t}\n\t\t}\n\t}\n}\n","import type { InternalRequest } from '../utils/types.js';\nimport type { RequestBody } from './DiscordAPIError.js';\n\n/**\n * Represents a HTTP error\n */\nexport class HTTPError extends Error {\n\tpublic requestBody: RequestBody;\n\n\tpublic override name = HTTPError.name;\n\n\t/**\n\t * @param status - The status code of the response\n\t * @param statusText - The status text of the response\n\t * @param method - The method of the request that erred\n\t * @param url - The url of the request that erred\n\t * @param bodyData - The unparsed data for the request that errored\n\t */\n\tpublic constructor(\n\t\tpublic status: number,\n\t\tstatusText: string,\n\t\tpublic method: string,\n\t\tpublic url: string,\n\t\tbodyData: Pick<InternalRequest, 'body' | 'files'>,\n\t) {\n\t\tsuper(statusText);\n\t\tthis.requestBody = { files: bodyData.files, json: bodyData.body };\n\t}\n}\n","import type { RateLimitData } from '../utils/types.js';\n\nexport class RateLimitError extends Error implements RateLimitData {\n\tpublic timeToReset: number;\n\n\tpublic limit: number;\n\n\tpublic method: string;\n\n\tpublic hash: string;\n\n\tpublic url: string;\n\n\tpublic route: string;\n\n\tpublic majorParameter: string;\n\n\tpublic global: boolean;\n\n\tpublic constructor({ timeToReset, limit, method, hash, url, route, majorParameter, global }: RateLimitData) {\n\t\tsuper();\n\t\tthis.timeToReset = timeToReset;\n\t\tthis.limit = limit;\n\t\tthis.method = method;\n\t\tthis.hash = hash;\n\t\tthis.url = url;\n\t\tthis.route = route;\n\t\tthis.majorParameter = majorParameter;\n\t\tthis.global = global;\n\t}\n\n\t/**\n\t * The name of the error\n\t */\n\tpublic override get name(): string {\n\t\treturn `${RateLimitError.name}[${this.route}]`;\n\t}\n}\n","import { Collection } from '@discordjs/collection';\nimport { DiscordSnowflake } from '@sapphire/snowflake';\nimport { AsyncEventEmitter } from '@vladfrangu/async_event_emitter';\nimport { filetypeinfo } from 'magic-bytes.js';\nimport type { RequestInit, BodyInit, Dispatcher } from 'undici';\nimport { CDN } from './CDN.js';\nimport { BurstHandler } from './handlers/BurstHandler.js';\nimport { SequentialHandler } from './handlers/SequentialHandler.js';\nimport type { IHandler } from './interfaces/Handler.js';\nimport {\n\tBurstHandlerMajorIdKey,\n\tDefaultRestOptions,\n\tDefaultUserAgent,\n\tOverwrittenMimeTypes,\n\tRESTEvents,\n} from './utils/constants.js';\nimport { RequestMethod } from './utils/types.js';\nimport type {\n\tRESTOptions,\n\tResponseLike,\n\tRestEventsMap,\n\tHashData,\n\tInternalRequest,\n\tRouteLike,\n\tRequestHeaders,\n\tRouteData,\n\tRequestData,\n} from './utils/types.js';\nimport { isBufferLike, parseResponse } from './utils/utils.js';\n\n/**\n * Represents the class that manages handlers for endpoints\n */\nexport class REST extends AsyncEventEmitter<RestEventsMap> {\n\t/**\n\t * The {@link https://undici.nodejs.org/#/docs/api/Agent | Agent} for all requests\n\t * performed by this manager.\n\t */\n\tpublic agent: Dispatcher | null = null;\n\n\tpublic readonly cdn: CDN;\n\n\t/**\n\t * The number of requests remaining in the global bucket\n\t */\n\tpublic globalRemaining: number;\n\n\t/**\n\t * The promise used to wait out the global rate limit\n\t */\n\tpublic globalDelay: Promise<void> | null = null;\n\n\t/**\n\t * The timestamp at which the global bucket resets\n\t */\n\tpublic globalReset = -1;\n\n\t/**\n\t * API bucket hashes that are cached from provided routes\n\t */\n\tpublic readonly hashes = new Collection<string, HashData>();\n\n\t/**\n\t * Request handlers created from the bucket hash and the major parameters\n\t */\n\tpublic readonly handlers = new Collection<string, IHandler>();\n\n\t#token: string | null = null;\n\n\tprivate hashTimer!: NodeJS.Timer | number;\n\n\tprivate handlerTimer!: NodeJS.Timer | number;\n\n\tpublic readonly options: RESTOptions;\n\n\tpublic constructor(options: Partial<RESTOptions> = {}) {\n\t\tsuper();\n\t\tthis.cdn = new CDN(options.cdn ?? DefaultRestOptions.cdn);\n\t\tthis.options = { ...DefaultRestOptions, ...options };\n\t\tthis.options.offset = Math.max(0, this.options.offset);\n\t\tthis.globalRemaining = Math.max(1, this.options.globalRequestsPerSecond);\n\t\tthis.agent = options.agent ?? null;\n\n\t\t// Start sweepers\n\t\tthis.setupSweepers();\n\t}\n\n\tprivate setupSweepers() {\n\t\t// eslint-disable-next-line unicorn/consistent-function-scoping\n\t\tconst validateMaxInterval = (interval: number) => {\n\t\t\tif (interval > 14_400_000) {\n\t\t\t\tthrow new Error('Cannot set an interval greater than 4 hours');\n\t\t\t}\n\t\t};\n\n\t\tif (this.options.hashSweepInterval !== 0 && this.options.hashSweepInterval !== Number.POSITIVE_INFINITY) {\n\t\t\tvalidateMaxInterval(this.options.hashSweepInterval);\n\t\t\tthis.hashTimer = setInterval(() => {\n\t\t\t\tconst sweptHashes = new Collection<string, HashData>();\n\t\t\t\tconst currentDate = Date.now();\n\n\t\t\t\t// Begin sweeping hash based on lifetimes\n\t\t\t\tthis.hashes.sweep((val, key) => {\n\t\t\t\t\t// `-1` indicates a global hash\n\t\t\t\t\tif (val.lastAccess === -1) return false;\n\n\t\t\t\t\t// Check if lifetime has been exceeded\n\t\t\t\t\tconst shouldSweep = Math.floor(currentDate - val.lastAccess) > this.options.hashLifetime;\n\n\t\t\t\t\t// Add hash to collection of swept hashes\n\t\t\t\t\tif (shouldSweep) {\n\t\t\t\t\t\t// Add to swept hashes\n\t\t\t\t\t\tsweptHashes.set(key, val);\n\n\t\t\t\t\t\t// Emit debug information\n\t\t\t\t\t\tthis.emit(RESTEvents.Debug, `Hash ${val.value} for ${key} swept due to lifetime being exceeded`);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn shouldSweep;\n\t\t\t\t});\n\n\t\t\t\t// Fire event\n\t\t\t\tthis.emit(RESTEvents.HashSweep, sweptHashes);\n\t\t\t}, this.options.hashSweepInterval);\n\n\t\t\tthis.hashTimer.unref?.();\n\t\t}\n\n\t\tif (this.options.handlerSweepInterval !== 0 && this.options.handlerSweepInterval !== Number.POSITIVE_INFINITY) {\n\t\t\tvalidateMaxInterval(this.options.handlerSweepInterval);\n\t\t\tthis.handlerTimer = setInterval(() => {\n\t\t\t\tconst sweptHandlers = new Collection<string, IHandler>();\n\n\t\t\t\t// Begin sweeping handlers based on activity\n\t\t\t\tthis.handlers.sweep((val, key) => {\n\t\t\t\t\tconst { inactive } = val;\n\n\t\t\t\t\t// Collect inactive handlers\n\t\t\t\t\tif (inactive) {\n\t\t\t\t\t\tsweptHandlers.set(key, val);\n\t\t\t\t\t\tthis.emit(RESTEvents.Debug, `Handler ${val.id} for ${key} swept due to being inactive`);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn inactive;\n\t\t\t\t});\n\n\t\t\t\t// Fire event\n\t\t\t\tthis.emit(RESTEvents.HandlerSweep, sweptHandlers);\n\t\t\t}, this.options.handlerSweepInterval);\n\n\t\t\tthis.handlerTimer.unref?.();\n\t\t}\n\t}\n\n\t/**\n\t * Runs a get request from the api\n\t *\n\t * @param fullRoute - The full route to query\n\t * @param options - Optional request options\n\t */\n\tpublic async get(fullRoute: RouteLike, options: RequestData = {}) {\n\t\treturn this.request({ ...options, fullRoute, method: RequestMethod.Get });\n\t}\n\n\t/**\n\t * Runs a delete request from the api\n\t *\n\t * @param fullRoute - The full route to query\n\t * @param options - Optional request options\n\t */\n\tpublic async delete(fullRoute: RouteLike, options: RequestData = {}) {\n\t\treturn this.request({ ...options, fullRoute, method: RequestMethod.Delete });\n\t}\n\n\t/**\n\t * Runs a post request from the api\n\t *\n\t * @param fullRoute - The full route to query\n\t * @param options - Optional request options\n\t */\n\tpublic async post(fullRoute: RouteLike, options: RequestData = {}) {\n\t\treturn this.request({ ...options, fullRoute, method: RequestMethod.Post });\n\t}\n\n\t/**\n\t * Runs a put request from the api\n\t *\n\t * @param fullRoute - The full route to query\n\t * @param options - Optional request options\n\t */\n\tpublic async put(fullRoute: RouteLike, options: RequestData = {}) {\n\t\treturn this.request({ ...options, fullRoute, method: RequestMethod.Put });\n\t}\n\n\t/**\n\t * Runs a patch request from the api\n\t *\n\t * @param fullRoute - The full route to query\n\t * @param options - Optional request options\n\t */\n\tpublic async patch(fullRoute: RouteLike, options: RequestData = {}) {\n\t\treturn this.request({ ...options, fullRoute, method: RequestMethod.Patch });\n\t}\n\n\t/**\n\t * Runs a request from the api\n\t *\n\t * @param options - Request options\n\t */\n\tpublic async request(options: InternalRequest) {\n\t\tconst response = await this.queueRequest(options);\n\t\treturn parseResponse(response);\n\t}\n\n\t/**\n\t * Sets the default agent to use for requests performed by this manager\n\t *\n\t * @param agent - The agent to use\n\t */\n\tpublic setAgent(agent: Dispatcher) {\n\t\tthis.agent = agent;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the authorization token that should be used for requests\n\t *\n\t * @param token - The authorization token to use\n\t */\n\tpublic setToken(token: string) {\n\t\tthis.#token = token;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Queues a request to be sent\n\t *\n\t * @param request - All the information needed to make a request\n\t * @returns The response from the api request\n\t */\n\tpublic async queueRequest(request: InternalRequest): Promise<ResponseLike> {\n\t\t// Generalize the endpoint to its route data\n\t\tconst routeId = REST.generateRouteData(request.fullRoute, request.method);\n\t\t// Get the bucket hash for the generic route, or point to a global route otherwise\n\t\tconst hash = this.hashes.get(`${request.method}:${routeId.bucketRoute}`) ?? {\n\t\t\tvalue: `Global(${request.method}:${routeId.bucketRoute})`,\n\t\t\tlastAccess: -1,\n\t\t};\n\n\t\t// Get the request handler for the obtained hash, with its major parameter\n\t\tconst handler =\n\t\t\tthis.handlers.get(`${hash.value}:${routeId.majorParameter}`) ??\n\t\t\tthis.createHandler(hash.value, routeId.majorParameter);\n\n\t\t// Resolve the request into usable fetch options\n\t\tconst { url, fetchOptions } = await this.resolveRequest(request);\n\n\t\t// Queue the request\n\t\treturn handler.queueRequest(routeId, url, fetchOptions, {\n\t\t\tbody: request.body,\n\t\t\tfiles: request.files,\n\t\t\tauth: request.auth !== false,\n\t\t\tsignal: request.signal,\n\t\t});\n\t}\n\n\t/**\n\t * Creates a new rate limit handler from a hash, based on the hash and the major parameter\n\t *\n\t * @param hash - The hash for the route\n\t * @param majorParameter - The major parameter for this handler\n\t * @internal\n\t */\n\tprivate createHandler(hash: string, majorParameter: string) {\n\t\t// Create the async request queue to handle requests\n\t\tconst queue =\n\t\t\tmajorParameter === BurstHandlerMajorIdKey\n\t\t\t\t? new BurstHandler(this, hash, majorParameter)\n\t\t\t\t: new SequentialHandler(this, hash, majorParameter);\n\t\t// Save the queue based on its id\n\t\tthis.handlers.set(queue.id, queue);\n\n\t\treturn queue;\n\t}\n\n\t/**\n\t * Formats the request data to a usable format for fetch\n\t *\n\t * @param request - The request data\n\t */\n\tprivate async resolveRequest(request: InternalRequest): Promise<{ fetchOptions: RequestInit; url: string }> {\n\t\tconst { options } = this;\n\n\t\tlet query = '';\n\n\t\t// If a query option is passed, use it\n\t\tif (request.query) {\n\t\t\tconst resolvedQuery = request.query.toString();\n\t\t\tif (resolvedQuery !== '') {\n\t\t\t\tquery = `?${resolvedQuery}`;\n\t\t\t}\n\t\t}\n\n\t\t// Create the required headers\n\t\tconst headers: RequestHeaders = {\n\t\t\t...this.options.headers,\n\t\t\t'User-Agent': `${DefaultUserAgent} ${options.userAgentAppendix}`.trim(),\n\t\t};\n\n\t\t// If this request requires authorization (allowing non-\"authorized\" requests for webhooks)\n\t\tif (request.auth !== false) {\n\t\t\t// If we haven't received a token, throw an error\n\t\t\tif (!this.#token) {\n\t\t\t\tthrow new Error('Expected token to be set for this request, but none was present');\n\t\t\t}\n\n\t\t\theaders.Authorization = `${request.authPrefix ?? this.options.authPrefix} ${this.#token}`;\n\t\t}\n\n\t\t// If a reason was set, set it's appropriate header\n\t\tif (request.reason?.length) {\n\t\t\theaders['X-Audit-Log-Reason'] = encodeURIComponent(request.reason);\n\t\t}\n\n\t\t// Format the full request URL (api base, optional version, endpoint, optional querystring)\n\t\tconst url = `${options.api}${request.versioned === false ? '' : `/v${options.version}`}${\n\t\t\trequest.fullRoute\n\t\t}${query}`;\n\n\t\tlet finalBody: RequestInit['body'];\n\t\tlet additionalHeaders: Record<string, string> = {};\n\n\t\tif (request.files?.length) {\n\t\t\tconst formData = new FormData();\n\n\t\t\t// Attach all files to the request\n\t\t\tfor (const [index, file] of request.files.entries()) {\n\t\t\t\tconst fileKey = file.key ?? `files[${index}]`;\n\n\t\t\t\t// https://developer.mozilla.org/en-US/docs/Web/API/FormData/append#parameters\n\t\t\t\t// FormData.append only accepts a string or Blob.\n\t\t\t\t// https://developer.mozilla.org/en-US/docs/Web/API/Blob/Blob#parameters\n\t\t\t\t// The Blob constructor accepts TypedArray/ArrayBuffer, strings, and Blobs.\n\t\t\t\tif (isBufferLike(file.data)) {\n\t\t\t\t\t// Try to infer the content type from the buffer if one isn't passed\n\t\t\t\t\tlet contentType = file.contentType;\n\n\t\t\t\t\tif (!contentType) {\n\t\t\t\t\t\tconst [parsedType] = filetypeinfo(file.data);\n\n\t\t\t\t\t\tif (parsedType) {\n\t\t\t\t\t\t\tcontentType =\n\t\t\t\t\t\t\t\tOverwrittenMimeTypes[parsedType.mime as keyof typeof OverwrittenMimeTypes] ??\n\t\t\t\t\t\t\t\tparsedType.mime ??\n\t\t\t\t\t\t\t\t'application/octet-stream';\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tformData.append(fileKey, new Blob([file.data], { type: contentType }), file.name);\n\t\t\t\t} else {\n\t\t\t\t\tformData.append(fileKey, new Blob([`${file.data}`], { type: file.contentType }), file.name);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If a JSON body was added as well, attach it to the form data, using payload_json unless otherwise specified\n\t\t\t// eslint-disable-next-line no-eq-null, eqeqeq\n\t\t\tif (request.body != null) {\n\t\t\t\tif (request.appendToFormData) {\n\t\t\t\t\tfor (const [key, value] of Object.entries(request.body as Record<string, unknown>)) {\n\t\t\t\t\t\tformData.append(key, value);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tformData.append('payload_json', JSON.stringify(request.body));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Set the final body to the form data\n\t\t\tfinalBody = formData;\n\n\t\t\t// eslint-disable-next-line no-eq-null, eqeqeq\n\t\t} else if (request.body != null) {\n\t\t\tif (request.passThroughBody) {\n\t\t\t\tfinalBody = request.body as BodyInit;\n\t\t\t} else {\n\t\t\t\t// Stringify the JSON data\n\t\t\t\tfinalBody = JSON.stringify(request.body);\n\t\t\t\t// Set the additional headers to specify the content-type\n\t\t\t\tadditionalHeaders = { 'Content-Type': 'application/json' };\n\t\t\t}\n\t\t}\n\n\t\tconst method = request.method.toUpperCase();\n\n\t\t// The non null assertions in the following block are due to exactOptionalPropertyTypes, they have been tested to work with undefined\n\t\tconst fetchOptions: RequestInit = {\n\t\t\t// Set body to null on get / head requests. This does not follow fetch spec (likely because it causes subtle bugs) but is aligned with what request was doing\n\t\t\tbody: ['GET', 'HEAD'].includes(method) ? null : finalBody!,\n\t\t\theaders: { ...request.headers, ...additionalHeaders, ...headers } as Record<string, string>,\n\t\t\tmethod,\n\t\t\t// Prioritize setting an agent per request, use the agent for this instance otherwise.\n\t\t\tdispatcher: request.dispatcher ?? this.agent ?? undefined!,\n\t\t};\n\n\t\treturn { url, fetchOptions };\n\t}\n\n\t/**\n\t * Stops the hash sweeping interval\n\t */\n\tpublic clearHashSweeper() {\n\t\tclearInterval(this.hashTimer);\n\t}\n\n\t/**\n\t * Stops the request handler sweeping interval\n\t */\n\tpublic clearHandlerSweeper() {\n\t\tclearInterval(this.handlerTimer);\n\t}\n\n\t/**\n\t * Generates route data for an endpoint:method\n\t *\n\t * @param endpoint - The raw endpoint to generalize\n\t * @param method - The HTTP method this endpoint is called without\n\t * @internal\n\t */\n\tprivate static generateRouteData(endpoint: RouteLike, method: RequestMethod): RouteData {\n\t\tif (endpoint.startsWith('/interactions/') && endpoint.endsWith('/callback')) {\n\t\t\treturn {\n\t\t\t\tmajorParameter: BurstHandlerMajorIdKey,\n\t\t\t\tbucketRoute: '/interactions/:id/:token/callback',\n\t\t\t\toriginal: endpoint,\n\t\t\t};\n\t\t}\n\n\t\tconst majorIdMatch = /^\\/(?:channels|guilds|webhooks)\\/(\\d{17,19})/.exec(endpoint);\n\n\t\t// Get the major id for this route - global otherwise\n\t\tconst majorId = majorIdMatch?.[1] ?? 'global';\n\n\t\tconst baseRoute = endpoint\n\t\t\t// Strip out all ids\n\t\t\t.replaceAll(/\\d{17,19}/g, ':id')\n\t\t\t// Strip out reaction as they fall under the same bucket\n\t\t\t.replace(/\\/reactions\\/(.*)/, '/reactions/:reaction');\n\n\t\tlet exceptions = '';\n\n\t\t// Hard-Code Old Message Deletion Exception (2 week+ old messages are a different bucket)\n\t\t// https://github.com/discord/discord-api-docs/issues/1295\n\t\tif (method === RequestMethod.Delete && baseRoute === '/channels/:id/messages/:id') {\n\t\t\tconst id = /\\d{17,19}$/.exec(endpoint)![0]!;\n\t\t\tconst timestamp = DiscordSnowflake.timestampFrom(id);\n\t\t\tif (Date.now() - timestamp > 1_000 * 60 * 60 * 24 * 14) {\n\t\t\t\texceptions += '/Delete Old Message';\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tmajorParameter: majorId,\n\t\t\tbucketRoute: baseRoute + exceptions,\n\t\t\toriginal: endpoint,\n\t\t};\n\t}\n}\n","import type { Readable } from 'node:stream';\nimport type { ReadableStream } from 'node:stream/web';\nimport type { Collection } from '@discordjs/collection';\nimport type { Agent, Dispatcher, RequestInit, BodyInit, Response } from 'undici';\nimport type { IHandler } from '../interfaces/Handler.js';\n\nexport interface RestEvents {\n\thandlerSweep: [sweptHandlers: Collection<string, IHandler>];\n\thashSweep: [sweptHashes: Collection<string, HashData>];\n\tinvalidRequestWarning: [invalidRequestInfo: InvalidRequestWarningData];\n\trateLimited: [rateLimitInfo: RateLimitData];\n\tresponse: [request: APIRequest, response: ResponseLike];\n\trestDebug: [info: string];\n}\n\nexport type RestEventsMap = {\n\t[K in keyof RestEvents]: RestEvents[K];\n};\n\n/**\n * Options to be passed when creating the REST instance\n */\nexport interface RESTOptions {\n\t/**\n\t * The agent to set globally\n\t */\n\tagent: Dispatcher | null;\n\t/**\n\t * The base api path, without version\n\t *\n\t * @defaultValue `'https://discord.com/api'`\n\t */\n\tapi: string;\n\t/**\n\t * The authorization prefix to use for requests, useful if you want to use\n\t * bearer tokens\n\t *\n\t * @defaultValue `'Bot'`\n\t */\n\tauthPrefix: 'Bearer' | 'Bot';\n\t/**\n\t * The cdn path\n\t *\n\t * @defaultValue `'https://cdn.discordapp.com'`\n\t */\n\tcdn: string;\n\t/**\n\t * How many requests to allow sending per second (Infinity for unlimited, 50 for the standard global limit used by Discord)\n\t *\n\t * @defaultValue `50`\n\t */\n\tglobalRequestsPerSecond: number;\n\t/**\n\t * The amount of time in milliseconds that passes between each hash sweep. (defaults to 1h)\n\t *\n\t * @defaultValue `3_600_000`\n\t */\n\thandlerSweepInterval: number;\n\t/**\n\t * The maximum amount of time a hash can exist in milliseconds without being hit with a request (defaults to 24h)\n\t *\n\t * @defaultValue `86_400_000`\n\t */\n\thashLifetime: number;\n\t/**\n\t * The amount of time in milliseconds that passes between each hash sweep. (defaults to 4h)\n\t *\n\t * @defaultValue `14_400_000`\n\t */\n\thashSweepInterval: number;\n\t/**\n\t * Additional headers to send for all API requests\n\t *\n\t * @defaultValue `{}`\n\t */\n\theaders: Record<string, string>;\n\t/**\n\t * The number of invalid REST requests (those that return 401, 403, or 429) in a 10 minute window between emitted warnings (0 for no warnings).\n\t * That is, if set to 500, warnings will be emitted at invalid request number 500, 1000, 1500, and so on.\n\t *\n\t * @defaultValue `0`\n\t */\n\tinvalidRequestWarningInterval: number;\n\t/**\n\t * The method called to perform the actual HTTP request given a url and web `fetch` options\n\t * For example, to use global fetch, simply provide `makeRequest: fetch`\n\t */\n\tmakeRequest(url: string, init: RequestInit): Promise<ResponseLike>;\n\t/**\n\t * The extra offset to add to rate limits in milliseconds\n\t *\n\t * @defaultValue `50`\n\t */\n\toffset: number;\n\t/**\n\t * Determines how rate limiting and pre-emptive throttling should be handled.\n\t * When an array of strings, each element is treated as a prefix for the request route\n\t * (e.g. `/channels` to match any route starting with `/channels` such as `/channels/:id/messages`)\n\t * for which to throw {@link RateLimitError}s. All other request routes will be queued normally\n\t *\n\t * @defaultValue `null`\n\t */\n\trejectOnRateLimit: RateLimitQueueFilter | string[] | null;\n\t/**\n\t * The number of retries for errors with the 500 code, or errors\n\t * that timeout\n\t *\n\t * @defaultValue `3`\n\t */\n\tretries: number;\n\t/**\n\t * The time to wait in milliseconds before a request is aborted\n\t *\n\t * @defaultValue `15_000`\n\t */\n\ttimeout: number;\n\t/**\n\t * Extra information to add to the user agent\n\t *\n\t * @defaultValue DefaultUserAgentAppendix\n\t */\n\tuserAgentAppendix: string;\n\t/**\n\t * The version of the API to use\n\t *\n\t * @defaultValue `'10'`\n\t */\n\tversion: string;\n}\n\n/**\n * Data emitted on `RESTEvents.RateLimited`\n */\nexport interface RateLimitData {\n\t/**\n\t * Whether the rate limit that was reached was the global limit\n\t */\n\tglobal: boolean;\n\t/**\n\t * The bucket hash for this request\n\t */\n\thash: string;\n\t/**\n\t * The amount of requests we can perform before locking requests\n\t */\n\tlimit: number;\n\t/**\n\t * The major parameter of the route\n\t *\n\t * For example, in `/channels/x`, this will be `x`.\n\t * If there is no major parameter (e.g: `/bot/gateway`) this will be `global`.\n\t */\n\tmajorParameter: string;\n\t/**\n\t * The HTTP method being performed\n\t */\n\tmethod: string;\n\t/**\n\t * The route being hit in this request\n\t */\n\troute: string;\n\t/**\n\t * The time, in milliseconds, until the request-lock is reset\n\t */\n\ttimeToReset: number;\n\t/**\n\t * The full URL for this request\n\t */\n\turl: string;\n}\n\n/**\n * A function that determines whether the rate limit hit should throw an Error\n */\nexport type RateLimitQueueFilter = (rateLimitData: RateLimitData) => Promise<boolean> | boolean;\n\nexport interface APIRequest {\n\t/**\n\t * The data that was used to form the body of this request\n\t */\n\tdata: HandlerRequestData;\n\t/**\n\t * The HTTP method used in this request\n\t */\n\tmethod: string;\n\t/**\n\t * Additional HTTP options for this request\n\t */\n\toptions: RequestInit;\n\t/**\n\t * The full path used to make the request\n\t */\n\tpath: RouteLike;\n\t/**\n\t * The number of times this request has been attempted\n\t */\n\tretries: number;\n\t/**\n\t * The API route identifying the ratelimit for this request\n\t */\n\troute: string;\n}\n\nexport interface ResponseLike\n\textends Pick<Response, 'arrayBuffer' | 'bodyUsed' | 'headers' | 'json' | 'ok' | 'status' | 'statusText' | 'text'> {\n\tbody: Readable | ReadableStream | null;\n}\n\nexport interface InvalidRequestWarningData {\n\t/**\n\t * Number of invalid requests that have been made in the window\n\t */\n\tcount: number;\n\t/**\n\t * Time in milliseconds remaining before the count resets\n\t */\n\tremainingTime: number;\n}\n\n/**\n * Represents a file to be added to the request\n */\nexport interface RawFile {\n\t/**\n\t * Content-Type of the file\n\t */\n\tcontentType?: string;\n\t/**\n\t * The actual data for the file\n\t */\n\tdata: Buffer | Uint8Array | boolean | number | string;\n\t/**\n\t * An explicit key to use for key of the formdata field for this file.\n\t * When not provided, the index of the file in the files array is used in the form `files[${index}]`.\n\t * If you wish to alter the placeholder snowflake, you must provide this property in the same form (`files[${placeholder}]`)\n\t */\n\tkey?: string;\n\t/**\n\t * The name of the file\n\t */\n\tname: string;\n}\n\n/**\n * Represents possible data to be given to an endpoint\n */\nexport interface RequestData {\n\t/**\n\t * Whether to append JSON data to form data instead of `payload_json` when sending files\n\t */\n\tappendToFormData?: boolean;\n\t/**\n\t * If this request needs the `Authorization` header\n\t *\n\t * @defaultValue `true`\n\t */\n\tauth?: boolean;\n\t/**\n\t * The authorization prefix to use for this request, useful if you use this with bearer tokens\n\t *\n\t * @defaultValue `'Bot'`\n\t */\n\tauthPrefix?: 'Bearer' | 'Bot';\n\t/**\n\t * The body to send to this request.\n\t * If providing as BodyInit, set `passThroughBody: true`\n\t */\n\tbody?: BodyInit | unknown;\n\t/**\n\t * The {@link https://undici.nodejs.org/#/docs/api/Agent | Agent} to use for the request.\n\t */\n\tdispatcher?: Agent;\n\t/**\n\t * Files to be attached to this request\n\t */\n\tfiles?: RawFile[] | undefined;\n\t/**\n\t * Additional headers to add to this request\n\t */\n\theaders?: Record<string, string>;\n\t/**\n\t * Whether to pass-through the body property directly to `fetch()`.\n\t * <warn>This only applies when files is NOT present</warn>\n\t */\n\tpassThroughBody?: boolean;\n\t/**\n\t * Query string parameters to append to the called endpoint\n\t */\n\tquery?: URLSearchParams;\n\t/**\n\t * Reason to show in the audit logs\n\t */\n\treason?: string | undefined;\n\t/**\n\t * The signal to abort the queue entry or the REST call, where applicable\n\t */\n\tsignal?: AbortSignal | undefined;\n\t/**\n\t * If this request should be versioned\n\t *\n\t * @defaultValue `true`\n\t */\n\tversioned?: boolean;\n}\n\n/**\n * Possible headers for an API call\n */\nexport interface RequestHeaders {\n\tAuthorization?: string;\n\t'User-Agent': string;\n\t'X-Audit-Log-Reason'?: string;\n}\n\n/**\n * Possible API methods to be used when doing requests\n */\nexport enum RequestMethod {\n\tDelete = 'DELETE',\n\tGet = 'GET',\n\tPatch = 'PATCH',\n\tPost = 'POST',\n\tPut = 'PUT',\n}\n\nexport type RouteLike = `/${string}`;\n\n/**\n * Internal request options\n *\n * @internal\n */\nexport interface InternalRequest extends RequestData {\n\tfullRoute: RouteLike;\n\tmethod: RequestMethod;\n}\n\nexport type HandlerRequestData = Pick<InternalRequest, 'auth' | 'body' | 'files' | 'signal'>;\n\n/**\n * Parsed route data for an endpoint\n *\n * @internal\n */\nexport interface RouteData {\n\tbucketRoute: string;\n\tmajorParameter: string;\n\toriginal: RouteLike;\n}\n\n/**\n * Represents a hash and its associated fields\n *\n * @internal\n */\nexport interface HashData {\n\tlastAccess: number;\n\tvalue: string;\n}\n","import type { RESTPatchAPIChannelJSONBody, Snowflake } from 'discord-api-types/v10';\nimport type { REST } from '../REST.js';\nimport { RateLimitError } from '../errors/RateLimitError.js';\nimport { RequestMethod, type RateLimitData, type ResponseLike } from './types.js';\n\nfunction serializeSearchParam(value: unknown): string | null {\n\tswitch (typeof value) {\n\t\tcase 'string':\n\t\t\treturn value;\n\t\tcase 'number':\n\t\tcase 'bigint':\n\t\tcase 'boolean':\n\t\t\treturn value.toString();\n\t\tcase 'object':\n\t\t\tif (value === null) return null;\n\t\t\tif (value instanceof Date) {\n\t\t\t\treturn Number.isNaN(value.getTime()) ? null : value.toISOString();\n\t\t\t}\n\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-base-to-string\n\t\t\tif (typeof value.toString === 'function' && value.toString !== Object.prototype.toString) return value.toString();\n\t\t\treturn null;\n\t\tdefault:\n\t\t\treturn null;\n\t}\n}\n\n/**\n * Creates and populates an URLSearchParams instance from an object, stripping\n * out null and undefined values, while also coercing non-strings to strings.\n *\n * @param options - The options to use\n * @returns A populated URLSearchParams instance\n */\nexport function makeURLSearchParams<T extends object>(options?: Readonly<T>) {\n\tconst params = new URLSearchParams();\n\tif (!options) return params;\n\n\tfor (const [key, value] of Object.entries(options)) {\n\t\tconst serialized = serializeSearchParam(value);\n\t\tif (serialized !== null) params.append(key, serialized);\n\t}\n\n\treturn params;\n}\n\n/**\n * Converts the response to usable data\n *\n * @param res - The fetch response\n */\nexport async function parseResponse(res: ResponseLike): Promise<unknown> {\n\tif (res.headers.get('Content-Type')?.startsWith('application/json')) {\n\t\treturn res.json();\n\t}\n\n\treturn res.arrayBuffer();\n}\n\n/**\n * Check whether a request falls under a sublimit\n *\n * @param bucketRoute - The buckets route identifier\n * @param body - The options provided as JSON data\n * @param method - The HTTP method that will be used to make the request\n * @returns Whether the request falls under a sublimit\n */\nexport function hasSublimit(bucketRoute: string, body?: unknown, method?: string): boolean {\n\t// TODO: Update for new sublimits\n\t// Currently known sublimits:\n\t// Editing channel `name` or `topic`\n\tif (bucketRoute === '/channels/:id') {\n\t\tif (typeof body !== 'object' || body === null) return false;\n\t\t// This should never be a POST body, but just in case\n\t\tif (method !== RequestMethod.Patch) return false;\n\t\tconst castedBody = body as RESTPatchAPIChannelJSONBody;\n\t\treturn ['name', 'topic'].some((key) => Reflect.has(castedBody, key));\n\t}\n\n\t// If we are checking if a request has a sublimit on a route not checked above, sublimit all requests to avoid a flood of 429s\n\treturn true;\n}\n\n/**\n * Check whether an error indicates that a retry can be attempted\n *\n * @param error - The error thrown by the network request\n * @returns Whether the error indicates a retry should be attempted\n */\nexport function shouldRetry(error: Error | NodeJS.ErrnoException) {\n\t// Retry for possible timed out requests\n\tif (error.name === 'AbortError') return true;\n\t// Downlevel ECONNRESET to retry as it may be recoverable\n\treturn ('code' in error && error.code === 'ECONNRESET') || error.message.includes('ECONNRESET');\n}\n\n/**\n * Determines whether the request should be queued or whether a RateLimitError should be thrown\n *\n * @internal\n */\nexport async function onRateLimit(manager: REST, rateLimitData: RateLimitData) {\n\tconst { options } = manager;\n\tif (!options.rejectOnRateLimit) return;\n\n\tconst shouldThrow =\n\t\ttypeof options.rejectOnRateLimit === 'function'\n\t\t\t? await options.rejectOnRateLimit(rateLimitData)\n\t\t\t: options.rejectOnRateLimit.some((route) => rateLimitData.route.startsWith(route.toLowerCase()));\n\tif (shouldThrow) {\n\t\tthrow new RateLimitError(rateLimitData);\n\t}\n}\n\n/**\n * Calculates the default avatar index for a given user id.\n *\n * @param userId - The user id to calculate the default avatar index for\n */\nexport function calculateUserDefaultAvatarIndex(userId: Snowflake) {\n\treturn Number(BigInt(userId) >> 22n) % 6;\n}\n\n/**\n * Sleeps for a given amount of time.\n *\n * @param ms - The amount of time (in milliseconds) to sleep for\n */\nexport async function sleep(ms: number): Promise<void> {\n\treturn new Promise<void>((resolve) => {\n\t\tsetTimeout(() => resolve(), ms);\n\t});\n}\n\n/**\n * Verifies that a value is a buffer-like object.\n *\n * @param value - The value to check\n */\nexport function isBufferLike(value: unknown): value is ArrayBuffer | Buffer | Uint8Array | Uint8ClampedArray {\n\treturn value instanceof ArrayBuffer || value instanceof Uint8Array || value instanceof Uint8ClampedArray;\n}\n","import type { RequestInit } from 'undici';\nimport type { REST } from '../REST.js';\nimport type { DiscordErrorData, OAuthErrorData } from '../errors/DiscordAPIError.js';\nimport { DiscordAPIError } from '../errors/DiscordAPIError.js';\nimport { HTTPError } from '../errors/HTTPError.js';\nimport { RESTEvents } from '../utils/constants.js';\nimport type { ResponseLike, HandlerRequestData, RouteData } from '../utils/types.js';\nimport { parseResponse, shouldRetry } from '../utils/utils.js';\n\n/**\n * Invalid request limiting is done on a per-IP basis, not a per-token basis.\n * The best we can do is track invalid counts process-wide (on the theory that\n * users could have multiple bots run from one process) rather than per-bot.\n * Therefore, store these at file scope here rather than in the client's\n * RESTManager object.\n */\nlet invalidCount = 0;\nlet invalidCountResetTime: number | null = null;\n\n/**\n * Increment the invalid request count and emit warning if necessary\n *\n * @internal\n */\nexport function incrementInvalidCount(manager: REST) {\n\tif (!invalidCountResetTime || invalidCountResetTime < Date.now()) {\n\t\tinvalidCountResetTime = Date.now() + 1_000 * 60 * 10;\n\t\tinvalidCount = 0;\n\t}\n\n\tinvalidCount++;\n\n\tconst emitInvalid =\n\t\tmanager.options.invalidRequestWarningInterval > 0 &&\n\t\tinvalidCount % manager.options.invalidRequestWarningInterval === 0;\n\tif (emitInvalid) {\n\t\t// Let library users know periodically about invalid requests\n\t\tmanager.emit(RESTEvents.InvalidRequestWarning, {\n\t\t\tcount: invalidCount,\n\t\t\tremainingTime: invalidCountResetTime - Date.now(),\n\t\t});\n\t}\n}\n\n/**\n * Performs the actual network request for a request handler\n *\n * @param manager - The manager that holds options and emits informational events\n * @param routeId - The generalized api route with literal ids for major parameters\n * @param url - The fully resolved url to make the request to\n * @param options - The fetch options needed to make the request\n * @param requestData - Extra data from the user's request needed for errors and additional processing\n * @param retries - The number of retries this request has already attempted (recursion occurs on the handler)\n * @returns The respond from the network or `null` when the request should be retried\n * @internal\n */\nexport async function makeNetworkRequest(\n\tmanager: REST,\n\trouteId: RouteData,\n\turl: string,\n\toptions: RequestInit,\n\trequestData: HandlerRequestData,\n\tretries: number,\n) {\n\tconst controller = new AbortController();\n\tconst timeout = setTimeout(() => controller.abort(), manager.options.timeout);\n\tif (requestData.signal) {\n\t\t// If the user signal was aborted, abort the controller, else abort the local signal.\n\t\t// The reason why we don't re-use the user's signal, is because users may use the same signal for multiple\n\t\t// requests, and we do not want to cause unexpected side-effects.\n\t\tif (requestData.signal.aborted) controller.abort();\n\t\telse requestData.signal.addEventListener('abort', () => controller.abort());\n\t}\n\n\tlet res: ResponseLike;\n\ttry {\n\t\tres = await manager.options.makeRequest(url, { ...options, signal: controller.signal });\n\t} catch (error: unknown) {\n\t\tif (!(error instanceof Error)) throw error;\n\t\t// Retry the specified number of times if needed\n\t\tif (shouldRetry(error) && retries !== manager.options.retries) {\n\t\t\t// Retry is handled by the handler upon receiving null\n\t\t\treturn null;\n\t\t}\n\n\t\tthrow error;\n\t} finally {\n\t\tclearTimeout(timeout);\n\t}\n\n\tif (manager.listenerCount(RESTEvents.Response)) {\n\t\tmanager.emit(\n\t\t\tRESTEvents.Response,\n\t\t\t{\n\t\t\t\tmethod: options.method ?? 'get',\n\t\t\t\tpath: routeId.original,\n\t\t\t\troute: routeId.bucketRoute,\n\t\t\t\toptions,\n\t\t\t\tdata: requestData,\n\t\t\t\tretries,\n\t\t\t},\n\t\t\tres instanceof Response ? res.clone() : { ...res },\n\t\t);\n\t}\n\n\treturn res;\n}\n\n/**\n * Handles 5xx and 4xx errors (not 429's) conventionally. 429's should be handled before calling this function\n *\n * @param manager - The manager that holds options and emits informational events\n * @param res - The response received from {@link makeNetworkRequest}\n * @param method - The method used to make the request\n * @param url - The fully resolved url to make the request to\n * @param requestData - Extra data from the user's request needed for errors and additional processing\n * @param retries - The number of retries this request has already attempted (recursion occurs on the handler)\n * @returns - The response if the status code is not handled or null to request a retry\n */\nexport async function handleErrors(\n\tmanager: REST,\n\tres: ResponseLike,\n\tmethod: string,\n\turl: string,\n\trequestData: HandlerRequestData,\n\tretries: number,\n) {\n\tconst status = res.status;\n\tif (status >= 500 && status < 600) {\n\t\t// Retry the specified number of times for possible server side issues\n\t\tif (retries !== manager.options.retries) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// We are out of retries, throw an error\n\t\tthrow new HTTPError(status, res.statusText, method, url, requestData);\n\t} else {\n\t\t// Handle possible malformed requests\n\t\tif (status >= 400 && status < 500) {\n\t\t\t// If we receive this status code, it means the token we had is no longer valid.\n\t\t\tif (status === 401 && requestData.auth) {\n\t\t\t\tmanager.setToken(null!);\n\t\t\t}\n\n\t\t\t// The request will not succeed for some reason, parse the error returned from the api\n\t\t\tconst data = (await parseResponse(res)) as DiscordErrorData | OAuthErrorData;\n\t\t\t// throw the API error\n\t\t\tthrow new DiscordAPIError(data, 'code' in data ? data.code : data.error, status, method, url, requestData);\n\t\t}\n\n\t\treturn res;\n\t}\n}\n","import type { RequestInit } from 'undici';\nimport type { REST } from '../REST.js';\nimport type { IHandler } from '../interfaces/Handler.js';\nimport { RESTEvents } from '../utils/constants.js';\nimport type { ResponseLike, HandlerRequestData, RouteData } from '../utils/types.js';\nimport { onRateLimit, sleep } from '../utils/utils.js';\nimport { handleErrors, incrementInvalidCount, makeNetworkRequest } from './Shared.js';\n\n/**\n * The structure used to handle burst requests for a given bucket.\n * Burst requests have no ratelimit handling but allow for pre- and post-processing\n * of data in the same manner as sequentially queued requests.\n *\n * @remarks\n * This queue may still emit a rate limit error if an unexpected 429 is hit\n */\nexport class BurstHandler implements IHandler {\n\t/**\n\t * {@inheritdoc IHandler.id}\n\t */\n\tpublic readonly id: string;\n\n\t/**\n\t * {@inheritDoc IHandler.inactive}\n\t */\n\tpublic inactive = false;\n\n\t/**\n\t * @param manager - The request manager\n\t * @param hash - The hash that this RequestHandler handles\n\t * @param majorParameter - The major parameter for this handler\n\t */\n\tpublic constructor(\n\t\tprivate readonly manager: REST,\n\t\tprivate readonly hash: string,\n\t\tprivate readonly majorParameter: string,\n\t) {\n\t\tthis.id = `${hash}:${majorParameter}`;\n\t}\n\n\t/**\n\t * Emits a debug message\n\t *\n\t * @param message - The message to debug\n\t */\n\tprivate debug(message: string) {\n\t\tthis.manager.emit(RESTEvents.Debug, `[REST ${this.id}] ${message}`);\n\t}\n\n\t/**\n\t * {@inheritDoc IHandler.queueRequest}\n\t */\n\tpublic async queueRequest(\n\t\trouteId: RouteData,\n\t\turl: string,\n\t\toptions: RequestInit,\n\t\trequestData: HandlerRequestData,\n\t): Promise<ResponseLike> {\n\t\treturn this.runRequest(routeId, url, options, requestData);\n\t}\n\n\t/**\n\t * The method that actually makes the request to the API, and updates info about the bucket accordingly\n\t *\n\t * @param routeId - The generalized API route with literal ids for major parameters\n\t * @param url - The fully resolved URL to make the request to\n\t * @param options - The fetch options needed to make the request\n\t * @param requestData - Extra data from the user's request needed for errors and additional processing\n\t * @param retries - The number of retries this request has already attempted (recursion)\n\t */\n\tprivate async runRequest(\n\t\trouteId: RouteData,\n\t\turl: string,\n\t\toptions: RequestInit,\n\t\trequestData: HandlerRequestData,\n\t\tretries = 0,\n\t): Promise<ResponseLike> {\n\t\tconst method = options.method ?? 'get';\n\n\t\tconst res = await makeNetworkRequest(this.manager, routeId, url, options, requestData, retries);\n\n\t\t// Retry requested\n\t\tif (res === null) {\n\t\t\t// eslint-disable-next-line no-param-reassign\n\t\t\treturn this.runRequest(routeId, url, options, requestData, ++retries);\n\t\t}\n\n\t\tconst status = res.status;\n\t\tlet retryAfter = 0;\n\t\tconst retry = res.headers.get('Retry-After');\n\n\t\t// Amount of time in milliseconds until we should retry if rate limited (globally or otherwise)\n\t\tif (retry) retryAfter = Number(retry) * 1_000 + this.manager.options.offset;\n\n\t\t// Count the invalid requests\n\t\tif (status === 401 || status === 403 || status === 429) {\n\t\t\tincrementInvalidCount(this.manager);\n\t\t}\n\n\t\tif (status >= 200 && status < 300) {\n\t\t\treturn res;\n\t\t} else if (status === 429) {\n\t\t\t// Unexpected ratelimit\n\t\t\tconst isGlobal = res.headers.has('X-RateLimit-Global');\n\t\t\tawait onRateLimit(this.manager, {\n\t\t\t\ttimeToReset: retryAfter,\n\t\t\t\tlimit: Number.POSITIVE_INFINITY,\n\t\t\t\tmethod,\n\t\t\t\thash: this.hash,\n\t\t\t\turl,\n\t\t\t\troute: routeId.bucketRoute,\n\t\t\t\tmajorParameter: this.majorParameter,\n\t\t\t\tglobal: isGlobal,\n\t\t\t});\n\t\t\tthis.debug(\n\t\t\t\t[\n\t\t\t\t\t'Encountered unexpected 429 rate limit',\n\t\t\t\t\t` Global : ${isGlobal}`,\n\t\t\t\t\t` Method : ${method}`,\n\t\t\t\t\t` URL : ${url}`,\n\t\t\t\t\t` Bucket : ${routeId.bucketRoute}`,\n\t\t\t\t\t` Major parameter: ${routeId.majorParameter}`,\n\t\t\t\t\t` Hash : ${this.hash}`,\n\t\t\t\t\t` Limit : ${Number.POSITIVE_INFINITY}`,\n\t\t\t\t\t` Retry After : ${retryAfter}ms`,\n\t\t\t\t\t` Sublimit : None`,\n\t\t\t\t].join('\\n'),\n\t\t\t);\n\n\t\t\t// We are bypassing all other limits, but an encountered limit should be respected (it's probably a non-punished rate limit anyways)\n\t\t\tawait sleep(retryAfter);\n\n\t\t\t// Since this is not a server side issue, the next request should pass, so we don't bump the retries counter\n\t\t\treturn this.runRequest(routeId, url, options, requestData, retries);\n\t\t} else {\n\t\t\tconst handled = await handleErrors(this.manager, res, method, url, requestData, retries);\n\t\t\tif (handled === null) {\n\t\t\t\t// eslint-disable-next-line no-param-reassign\n\t\t\t\treturn this.runRequest(routeId, url, options, requestData, ++retries);\n\t\t\t}\n\n\t\t\treturn handled;\n\t\t}\n\t}\n}\n","import { AsyncQueue } from '@sapphire/async-queue';\nimport type { RequestInit } from 'undici';\nimport type { REST } from '../REST.js';\nimport type { IHandler } from '../interfaces/Handler.js';\nimport { RESTEvents } from '../utils/constants.js';\nimport type { RateLimitData, ResponseLike, HandlerRequestData, RouteData } from '../utils/types.js';\nimport { hasSublimit, onRateLimit, sleep } from '../utils/utils.js';\nimport { handleErrors, incrementInvalidCount, makeNetworkRequest } from './Shared.js';\n\nconst enum QueueType {\n\tStandard,\n\tSublimit,\n}\n\n/**\n * The structure used to handle sequential requests for a given bucket\n */\nexport class SequentialHandler implements IHandler {\n\t/**\n\t * {@inheritDoc IHandler.id}\n\t */\n\tpublic readonly id: string;\n\n\t/**\n\t * The time this rate limit bucket will reset\n\t */\n\tprivate reset = -1;\n\n\t/**\n\t * The remaining requests that can be made before we are rate limited\n\t */\n\tprivate remaining = 1;\n\n\t/**\n\t * The total number of requests that can be made before we are rate limited\n\t */\n\tprivate limit = Number.POSITIVE_INFINITY;\n\n\t/**\n\t * The interface used to sequence async requests sequentially\n\t */\n\t#asyncQueue = new AsyncQueue();\n\n\t/**\n\t * The interface used to sequence sublimited async requests sequentially\n\t */\n\t#sublimitedQueue: AsyncQueue | null = null;\n\n\t/**\n\t * A promise wrapper for when the sublimited queue is finished being processed or null when not being processed\n\t */\n\t#sublimitPromise: { promise: Promise<void>; resolve(): void } | null = null;\n\n\t/**\n\t * Whether the sublimit queue needs to be shifted in the finally block\n\t */\n\t#shiftSublimit = false;\n\n\t/**\n\t * @param manager - The request manager\n\t * @param hash - The hash that this RequestHandler handles\n\t * @param majorParameter - The major parameter for this handler\n\t */\n\tpublic constructor(\n\t\tprivate readonly manager: REST,\n\t\tprivate readonly hash: string,\n\t\tprivate readonly majorParameter: string,\n\t) {\n\t\tthis.id = `${hash}:${majorParameter}`;\n\t}\n\n\t/**\n\t * {@inheritDoc IHandler.inactive}\n\t */\n\tpublic get inactive(): boolean {\n\t\treturn (\n\t\t\tthis.#asyncQueue.remaining === 0 &&\n\t\t\t(this.#sublimitedQueue === null || this.#sublimitedQueue.remaining === 0) &&\n\t\t\t!this.limited\n\t\t);\n\t}\n\n\t/**\n\t * If the rate limit bucket is currently limited by the global limit\n\t */\n\tprivate get globalLimited(): boolean {\n\t\treturn this.manager.globalRemaining <= 0 && Date.now() < this.manager.globalReset;\n\t}\n\n\t/**\n\t * If the rate limit bucket is currently limited by its limit\n\t */\n\tprivate get localLimited(): boolean {\n\t\treturn this.remaining <= 0 && Date.now() < this.reset;\n\t}\n\n\t/**\n\t * If the rate limit bucket is currently limited\n\t */\n\tprivate get limited(): boolean {\n\t\treturn this.globalLimited || this.localLimited;\n\t}\n\n\t/**\n\t * The time until queued requests can continue\n\t */\n\tprivate get timeToReset(): number {\n\t\treturn this.reset + this.manager.options.offset - Date.now();\n\t}\n\n\t/**\n\t * Emits a debug message\n\t *\n\t * @param message - The message to debug\n\t */\n\tprivate debug(message: string) {\n\t\tthis.manager.emit(RESTEvents.Debug, `[REST ${this.id}] ${message}`);\n\t}\n\n\t/**\n\t * Delay all requests for the specified amount of time, handling global rate limits\n\t *\n\t * @param time - The amount of time to delay all requests for\n\t */\n\tprivate async globalDelayFor(time: number): Promise<void> {\n\t\tawait sleep(time);\n\t\tthis.manager.globalDelay = null;\n\t}\n\n\t/**\n\t * {@inheritDoc IHandler.queueRequest}\n\t */\n\tpublic async queueRequest(\n\t\trouteId: RouteData,\n\t\turl: string,\n\t\toptions: RequestInit,\n\t\trequestData: HandlerRequestData,\n\t): Promise<ResponseLike> {\n\t\tlet queue = this.#asyncQueue;\n\t\tlet queueType = QueueType.Standard;\n\t\t// Separate sublimited requests when already sublimited\n\t\tif (this.#sublimitedQueue && hasSublimit(routeId.bucketRoute, requestData.body, options.method)) {\n\t\t\tqueue = this.#sublimitedQueue!;\n\t\t\tqueueType = QueueType.Sublimit;\n\t\t}\n\n\t\t// Wait for any previous requests to be completed before this one is run\n\t\tawait queue.wait({ signal: requestData.signal });\n\t\t// This set handles retroactively sublimiting requests\n\t\tif (queueType === QueueType.Standard) {\n\t\t\tif (this.#sublimitedQueue && hasSublimit(routeId.bucketRoute, requestData.body, options.method)) {\n\t\t\t\t/**\n\t\t\t\t * Remove the request from the standard queue, it should never be possible to get here while processing the\n\t\t\t\t * sublimit queue so there is no need to worry about shifting the wrong request\n\t\t\t\t */\n\t\t\t\tqueue = this.#sublimitedQueue!;\n\t\t\t\tconst wait = queue.wait();\n\t\t\t\tthis.#asyncQueue.shift();\n\t\t\t\tawait wait;\n\t\t\t} else if (this.#sublimitPromise) {\n\t\t\t\t// Stall requests while the sublimit queue gets processed\n\t\t\t\tawait this.#sublimitPromise.promise;\n\t\t\t}\n\t\t}\n\n\t\ttry {\n\t\t\t// Make the request, and return the results\n\t\t\treturn await this.runRequest(routeId, url, options, requestData);\n\t\t} finally {\n\t\t\t// Allow the next request to fire\n\t\t\tqueue.shift();\n\t\t\tif (this.#shiftSublimit) {\n\t\t\t\tthis.#shiftSublimit = false;\n\t\t\t\tthis.#sublimitedQueue?.shift();\n\t\t\t}\n\n\t\t\t// If this request is the last request in a sublimit\n\t\t\tif (this.#sublimitedQueue?.remaining === 0) {\n\t\t\t\tthis.#sublimitPromise?.resolve();\n\t\t\t\tthis.#sublimitedQueue = null;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * The method that actually makes the request to the api, and updates info about the bucket accordingly\n\t *\n\t * @param routeId - The generalized api route with literal ids for major parameters\n\t * @param url - The fully resolved url to make the request to\n\t * @param options - The fetch options needed to make the request\n\t * @param requestData - Extra data from the user's request needed for errors and additional processing\n\t * @param retries - The number of retries this request has already attempted (recursion)\n\t */\n\tprivate async runRequest(\n\t\trouteId: RouteData,\n\t\turl: string,\n\t\toptions: RequestInit,\n\t\trequestData: HandlerRequestData,\n\t\tretries = 0,\n\t): Promise<ResponseLike> {\n\t\t/*\n\t\t * After calculations have been done, pre-emptively stop further requests\n\t\t * Potentially loop until this task can run if e.g. the global rate limit is hit twice\n\t\t */\n\t\twhile (this.limited) {\n\t\t\tconst isGlobal = this.globalLimited;\n\t\t\tlet limit: number;\n\t\t\tlet timeout: number;\n\t\t\tlet delay: Promise<void>;\n\n\t\t\tif (isGlobal) {\n\t\t\t\t// Set RateLimitData based on the global limit\n\t\t\t\tlimit = this.manager.options.globalRequestsPerSecond;\n\t\t\t\ttimeout = this.manager.globalReset + this.manager.options.offset - Date.now();\n\t\t\t\t// If this is the first task to reach the global timeout, set the global delay\n\t\t\t\tif (!this.manager.globalDelay) {\n\t\t\t\t\t// The global delay function clears the global delay state when it is resolved\n\t\t\t\t\tthis.manager.globalDelay = this.globalDelayFor(timeout);\n\t\t\t\t}\n\n\t\t\t\tdelay = this.manager.globalDelay;\n\t\t\t} else {\n\t\t\t\t// Set RateLimitData based on the route-specific limit\n\t\t\t\tlimit = this.limit;\n\t\t\t\ttimeout = this.timeToReset;\n\t\t\t\tdelay = sleep(timeout);\n\t\t\t}\n\n\t\t\tconst rateLimitData: RateLimitData = {\n\t\t\t\ttimeToReset: timeout,\n\t\t\t\tlimit,\n\t\t\t\tmethod: options.method ?? 'get',\n\t\t\t\thash: this.hash,\n\t\t\t\turl,\n\t\t\t\troute: routeId.bucketRoute,\n\t\t\t\tmajorParameter: this.majorParameter,\n\t\t\t\tglobal: isGlobal,\n\t\t\t};\n\t\t\t// Let library users know they have hit a rate limit\n\t\t\tthis.manager.emit(RESTEvents.RateLimited, rateLimitData);\n\t\t\t// Determine whether a RateLimitError should be thrown\n\t\t\tawait onRateLimit(this.manager, rateLimitData);\n\t\t\t// When not erroring, emit debug for what is happening\n\t\t\tif (isGlobal) {\n\t\t\t\tthis.debug(`Global rate limit hit, blocking all requests for ${timeout}ms`);\n\t\t\t} else {\n\t\t\t\tthis.debug(`Waiting ${timeout}ms for rate limit to pass`);\n\t\t\t}\n\n\t\t\t// Wait the remaining time left before the rate limit resets\n\t\t\tawait delay;\n\t\t}\n\n\t\t// As the request goes out, update the global usage information\n\t\tif (!this.manager.globalReset || this.manager.globalReset < Date.now()) {\n\t\t\tthis.manager.globalReset = Date.now() + 1_000;\n\t\t\tthis.manager.globalRemaining = this.manager.options.globalRequestsPerSecond;\n\t\t}\n\n\t\tthis.manager.globalRemaining--;\n\n\t\tconst method = options.method ?? 'get';\n\n\t\tconst res = await makeNetworkRequest(this.manager, routeId, url, options, requestData, retries);\n\n\t\t// Retry requested\n\t\tif (res === null) {\n\t\t\t// eslint-disable-next-line no-param-reassign\n\t\t\treturn this.runRequest(routeId, url, options, requestData, ++retries);\n\t\t}\n\n\t\tconst status = res.status;\n\t\tlet retryAfter = 0;\n\n\t\tconst limit = res.headers.get('X-RateLimit-Limit');\n\t\tconst remaining = res.headers.get('X-RateLimit-Remaining');\n\t\tconst reset = res.headers.get('X-RateLimit-Reset-After');\n\t\tconst hash = res.headers.get('X-RateLimit-Bucket');\n\t\tconst retry = res.headers.get('Retry-After');\n\n\t\t// Update the total number of requests that can be made before the rate limit resets\n\t\tthis.limit = limit ? Number(limit) : Number.POSITIVE_INFINITY;\n\t\t// Update the number of remaining requests that can be made before the rate limit resets\n\t\tthis.remaining = remaining ? Number(remaining) : 1;\n\t\t// Update the time when this rate limit resets (reset-after is in seconds)\n\t\tthis.reset = reset ? Number(reset) * 1_000 + Date.now() + this.manager.options.offset : Date.now();\n\n\t\t// Amount of time in milliseconds until we should retry if rate limited (globally or otherwise)\n\t\tif (retry) retryAfter = Number(retry) * 1_000 + this.manager.options.offset;\n\n\t\t// Handle buckets via the hash header retroactively\n\t\tif (hash && hash !== this.hash) {\n\t\t\t// Let library users know when rate limit buckets have been updated\n\t\t\tthis.debug(['Received bucket hash update', ` Old Hash : ${this.hash}`, ` New Hash : ${hash}`].join('\\n'));\n\t\t\t// This queue will eventually be eliminated via attrition\n\t\t\tthis.manager.hashes.set(`${method}:${routeId.bucketRoute}`, { value: hash, lastAccess: Date.now() });\n\t\t} else if (hash) {\n\t\t\t// Handle the case where hash value doesn't change\n\t\t\t// Fetch the hash data from the manager\n\t\t\tconst hashData = this.manager.hashes.get(`${method}:${routeId.bucketRoute}`);\n\n\t\t\t// When fetched, update the last access of the hash\n\t\t\tif (hashData) {\n\t\t\t\thashData.lastAccess = Date.now();\n\t\t\t}\n\t\t}\n\n\t\t// Handle retryAfter, which means we have actually hit a rate limit\n\t\tlet sublimitTimeout: number | null = null;\n\t\tif (retryAfter > 0) {\n\t\t\tif (res.headers.has('X-RateLimit-Global')) {\n\t\t\t\tthis.manager.globalRemaining = 0;\n\t\t\t\tthis.manager.globalReset = Date.now() + retryAfter;\n\t\t\t} else if (!this.localLimited) {\n\t\t\t\t/*\n\t\t\t\t * This is a sublimit (e.g. 2 channel name changes/10 minutes) since the headers don't indicate a\n\t\t\t\t * route-wide rate limit. Don't update remaining or reset to avoid rate limiting the whole\n\t\t\t\t * endpoint, just set a reset time on the request itself to avoid retrying too soon.\n\t\t\t\t */\n\t\t\t\tsublimitTimeout = retryAfter;\n\t\t\t}\n\t\t}\n\n\t\t// Count the invalid requests\n\t\tif (status === 401 || status === 403 || status === 429) {\n\t\t\tincrementInvalidCount(this.manager);\n\t\t}\n\n\t\tif (res.ok) {\n\t\t\treturn res;\n\t\t} else if (status === 429) {\n\t\t\t// A rate limit was hit - this may happen if the route isn't associated with an official bucket hash yet, or when first globally rate limited\n\t\t\tconst isGlobal = this.globalLimited;\n\t\t\tlet limit: number;\n\t\t\tlet timeout: number;\n\n\t\t\tif (isGlobal) {\n\t\t\t\t// Set RateLimitData based on the global limit\n\t\t\t\tlimit = this.manager.options.globalRequestsPerSecond;\n\t\t\t\ttimeout = this.manager.globalReset + this.manager.options.offset - Date.now();\n\t\t\t} else {\n\t\t\t\t// Set RateLimitData based on the route-specific limit\n\t\t\t\tlimit = this.limit;\n\t\t\t\ttimeout = this.timeToReset;\n\t\t\t}\n\n\t\t\tawait onRateLimit(this.manager, {\n\t\t\t\ttimeToReset: timeout,\n\t\t\t\tlimit,\n\t\t\t\tmethod,\n\t\t\t\thash: this.hash,\n\t\t\t\turl,\n\t\t\t\troute: routeId.bucketRoute,\n\t\t\t\tmajorParameter: this.majorParameter,\n\t\t\t\tglobal: isGlobal,\n\t\t\t});\n\t\t\tthis.debug(\n\t\t\t\t[\n\t\t\t\t\t'Encountered unexpected 429 rate limit',\n\t\t\t\t\t` Global : ${isGlobal.toString()}`,\n\t\t\t\t\t` Method : ${method}`,\n\t\t\t\t\t` URL : ${url}`,\n\t\t\t\t\t` Bucket : ${routeId.bucketRoute}`,\n\t\t\t\t\t` Major parameter: ${routeId.majorParameter}`,\n\t\t\t\t\t` Hash : ${this.hash}`,\n\t\t\t\t\t` Limit : ${limit}`,\n\t\t\t\t\t` Retry After : ${retryAfter}ms`,\n\t\t\t\t\t` Sublimit : ${sublimitTimeout ? `${sublimitTimeout}ms` : 'None'}`,\n\t\t\t\t].join('\\n'),\n\t\t\t);\n\t\t\t// If caused by a sublimit, wait it out here so other requests on the route can be handled\n\t\t\tif (sublimitTimeout) {\n\t\t\t\t// Normally the sublimit queue will not exist, however, if a sublimit is hit while in the sublimit queue, it will\n\t\t\t\tconst firstSublimit = !this.#sublimitedQueue;\n\t\t\t\tif (firstSublimit) {\n\t\t\t\t\tthis.#sublimitedQueue = new AsyncQueue();\n\t\t\t\t\tvoid this.#sublimitedQueue.wait();\n\t\t\t\t\tthis.#asyncQueue.shift();\n\t\t\t\t}\n\n\t\t\t\tthis.#sublimitPromise?.resolve();\n\t\t\t\tthis.#sublimitPromise = null;\n\t\t\t\tawait sleep(sublimitTimeout);\n\t\t\t\tlet resolve: () => void;\n\t\t\t\t// eslint-disable-next-line promise/param-names, no-promise-executor-return\n\t\t\t\tconst promise = new Promise<void>((res) => (resolve = res));\n\t\t\t\tthis.#sublimitPromise = { promise, resolve: resolve! };\n\t\t\t\tif (firstSublimit) {\n\t\t\t\t\t// Re-queue this request so it can be shifted by the finally\n\t\t\t\t\tawait this.#asyncQueue.wait();\n\t\t\t\t\tthis.#shiftSublimit = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Since this is not a server side issue, the next request should pass, so we don't bump the retries counter\n\t\t\treturn this.runRequest(routeId, url, options, requestData, retries);\n\t\t} else {\n\t\t\tconst handled = await handleErrors(this.manager, res, method, url, requestData, retries);\n\t\t\tif (handled === null) {\n\t\t\t\t// eslint-disable-next-line no-param-reassign\n\t\t\t\treturn this.runRequest(routeId, url, options, requestData, ++retries);\n\t\t\t}\n\n\t\t\treturn handled;\n\t\t}\n\t}\n}\n","export * from './lib/CDN.js';\nexport * from './lib/errors/DiscordAPIError.js';\nexport * from './lib/errors/HTTPError.js';\nexport * from './lib/errors/RateLimitError.js';\nexport * from './lib/REST.js';\nexport * from './lib/utils/constants.js';\nexport * from './lib/utils/types.js';\nexport { calculateUserDefaultAvatarIndex, makeURLSearchParams, parseResponse } from './lib/utils/utils.js';\n\n/**\n * The {@link https://github.com/discordjs/discord.js/blob/main/packages/rest/#readme | @discordjs/rest} version\n * that you are currently using.\n */\n// This needs to explicitly be `string` so it is not typed as a \"const string\" that gets injected by esbuild\nexport const version = '2.0.1' as string;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACEA,IAAI;AAEG,SAAS,mBAAmB,aAAyC;AAC3E,oBAAkB;AACnB;AAFgB;AAIT,SAAS,qBAAqB;AACpC,SAAO;AACR;AAFgB;;;ACRhB,kBAAqC;AACrC,iBAA2B;AAIpB,IAAM,mBACZ;AAKM,IAAM,+BAA2B,kCAAqB;AAEtD,IAAM,qBAAqB;AAAA,EACjC,OAAO;AAAA,EACP,KAAK;AAAA,EACL,YAAY;AAAA,EACZ,KAAK;AAAA,EACL,SAAS,CAAC;AAAA,EACV,+BAA+B;AAAA,EAC/B,yBAAyB;AAAA,EACzB,QAAQ;AAAA,EACR,mBAAmB;AAAA,EACnB,SAAS;AAAA,EACT,SAAS;AAAA,EACT,mBAAmB;AAAA,EACnB,SAAS;AAAA,EACT,mBAAmB;AAAA;AAAA,EACnB,cAAc;AAAA;AAAA,EACd,sBAAsB;AAAA;AAAA,EACtB,MAAM,eAAe,MAA6B;AACjD,WAAO,mBAAmB,EAAE,GAAG,IAAI;AAAA,EACpC;AACD;AAKO,IAAK,aAAL,kBAAKA,gBAAL;AACN,EAAAA,YAAA,WAAQ;AACR,EAAAA,YAAA,kBAAe;AACf,EAAAA,YAAA,eAAY;AACZ,EAAAA,YAAA,2BAAwB;AACxB,EAAAA,YAAA,iBAAc;AACd,EAAAA,YAAA,cAAW;AANA,SAAAA;AAAA,GAAA;AASL,IAAM,qBAAqB,CAAC,QAAQ,OAAO,OAAO,QAAQ,KAAK;AAC/D,IAAM,6BAA6B,CAAC,OAAO,QAAQ,KAAK;AACxD,IAAM,gBAAgB,CAAC,IAAI,IAAI,IAAI,KAAK,KAAK,KAAK,MAAO,MAAO,IAAK;AAMrE,IAAM,uBAAuB;AAAA;AAAA,EAEnC,cAAc;AACf;AAEO,IAAM,yBAAyB;;;ACA/B,IAAM,MAAN,MAAU;AAAA,EACT,YAA6B,OAAe,mBAAmB,KAAK;AAAvC;AAAA,EAAwC;AAAA,EA7D7E,OA4DiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUT,SAAS,UAAkB,WAAmB,SAAiD;AACrG,WAAO,KAAK,QAAQ,eAAe,QAAQ,IAAI,SAAS,IAAI,OAAO;AAAA,EACpE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASO,QAAQ,UAAkB,UAAkB,SAAiD;AACnG,WAAO,KAAK,QAAQ,cAAc,QAAQ,IAAI,QAAQ,IAAI,OAAO;AAAA,EAClE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASO,OAAO,IAAY,YAAoB,SAA6C;AAC1F,WAAO,KAAK,eAAe,YAAY,EAAE,IAAI,UAAU,IAAI,YAAY,OAAO;AAAA,EAC/E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASO,iBACN,QACA,sBACA,SACS;AACT,WAAO,KAAK,QAAQ,uBAAuB,MAAM,IAAI,oBAAoB,IAAI,OAAO;AAAA,EACrF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASO,OAAO,IAAY,YAAoB,SAA6C;AAC1F,WAAO,KAAK,eAAe,YAAY,EAAE,IAAI,UAAU,IAAI,YAAY,OAAO;AAAA,EAC/E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASO,YAAY,WAAmB,UAAkB,SAAiD;AACxG,WAAO,KAAK,QAAQ,kBAAkB,SAAS,IAAI,QAAQ,IAAI,OAAO;AAAA,EACvE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUO,cAAc,OAAuB;AAC3C,WAAO,KAAK,QAAQ,kBAAkB,KAAK,IAAI,EAAE,WAAW,MAAM,CAAC;AAAA,EACpE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASO,gBAAgB,SAAiB,YAAoB,SAAiD;AAC5G,WAAO,KAAK,QAAQ,uBAAuB,OAAO,IAAI,UAAU,IAAI,OAAO;AAAA,EAC5E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQO,MAAM,SAAiB,WAAoC;AACjE,WAAO,KAAK,QAAQ,WAAW,OAAO,IAAI,EAAE,UAAU,CAAC;AAAA,EACxD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUO,kBACN,SACA,QACA,YACA,SACS;AACT,WAAO,KAAK,eAAe,WAAW,OAAO,UAAU,MAAM,YAAY,UAAU,IAAI,YAAY,OAAO;AAAA,EAC3G;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUO,kBACN,SACA,QACA,YACA,SACS;AACT,WAAO,KAAK,eAAe,WAAW,OAAO,UAAU,MAAM,WAAW,YAAY,OAAO;AAAA,EAC5F;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASO,KAAK,IAAY,UAAkB,SAA6C;AACtF,WAAO,KAAK,eAAe,UAAU,EAAE,IAAI,QAAQ,IAAI,UAAU,OAAO;AAAA,EACzE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASO,SAAS,QAAgB,cAAsB,SAAiD;AACtG,WAAO,KAAK,QAAQ,eAAe,MAAM,IAAI,YAAY,IAAI,OAAO;AAAA,EACrE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASO,OAAO,SAAiB,YAAoB,SAAiD;AACnG,WAAO,KAAK,QAAQ,aAAa,OAAO,IAAI,UAAU,IAAI,OAAO;AAAA,EAClE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUO,QAAQ,WAAmB,YAA8B,OAAe;AAC9E,WAAO,KAAK,QAAQ,aAAa,SAAS,IAAI,EAAE,mBAAmB,4BAA4B,UAAU,CAAC;AAAA,EAC3G;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQO,kBAAkB,UAAkB,SAAiD;AAC3F,WAAO,KAAK,QAAQ,wCAAwC,QAAQ,IAAI,OAAO;AAAA,EAChF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASO,SAAS,QAAgB,UAAkB,SAAiD;AAClG,WAAO,KAAK,QAAQ,eAAe,MAAM,IAAI,QAAQ,IAAI,OAAO;AAAA,EACjE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASO,yBACN,kBACA,WACA,SACS;AACT,WAAO,KAAK,QAAQ,iBAAiB,gBAAgB,IAAI,SAAS,IAAI,OAAO;AAAA,EAC9E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASQ,eACP,OACA,MACA,EAAE,cAAc,OAAO,GAAG,QAAQ,IAA+B,CAAC,GACzD;AACT,WAAO,KAAK,QAAQ,OAAO,CAAC,eAAe,KAAK,WAAW,IAAI,IAAI,EAAE,GAAG,SAAS,WAAW,MAAM,IAAI,OAAO;AAAA,EAC9G;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,QACP,OACA,EAAE,oBAAoB,oBAAoB,YAAY,QAAQ,KAAK,IAA8B,CAAC,GACzF;AAET,gBAAY,OAAO,SAAS,EAAE,YAAY;AAE1C,QAAI,CAAC,kBAAkB,SAAS,SAAS,GAAG;AAC3C,YAAM,IAAI,WAAW,+BAA+B,SAAS;AAAA,kBAAqB,kBAAkB,KAAK,IAAI,CAAC,EAAE;AAAA,IACjH;AAEA,QAAI,QAAQ,CAAC,cAAc,SAAS,IAAI,GAAG;AAC1C,YAAM,IAAI,WAAW,0BAA0B,IAAI;AAAA,kBAAqB,cAAc,KAAK,IAAI,CAAC,EAAE;AAAA,IACnG;AAEA,UAAM,MAAM,IAAI,IAAI,GAAG,KAAK,IAAI,GAAG,KAAK,IAAI,SAAS,EAAE;AAEvD,QAAI,MAAM;AACT,UAAI,aAAa,IAAI,QAAQ,OAAO,IAAI,CAAC;AAAA,IAC1C;AAEA,WAAO,IAAI,SAAS;AAAA,EACrB;AACD;;;ACxSA,SAAS,oBAAoB,OAAwD;AACpF,SAAO,QAAQ,IAAI,OAAkC,SAAS;AAC/D;AAFS;AAIT,SAAS,gBAAgB,OAA4D;AACpF,SAAO,OAAO,QAAQ,IAAI,OAAkC,SAAS,MAAM;AAC5E;AAFS;AAOF,IAAM,kBAAN,MAAM,yBAAwB,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWnC,YACC,UACA,MACA,QACA,QACA,KACP,UACC;AACD,UAAM,iBAAgB,WAAW,QAAQ,CAAC;AAPnC;AACA;AACA;AACA;AACA;AAKP,SAAK,cAAc,EAAE,OAAO,SAAS,OAAO,MAAM,SAAS,KAAK;AAAA,EACjE;AAAA,EA9DD,OAwC2C;AAAA;AAAA;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA,EA0BP,IAAoB,OAAe;AAClC,WAAO,GAAG,iBAAgB,IAAI,IAAI,KAAK,IAAI;AAAA,EAC5C;AAAA,EAEA,OAAe,WAAW,OAA0C;AACnE,QAAI,YAAY;AAChB,QAAI,UAAU,OAAO;AACpB,UAAI,MAAM,QAAQ;AACjB,oBAAY,CAAC,GAAG,KAAK,oBAAoB,MAAM,MAAM,CAAC,EAAE,KAAK,IAAI;AAAA,MAClE;AAEA,aAAO,MAAM,WAAW,YACrB,GAAG,MAAM,OAAO;AAAA,EAAK,SAAS,KAC9B,MAAM,WAAW,aAAa;AAAA,IAClC;AAEA,WAAO,MAAM,qBAAqB;AAAA,EACnC;AAAA,EAEA,QAAgB,oBAAoB,KAAmB,MAAM,IAA8B;AAC1F,QAAI,gBAAgB,GAAG,GAAG;AACzB,aAAO,MAAM,GAAG,IAAI,SAAS,GAAG,GAAG,IAAI,IAAI,IAAI,MAAM,GAAG,IAAI,IAAI,EAAE,KAAK,IAAI,OAAO,GAAG,KAAK;AAAA,IAC3F;AAEA,eAAW,CAAC,UAAU,GAAG,KAAK,OAAO,QAAQ,GAAG,GAAG;AAClD,YAAM,UAAU,SAAS,WAAW,GAAG,IACpC,MACA,MACA,OAAO,MAAM,OAAO,QAAQ,CAAC,IAC5B,GAAG,GAAG,IAAI,QAAQ,KAClB,GAAG,GAAG,IAAI,QAAQ,MACnB;AAEH,UAAI,OAAO,QAAQ,UAAU;AAC5B,cAAM;AAAA,MACP,WAAW,oBAAoB,GAAG,GAAG;AACpC,mBAAW,SAAS,IAAI,SAAS;AAChC,iBAAO,KAAK,oBAAoB,OAAO,OAAO;AAAA,QAC/C;AAAA,MACD,OAAO;AACN,eAAO,KAAK,oBAAoB,KAAK,OAAO;AAAA,MAC7C;AAAA,IACD;AAAA,EACD;AACD;;;ACzGO,IAAM,YAAN,MAAM,mBAAkB,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAY7B,YACC,QACP,YACO,QACA,KACP,UACC;AACD,UAAM,UAAU;AANT;AAEA;AACA;AAIP,SAAK,cAAc,EAAE,OAAO,SAAS,OAAO,MAAM,SAAS,KAAK;AAAA,EACjE;AAAA,EA3BD,OAMqC;AAAA;AAAA;AAAA,EAC7B;AAAA,EAES,OAAO,WAAU;AAmBlC;;;AC1BO,IAAM,iBAAN,MAAM,wBAAuB,MAA+B;AAAA,EAFnE,OAEmE;AAAA;AAAA;AAAA,EAC3D;AAAA,EAEA;AAAA,EAEA;AAAA,EAEA;AAAA,EAEA;AAAA,EAEA;AAAA,EAEA;AAAA,EAEA;AAAA,EAEA,YAAY,EAAE,aAAa,OAAO,QAAQ,MAAM,KAAK,OAAO,gBAAgB,OAAO,GAAkB;AAC3G,UAAM;AACN,SAAK,cAAc;AACnB,SAAK,QAAQ;AACb,SAAK,SAAS;AACd,SAAK,OAAO;AACZ,SAAK,MAAM;AACX,SAAK,QAAQ;AACb,SAAK,iBAAiB;AACtB,SAAK,SAAS;AAAA,EACf;AAAA;AAAA;AAAA;AAAA,EAKA,IAAoB,OAAe;AAClC,WAAO,GAAG,gBAAe,IAAI,IAAI,KAAK,KAAK;AAAA,EAC5C;AACD;;;ACrCA,wBAA2B;AAC3B,uBAAiC;AACjC,iCAAkC;AAClC,yBAA6B;;;AC0TtB,IAAK,gBAAL,kBAAKC,mBAAL;AACN,EAAAA,eAAA,YAAS;AACT,EAAAA,eAAA,SAAM;AACN,EAAAA,eAAA,WAAQ;AACR,EAAAA,eAAA,UAAO;AACP,EAAAA,eAAA,SAAM;AALK,SAAAA;AAAA,GAAA;;;ACxTZ,SAAS,qBAAqB,OAA+B;AAC5D,UAAQ,OAAO,OAAO;AAAA,IACrB,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACJ,aAAO,MAAM,SAAS;AAAA,IACvB,KAAK;AACJ,UAAI,UAAU;AAAM,eAAO;AAC3B,UAAI,iBAAiB,MAAM;AAC1B,eAAO,OAAO,MAAM,MAAM,QAAQ,CAAC,IAAI,OAAO,MAAM,YAAY;AAAA,MACjE;AAGA,UAAI,OAAO,MAAM,aAAa,cAAc,MAAM,aAAa,OAAO,UAAU;AAAU,eAAO,MAAM,SAAS;AAChH,aAAO;AAAA,IACR;AACC,aAAO;AAAA,EACT;AACD;AApBS;AA6BF,SAAS,oBAAsC,SAAuB;AAC5E,QAAM,SAAS,IAAI,gBAAgB;AACnC,MAAI,CAAC;AAAS,WAAO;AAErB,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,OAAO,GAAG;AACnD,UAAM,aAAa,qBAAqB,KAAK;AAC7C,QAAI,eAAe;AAAM,aAAO,OAAO,KAAK,UAAU;AAAA,EACvD;AAEA,SAAO;AACR;AAVgB;AAiBhB,eAAsB,cAAc,KAAqC;AACxE,MAAI,IAAI,QAAQ,IAAI,cAAc,GAAG,WAAW,kBAAkB,GAAG;AACpE,WAAO,IAAI,KAAK;AAAA,EACjB;AAEA,SAAO,IAAI,YAAY;AACxB;AANsB;AAgBf,SAAS,YAAY,aAAqB,MAAgB,QAA0B;AAI1F,MAAI,gBAAgB,iBAAiB;AACpC,QAAI,OAAO,SAAS,YAAY,SAAS;AAAM,aAAO;AAEtD,QAAI;AAAgC,aAAO;AAC3C,UAAM,aAAa;AACnB,WAAO,CAAC,QAAQ,OAAO,EAAE,KAAK,CAAC,QAAQ,QAAQ,IAAI,YAAY,GAAG,CAAC;AAAA,EACpE;AAGA,SAAO;AACR;AAdgB;AAsBT,SAAS,YAAY,OAAsC;AAEjE,MAAI,MAAM,SAAS;AAAc,WAAO;AAExC,SAAQ,UAAU,SAAS,MAAM,SAAS,gBAAiB,MAAM,QAAQ,SAAS,YAAY;AAC/F;AALgB;AAYhB,eAAsB,YAAY,SAAe,eAA8B;AAC9E,QAAM,EAAE,QAAQ,IAAI;AACpB,MAAI,CAAC,QAAQ;AAAmB;AAEhC,QAAM,cACL,OAAO,QAAQ,sBAAsB,aAClC,MAAM,QAAQ,kBAAkB,aAAa,IAC7C,QAAQ,kBAAkB,KAAK,CAAC,UAAU,cAAc,MAAM,WAAW,MAAM,YAAY,CAAC,CAAC;AACjG,MAAI,aAAa;AAChB,UAAM,IAAI,eAAe,aAAa;AAAA,EACvC;AACD;AAXsB;AAkBf,SAAS,gCAAgC,QAAmB;AAClE,SAAO,OAAO,OAAO,MAAM,KAAK,GAAG,IAAI;AACxC;AAFgB;AAShB,eAAsB,MAAM,IAA2B;AACtD,SAAO,IAAI,QAAc,CAAC,YAAY;AACrC,eAAW,MAAM,QAAQ,GAAG,EAAE;AAAA,EAC/B,CAAC;AACF;AAJsB;AAWf,SAAS,aAAa,OAAgF;AAC5G,SAAO,iBAAiB,eAAe,iBAAiB,cAAc,iBAAiB;AACxF;AAFgB;;;AC3HhB,IAAI,eAAe;AACnB,IAAI,wBAAuC;AAOpC,SAAS,sBAAsB,SAAe;AACpD,MAAI,CAAC,yBAAyB,wBAAwB,KAAK,IAAI,GAAG;AACjE,4BAAwB,KAAK,IAAI,IAAI,MAAQ,KAAK;AAClD,mBAAe;AAAA,EAChB;AAEA;AAEA,QAAM,cACL,QAAQ,QAAQ,gCAAgC,KAChD,eAAe,QAAQ,QAAQ,kCAAkC;AAClE,MAAI,aAAa;AAEhB,YAAQ,0DAAuC;AAAA,MAC9C,OAAO;AAAA,MACP,eAAe,wBAAwB,KAAK,IAAI;AAAA,IACjD,CAAC;AAAA,EACF;AACD;AAlBgB;AAgChB,eAAsB,mBACrB,SACA,SACA,KACA,SACA,aACA,SACC;AACD,QAAM,aAAa,IAAI,gBAAgB;AACvC,QAAM,UAAU,WAAW,MAAM,WAAW,MAAM,GAAG,QAAQ,QAAQ,OAAO;AAC5E,MAAI,YAAY,QAAQ;AAIvB,QAAI,YAAY,OAAO;AAAS,iBAAW,MAAM;AAAA;AAC5C,kBAAY,OAAO,iBAAiB,SAAS,MAAM,WAAW,MAAM,CAAC;AAAA,EAC3E;AAEA,MAAI;AACJ,MAAI;AACH,UAAM,MAAM,QAAQ,QAAQ,YAAY,KAAK,EAAE,GAAG,SAAS,QAAQ,WAAW,OAAO,CAAC;AAAA,EACvF,SAAS,OAAgB;AACxB,QAAI,EAAE,iBAAiB;AAAQ,YAAM;AAErC,QAAI,YAAY,KAAK,KAAK,YAAY,QAAQ,QAAQ,SAAS;AAE9D,aAAO;AAAA,IACR;AAEA,UAAM;AAAA,EACP,UAAE;AACD,iBAAa,OAAO;AAAA,EACrB;AAEA,MAAI,QAAQ,uCAAiC,GAAG;AAC/C,YAAQ;AAAA;AAAA,MAEP;AAAA,QACC,QAAQ,QAAQ,UAAU;AAAA,QAC1B,MAAM,QAAQ;AAAA,QACd,OAAO,QAAQ;AAAA,QACf;AAAA,QACA,MAAM;AAAA,QACN;AAAA,MACD;AAAA,MACA,eAAe,WAAW,IAAI,MAAM,IAAI,EAAE,GAAG,IAAI;AAAA,IAClD;AAAA,EACD;AAEA,SAAO;AACR;AAlDsB;AA+DtB,eAAsB,aACrB,SACA,KACA,QACA,KACA,aACA,SACC;AACD,QAAM,SAAS,IAAI;AACnB,MAAI,UAAU,OAAO,SAAS,KAAK;AAElC,QAAI,YAAY,QAAQ,QAAQ,SAAS;AACxC,aAAO;AAAA,IACR;AAGA,UAAM,IAAI,UAAU,QAAQ,IAAI,YAAY,QAAQ,KAAK,WAAW;AAAA,EACrE,OAAO;AAEN,QAAI,UAAU,OAAO,SAAS,KAAK;AAElC,UAAI,WAAW,OAAO,YAAY,MAAM;AACvC,gBAAQ,SAAS,IAAK;AAAA,MACvB;AAGA,YAAM,OAAQ,MAAM,cAAc,GAAG;AAErC,YAAM,IAAI,gBAAgB,MAAM,UAAU,OAAO,KAAK,OAAO,KAAK,OAAO,QAAQ,QAAQ,KAAK,WAAW;AAAA,IAC1G;AAEA,WAAO;AAAA,EACR;AACD;AAjCsB;;;ACvGf,IAAM,eAAN,MAAuC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBtC,YACW,SACA,MACA,gBAChB;AAHgB;AACA;AACA;AAEjB,SAAK,KAAK,GAAG,IAAI,IAAI,cAAc;AAAA,EACpC;AAAA,EAtCD,OAgB8C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAI7B;AAAA;AAAA;AAAA;AAAA,EAKT,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAoBV,MAAM,SAAiB;AAC9B,SAAK,QAAQ,8BAAuB,SAAS,KAAK,EAAE,KAAK,OAAO,EAAE;AAAA,EACnE;AAAA;AAAA;AAAA;AAAA,EAKA,MAAa,aACZ,SACA,KACA,SACA,aACwB;AACxB,WAAO,KAAK,WAAW,SAAS,KAAK,SAAS,WAAW;AAAA,EAC1D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAc,WACb,SACA,KACA,SACA,aACA,UAAU,GACc;AACxB,UAAM,SAAS,QAAQ,UAAU;AAEjC,UAAM,MAAM,MAAM,mBAAmB,KAAK,SAAS,SAAS,KAAK,SAAS,aAAa,OAAO;AAG9F,QAAI,QAAQ,MAAM;AAEjB,aAAO,KAAK,WAAW,SAAS,KAAK,SAAS,aAAa,EAAE,OAAO;AAAA,IACrE;AAEA,UAAM,SAAS,IAAI;AACnB,QAAI,aAAa;AACjB,UAAM,QAAQ,IAAI,QAAQ,IAAI,aAAa;AAG3C,QAAI;AAAO,mBAAa,OAAO,KAAK,IAAI,MAAQ,KAAK,QAAQ,QAAQ;AAGrE,QAAI,WAAW,OAAO,WAAW,OAAO,WAAW,KAAK;AACvD,4BAAsB,KAAK,OAAO;AAAA,IACnC;AAEA,QAAI,UAAU,OAAO,SAAS,KAAK;AAClC,aAAO;AAAA,IACR,WAAW,WAAW,KAAK;AAE1B,YAAM,WAAW,IAAI,QAAQ,IAAI,oBAAoB;AACrD,YAAM,YAAY,KAAK,SAAS;AAAA,QAC/B,aAAa;AAAA,QACb,OAAO,OAAO;AAAA,QACd;AAAA,QACA,MAAM,KAAK;AAAA,QACX;AAAA,QACA,OAAO,QAAQ;AAAA,QACf,gBAAgB,KAAK;AAAA,QACrB,QAAQ;AAAA,MACT,CAAC;AACD,WAAK;AAAA,QACJ;AAAA,UACC;AAAA,UACA,sBAAsB,QAAQ;AAAA,UAC9B,sBAAsB,MAAM;AAAA,UAC5B,sBAAsB,GAAG;AAAA,UACzB,sBAAsB,QAAQ,WAAW;AAAA,UACzC,sBAAsB,QAAQ,cAAc;AAAA,UAC5C,sBAAsB,KAAK,IAAI;AAAA,UAC/B,sBAAsB,OAAO,iBAAiB;AAAA,UAC9C,sBAAsB,UAAU;AAAA,UAChC;AAAA,QACD,EAAE,KAAK,IAAI;AAAA,MACZ;AAGA,YAAM,MAAM,UAAU;AAGtB,aAAO,KAAK,WAAW,SAAS,KAAK,SAAS,aAAa,OAAO;AAAA,IACnE,OAAO;AACN,YAAM,UAAU,MAAM,aAAa,KAAK,SAAS,KAAK,QAAQ,KAAK,aAAa,OAAO;AACvF,UAAI,YAAY,MAAM;AAErB,eAAO,KAAK,WAAW,SAAS,KAAK,SAAS,aAAa,EAAE,OAAO;AAAA,MACrE;AAEA,aAAO;AAAA,IACR;AAAA,EACD;AACD;;;AChJA,yBAA2B;AAiBpB,IAAM,oBAAN,MAA4C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA8C3C,YACW,SACA,MACA,gBAChB;AAHgB;AACA;AACA;AAEjB,SAAK,KAAK,GAAG,IAAI,IAAI,cAAc;AAAA,EACpC;AAAA,EArED,OAiBmD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAIlC;AAAA;AAAA;AAAA;AAAA,EAKR,QAAQ;AAAA;AAAA;AAAA;AAAA,EAKR,YAAY;AAAA;AAAA;AAAA;AAAA,EAKZ,QAAQ,OAAO;AAAA;AAAA;AAAA;AAAA,EAKvB,cAAc,IAAI,8BAAW;AAAA;AAAA;AAAA;AAAA,EAK7B,mBAAsC;AAAA;AAAA;AAAA;AAAA,EAKtC,mBAAuE;AAAA;AAAA;AAAA;AAAA,EAKvE,iBAAiB;AAAA;AAAA;AAAA;AAAA,EAkBjB,IAAW,WAAoB;AAC9B,WACC,KAAK,YAAY,cAAc,MAC9B,KAAK,qBAAqB,QAAQ,KAAK,iBAAiB,cAAc,MACvE,CAAC,KAAK;AAAA,EAER;AAAA;AAAA;AAAA;AAAA,EAKA,IAAY,gBAAyB;AACpC,WAAO,KAAK,QAAQ,mBAAmB,KAAK,KAAK,IAAI,IAAI,KAAK,QAAQ;AAAA,EACvE;AAAA;AAAA;AAAA;AAAA,EAKA,IAAY,eAAwB;AACnC,WAAO,KAAK,aAAa,KAAK,KAAK,IAAI,IAAI,KAAK;AAAA,EACjD;AAAA;AAAA;AAAA;AAAA,EAKA,IAAY,UAAmB;AAC9B,WAAO,KAAK,iBAAiB,KAAK;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA,EAKA,IAAY,cAAsB;AACjC,WAAO,KAAK,QAAQ,KAAK,QAAQ,QAAQ,SAAS,KAAK,IAAI;AAAA,EAC5D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,MAAM,SAAiB;AAC9B,SAAK,QAAQ,8BAAuB,SAAS,KAAK,EAAE,KAAK,OAAO,EAAE;AAAA,EACnE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAc,eAAe,MAA6B;AACzD,UAAM,MAAM,IAAI;AAChB,SAAK,QAAQ,cAAc;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA,EAKA,MAAa,aACZ,SACA,KACA,SACA,aACwB;AACxB,QAAI,QAAQ,KAAK;AACjB,QAAI,YAAY;AAEhB,QAAI,KAAK,oBAAoB,YAAY,QAAQ,aAAa,YAAY,MAAM,QAAQ,MAAM,GAAG;AAChG,cAAQ,KAAK;AACb,kBAAY;AAAA,IACb;AAGA,UAAM,MAAM,KAAK,EAAE,QAAQ,YAAY,OAAO,CAAC;AAE/C,QAAI,cAAc,kBAAoB;AACrC,UAAI,KAAK,oBAAoB,YAAY,QAAQ,aAAa,YAAY,MAAM,QAAQ,MAAM,GAAG;AAKhG,gBAAQ,KAAK;AACb,cAAM,OAAO,MAAM,KAAK;AACxB,aAAK,YAAY,MAAM;AACvB,cAAM;AAAA,MACP,WAAW,KAAK,kBAAkB;AAEjC,cAAM,KAAK,iBAAiB;AAAA,MAC7B;AAAA,IACD;AAEA,QAAI;AAEH,aAAO,MAAM,KAAK,WAAW,SAAS,KAAK,SAAS,WAAW;AAAA,IAChE,UAAE;AAED,YAAM,MAAM;AACZ,UAAI,KAAK,gBAAgB;AACxB,aAAK,iBAAiB;AACtB,aAAK,kBAAkB,MAAM;AAAA,MAC9B;AAGA,UAAI,KAAK,kBAAkB,cAAc,GAAG;AAC3C,aAAK,kBAAkB,QAAQ;AAC/B,aAAK,mBAAmB;AAAA,MACzB;AAAA,IACD;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAc,WACb,SACA,KACA,SACA,aACA,UAAU,GACc;AAKxB,WAAO,KAAK,SAAS;AACpB,YAAM,WAAW,KAAK;AACtB,UAAIC;AACJ,UAAI;AACJ,UAAI;AAEJ,UAAI,UAAU;AAEb,QAAAA,SAAQ,KAAK,QAAQ,QAAQ;AAC7B,kBAAU,KAAK,QAAQ,cAAc,KAAK,QAAQ,QAAQ,SAAS,KAAK,IAAI;AAE5E,YAAI,CAAC,KAAK,QAAQ,aAAa;AAE9B,eAAK,QAAQ,cAAc,KAAK,eAAe,OAAO;AAAA,QACvD;AAEA,gBAAQ,KAAK,QAAQ;AAAA,MACtB,OAAO;AAEN,QAAAA,SAAQ,KAAK;AACb,kBAAU,KAAK;AACf,gBAAQ,MAAM,OAAO;AAAA,MACtB;AAEA,YAAM,gBAA+B;AAAA,QACpC,aAAa;AAAA,QACb,OAAAA;AAAA,QACA,QAAQ,QAAQ,UAAU;AAAA,QAC1B,MAAM,KAAK;AAAA,QACX;AAAA,QACA,OAAO,QAAQ;AAAA,QACf,gBAAgB,KAAK;AAAA,QACrB,QAAQ;AAAA,MACT;AAEA,WAAK,QAAQ,sCAA6B,aAAa;AAEvD,YAAM,YAAY,KAAK,SAAS,aAAa;AAE7C,UAAI,UAAU;AACb,aAAK,MAAM,oDAAoD,OAAO,IAAI;AAAA,MAC3E,OAAO;AACN,aAAK,MAAM,WAAW,OAAO,2BAA2B;AAAA,MACzD;AAGA,YAAM;AAAA,IACP;AAGA,QAAI,CAAC,KAAK,QAAQ,eAAe,KAAK,QAAQ,cAAc,KAAK,IAAI,GAAG;AACvE,WAAK,QAAQ,cAAc,KAAK,IAAI,IAAI;AACxC,WAAK,QAAQ,kBAAkB,KAAK,QAAQ,QAAQ;AAAA,IACrD;AAEA,SAAK,QAAQ;AAEb,UAAM,SAAS,QAAQ,UAAU;AAEjC,UAAM,MAAM,MAAM,mBAAmB,KAAK,SAAS,SAAS,KAAK,SAAS,aAAa,OAAO;AAG9F,QAAI,QAAQ,MAAM;AAEjB,aAAO,KAAK,WAAW,SAAS,KAAK,SAAS,aAAa,EAAE,OAAO;AAAA,IACrE;AAEA,UAAM,SAAS,IAAI;AACnB,QAAI,aAAa;AAEjB,UAAM,QAAQ,IAAI,QAAQ,IAAI,mBAAmB;AACjD,UAAM,YAAY,IAAI,QAAQ,IAAI,uBAAuB;AACzD,UAAM,QAAQ,IAAI,QAAQ,IAAI,yBAAyB;AACvD,UAAM,OAAO,IAAI,QAAQ,IAAI,oBAAoB;AACjD,UAAM,QAAQ,IAAI,QAAQ,IAAI,aAAa;AAG3C,SAAK,QAAQ,QAAQ,OAAO,KAAK,IAAI,OAAO;AAE5C,SAAK,YAAY,YAAY,OAAO,SAAS,IAAI;AAEjD,SAAK,QAAQ,QAAQ,OAAO,KAAK,IAAI,MAAQ,KAAK,IAAI,IAAI,KAAK,QAAQ,QAAQ,SAAS,KAAK,IAAI;AAGjG,QAAI;AAAO,mBAAa,OAAO,KAAK,IAAI,MAAQ,KAAK,QAAQ,QAAQ;AAGrE,QAAI,QAAQ,SAAS,KAAK,MAAM;AAE/B,WAAK,MAAM,CAAC,+BAA+B,iBAAiB,KAAK,IAAI,IAAI,iBAAiB,IAAI,EAAE,EAAE,KAAK,IAAI,CAAC;AAE5G,WAAK,QAAQ,OAAO,IAAI,GAAG,MAAM,IAAI,QAAQ,WAAW,IAAI,EAAE,OAAO,MAAM,YAAY,KAAK,IAAI,EAAE,CAAC;AAAA,IACpG,WAAW,MAAM;AAGhB,YAAM,WAAW,KAAK,QAAQ,OAAO,IAAI,GAAG,MAAM,IAAI,QAAQ,WAAW,EAAE;AAG3E,UAAI,UAAU;AACb,iBAAS,aAAa,KAAK,IAAI;AAAA,MAChC;AAAA,IACD;AAGA,QAAI,kBAAiC;AACrC,QAAI,aAAa,GAAG;AACnB,UAAI,IAAI,QAAQ,IAAI,oBAAoB,GAAG;AAC1C,aAAK,QAAQ,kBAAkB;AAC/B,aAAK,QAAQ,cAAc,KAAK,IAAI,IAAI;AAAA,MACzC,WAAW,CAAC,KAAK,cAAc;AAM9B,0BAAkB;AAAA,MACnB;AAAA,IACD;AAGA,QAAI,WAAW,OAAO,WAAW,OAAO,WAAW,KAAK;AACvD,4BAAsB,KAAK,OAAO;AAAA,IACnC;AAEA,QAAI,IAAI,IAAI;AACX,aAAO;AAAA,IACR,WAAW,WAAW,KAAK;AAE1B,YAAM,WAAW,KAAK;AACtB,UAAIA;AACJ,UAAI;AAEJ,UAAI,UAAU;AAEb,QAAAA,SAAQ,KAAK,QAAQ,QAAQ;AAC7B,kBAAU,KAAK,QAAQ,cAAc,KAAK,QAAQ,QAAQ,SAAS,KAAK,IAAI;AAAA,MAC7E,OAAO;AAEN,QAAAA,SAAQ,KAAK;AACb,kBAAU,KAAK;AAAA,MAChB;AAEA,YAAM,YAAY,KAAK,SAAS;AAAA,QAC/B,aAAa;AAAA,QACb,OAAAA;AAAA,QACA;AAAA,QACA,MAAM,KAAK;AAAA,QACX;AAAA,QACA,OAAO,QAAQ;AAAA,QACf,gBAAgB,KAAK;AAAA,QACrB,QAAQ;AAAA,MACT,CAAC;AACD,WAAK;AAAA,QACJ;AAAA,UACC;AAAA,UACA,sBAAsB,SAAS,SAAS,CAAC;AAAA,UACzC,sBAAsB,MAAM;AAAA,UAC5B,sBAAsB,GAAG;AAAA,UACzB,sBAAsB,QAAQ,WAAW;AAAA,UACzC,sBAAsB,QAAQ,cAAc;AAAA,UAC5C,sBAAsB,KAAK,IAAI;AAAA,UAC/B,sBAAsBA,MAAK;AAAA,UAC3B,sBAAsB,UAAU;AAAA,UAChC,sBAAsB,kBAAkB,GAAG,eAAe,OAAO,MAAM;AAAA,QACxE,EAAE,KAAK,IAAI;AAAA,MACZ;AAEA,UAAI,iBAAiB;AAEpB,cAAM,gBAAgB,CAAC,KAAK;AAC5B,YAAI,eAAe;AAClB,eAAK,mBAAmB,IAAI,8BAAW;AACvC,eAAK,KAAK,iBAAiB,KAAK;AAChC,eAAK,YAAY,MAAM;AAAA,QACxB;AAEA,aAAK,kBAAkB,QAAQ;AAC/B,aAAK,mBAAmB;AACxB,cAAM,MAAM,eAAe;AAC3B,YAAI;AAEJ,cAAM,UAAU,IAAI,QAAc,CAACC,SAAS,UAAUA,IAAI;AAC1D,aAAK,mBAAmB,EAAE,SAAS,QAAkB;AACrD,YAAI,eAAe;AAElB,gBAAM,KAAK,YAAY,KAAK;AAC5B,eAAK,iBAAiB;AAAA,QACvB;AAAA,MACD;AAGA,aAAO,KAAK,WAAW,SAAS,KAAK,SAAS,aAAa,OAAO;AAAA,IACnE,OAAO;AACN,YAAM,UAAU,MAAM,aAAa,KAAK,SAAS,KAAK,QAAQ,KAAK,aAAa,OAAO;AACvF,UAAI,YAAY,MAAM;AAErB,eAAO,KAAK,WAAW,SAAS,KAAK,SAAS,aAAa,EAAE,OAAO;AAAA,MACrE;AAEA,aAAO;AAAA,IACR;AAAA,EACD;AACD;;;ALrXO,IAAM,OAAN,MAAM,cAAa,6CAAiC;AAAA,EAjC3D,OAiC2D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAKnD,QAA2B;AAAA,EAElB;AAAA;AAAA;AAAA;AAAA,EAKT;AAAA;AAAA;AAAA;AAAA,EAKA,cAAoC;AAAA;AAAA;AAAA;AAAA,EAKpC,cAAc;AAAA;AAAA;AAAA;AAAA,EAKL,SAAS,IAAI,6BAA6B;AAAA;AAAA;AAAA;AAAA,EAK1C,WAAW,IAAI,6BAA6B;AAAA,EAE5D,SAAwB;AAAA,EAEhB;AAAA,EAEA;AAAA,EAEQ;AAAA,EAET,YAAY,UAAgC,CAAC,GAAG;AACtD,UAAM;AACN,SAAK,MAAM,IAAI,IAAI,QAAQ,OAAO,mBAAmB,GAAG;AACxD,SAAK,UAAU,EAAE,GAAG,oBAAoB,GAAG,QAAQ;AACnD,SAAK,QAAQ,SAAS,KAAK,IAAI,GAAG,KAAK,QAAQ,MAAM;AACrD,SAAK,kBAAkB,KAAK,IAAI,GAAG,KAAK,QAAQ,uBAAuB;AACvE,SAAK,QAAQ,QAAQ,SAAS;AAG9B,SAAK,cAAc;AAAA,EACpB;AAAA,EAEQ,gBAAgB;AAEvB,UAAM,sBAAsB,wBAAC,aAAqB;AACjD,UAAI,WAAW,OAAY;AAC1B,cAAM,IAAI,MAAM,6CAA6C;AAAA,MAC9D;AAAA,IACD,GAJ4B;AAM5B,QAAI,KAAK,QAAQ,sBAAsB,KAAK,KAAK,QAAQ,sBAAsB,OAAO,mBAAmB;AACxG,0BAAoB,KAAK,QAAQ,iBAAiB;AAClD,WAAK,YAAY,YAAY,MAAM;AAClC,cAAM,cAAc,IAAI,6BAA6B;AACrD,cAAM,cAAc,KAAK,IAAI;AAG7B,aAAK,OAAO,MAAM,CAAC,KAAK,QAAQ;AAE/B,cAAI,IAAI,eAAe;AAAI,mBAAO;AAGlC,gBAAM,cAAc,KAAK,MAAM,cAAc,IAAI,UAAU,IAAI,KAAK,QAAQ;AAG5E,cAAI,aAAa;AAEhB,wBAAY,IAAI,KAAK,GAAG;AAGxB,iBAAK,8BAAuB,QAAQ,IAAI,KAAK,QAAQ,GAAG,uCAAuC;AAAA,UAChG;AAEA,iBAAO;AAAA,QACR,CAAC;AAGD,aAAK,kCAA2B,WAAW;AAAA,MAC5C,GAAG,KAAK,QAAQ,iBAAiB;AAEjC,WAAK,UAAU,QAAQ;AAAA,IACxB;AAEA,QAAI,KAAK,QAAQ,yBAAyB,KAAK,KAAK,QAAQ,yBAAyB,OAAO,mBAAmB;AAC9G,0BAAoB,KAAK,QAAQ,oBAAoB;AACrD,WAAK,eAAe,YAAY,MAAM;AACrC,cAAM,gBAAgB,IAAI,6BAA6B;AAGvD,aAAK,SAAS,MAAM,CAAC,KAAK,QAAQ;AACjC,gBAAM,EAAE,SAAS,IAAI;AAGrB,cAAI,UAAU;AACb,0BAAc,IAAI,KAAK,GAAG;AAC1B,iBAAK,8BAAuB,WAAW,IAAI,EAAE,QAAQ,GAAG,8BAA8B;AAAA,UACvF;AAEA,iBAAO;AAAA,QACR,CAAC;AAGD,aAAK,wCAA8B,aAAa;AAAA,MACjD,GAAG,KAAK,QAAQ,oBAAoB;AAEpC,WAAK,aAAa,QAAQ;AAAA,IAC3B;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAa,IAAI,WAAsB,UAAuB,CAAC,GAAG;AACjE,WAAO,KAAK,QAAQ,EAAE,GAAG,SAAS,WAAW,wBAA0B,CAAC;AAAA,EACzE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAa,OAAO,WAAsB,UAAuB,CAAC,GAAG;AACpE,WAAO,KAAK,QAAQ,EAAE,GAAG,SAAS,WAAW,8BAA6B,CAAC;AAAA,EAC5E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAa,KAAK,WAAsB,UAAuB,CAAC,GAAG;AAClE,WAAO,KAAK,QAAQ,EAAE,GAAG,SAAS,WAAW,0BAA2B,CAAC;AAAA,EAC1E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAa,IAAI,WAAsB,UAAuB,CAAC,GAAG;AACjE,WAAO,KAAK,QAAQ,EAAE,GAAG,SAAS,WAAW,wBAA0B,CAAC;AAAA,EACzE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAa,MAAM,WAAsB,UAAuB,CAAC,GAAG;AACnE,WAAO,KAAK,QAAQ,EAAE,GAAG,SAAS,WAAW,4BAA4B,CAAC;AAAA,EAC3E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAa,QAAQ,SAA0B;AAC9C,UAAM,WAAW,MAAM,KAAK,aAAa,OAAO;AAChD,WAAO,cAAc,QAAQ;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOO,SAAS,OAAmB;AAClC,SAAK,QAAQ;AACb,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOO,SAAS,OAAe;AAC9B,SAAK,SAAS;AACd,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAa,aAAa,SAAiD;AAE1E,UAAM,UAAU,MAAK,kBAAkB,QAAQ,WAAW,QAAQ,MAAM;AAExE,UAAM,OAAO,KAAK,OAAO,IAAI,GAAG,QAAQ,MAAM,IAAI,QAAQ,WAAW,EAAE,KAAK;AAAA,MAC3E,OAAO,UAAU,QAAQ,MAAM,IAAI,QAAQ,WAAW;AAAA,MACtD,YAAY;AAAA,IACb;AAGA,UAAM,UACL,KAAK,SAAS,IAAI,GAAG,KAAK,KAAK,IAAI,QAAQ,cAAc,EAAE,KAC3D,KAAK,cAAc,KAAK,OAAO,QAAQ,cAAc;AAGtD,UAAM,EAAE,KAAK,aAAa,IAAI,MAAM,KAAK,eAAe,OAAO;AAG/D,WAAO,QAAQ,aAAa,SAAS,KAAK,cAAc;AAAA,MACvD,MAAM,QAAQ;AAAA,MACd,OAAO,QAAQ;AAAA,MACf,MAAM,QAAQ,SAAS;AAAA,MACvB,QAAQ,QAAQ;AAAA,IACjB,CAAC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASQ,cAAc,MAAc,gBAAwB;AAE3D,UAAM,QACL,mBAAmB,yBAChB,IAAI,aAAa,MAAM,MAAM,cAAc,IAC3C,IAAI,kBAAkB,MAAM,MAAM,cAAc;AAEpD,SAAK,SAAS,IAAI,MAAM,IAAI,KAAK;AAEjC,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAc,eAAe,SAA+E;AAC3G,UAAM,EAAE,QAAQ,IAAI;AAEpB,QAAI,QAAQ;AAGZ,QAAI,QAAQ,OAAO;AAClB,YAAM,gBAAgB,QAAQ,MAAM,SAAS;AAC7C,UAAI,kBAAkB,IAAI;AACzB,gBAAQ,IAAI,aAAa;AAAA,MAC1B;AAAA,IACD;AAGA,UAAM,UAA0B;AAAA,MAC/B,GAAG,KAAK,QAAQ;AAAA,MAChB,cAAc,GAAG,gBAAgB,IAAI,QAAQ,iBAAiB,GAAG,KAAK;AAAA,IACvE;AAGA,QAAI,QAAQ,SAAS,OAAO;AAE3B,UAAI,CAAC,KAAK,QAAQ;AACjB,cAAM,IAAI,MAAM,iEAAiE;AAAA,MAClF;AAEA,cAAQ,gBAAgB,GAAG,QAAQ,cAAc,KAAK,QAAQ,UAAU,IAAI,KAAK,MAAM;AAAA,IACxF;AAGA,QAAI,QAAQ,QAAQ,QAAQ;AAC3B,cAAQ,oBAAoB,IAAI,mBAAmB,QAAQ,MAAM;AAAA,IAClE;AAGA,UAAM,MAAM,GAAG,QAAQ,GAAG,GAAG,QAAQ,cAAc,QAAQ,KAAK,KAAK,QAAQ,OAAO,EAAE,GACrF,QAAQ,SACT,GAAG,KAAK;AAER,QAAI;AACJ,QAAI,oBAA4C,CAAC;AAEjD,QAAI,QAAQ,OAAO,QAAQ;AAC1B,YAAM,WAAW,IAAI,SAAS;AAG9B,iBAAW,CAAC,OAAO,IAAI,KAAK,QAAQ,MAAM,QAAQ,GAAG;AACpD,cAAM,UAAU,KAAK,OAAO,SAAS,KAAK;AAM1C,YAAI,aAAa,KAAK,IAAI,GAAG;AAE5B,cAAI,cAAc,KAAK;AAEvB,cAAI,CAAC,aAAa;AACjB,kBAAM,CAAC,UAAU,QAAI,iCAAa,KAAK,IAAI;AAE3C,gBAAI,YAAY;AACf,4BACC,qBAAqB,WAAW,IAAyC,KACzE,WAAW,QACX;AAAA,YACF;AAAA,UACD;AAEA,mBAAS,OAAO,SAAS,IAAI,KAAK,CAAC,KAAK,IAAI,GAAG,EAAE,MAAM,YAAY,CAAC,GAAG,KAAK,IAAI;AAAA,QACjF,OAAO;AACN,mBAAS,OAAO,SAAS,IAAI,KAAK,CAAC,GAAG,KAAK,IAAI,EAAE,GAAG,EAAE,MAAM,KAAK,YAAY,CAAC,GAAG,KAAK,IAAI;AAAA,QAC3F;AAAA,MACD;AAIA,UAAI,QAAQ,QAAQ,MAAM;AACzB,YAAI,QAAQ,kBAAkB;AAC7B,qBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,QAAQ,IAA+B,GAAG;AACnF,qBAAS,OAAO,KAAK,KAAK;AAAA,UAC3B;AAAA,QACD,OAAO;AACN,mBAAS,OAAO,gBAAgB,KAAK,UAAU,QAAQ,IAAI,CAAC;AAAA,QAC7D;AAAA,MACD;AAGA,kBAAY;AAAA,IAGb,WAAW,QAAQ,QAAQ,MAAM;AAChC,UAAI,QAAQ,iBAAiB;AAC5B,oBAAY,QAAQ;AAAA,MACrB,OAAO;AAEN,oBAAY,KAAK,UAAU,QAAQ,IAAI;AAEvC,4BAAoB,EAAE,gBAAgB,mBAAmB;AAAA,MAC1D;AAAA,IACD;AAEA,UAAM,SAAS,QAAQ,OAAO,YAAY;AAG1C,UAAM,eAA4B;AAAA;AAAA,MAEjC,MAAM,CAAC,OAAO,MAAM,EAAE,SAAS,MAAM,IAAI,OAAO;AAAA,MAChD,SAAS,EAAE,GAAG,QAAQ,SAAS,GAAG,mBAAmB,GAAG,QAAQ;AAAA,MAChE;AAAA;AAAA,MAEA,YAAY,QAAQ,cAAc,KAAK,SAAS;AAAA,IACjD;AAEA,WAAO,EAAE,KAAK,aAAa;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA,EAKO,mBAAmB;AACzB,kBAAc,KAAK,SAAS;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA,EAKO,sBAAsB;AAC5B,kBAAc,KAAK,YAAY;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,OAAe,kBAAkB,UAAqB,QAAkC;AACvF,QAAI,SAAS,WAAW,gBAAgB,KAAK,SAAS,SAAS,WAAW,GAAG;AAC5E,aAAO;AAAA,QACN,gBAAgB;AAAA,QAChB,aAAa;AAAA,QACb,UAAU;AAAA,MACX;AAAA,IACD;AAEA,UAAM,eAAe,+CAA+C,KAAK,QAAQ;AAGjF,UAAM,UAAU,eAAe,CAAC,KAAK;AAErC,UAAM,YAAY,SAEhB,WAAW,cAAc,KAAK,EAE9B,QAAQ,qBAAqB,sBAAsB;AAErD,QAAI,aAAa;AAIjB,QAAI,oCAAmC,cAAc,8BAA8B;AAClF,YAAM,KAAK,aAAa,KAAK,QAAQ,EAAG,CAAC;AACzC,YAAM,YAAY,kCAAiB,cAAc,EAAE;AACnD,UAAI,KAAK,IAAI,IAAI,YAAY,MAAQ,KAAK,KAAK,KAAK,IAAI;AACvD,sBAAc;AAAA,MACf;AAAA,IACD;AAEA,WAAO;AAAA,MACN,gBAAgB;AAAA,MAChB,aAAa,YAAY;AAAA,MACzB,UAAU;AAAA,IACX;AAAA,EACD;AACD;;;AMncO,IAAM,UAAU;;;AbZvB,mBAAmB,KAAK;","names":["RESTEvents","RequestMethod","limit","res"]}
\ No newline at end of file diff --git a/node_modules/@discordjs/rest/dist/web.mjs b/node_modules/@discordjs/rest/dist/web.mjs new file mode 100644 index 0000000..8c70b4f --- /dev/null +++ b/node_modules/@discordjs/rest/dist/web.mjs @@ -0,0 +1,1312 @@ +var __defProp = Object.defineProperty; +var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); + +// src/environment.ts +var defaultStrategy; +function setDefaultStrategy(newStrategy) { + defaultStrategy = newStrategy; +} +__name(setDefaultStrategy, "setDefaultStrategy"); +function getDefaultStrategy() { + return defaultStrategy; +} +__name(getDefaultStrategy, "getDefaultStrategy"); + +// src/lib/utils/constants.ts +import { getUserAgentAppendix } from "@discordjs/util"; +import { APIVersion } from "discord-api-types/v10"; +var DefaultUserAgent = `DiscordBot (https://discord.js.org, 2.0.1)`; +var DefaultUserAgentAppendix = getUserAgentAppendix(); +var DefaultRestOptions = { + agent: null, + api: "https://discord.com/api", + authPrefix: "Bot", + cdn: "https://cdn.discordapp.com", + headers: {}, + invalidRequestWarningInterval: 0, + globalRequestsPerSecond: 50, + offset: 50, + rejectOnRateLimit: null, + retries: 3, + timeout: 15e3, + userAgentAppendix: DefaultUserAgentAppendix, + version: APIVersion, + hashSweepInterval: 144e5, + // 4 Hours + hashLifetime: 864e5, + // 24 Hours + handlerSweepInterval: 36e5, + // 1 Hour + async makeRequest(...args) { + return getDefaultStrategy()(...args); + } +}; +var RESTEvents = /* @__PURE__ */ ((RESTEvents2) => { + RESTEvents2["Debug"] = "restDebug"; + RESTEvents2["HandlerSweep"] = "handlerSweep"; + RESTEvents2["HashSweep"] = "hashSweep"; + RESTEvents2["InvalidRequestWarning"] = "invalidRequestWarning"; + RESTEvents2["RateLimited"] = "rateLimited"; + RESTEvents2["Response"] = "response"; + return RESTEvents2; +})(RESTEvents || {}); +var ALLOWED_EXTENSIONS = ["webp", "png", "jpg", "jpeg", "gif"]; +var ALLOWED_STICKER_EXTENSIONS = ["png", "json", "gif"]; +var ALLOWED_SIZES = [16, 32, 64, 128, 256, 512, 1024, 2048, 4096]; +var OverwrittenMimeTypes = { + // https://github.com/discordjs/discord.js/issues/8557 + "image/apng": "image/png" +}; +var BurstHandlerMajorIdKey = "burst"; + +// src/lib/CDN.ts +var CDN = class { + constructor(base = DefaultRestOptions.cdn) { + this.base = base; + } + static { + __name(this, "CDN"); + } + /** + * Generates an app asset URL for a client's asset. + * + * @param clientId - The client id that has the asset + * @param assetHash - The hash provided by Discord for this asset + * @param options - Optional options for the asset + */ + appAsset(clientId, assetHash, options) { + return this.makeURL(`/app-assets/${clientId}/${assetHash}`, options); + } + /** + * Generates an app icon URL for a client's icon. + * + * @param clientId - The client id that has the icon + * @param iconHash - The hash provided by Discord for this icon + * @param options - Optional options for the icon + */ + appIcon(clientId, iconHash, options) { + return this.makeURL(`/app-icons/${clientId}/${iconHash}`, options); + } + /** + * Generates an avatar URL, e.g. for a user or a webhook. + * + * @param id - The id that has the icon + * @param avatarHash - The hash provided by Discord for this avatar + * @param options - Optional options for the avatar + */ + avatar(id, avatarHash, options) { + return this.dynamicMakeURL(`/avatars/${id}/${avatarHash}`, avatarHash, options); + } + /** + * Generates a user avatar decoration URL. + * + * @param userId - The id of the user + * @param userAvatarDecoration - The hash provided by Discord for this avatar decoration + * @param options - Optional options for the avatar decoration + */ + avatarDecoration(userId, userAvatarDecoration, options) { + return this.makeURL(`/avatar-decorations/${userId}/${userAvatarDecoration}`, options); + } + /** + * Generates a banner URL, e.g. for a user or a guild. + * + * @param id - The id that has the banner splash + * @param bannerHash - The hash provided by Discord for this banner + * @param options - Optional options for the banner + */ + banner(id, bannerHash, options) { + return this.dynamicMakeURL(`/banners/${id}/${bannerHash}`, bannerHash, options); + } + /** + * Generates an icon URL for a channel, e.g. a group DM. + * + * @param channelId - The channel id that has the icon + * @param iconHash - The hash provided by Discord for this channel + * @param options - Optional options for the icon + */ + channelIcon(channelId, iconHash, options) { + return this.makeURL(`/channel-icons/${channelId}/${iconHash}`, options); + } + /** + * Generates a default avatar URL + * + * @param index - The default avatar index + * @remarks + * To calculate the index for a user do `(userId >> 22) % 6`, + * or `discriminator % 5` if they're using the legacy username system. + */ + defaultAvatar(index) { + return this.makeURL(`/embed/avatars/${index}`, { extension: "png" }); + } + /** + * Generates a discovery splash URL for a guild's discovery splash. + * + * @param guildId - The guild id that has the discovery splash + * @param splashHash - The hash provided by Discord for this splash + * @param options - Optional options for the splash + */ + discoverySplash(guildId, splashHash, options) { + return this.makeURL(`/discovery-splashes/${guildId}/${splashHash}`, options); + } + /** + * Generates an emoji's URL for an emoji. + * + * @param emojiId - The emoji id + * @param extension - The extension of the emoji + */ + emoji(emojiId, extension) { + return this.makeURL(`/emojis/${emojiId}`, { extension }); + } + /** + * Generates a guild member avatar URL. + * + * @param guildId - The id of the guild + * @param userId - The id of the user + * @param avatarHash - The hash provided by Discord for this avatar + * @param options - Optional options for the avatar + */ + guildMemberAvatar(guildId, userId, avatarHash, options) { + return this.dynamicMakeURL(`/guilds/${guildId}/users/${userId}/avatars/${avatarHash}`, avatarHash, options); + } + /** + * Generates a guild member banner URL. + * + * @param guildId - The id of the guild + * @param userId - The id of the user + * @param bannerHash - The hash provided by Discord for this banner + * @param options - Optional options for the banner + */ + guildMemberBanner(guildId, userId, bannerHash, options) { + return this.dynamicMakeURL(`/guilds/${guildId}/users/${userId}/banner`, bannerHash, options); + } + /** + * Generates an icon URL, e.g. for a guild. + * + * @param id - The id that has the icon splash + * @param iconHash - The hash provided by Discord for this icon + * @param options - Optional options for the icon + */ + icon(id, iconHash, options) { + return this.dynamicMakeURL(`/icons/${id}/${iconHash}`, iconHash, options); + } + /** + * Generates a URL for the icon of a role + * + * @param roleId - The id of the role that has the icon + * @param roleIconHash - The hash provided by Discord for this role icon + * @param options - Optional options for the role icon + */ + roleIcon(roleId, roleIconHash, options) { + return this.makeURL(`/role-icons/${roleId}/${roleIconHash}`, options); + } + /** + * Generates a guild invite splash URL for a guild's invite splash. + * + * @param guildId - The guild id that has the invite splash + * @param splashHash - The hash provided by Discord for this splash + * @param options - Optional options for the splash + */ + splash(guildId, splashHash, options) { + return this.makeURL(`/splashes/${guildId}/${splashHash}`, options); + } + /** + * Generates a sticker URL. + * + * @param stickerId - The sticker id + * @param extension - The extension of the sticker + * @privateRemarks + * Stickers cannot have a `.webp` extension, so we default to a `.png` + */ + sticker(stickerId, extension = "png") { + return this.makeURL(`/stickers/${stickerId}`, { allowedExtensions: ALLOWED_STICKER_EXTENSIONS, extension }); + } + /** + * Generates a sticker pack banner URL. + * + * @param bannerId - The banner id + * @param options - Optional options for the banner + */ + stickerPackBanner(bannerId, options) { + return this.makeURL(`/app-assets/710982414301790216/store/${bannerId}`, options); + } + /** + * Generates a team icon URL for a team's icon. + * + * @param teamId - The team id that has the icon + * @param iconHash - The hash provided by Discord for this icon + * @param options - Optional options for the icon + */ + teamIcon(teamId, iconHash, options) { + return this.makeURL(`/team-icons/${teamId}/${iconHash}`, options); + } + /** + * Generates a cover image for a guild scheduled event. + * + * @param scheduledEventId - The scheduled event id + * @param coverHash - The hash provided by discord for this cover image + * @param options - Optional options for the cover image + */ + guildScheduledEventCover(scheduledEventId, coverHash, options) { + return this.makeURL(`/guild-events/${scheduledEventId}/${coverHash}`, options); + } + /** + * Constructs the URL for the resource, checking whether or not `hash` starts with `a_` if `dynamic` is set to `true`. + * + * @param route - The base cdn route + * @param hash - The hash provided by Discord for this icon + * @param options - Optional options for the link + */ + dynamicMakeURL(route, hash, { forceStatic = false, ...options } = {}) { + return this.makeURL(route, !forceStatic && hash.startsWith("a_") ? { ...options, extension: "gif" } : options); + } + /** + * Constructs the URL for the resource + * + * @param route - The base cdn route + * @param options - The extension/size options for the link + */ + makeURL(route, { allowedExtensions = ALLOWED_EXTENSIONS, extension = "webp", size } = {}) { + extension = String(extension).toLowerCase(); + if (!allowedExtensions.includes(extension)) { + throw new RangeError(`Invalid extension provided: ${extension} +Must be one of: ${allowedExtensions.join(", ")}`); + } + if (size && !ALLOWED_SIZES.includes(size)) { + throw new RangeError(`Invalid size provided: ${size} +Must be one of: ${ALLOWED_SIZES.join(", ")}`); + } + const url = new URL(`${this.base}${route}.${extension}`); + if (size) { + url.searchParams.set("size", String(size)); + } + return url.toString(); + } +}; + +// src/lib/errors/DiscordAPIError.ts +function isErrorGroupWrapper(error) { + return Reflect.has(error, "_errors"); +} +__name(isErrorGroupWrapper, "isErrorGroupWrapper"); +function isErrorResponse(error) { + return typeof Reflect.get(error, "message") === "string"; +} +__name(isErrorResponse, "isErrorResponse"); +var DiscordAPIError = class _DiscordAPIError extends Error { + /** + * @param rawError - The error reported by Discord + * @param code - The error code reported by Discord + * @param status - The status code of the response + * @param method - The method of the request that erred + * @param url - The url of the request that erred + * @param bodyData - The unparsed data for the request that errored + */ + constructor(rawError, code, status, method, url, bodyData) { + super(_DiscordAPIError.getMessage(rawError)); + this.rawError = rawError; + this.code = code; + this.status = status; + this.method = method; + this.url = url; + this.requestBody = { files: bodyData.files, json: bodyData.body }; + } + static { + __name(this, "DiscordAPIError"); + } + requestBody; + /** + * The name of the error + */ + get name() { + return `${_DiscordAPIError.name}[${this.code}]`; + } + static getMessage(error) { + let flattened = ""; + if ("code" in error) { + if (error.errors) { + flattened = [...this.flattenDiscordError(error.errors)].join("\n"); + } + return error.message && flattened ? `${error.message} +${flattened}` : error.message || flattened || "Unknown Error"; + } + return error.error_description ?? "No Description"; + } + static *flattenDiscordError(obj, key = "") { + if (isErrorResponse(obj)) { + return yield `${key.length ? `${key}[${obj.code}]` : `${obj.code}`}: ${obj.message}`.trim(); + } + for (const [otherKey, val] of Object.entries(obj)) { + const nextKey = otherKey.startsWith("_") ? key : key ? Number.isNaN(Number(otherKey)) ? `${key}.${otherKey}` : `${key}[${otherKey}]` : otherKey; + if (typeof val === "string") { + yield val; + } else if (isErrorGroupWrapper(val)) { + for (const error of val._errors) { + yield* this.flattenDiscordError(error, nextKey); + } + } else { + yield* this.flattenDiscordError(val, nextKey); + } + } + } +}; + +// src/lib/errors/HTTPError.ts +var HTTPError = class _HTTPError extends Error { + /** + * @param status - The status code of the response + * @param statusText - The status text of the response + * @param method - The method of the request that erred + * @param url - The url of the request that erred + * @param bodyData - The unparsed data for the request that errored + */ + constructor(status, statusText, method, url, bodyData) { + super(statusText); + this.status = status; + this.method = method; + this.url = url; + this.requestBody = { files: bodyData.files, json: bodyData.body }; + } + static { + __name(this, "HTTPError"); + } + requestBody; + name = _HTTPError.name; +}; + +// src/lib/errors/RateLimitError.ts +var RateLimitError = class _RateLimitError extends Error { + static { + __name(this, "RateLimitError"); + } + timeToReset; + limit; + method; + hash; + url; + route; + majorParameter; + global; + constructor({ timeToReset, limit, method, hash, url, route, majorParameter, global }) { + super(); + this.timeToReset = timeToReset; + this.limit = limit; + this.method = method; + this.hash = hash; + this.url = url; + this.route = route; + this.majorParameter = majorParameter; + this.global = global; + } + /** + * The name of the error + */ + get name() { + return `${_RateLimitError.name}[${this.route}]`; + } +}; + +// src/lib/REST.ts +import { Collection } from "@discordjs/collection"; +import { DiscordSnowflake } from "@sapphire/snowflake"; +import { AsyncEventEmitter } from "@vladfrangu/async_event_emitter"; +import { filetypeinfo } from "magic-bytes.js"; + +// src/lib/utils/types.ts +var RequestMethod = /* @__PURE__ */ ((RequestMethod2) => { + RequestMethod2["Delete"] = "DELETE"; + RequestMethod2["Get"] = "GET"; + RequestMethod2["Patch"] = "PATCH"; + RequestMethod2["Post"] = "POST"; + RequestMethod2["Put"] = "PUT"; + return RequestMethod2; +})(RequestMethod || {}); + +// src/lib/utils/utils.ts +function serializeSearchParam(value) { + switch (typeof value) { + case "string": + return value; + case "number": + case "bigint": + case "boolean": + return value.toString(); + case "object": + if (value === null) + return null; + if (value instanceof Date) { + return Number.isNaN(value.getTime()) ? null : value.toISOString(); + } + if (typeof value.toString === "function" && value.toString !== Object.prototype.toString) + return value.toString(); + return null; + default: + return null; + } +} +__name(serializeSearchParam, "serializeSearchParam"); +function makeURLSearchParams(options) { + const params = new URLSearchParams(); + if (!options) + return params; + for (const [key, value] of Object.entries(options)) { + const serialized = serializeSearchParam(value); + if (serialized !== null) + params.append(key, serialized); + } + return params; +} +__name(makeURLSearchParams, "makeURLSearchParams"); +async function parseResponse(res) { + if (res.headers.get("Content-Type")?.startsWith("application/json")) { + return res.json(); + } + return res.arrayBuffer(); +} +__name(parseResponse, "parseResponse"); +function hasSublimit(bucketRoute, body, method) { + if (bucketRoute === "/channels/:id") { + if (typeof body !== "object" || body === null) + return false; + if (method !== "PATCH" /* Patch */) + return false; + const castedBody = body; + return ["name", "topic"].some((key) => Reflect.has(castedBody, key)); + } + return true; +} +__name(hasSublimit, "hasSublimit"); +function shouldRetry(error) { + if (error.name === "AbortError") + return true; + return "code" in error && error.code === "ECONNRESET" || error.message.includes("ECONNRESET"); +} +__name(shouldRetry, "shouldRetry"); +async function onRateLimit(manager, rateLimitData) { + const { options } = manager; + if (!options.rejectOnRateLimit) + return; + const shouldThrow = typeof options.rejectOnRateLimit === "function" ? await options.rejectOnRateLimit(rateLimitData) : options.rejectOnRateLimit.some((route) => rateLimitData.route.startsWith(route.toLowerCase())); + if (shouldThrow) { + throw new RateLimitError(rateLimitData); + } +} +__name(onRateLimit, "onRateLimit"); +function calculateUserDefaultAvatarIndex(userId) { + return Number(BigInt(userId) >> 22n) % 6; +} +__name(calculateUserDefaultAvatarIndex, "calculateUserDefaultAvatarIndex"); +async function sleep(ms) { + return new Promise((resolve) => { + setTimeout(() => resolve(), ms); + }); +} +__name(sleep, "sleep"); +function isBufferLike(value) { + return value instanceof ArrayBuffer || value instanceof Uint8Array || value instanceof Uint8ClampedArray; +} +__name(isBufferLike, "isBufferLike"); + +// src/lib/handlers/Shared.ts +var invalidCount = 0; +var invalidCountResetTime = null; +function incrementInvalidCount(manager) { + if (!invalidCountResetTime || invalidCountResetTime < Date.now()) { + invalidCountResetTime = Date.now() + 1e3 * 60 * 10; + invalidCount = 0; + } + invalidCount++; + const emitInvalid = manager.options.invalidRequestWarningInterval > 0 && invalidCount % manager.options.invalidRequestWarningInterval === 0; + if (emitInvalid) { + manager.emit("invalidRequestWarning" /* InvalidRequestWarning */, { + count: invalidCount, + remainingTime: invalidCountResetTime - Date.now() + }); + } +} +__name(incrementInvalidCount, "incrementInvalidCount"); +async function makeNetworkRequest(manager, routeId, url, options, requestData, retries) { + const controller = new AbortController(); + const timeout = setTimeout(() => controller.abort(), manager.options.timeout); + if (requestData.signal) { + if (requestData.signal.aborted) + controller.abort(); + else + requestData.signal.addEventListener("abort", () => controller.abort()); + } + let res; + try { + res = await manager.options.makeRequest(url, { ...options, signal: controller.signal }); + } catch (error) { + if (!(error instanceof Error)) + throw error; + if (shouldRetry(error) && retries !== manager.options.retries) { + return null; + } + throw error; + } finally { + clearTimeout(timeout); + } + if (manager.listenerCount("response" /* Response */)) { + manager.emit( + "response" /* Response */, + { + method: options.method ?? "get", + path: routeId.original, + route: routeId.bucketRoute, + options, + data: requestData, + retries + }, + res instanceof Response ? res.clone() : { ...res } + ); + } + return res; +} +__name(makeNetworkRequest, "makeNetworkRequest"); +async function handleErrors(manager, res, method, url, requestData, retries) { + const status = res.status; + if (status >= 500 && status < 600) { + if (retries !== manager.options.retries) { + return null; + } + throw new HTTPError(status, res.statusText, method, url, requestData); + } else { + if (status >= 400 && status < 500) { + if (status === 401 && requestData.auth) { + manager.setToken(null); + } + const data = await parseResponse(res); + throw new DiscordAPIError(data, "code" in data ? data.code : data.error, status, method, url, requestData); + } + return res; + } +} +__name(handleErrors, "handleErrors"); + +// src/lib/handlers/BurstHandler.ts +var BurstHandler = class { + /** + * @param manager - The request manager + * @param hash - The hash that this RequestHandler handles + * @param majorParameter - The major parameter for this handler + */ + constructor(manager, hash, majorParameter) { + this.manager = manager; + this.hash = hash; + this.majorParameter = majorParameter; + this.id = `${hash}:${majorParameter}`; + } + static { + __name(this, "BurstHandler"); + } + /** + * {@inheritdoc IHandler.id} + */ + id; + /** + * {@inheritDoc IHandler.inactive} + */ + inactive = false; + /** + * Emits a debug message + * + * @param message - The message to debug + */ + debug(message) { + this.manager.emit("restDebug" /* Debug */, `[REST ${this.id}] ${message}`); + } + /** + * {@inheritDoc IHandler.queueRequest} + */ + async queueRequest(routeId, url, options, requestData) { + return this.runRequest(routeId, url, options, requestData); + } + /** + * The method that actually makes the request to the API, and updates info about the bucket accordingly + * + * @param routeId - The generalized API route with literal ids for major parameters + * @param url - The fully resolved URL to make the request to + * @param options - The fetch options needed to make the request + * @param requestData - Extra data from the user's request needed for errors and additional processing + * @param retries - The number of retries this request has already attempted (recursion) + */ + async runRequest(routeId, url, options, requestData, retries = 0) { + const method = options.method ?? "get"; + const res = await makeNetworkRequest(this.manager, routeId, url, options, requestData, retries); + if (res === null) { + return this.runRequest(routeId, url, options, requestData, ++retries); + } + const status = res.status; + let retryAfter = 0; + const retry = res.headers.get("Retry-After"); + if (retry) + retryAfter = Number(retry) * 1e3 + this.manager.options.offset; + if (status === 401 || status === 403 || status === 429) { + incrementInvalidCount(this.manager); + } + if (status >= 200 && status < 300) { + return res; + } else if (status === 429) { + const isGlobal = res.headers.has("X-RateLimit-Global"); + await onRateLimit(this.manager, { + timeToReset: retryAfter, + limit: Number.POSITIVE_INFINITY, + method, + hash: this.hash, + url, + route: routeId.bucketRoute, + majorParameter: this.majorParameter, + global: isGlobal + }); + this.debug( + [ + "Encountered unexpected 429 rate limit", + ` Global : ${isGlobal}`, + ` Method : ${method}`, + ` URL : ${url}`, + ` Bucket : ${routeId.bucketRoute}`, + ` Major parameter: ${routeId.majorParameter}`, + ` Hash : ${this.hash}`, + ` Limit : ${Number.POSITIVE_INFINITY}`, + ` Retry After : ${retryAfter}ms`, + ` Sublimit : None` + ].join("\n") + ); + await sleep(retryAfter); + return this.runRequest(routeId, url, options, requestData, retries); + } else { + const handled = await handleErrors(this.manager, res, method, url, requestData, retries); + if (handled === null) { + return this.runRequest(routeId, url, options, requestData, ++retries); + } + return handled; + } + } +}; + +// src/lib/handlers/SequentialHandler.ts +import { AsyncQueue } from "@sapphire/async-queue"; +var SequentialHandler = class { + /** + * @param manager - The request manager + * @param hash - The hash that this RequestHandler handles + * @param majorParameter - The major parameter for this handler + */ + constructor(manager, hash, majorParameter) { + this.manager = manager; + this.hash = hash; + this.majorParameter = majorParameter; + this.id = `${hash}:${majorParameter}`; + } + static { + __name(this, "SequentialHandler"); + } + /** + * {@inheritDoc IHandler.id} + */ + id; + /** + * The time this rate limit bucket will reset + */ + reset = -1; + /** + * The remaining requests that can be made before we are rate limited + */ + remaining = 1; + /** + * The total number of requests that can be made before we are rate limited + */ + limit = Number.POSITIVE_INFINITY; + /** + * The interface used to sequence async requests sequentially + */ + #asyncQueue = new AsyncQueue(); + /** + * The interface used to sequence sublimited async requests sequentially + */ + #sublimitedQueue = null; + /** + * A promise wrapper for when the sublimited queue is finished being processed or null when not being processed + */ + #sublimitPromise = null; + /** + * Whether the sublimit queue needs to be shifted in the finally block + */ + #shiftSublimit = false; + /** + * {@inheritDoc IHandler.inactive} + */ + get inactive() { + return this.#asyncQueue.remaining === 0 && (this.#sublimitedQueue === null || this.#sublimitedQueue.remaining === 0) && !this.limited; + } + /** + * If the rate limit bucket is currently limited by the global limit + */ + get globalLimited() { + return this.manager.globalRemaining <= 0 && Date.now() < this.manager.globalReset; + } + /** + * If the rate limit bucket is currently limited by its limit + */ + get localLimited() { + return this.remaining <= 0 && Date.now() < this.reset; + } + /** + * If the rate limit bucket is currently limited + */ + get limited() { + return this.globalLimited || this.localLimited; + } + /** + * The time until queued requests can continue + */ + get timeToReset() { + return this.reset + this.manager.options.offset - Date.now(); + } + /** + * Emits a debug message + * + * @param message - The message to debug + */ + debug(message) { + this.manager.emit("restDebug" /* Debug */, `[REST ${this.id}] ${message}`); + } + /** + * Delay all requests for the specified amount of time, handling global rate limits + * + * @param time - The amount of time to delay all requests for + */ + async globalDelayFor(time) { + await sleep(time); + this.manager.globalDelay = null; + } + /** + * {@inheritDoc IHandler.queueRequest} + */ + async queueRequest(routeId, url, options, requestData) { + let queue = this.#asyncQueue; + let queueType = 0 /* Standard */; + if (this.#sublimitedQueue && hasSublimit(routeId.bucketRoute, requestData.body, options.method)) { + queue = this.#sublimitedQueue; + queueType = 1 /* Sublimit */; + } + await queue.wait({ signal: requestData.signal }); + if (queueType === 0 /* Standard */) { + if (this.#sublimitedQueue && hasSublimit(routeId.bucketRoute, requestData.body, options.method)) { + queue = this.#sublimitedQueue; + const wait = queue.wait(); + this.#asyncQueue.shift(); + await wait; + } else if (this.#sublimitPromise) { + await this.#sublimitPromise.promise; + } + } + try { + return await this.runRequest(routeId, url, options, requestData); + } finally { + queue.shift(); + if (this.#shiftSublimit) { + this.#shiftSublimit = false; + this.#sublimitedQueue?.shift(); + } + if (this.#sublimitedQueue?.remaining === 0) { + this.#sublimitPromise?.resolve(); + this.#sublimitedQueue = null; + } + } + } + /** + * The method that actually makes the request to the api, and updates info about the bucket accordingly + * + * @param routeId - The generalized api route with literal ids for major parameters + * @param url - The fully resolved url to make the request to + * @param options - The fetch options needed to make the request + * @param requestData - Extra data from the user's request needed for errors and additional processing + * @param retries - The number of retries this request has already attempted (recursion) + */ + async runRequest(routeId, url, options, requestData, retries = 0) { + while (this.limited) { + const isGlobal = this.globalLimited; + let limit2; + let timeout; + let delay; + if (isGlobal) { + limit2 = this.manager.options.globalRequestsPerSecond; + timeout = this.manager.globalReset + this.manager.options.offset - Date.now(); + if (!this.manager.globalDelay) { + this.manager.globalDelay = this.globalDelayFor(timeout); + } + delay = this.manager.globalDelay; + } else { + limit2 = this.limit; + timeout = this.timeToReset; + delay = sleep(timeout); + } + const rateLimitData = { + timeToReset: timeout, + limit: limit2, + method: options.method ?? "get", + hash: this.hash, + url, + route: routeId.bucketRoute, + majorParameter: this.majorParameter, + global: isGlobal + }; + this.manager.emit("rateLimited" /* RateLimited */, rateLimitData); + await onRateLimit(this.manager, rateLimitData); + if (isGlobal) { + this.debug(`Global rate limit hit, blocking all requests for ${timeout}ms`); + } else { + this.debug(`Waiting ${timeout}ms for rate limit to pass`); + } + await delay; + } + if (!this.manager.globalReset || this.manager.globalReset < Date.now()) { + this.manager.globalReset = Date.now() + 1e3; + this.manager.globalRemaining = this.manager.options.globalRequestsPerSecond; + } + this.manager.globalRemaining--; + const method = options.method ?? "get"; + const res = await makeNetworkRequest(this.manager, routeId, url, options, requestData, retries); + if (res === null) { + return this.runRequest(routeId, url, options, requestData, ++retries); + } + const status = res.status; + let retryAfter = 0; + const limit = res.headers.get("X-RateLimit-Limit"); + const remaining = res.headers.get("X-RateLimit-Remaining"); + const reset = res.headers.get("X-RateLimit-Reset-After"); + const hash = res.headers.get("X-RateLimit-Bucket"); + const retry = res.headers.get("Retry-After"); + this.limit = limit ? Number(limit) : Number.POSITIVE_INFINITY; + this.remaining = remaining ? Number(remaining) : 1; + this.reset = reset ? Number(reset) * 1e3 + Date.now() + this.manager.options.offset : Date.now(); + if (retry) + retryAfter = Number(retry) * 1e3 + this.manager.options.offset; + if (hash && hash !== this.hash) { + this.debug(["Received bucket hash update", ` Old Hash : ${this.hash}`, ` New Hash : ${hash}`].join("\n")); + this.manager.hashes.set(`${method}:${routeId.bucketRoute}`, { value: hash, lastAccess: Date.now() }); + } else if (hash) { + const hashData = this.manager.hashes.get(`${method}:${routeId.bucketRoute}`); + if (hashData) { + hashData.lastAccess = Date.now(); + } + } + let sublimitTimeout = null; + if (retryAfter > 0) { + if (res.headers.has("X-RateLimit-Global")) { + this.manager.globalRemaining = 0; + this.manager.globalReset = Date.now() + retryAfter; + } else if (!this.localLimited) { + sublimitTimeout = retryAfter; + } + } + if (status === 401 || status === 403 || status === 429) { + incrementInvalidCount(this.manager); + } + if (res.ok) { + return res; + } else if (status === 429) { + const isGlobal = this.globalLimited; + let limit2; + let timeout; + if (isGlobal) { + limit2 = this.manager.options.globalRequestsPerSecond; + timeout = this.manager.globalReset + this.manager.options.offset - Date.now(); + } else { + limit2 = this.limit; + timeout = this.timeToReset; + } + await onRateLimit(this.manager, { + timeToReset: timeout, + limit: limit2, + method, + hash: this.hash, + url, + route: routeId.bucketRoute, + majorParameter: this.majorParameter, + global: isGlobal + }); + this.debug( + [ + "Encountered unexpected 429 rate limit", + ` Global : ${isGlobal.toString()}`, + ` Method : ${method}`, + ` URL : ${url}`, + ` Bucket : ${routeId.bucketRoute}`, + ` Major parameter: ${routeId.majorParameter}`, + ` Hash : ${this.hash}`, + ` Limit : ${limit2}`, + ` Retry After : ${retryAfter}ms`, + ` Sublimit : ${sublimitTimeout ? `${sublimitTimeout}ms` : "None"}` + ].join("\n") + ); + if (sublimitTimeout) { + const firstSublimit = !this.#sublimitedQueue; + if (firstSublimit) { + this.#sublimitedQueue = new AsyncQueue(); + void this.#sublimitedQueue.wait(); + this.#asyncQueue.shift(); + } + this.#sublimitPromise?.resolve(); + this.#sublimitPromise = null; + await sleep(sublimitTimeout); + let resolve; + const promise = new Promise((res2) => resolve = res2); + this.#sublimitPromise = { promise, resolve }; + if (firstSublimit) { + await this.#asyncQueue.wait(); + this.#shiftSublimit = true; + } + } + return this.runRequest(routeId, url, options, requestData, retries); + } else { + const handled = await handleErrors(this.manager, res, method, url, requestData, retries); + if (handled === null) { + return this.runRequest(routeId, url, options, requestData, ++retries); + } + return handled; + } + } +}; + +// src/lib/REST.ts +var REST = class _REST extends AsyncEventEmitter { + static { + __name(this, "REST"); + } + /** + * The {@link https://undici.nodejs.org/#/docs/api/Agent | Agent} for all requests + * performed by this manager. + */ + agent = null; + cdn; + /** + * The number of requests remaining in the global bucket + */ + globalRemaining; + /** + * The promise used to wait out the global rate limit + */ + globalDelay = null; + /** + * The timestamp at which the global bucket resets + */ + globalReset = -1; + /** + * API bucket hashes that are cached from provided routes + */ + hashes = new Collection(); + /** + * Request handlers created from the bucket hash and the major parameters + */ + handlers = new Collection(); + #token = null; + hashTimer; + handlerTimer; + options; + constructor(options = {}) { + super(); + this.cdn = new CDN(options.cdn ?? DefaultRestOptions.cdn); + this.options = { ...DefaultRestOptions, ...options }; + this.options.offset = Math.max(0, this.options.offset); + this.globalRemaining = Math.max(1, this.options.globalRequestsPerSecond); + this.agent = options.agent ?? null; + this.setupSweepers(); + } + setupSweepers() { + const validateMaxInterval = /* @__PURE__ */ __name((interval) => { + if (interval > 144e5) { + throw new Error("Cannot set an interval greater than 4 hours"); + } + }, "validateMaxInterval"); + if (this.options.hashSweepInterval !== 0 && this.options.hashSweepInterval !== Number.POSITIVE_INFINITY) { + validateMaxInterval(this.options.hashSweepInterval); + this.hashTimer = setInterval(() => { + const sweptHashes = new Collection(); + const currentDate = Date.now(); + this.hashes.sweep((val, key) => { + if (val.lastAccess === -1) + return false; + const shouldSweep = Math.floor(currentDate - val.lastAccess) > this.options.hashLifetime; + if (shouldSweep) { + sweptHashes.set(key, val); + this.emit("restDebug" /* Debug */, `Hash ${val.value} for ${key} swept due to lifetime being exceeded`); + } + return shouldSweep; + }); + this.emit("hashSweep" /* HashSweep */, sweptHashes); + }, this.options.hashSweepInterval); + this.hashTimer.unref?.(); + } + if (this.options.handlerSweepInterval !== 0 && this.options.handlerSweepInterval !== Number.POSITIVE_INFINITY) { + validateMaxInterval(this.options.handlerSweepInterval); + this.handlerTimer = setInterval(() => { + const sweptHandlers = new Collection(); + this.handlers.sweep((val, key) => { + const { inactive } = val; + if (inactive) { + sweptHandlers.set(key, val); + this.emit("restDebug" /* Debug */, `Handler ${val.id} for ${key} swept due to being inactive`); + } + return inactive; + }); + this.emit("handlerSweep" /* HandlerSweep */, sweptHandlers); + }, this.options.handlerSweepInterval); + this.handlerTimer.unref?.(); + } + } + /** + * Runs a get request from the api + * + * @param fullRoute - The full route to query + * @param options - Optional request options + */ + async get(fullRoute, options = {}) { + return this.request({ ...options, fullRoute, method: "GET" /* Get */ }); + } + /** + * Runs a delete request from the api + * + * @param fullRoute - The full route to query + * @param options - Optional request options + */ + async delete(fullRoute, options = {}) { + return this.request({ ...options, fullRoute, method: "DELETE" /* Delete */ }); + } + /** + * Runs a post request from the api + * + * @param fullRoute - The full route to query + * @param options - Optional request options + */ + async post(fullRoute, options = {}) { + return this.request({ ...options, fullRoute, method: "POST" /* Post */ }); + } + /** + * Runs a put request from the api + * + * @param fullRoute - The full route to query + * @param options - Optional request options + */ + async put(fullRoute, options = {}) { + return this.request({ ...options, fullRoute, method: "PUT" /* Put */ }); + } + /** + * Runs a patch request from the api + * + * @param fullRoute - The full route to query + * @param options - Optional request options + */ + async patch(fullRoute, options = {}) { + return this.request({ ...options, fullRoute, method: "PATCH" /* Patch */ }); + } + /** + * Runs a request from the api + * + * @param options - Request options + */ + async request(options) { + const response = await this.queueRequest(options); + return parseResponse(response); + } + /** + * Sets the default agent to use for requests performed by this manager + * + * @param agent - The agent to use + */ + setAgent(agent) { + this.agent = agent; + return this; + } + /** + * Sets the authorization token that should be used for requests + * + * @param token - The authorization token to use + */ + setToken(token) { + this.#token = token; + return this; + } + /** + * Queues a request to be sent + * + * @param request - All the information needed to make a request + * @returns The response from the api request + */ + async queueRequest(request) { + const routeId = _REST.generateRouteData(request.fullRoute, request.method); + const hash = this.hashes.get(`${request.method}:${routeId.bucketRoute}`) ?? { + value: `Global(${request.method}:${routeId.bucketRoute})`, + lastAccess: -1 + }; + const handler = this.handlers.get(`${hash.value}:${routeId.majorParameter}`) ?? this.createHandler(hash.value, routeId.majorParameter); + const { url, fetchOptions } = await this.resolveRequest(request); + return handler.queueRequest(routeId, url, fetchOptions, { + body: request.body, + files: request.files, + auth: request.auth !== false, + signal: request.signal + }); + } + /** + * Creates a new rate limit handler from a hash, based on the hash and the major parameter + * + * @param hash - The hash for the route + * @param majorParameter - The major parameter for this handler + * @internal + */ + createHandler(hash, majorParameter) { + const queue = majorParameter === BurstHandlerMajorIdKey ? new BurstHandler(this, hash, majorParameter) : new SequentialHandler(this, hash, majorParameter); + this.handlers.set(queue.id, queue); + return queue; + } + /** + * Formats the request data to a usable format for fetch + * + * @param request - The request data + */ + async resolveRequest(request) { + const { options } = this; + let query = ""; + if (request.query) { + const resolvedQuery = request.query.toString(); + if (resolvedQuery !== "") { + query = `?${resolvedQuery}`; + } + } + const headers = { + ...this.options.headers, + "User-Agent": `${DefaultUserAgent} ${options.userAgentAppendix}`.trim() + }; + if (request.auth !== false) { + if (!this.#token) { + throw new Error("Expected token to be set for this request, but none was present"); + } + headers.Authorization = `${request.authPrefix ?? this.options.authPrefix} ${this.#token}`; + } + if (request.reason?.length) { + headers["X-Audit-Log-Reason"] = encodeURIComponent(request.reason); + } + const url = `${options.api}${request.versioned === false ? "" : `/v${options.version}`}${request.fullRoute}${query}`; + let finalBody; + let additionalHeaders = {}; + if (request.files?.length) { + const formData = new FormData(); + for (const [index, file] of request.files.entries()) { + const fileKey = file.key ?? `files[${index}]`; + if (isBufferLike(file.data)) { + let contentType = file.contentType; + if (!contentType) { + const [parsedType] = filetypeinfo(file.data); + if (parsedType) { + contentType = OverwrittenMimeTypes[parsedType.mime] ?? parsedType.mime ?? "application/octet-stream"; + } + } + formData.append(fileKey, new Blob([file.data], { type: contentType }), file.name); + } else { + formData.append(fileKey, new Blob([`${file.data}`], { type: file.contentType }), file.name); + } + } + if (request.body != null) { + if (request.appendToFormData) { + for (const [key, value] of Object.entries(request.body)) { + formData.append(key, value); + } + } else { + formData.append("payload_json", JSON.stringify(request.body)); + } + } + finalBody = formData; + } else if (request.body != null) { + if (request.passThroughBody) { + finalBody = request.body; + } else { + finalBody = JSON.stringify(request.body); + additionalHeaders = { "Content-Type": "application/json" }; + } + } + const method = request.method.toUpperCase(); + const fetchOptions = { + // Set body to null on get / head requests. This does not follow fetch spec (likely because it causes subtle bugs) but is aligned with what request was doing + body: ["GET", "HEAD"].includes(method) ? null : finalBody, + headers: { ...request.headers, ...additionalHeaders, ...headers }, + method, + // Prioritize setting an agent per request, use the agent for this instance otherwise. + dispatcher: request.dispatcher ?? this.agent ?? void 0 + }; + return { url, fetchOptions }; + } + /** + * Stops the hash sweeping interval + */ + clearHashSweeper() { + clearInterval(this.hashTimer); + } + /** + * Stops the request handler sweeping interval + */ + clearHandlerSweeper() { + clearInterval(this.handlerTimer); + } + /** + * Generates route data for an endpoint:method + * + * @param endpoint - The raw endpoint to generalize + * @param method - The HTTP method this endpoint is called without + * @internal + */ + static generateRouteData(endpoint, method) { + if (endpoint.startsWith("/interactions/") && endpoint.endsWith("/callback")) { + return { + majorParameter: BurstHandlerMajorIdKey, + bucketRoute: "/interactions/:id/:token/callback", + original: endpoint + }; + } + const majorIdMatch = /^\/(?:channels|guilds|webhooks)\/(\d{17,19})/.exec(endpoint); + const majorId = majorIdMatch?.[1] ?? "global"; + const baseRoute = endpoint.replaceAll(/\d{17,19}/g, ":id").replace(/\/reactions\/(.*)/, "/reactions/:reaction"); + let exceptions = ""; + if (method === "DELETE" /* Delete */ && baseRoute === "/channels/:id/messages/:id") { + const id = /\d{17,19}$/.exec(endpoint)[0]; + const timestamp = DiscordSnowflake.timestampFrom(id); + if (Date.now() - timestamp > 1e3 * 60 * 60 * 24 * 14) { + exceptions += "/Delete Old Message"; + } + } + return { + majorParameter: majorId, + bucketRoute: baseRoute + exceptions, + original: endpoint + }; + } +}; + +// src/shared.ts +var version = "2.0.1"; + +// src/web.ts +setDefaultStrategy(fetch); +export { + ALLOWED_EXTENSIONS, + ALLOWED_SIZES, + ALLOWED_STICKER_EXTENSIONS, + BurstHandlerMajorIdKey, + CDN, + DefaultRestOptions, + DefaultUserAgent, + DefaultUserAgentAppendix, + DiscordAPIError, + HTTPError, + OverwrittenMimeTypes, + REST, + RESTEvents, + RateLimitError, + RequestMethod, + calculateUserDefaultAvatarIndex, + makeURLSearchParams, + parseResponse, + version +}; +//# sourceMappingURL=web.mjs.map
\ No newline at end of file diff --git a/node_modules/@discordjs/rest/dist/web.mjs.map b/node_modules/@discordjs/rest/dist/web.mjs.map new file mode 100644 index 0000000..e0459eb --- /dev/null +++ b/node_modules/@discordjs/rest/dist/web.mjs.map @@ -0,0 +1 @@ +{"version":3,"sources":["../src/environment.ts","../src/lib/utils/constants.ts","../src/lib/CDN.ts","../src/lib/errors/DiscordAPIError.ts","../src/lib/errors/HTTPError.ts","../src/lib/errors/RateLimitError.ts","../src/lib/REST.ts","../src/lib/utils/types.ts","../src/lib/utils/utils.ts","../src/lib/handlers/Shared.ts","../src/lib/handlers/BurstHandler.ts","../src/lib/handlers/SequentialHandler.ts","../src/shared.ts","../src/web.ts"],"sourcesContent":["import type { RESTOptions } from './shared.js';\n\nlet defaultStrategy: RESTOptions['makeRequest'];\n\nexport function setDefaultStrategy(newStrategy: RESTOptions['makeRequest']) {\n\tdefaultStrategy = newStrategy;\n}\n\nexport function getDefaultStrategy() {\n\treturn defaultStrategy;\n}\n","import { getUserAgentAppendix } from '@discordjs/util';\nimport { APIVersion } from 'discord-api-types/v10';\nimport { getDefaultStrategy } from '../../environment.js';\nimport type { RESTOptions, ResponseLike } from './types.js';\n\nexport const DefaultUserAgent =\n\t`DiscordBot (https://discord.js.org, 2.0.1)` as `DiscordBot (https://discord.js.org, ${string})`;\n\n/**\n * The default string to append onto the user agent.\n */\nexport const DefaultUserAgentAppendix = getUserAgentAppendix();\n\nexport const DefaultRestOptions = {\n\tagent: null,\n\tapi: 'https://discord.com/api',\n\tauthPrefix: 'Bot',\n\tcdn: 'https://cdn.discordapp.com',\n\theaders: {},\n\tinvalidRequestWarningInterval: 0,\n\tglobalRequestsPerSecond: 50,\n\toffset: 50,\n\trejectOnRateLimit: null,\n\tretries: 3,\n\ttimeout: 15_000,\n\tuserAgentAppendix: DefaultUserAgentAppendix,\n\tversion: APIVersion,\n\thashSweepInterval: 14_400_000, // 4 Hours\n\thashLifetime: 86_400_000, // 24 Hours\n\thandlerSweepInterval: 3_600_000, // 1 Hour\n\tasync makeRequest(...args): Promise<ResponseLike> {\n\t\treturn getDefaultStrategy()(...args);\n\t},\n} as const satisfies Required<RESTOptions>;\n\n/**\n * The events that the REST manager emits\n */\nexport enum RESTEvents {\n\tDebug = 'restDebug',\n\tHandlerSweep = 'handlerSweep',\n\tHashSweep = 'hashSweep',\n\tInvalidRequestWarning = 'invalidRequestWarning',\n\tRateLimited = 'rateLimited',\n\tResponse = 'response',\n}\n\nexport const ALLOWED_EXTENSIONS = ['webp', 'png', 'jpg', 'jpeg', 'gif'] as const satisfies readonly string[];\nexport const ALLOWED_STICKER_EXTENSIONS = ['png', 'json', 'gif'] as const satisfies readonly string[];\nexport const ALLOWED_SIZES = [16, 32, 64, 128, 256, 512, 1_024, 2_048, 4_096] as const satisfies readonly number[];\n\nexport type ImageExtension = (typeof ALLOWED_EXTENSIONS)[number];\nexport type StickerExtension = (typeof ALLOWED_STICKER_EXTENSIONS)[number];\nexport type ImageSize = (typeof ALLOWED_SIZES)[number];\n\nexport const OverwrittenMimeTypes = {\n\t// https://github.com/discordjs/discord.js/issues/8557\n\t'image/apng': 'image/png',\n} as const satisfies Readonly<Record<string, string>>;\n\nexport const BurstHandlerMajorIdKey = 'burst';\n","/* eslint-disable jsdoc/check-param-names */\nimport {\n\tALLOWED_EXTENSIONS,\n\tALLOWED_SIZES,\n\tALLOWED_STICKER_EXTENSIONS,\n\tDefaultRestOptions,\n\ttype ImageExtension,\n\ttype ImageSize,\n\ttype StickerExtension,\n} from './utils/constants.js';\n\n/**\n * The options used for image URLs\n */\nexport interface BaseImageURLOptions {\n\t/**\n\t * The extension to use for the image URL\n\t *\n\t * @defaultValue `'webp'`\n\t */\n\textension?: ImageExtension;\n\t/**\n\t * The size specified in the image URL\n\t */\n\tsize?: ImageSize;\n}\n\n/**\n * The options used for image URLs with animated content\n */\nexport interface ImageURLOptions extends BaseImageURLOptions {\n\t/**\n\t * Whether or not to prefer the static version of an image asset.\n\t */\n\tforceStatic?: boolean;\n}\n\n/**\n * The options to use when making a CDN URL\n */\nexport interface MakeURLOptions {\n\t/**\n\t * The allowed extensions that can be used\n\t */\n\tallowedExtensions?: readonly string[];\n\t/**\n\t * The extension to use for the image URL\n\t *\n\t * @defaultValue `'webp'`\n\t */\n\textension?: string | undefined;\n\t/**\n\t * The size specified in the image URL\n\t */\n\tsize?: ImageSize;\n}\n\n/**\n * The CDN link builder\n */\nexport class CDN {\n\tpublic constructor(private readonly base: string = DefaultRestOptions.cdn) {}\n\n\t/**\n\t * Generates an app asset URL for a client's asset.\n\t *\n\t * @param clientId - The client id that has the asset\n\t * @param assetHash - The hash provided by Discord for this asset\n\t * @param options - Optional options for the asset\n\t */\n\tpublic appAsset(clientId: string, assetHash: string, options?: Readonly<BaseImageURLOptions>): string {\n\t\treturn this.makeURL(`/app-assets/${clientId}/${assetHash}`, options);\n\t}\n\n\t/**\n\t * Generates an app icon URL for a client's icon.\n\t *\n\t * @param clientId - The client id that has the icon\n\t * @param iconHash - The hash provided by Discord for this icon\n\t * @param options - Optional options for the icon\n\t */\n\tpublic appIcon(clientId: string, iconHash: string, options?: Readonly<BaseImageURLOptions>): string {\n\t\treturn this.makeURL(`/app-icons/${clientId}/${iconHash}`, options);\n\t}\n\n\t/**\n\t * Generates an avatar URL, e.g. for a user or a webhook.\n\t *\n\t * @param id - The id that has the icon\n\t * @param avatarHash - The hash provided by Discord for this avatar\n\t * @param options - Optional options for the avatar\n\t */\n\tpublic avatar(id: string, avatarHash: string, options?: Readonly<ImageURLOptions>): string {\n\t\treturn this.dynamicMakeURL(`/avatars/${id}/${avatarHash}`, avatarHash, options);\n\t}\n\n\t/**\n\t * Generates a user avatar decoration URL.\n\t *\n\t * @param userId - The id of the user\n\t * @param userAvatarDecoration - The hash provided by Discord for this avatar decoration\n\t * @param options - Optional options for the avatar decoration\n\t */\n\tpublic avatarDecoration(\n\t\tuserId: string,\n\t\tuserAvatarDecoration: string,\n\t\toptions?: Readonly<BaseImageURLOptions>,\n\t): string {\n\t\treturn this.makeURL(`/avatar-decorations/${userId}/${userAvatarDecoration}`, options);\n\t}\n\n\t/**\n\t * Generates a banner URL, e.g. for a user or a guild.\n\t *\n\t * @param id - The id that has the banner splash\n\t * @param bannerHash - The hash provided by Discord for this banner\n\t * @param options - Optional options for the banner\n\t */\n\tpublic banner(id: string, bannerHash: string, options?: Readonly<ImageURLOptions>): string {\n\t\treturn this.dynamicMakeURL(`/banners/${id}/${bannerHash}`, bannerHash, options);\n\t}\n\n\t/**\n\t * Generates an icon URL for a channel, e.g. a group DM.\n\t *\n\t * @param channelId - The channel id that has the icon\n\t * @param iconHash - The hash provided by Discord for this channel\n\t * @param options - Optional options for the icon\n\t */\n\tpublic channelIcon(channelId: string, iconHash: string, options?: Readonly<BaseImageURLOptions>): string {\n\t\treturn this.makeURL(`/channel-icons/${channelId}/${iconHash}`, options);\n\t}\n\n\t/**\n\t * Generates a default avatar URL\n\t *\n\t * @param index - The default avatar index\n\t * @remarks\n\t * To calculate the index for a user do `(userId >> 22) % 6`,\n\t * or `discriminator % 5` if they're using the legacy username system.\n\t */\n\tpublic defaultAvatar(index: number): string {\n\t\treturn this.makeURL(`/embed/avatars/${index}`, { extension: 'png' });\n\t}\n\n\t/**\n\t * Generates a discovery splash URL for a guild's discovery splash.\n\t *\n\t * @param guildId - The guild id that has the discovery splash\n\t * @param splashHash - The hash provided by Discord for this splash\n\t * @param options - Optional options for the splash\n\t */\n\tpublic discoverySplash(guildId: string, splashHash: string, options?: Readonly<BaseImageURLOptions>): string {\n\t\treturn this.makeURL(`/discovery-splashes/${guildId}/${splashHash}`, options);\n\t}\n\n\t/**\n\t * Generates an emoji's URL for an emoji.\n\t *\n\t * @param emojiId - The emoji id\n\t * @param extension - The extension of the emoji\n\t */\n\tpublic emoji(emojiId: string, extension?: ImageExtension): string {\n\t\treturn this.makeURL(`/emojis/${emojiId}`, { extension });\n\t}\n\n\t/**\n\t * Generates a guild member avatar URL.\n\t *\n\t * @param guildId - The id of the guild\n\t * @param userId - The id of the user\n\t * @param avatarHash - The hash provided by Discord for this avatar\n\t * @param options - Optional options for the avatar\n\t */\n\tpublic guildMemberAvatar(\n\t\tguildId: string,\n\t\tuserId: string,\n\t\tavatarHash: string,\n\t\toptions?: Readonly<ImageURLOptions>,\n\t): string {\n\t\treturn this.dynamicMakeURL(`/guilds/${guildId}/users/${userId}/avatars/${avatarHash}`, avatarHash, options);\n\t}\n\n\t/**\n\t * Generates a guild member banner URL.\n\t *\n\t * @param guildId - The id of the guild\n\t * @param userId - The id of the user\n\t * @param bannerHash - The hash provided by Discord for this banner\n\t * @param options - Optional options for the banner\n\t */\n\tpublic guildMemberBanner(\n\t\tguildId: string,\n\t\tuserId: string,\n\t\tbannerHash: string,\n\t\toptions?: Readonly<ImageURLOptions>,\n\t): string {\n\t\treturn this.dynamicMakeURL(`/guilds/${guildId}/users/${userId}/banner`, bannerHash, options);\n\t}\n\n\t/**\n\t * Generates an icon URL, e.g. for a guild.\n\t *\n\t * @param id - The id that has the icon splash\n\t * @param iconHash - The hash provided by Discord for this icon\n\t * @param options - Optional options for the icon\n\t */\n\tpublic icon(id: string, iconHash: string, options?: Readonly<ImageURLOptions>): string {\n\t\treturn this.dynamicMakeURL(`/icons/${id}/${iconHash}`, iconHash, options);\n\t}\n\n\t/**\n\t * Generates a URL for the icon of a role\n\t *\n\t * @param roleId - The id of the role that has the icon\n\t * @param roleIconHash - The hash provided by Discord for this role icon\n\t * @param options - Optional options for the role icon\n\t */\n\tpublic roleIcon(roleId: string, roleIconHash: string, options?: Readonly<BaseImageURLOptions>): string {\n\t\treturn this.makeURL(`/role-icons/${roleId}/${roleIconHash}`, options);\n\t}\n\n\t/**\n\t * Generates a guild invite splash URL for a guild's invite splash.\n\t *\n\t * @param guildId - The guild id that has the invite splash\n\t * @param splashHash - The hash provided by Discord for this splash\n\t * @param options - Optional options for the splash\n\t */\n\tpublic splash(guildId: string, splashHash: string, options?: Readonly<BaseImageURLOptions>): string {\n\t\treturn this.makeURL(`/splashes/${guildId}/${splashHash}`, options);\n\t}\n\n\t/**\n\t * Generates a sticker URL.\n\t *\n\t * @param stickerId - The sticker id\n\t * @param extension - The extension of the sticker\n\t * @privateRemarks\n\t * Stickers cannot have a `.webp` extension, so we default to a `.png`\n\t */\n\tpublic sticker(stickerId: string, extension: StickerExtension = 'png'): string {\n\t\treturn this.makeURL(`/stickers/${stickerId}`, { allowedExtensions: ALLOWED_STICKER_EXTENSIONS, extension });\n\t}\n\n\t/**\n\t * Generates a sticker pack banner URL.\n\t *\n\t * @param bannerId - The banner id\n\t * @param options - Optional options for the banner\n\t */\n\tpublic stickerPackBanner(bannerId: string, options?: Readonly<BaseImageURLOptions>): string {\n\t\treturn this.makeURL(`/app-assets/710982414301790216/store/${bannerId}`, options);\n\t}\n\n\t/**\n\t * Generates a team icon URL for a team's icon.\n\t *\n\t * @param teamId - The team id that has the icon\n\t * @param iconHash - The hash provided by Discord for this icon\n\t * @param options - Optional options for the icon\n\t */\n\tpublic teamIcon(teamId: string, iconHash: string, options?: Readonly<BaseImageURLOptions>): string {\n\t\treturn this.makeURL(`/team-icons/${teamId}/${iconHash}`, options);\n\t}\n\n\t/**\n\t * Generates a cover image for a guild scheduled event.\n\t *\n\t * @param scheduledEventId - The scheduled event id\n\t * @param coverHash - The hash provided by discord for this cover image\n\t * @param options - Optional options for the cover image\n\t */\n\tpublic guildScheduledEventCover(\n\t\tscheduledEventId: string,\n\t\tcoverHash: string,\n\t\toptions?: Readonly<BaseImageURLOptions>,\n\t): string {\n\t\treturn this.makeURL(`/guild-events/${scheduledEventId}/${coverHash}`, options);\n\t}\n\n\t/**\n\t * Constructs the URL for the resource, checking whether or not `hash` starts with `a_` if `dynamic` is set to `true`.\n\t *\n\t * @param route - The base cdn route\n\t * @param hash - The hash provided by Discord for this icon\n\t * @param options - Optional options for the link\n\t */\n\tprivate dynamicMakeURL(\n\t\troute: string,\n\t\thash: string,\n\t\t{ forceStatic = false, ...options }: Readonly<ImageURLOptions> = {},\n\t): string {\n\t\treturn this.makeURL(route, !forceStatic && hash.startsWith('a_') ? { ...options, extension: 'gif' } : options);\n\t}\n\n\t/**\n\t * Constructs the URL for the resource\n\t *\n\t * @param route - The base cdn route\n\t * @param options - The extension/size options for the link\n\t */\n\tprivate makeURL(\n\t\troute: string,\n\t\t{ allowedExtensions = ALLOWED_EXTENSIONS, extension = 'webp', size }: Readonly<MakeURLOptions> = {},\n\t): string {\n\t\t// eslint-disable-next-line no-param-reassign\n\t\textension = String(extension).toLowerCase();\n\n\t\tif (!allowedExtensions.includes(extension)) {\n\t\t\tthrow new RangeError(`Invalid extension provided: ${extension}\\nMust be one of: ${allowedExtensions.join(', ')}`);\n\t\t}\n\n\t\tif (size && !ALLOWED_SIZES.includes(size)) {\n\t\t\tthrow new RangeError(`Invalid size provided: ${size}\\nMust be one of: ${ALLOWED_SIZES.join(', ')}`);\n\t\t}\n\n\t\tconst url = new URL(`${this.base}${route}.${extension}`);\n\n\t\tif (size) {\n\t\t\turl.searchParams.set('size', String(size));\n\t\t}\n\n\t\treturn url.toString();\n\t}\n}\n","import type { InternalRequest, RawFile } from '../utils/types.js';\n\ninterface DiscordErrorFieldInformation {\n\tcode: string;\n\tmessage: string;\n}\n\ninterface DiscordErrorGroupWrapper {\n\t_errors: DiscordError[];\n}\n\ntype DiscordError = DiscordErrorFieldInformation | DiscordErrorGroupWrapper | string | { [k: string]: DiscordError };\n\nexport interface DiscordErrorData {\n\tcode: number;\n\terrors?: DiscordError;\n\tmessage: string;\n}\n\nexport interface OAuthErrorData {\n\terror: string;\n\terror_description?: string;\n}\n\nexport interface RequestBody {\n\tfiles: RawFile[] | undefined;\n\tjson: unknown | undefined;\n}\n\nfunction isErrorGroupWrapper(error: DiscordError): error is DiscordErrorGroupWrapper {\n\treturn Reflect.has(error as Record<string, unknown>, '_errors');\n}\n\nfunction isErrorResponse(error: DiscordError): error is DiscordErrorFieldInformation {\n\treturn typeof Reflect.get(error as Record<string, unknown>, 'message') === 'string';\n}\n\n/**\n * Represents an API error returned by Discord\n */\nexport class DiscordAPIError extends Error {\n\tpublic requestBody: RequestBody;\n\n\t/**\n\t * @param rawError - The error reported by Discord\n\t * @param code - The error code reported by Discord\n\t * @param status - The status code of the response\n\t * @param method - The method of the request that erred\n\t * @param url - The url of the request that erred\n\t * @param bodyData - The unparsed data for the request that errored\n\t */\n\tpublic constructor(\n\t\tpublic rawError: DiscordErrorData | OAuthErrorData,\n\t\tpublic code: number | string,\n\t\tpublic status: number,\n\t\tpublic method: string,\n\t\tpublic url: string,\n\t\tbodyData: Pick<InternalRequest, 'body' | 'files'>,\n\t) {\n\t\tsuper(DiscordAPIError.getMessage(rawError));\n\n\t\tthis.requestBody = { files: bodyData.files, json: bodyData.body };\n\t}\n\n\t/**\n\t * The name of the error\n\t */\n\tpublic override get name(): string {\n\t\treturn `${DiscordAPIError.name}[${this.code}]`;\n\t}\n\n\tprivate static getMessage(error: DiscordErrorData | OAuthErrorData) {\n\t\tlet flattened = '';\n\t\tif ('code' in error) {\n\t\t\tif (error.errors) {\n\t\t\t\tflattened = [...this.flattenDiscordError(error.errors)].join('\\n');\n\t\t\t}\n\n\t\t\treturn error.message && flattened\n\t\t\t\t? `${error.message}\\n${flattened}`\n\t\t\t\t: error.message || flattened || 'Unknown Error';\n\t\t}\n\n\t\treturn error.error_description ?? 'No Description';\n\t}\n\n\tprivate static *flattenDiscordError(obj: DiscordError, key = ''): IterableIterator<string> {\n\t\tif (isErrorResponse(obj)) {\n\t\t\treturn yield `${key.length ? `${key}[${obj.code}]` : `${obj.code}`}: ${obj.message}`.trim();\n\t\t}\n\n\t\tfor (const [otherKey, val] of Object.entries(obj)) {\n\t\t\tconst nextKey = otherKey.startsWith('_')\n\t\t\t\t? key\n\t\t\t\t: key\n\t\t\t\t? Number.isNaN(Number(otherKey))\n\t\t\t\t\t? `${key}.${otherKey}`\n\t\t\t\t\t: `${key}[${otherKey}]`\n\t\t\t\t: otherKey;\n\n\t\t\tif (typeof val === 'string') {\n\t\t\t\tyield val;\n\t\t\t} else if (isErrorGroupWrapper(val)) {\n\t\t\t\tfor (const error of val._errors) {\n\t\t\t\t\tyield* this.flattenDiscordError(error, nextKey);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tyield* this.flattenDiscordError(val, nextKey);\n\t\t\t}\n\t\t}\n\t}\n}\n","import type { InternalRequest } from '../utils/types.js';\nimport type { RequestBody } from './DiscordAPIError.js';\n\n/**\n * Represents a HTTP error\n */\nexport class HTTPError extends Error {\n\tpublic requestBody: RequestBody;\n\n\tpublic override name = HTTPError.name;\n\n\t/**\n\t * @param status - The status code of the response\n\t * @param statusText - The status text of the response\n\t * @param method - The method of the request that erred\n\t * @param url - The url of the request that erred\n\t * @param bodyData - The unparsed data for the request that errored\n\t */\n\tpublic constructor(\n\t\tpublic status: number,\n\t\tstatusText: string,\n\t\tpublic method: string,\n\t\tpublic url: string,\n\t\tbodyData: Pick<InternalRequest, 'body' | 'files'>,\n\t) {\n\t\tsuper(statusText);\n\t\tthis.requestBody = { files: bodyData.files, json: bodyData.body };\n\t}\n}\n","import type { RateLimitData } from '../utils/types.js';\n\nexport class RateLimitError extends Error implements RateLimitData {\n\tpublic timeToReset: number;\n\n\tpublic limit: number;\n\n\tpublic method: string;\n\n\tpublic hash: string;\n\n\tpublic url: string;\n\n\tpublic route: string;\n\n\tpublic majorParameter: string;\n\n\tpublic global: boolean;\n\n\tpublic constructor({ timeToReset, limit, method, hash, url, route, majorParameter, global }: RateLimitData) {\n\t\tsuper();\n\t\tthis.timeToReset = timeToReset;\n\t\tthis.limit = limit;\n\t\tthis.method = method;\n\t\tthis.hash = hash;\n\t\tthis.url = url;\n\t\tthis.route = route;\n\t\tthis.majorParameter = majorParameter;\n\t\tthis.global = global;\n\t}\n\n\t/**\n\t * The name of the error\n\t */\n\tpublic override get name(): string {\n\t\treturn `${RateLimitError.name}[${this.route}]`;\n\t}\n}\n","import { Collection } from '@discordjs/collection';\nimport { DiscordSnowflake } from '@sapphire/snowflake';\nimport { AsyncEventEmitter } from '@vladfrangu/async_event_emitter';\nimport { filetypeinfo } from 'magic-bytes.js';\nimport type { RequestInit, BodyInit, Dispatcher } from 'undici';\nimport { CDN } from './CDN.js';\nimport { BurstHandler } from './handlers/BurstHandler.js';\nimport { SequentialHandler } from './handlers/SequentialHandler.js';\nimport type { IHandler } from './interfaces/Handler.js';\nimport {\n\tBurstHandlerMajorIdKey,\n\tDefaultRestOptions,\n\tDefaultUserAgent,\n\tOverwrittenMimeTypes,\n\tRESTEvents,\n} from './utils/constants.js';\nimport { RequestMethod } from './utils/types.js';\nimport type {\n\tRESTOptions,\n\tResponseLike,\n\tRestEventsMap,\n\tHashData,\n\tInternalRequest,\n\tRouteLike,\n\tRequestHeaders,\n\tRouteData,\n\tRequestData,\n} from './utils/types.js';\nimport { isBufferLike, parseResponse } from './utils/utils.js';\n\n/**\n * Represents the class that manages handlers for endpoints\n */\nexport class REST extends AsyncEventEmitter<RestEventsMap> {\n\t/**\n\t * The {@link https://undici.nodejs.org/#/docs/api/Agent | Agent} for all requests\n\t * performed by this manager.\n\t */\n\tpublic agent: Dispatcher | null = null;\n\n\tpublic readonly cdn: CDN;\n\n\t/**\n\t * The number of requests remaining in the global bucket\n\t */\n\tpublic globalRemaining: number;\n\n\t/**\n\t * The promise used to wait out the global rate limit\n\t */\n\tpublic globalDelay: Promise<void> | null = null;\n\n\t/**\n\t * The timestamp at which the global bucket resets\n\t */\n\tpublic globalReset = -1;\n\n\t/**\n\t * API bucket hashes that are cached from provided routes\n\t */\n\tpublic readonly hashes = new Collection<string, HashData>();\n\n\t/**\n\t * Request handlers created from the bucket hash and the major parameters\n\t */\n\tpublic readonly handlers = new Collection<string, IHandler>();\n\n\t#token: string | null = null;\n\n\tprivate hashTimer!: NodeJS.Timer | number;\n\n\tprivate handlerTimer!: NodeJS.Timer | number;\n\n\tpublic readonly options: RESTOptions;\n\n\tpublic constructor(options: Partial<RESTOptions> = {}) {\n\t\tsuper();\n\t\tthis.cdn = new CDN(options.cdn ?? DefaultRestOptions.cdn);\n\t\tthis.options = { ...DefaultRestOptions, ...options };\n\t\tthis.options.offset = Math.max(0, this.options.offset);\n\t\tthis.globalRemaining = Math.max(1, this.options.globalRequestsPerSecond);\n\t\tthis.agent = options.agent ?? null;\n\n\t\t// Start sweepers\n\t\tthis.setupSweepers();\n\t}\n\n\tprivate setupSweepers() {\n\t\t// eslint-disable-next-line unicorn/consistent-function-scoping\n\t\tconst validateMaxInterval = (interval: number) => {\n\t\t\tif (interval > 14_400_000) {\n\t\t\t\tthrow new Error('Cannot set an interval greater than 4 hours');\n\t\t\t}\n\t\t};\n\n\t\tif (this.options.hashSweepInterval !== 0 && this.options.hashSweepInterval !== Number.POSITIVE_INFINITY) {\n\t\t\tvalidateMaxInterval(this.options.hashSweepInterval);\n\t\t\tthis.hashTimer = setInterval(() => {\n\t\t\t\tconst sweptHashes = new Collection<string, HashData>();\n\t\t\t\tconst currentDate = Date.now();\n\n\t\t\t\t// Begin sweeping hash based on lifetimes\n\t\t\t\tthis.hashes.sweep((val, key) => {\n\t\t\t\t\t// `-1` indicates a global hash\n\t\t\t\t\tif (val.lastAccess === -1) return false;\n\n\t\t\t\t\t// Check if lifetime has been exceeded\n\t\t\t\t\tconst shouldSweep = Math.floor(currentDate - val.lastAccess) > this.options.hashLifetime;\n\n\t\t\t\t\t// Add hash to collection of swept hashes\n\t\t\t\t\tif (shouldSweep) {\n\t\t\t\t\t\t// Add to swept hashes\n\t\t\t\t\t\tsweptHashes.set(key, val);\n\n\t\t\t\t\t\t// Emit debug information\n\t\t\t\t\t\tthis.emit(RESTEvents.Debug, `Hash ${val.value} for ${key} swept due to lifetime being exceeded`);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn shouldSweep;\n\t\t\t\t});\n\n\t\t\t\t// Fire event\n\t\t\t\tthis.emit(RESTEvents.HashSweep, sweptHashes);\n\t\t\t}, this.options.hashSweepInterval);\n\n\t\t\tthis.hashTimer.unref?.();\n\t\t}\n\n\t\tif (this.options.handlerSweepInterval !== 0 && this.options.handlerSweepInterval !== Number.POSITIVE_INFINITY) {\n\t\t\tvalidateMaxInterval(this.options.handlerSweepInterval);\n\t\t\tthis.handlerTimer = setInterval(() => {\n\t\t\t\tconst sweptHandlers = new Collection<string, IHandler>();\n\n\t\t\t\t// Begin sweeping handlers based on activity\n\t\t\t\tthis.handlers.sweep((val, key) => {\n\t\t\t\t\tconst { inactive } = val;\n\n\t\t\t\t\t// Collect inactive handlers\n\t\t\t\t\tif (inactive) {\n\t\t\t\t\t\tsweptHandlers.set(key, val);\n\t\t\t\t\t\tthis.emit(RESTEvents.Debug, `Handler ${val.id} for ${key} swept due to being inactive`);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn inactive;\n\t\t\t\t});\n\n\t\t\t\t// Fire event\n\t\t\t\tthis.emit(RESTEvents.HandlerSweep, sweptHandlers);\n\t\t\t}, this.options.handlerSweepInterval);\n\n\t\t\tthis.handlerTimer.unref?.();\n\t\t}\n\t}\n\n\t/**\n\t * Runs a get request from the api\n\t *\n\t * @param fullRoute - The full route to query\n\t * @param options - Optional request options\n\t */\n\tpublic async get(fullRoute: RouteLike, options: RequestData = {}) {\n\t\treturn this.request({ ...options, fullRoute, method: RequestMethod.Get });\n\t}\n\n\t/**\n\t * Runs a delete request from the api\n\t *\n\t * @param fullRoute - The full route to query\n\t * @param options - Optional request options\n\t */\n\tpublic async delete(fullRoute: RouteLike, options: RequestData = {}) {\n\t\treturn this.request({ ...options, fullRoute, method: RequestMethod.Delete });\n\t}\n\n\t/**\n\t * Runs a post request from the api\n\t *\n\t * @param fullRoute - The full route to query\n\t * @param options - Optional request options\n\t */\n\tpublic async post(fullRoute: RouteLike, options: RequestData = {}) {\n\t\treturn this.request({ ...options, fullRoute, method: RequestMethod.Post });\n\t}\n\n\t/**\n\t * Runs a put request from the api\n\t *\n\t * @param fullRoute - The full route to query\n\t * @param options - Optional request options\n\t */\n\tpublic async put(fullRoute: RouteLike, options: RequestData = {}) {\n\t\treturn this.request({ ...options, fullRoute, method: RequestMethod.Put });\n\t}\n\n\t/**\n\t * Runs a patch request from the api\n\t *\n\t * @param fullRoute - The full route to query\n\t * @param options - Optional request options\n\t */\n\tpublic async patch(fullRoute: RouteLike, options: RequestData = {}) {\n\t\treturn this.request({ ...options, fullRoute, method: RequestMethod.Patch });\n\t}\n\n\t/**\n\t * Runs a request from the api\n\t *\n\t * @param options - Request options\n\t */\n\tpublic async request(options: InternalRequest) {\n\t\tconst response = await this.queueRequest(options);\n\t\treturn parseResponse(response);\n\t}\n\n\t/**\n\t * Sets the default agent to use for requests performed by this manager\n\t *\n\t * @param agent - The agent to use\n\t */\n\tpublic setAgent(agent: Dispatcher) {\n\t\tthis.agent = agent;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the authorization token that should be used for requests\n\t *\n\t * @param token - The authorization token to use\n\t */\n\tpublic setToken(token: string) {\n\t\tthis.#token = token;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Queues a request to be sent\n\t *\n\t * @param request - All the information needed to make a request\n\t * @returns The response from the api request\n\t */\n\tpublic async queueRequest(request: InternalRequest): Promise<ResponseLike> {\n\t\t// Generalize the endpoint to its route data\n\t\tconst routeId = REST.generateRouteData(request.fullRoute, request.method);\n\t\t// Get the bucket hash for the generic route, or point to a global route otherwise\n\t\tconst hash = this.hashes.get(`${request.method}:${routeId.bucketRoute}`) ?? {\n\t\t\tvalue: `Global(${request.method}:${routeId.bucketRoute})`,\n\t\t\tlastAccess: -1,\n\t\t};\n\n\t\t// Get the request handler for the obtained hash, with its major parameter\n\t\tconst handler =\n\t\t\tthis.handlers.get(`${hash.value}:${routeId.majorParameter}`) ??\n\t\t\tthis.createHandler(hash.value, routeId.majorParameter);\n\n\t\t// Resolve the request into usable fetch options\n\t\tconst { url, fetchOptions } = await this.resolveRequest(request);\n\n\t\t// Queue the request\n\t\treturn handler.queueRequest(routeId, url, fetchOptions, {\n\t\t\tbody: request.body,\n\t\t\tfiles: request.files,\n\t\t\tauth: request.auth !== false,\n\t\t\tsignal: request.signal,\n\t\t});\n\t}\n\n\t/**\n\t * Creates a new rate limit handler from a hash, based on the hash and the major parameter\n\t *\n\t * @param hash - The hash for the route\n\t * @param majorParameter - The major parameter for this handler\n\t * @internal\n\t */\n\tprivate createHandler(hash: string, majorParameter: string) {\n\t\t// Create the async request queue to handle requests\n\t\tconst queue =\n\t\t\tmajorParameter === BurstHandlerMajorIdKey\n\t\t\t\t? new BurstHandler(this, hash, majorParameter)\n\t\t\t\t: new SequentialHandler(this, hash, majorParameter);\n\t\t// Save the queue based on its id\n\t\tthis.handlers.set(queue.id, queue);\n\n\t\treturn queue;\n\t}\n\n\t/**\n\t * Formats the request data to a usable format for fetch\n\t *\n\t * @param request - The request data\n\t */\n\tprivate async resolveRequest(request: InternalRequest): Promise<{ fetchOptions: RequestInit; url: string }> {\n\t\tconst { options } = this;\n\n\t\tlet query = '';\n\n\t\t// If a query option is passed, use it\n\t\tif (request.query) {\n\t\t\tconst resolvedQuery = request.query.toString();\n\t\t\tif (resolvedQuery !== '') {\n\t\t\t\tquery = `?${resolvedQuery}`;\n\t\t\t}\n\t\t}\n\n\t\t// Create the required headers\n\t\tconst headers: RequestHeaders = {\n\t\t\t...this.options.headers,\n\t\t\t'User-Agent': `${DefaultUserAgent} ${options.userAgentAppendix}`.trim(),\n\t\t};\n\n\t\t// If this request requires authorization (allowing non-\"authorized\" requests for webhooks)\n\t\tif (request.auth !== false) {\n\t\t\t// If we haven't received a token, throw an error\n\t\t\tif (!this.#token) {\n\t\t\t\tthrow new Error('Expected token to be set for this request, but none was present');\n\t\t\t}\n\n\t\t\theaders.Authorization = `${request.authPrefix ?? this.options.authPrefix} ${this.#token}`;\n\t\t}\n\n\t\t// If a reason was set, set it's appropriate header\n\t\tif (request.reason?.length) {\n\t\t\theaders['X-Audit-Log-Reason'] = encodeURIComponent(request.reason);\n\t\t}\n\n\t\t// Format the full request URL (api base, optional version, endpoint, optional querystring)\n\t\tconst url = `${options.api}${request.versioned === false ? '' : `/v${options.version}`}${\n\t\t\trequest.fullRoute\n\t\t}${query}`;\n\n\t\tlet finalBody: RequestInit['body'];\n\t\tlet additionalHeaders: Record<string, string> = {};\n\n\t\tif (request.files?.length) {\n\t\t\tconst formData = new FormData();\n\n\t\t\t// Attach all files to the request\n\t\t\tfor (const [index, file] of request.files.entries()) {\n\t\t\t\tconst fileKey = file.key ?? `files[${index}]`;\n\n\t\t\t\t// https://developer.mozilla.org/en-US/docs/Web/API/FormData/append#parameters\n\t\t\t\t// FormData.append only accepts a string or Blob.\n\t\t\t\t// https://developer.mozilla.org/en-US/docs/Web/API/Blob/Blob#parameters\n\t\t\t\t// The Blob constructor accepts TypedArray/ArrayBuffer, strings, and Blobs.\n\t\t\t\tif (isBufferLike(file.data)) {\n\t\t\t\t\t// Try to infer the content type from the buffer if one isn't passed\n\t\t\t\t\tlet contentType = file.contentType;\n\n\t\t\t\t\tif (!contentType) {\n\t\t\t\t\t\tconst [parsedType] = filetypeinfo(file.data);\n\n\t\t\t\t\t\tif (parsedType) {\n\t\t\t\t\t\t\tcontentType =\n\t\t\t\t\t\t\t\tOverwrittenMimeTypes[parsedType.mime as keyof typeof OverwrittenMimeTypes] ??\n\t\t\t\t\t\t\t\tparsedType.mime ??\n\t\t\t\t\t\t\t\t'application/octet-stream';\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tformData.append(fileKey, new Blob([file.data], { type: contentType }), file.name);\n\t\t\t\t} else {\n\t\t\t\t\tformData.append(fileKey, new Blob([`${file.data}`], { type: file.contentType }), file.name);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If a JSON body was added as well, attach it to the form data, using payload_json unless otherwise specified\n\t\t\t// eslint-disable-next-line no-eq-null, eqeqeq\n\t\t\tif (request.body != null) {\n\t\t\t\tif (request.appendToFormData) {\n\t\t\t\t\tfor (const [key, value] of Object.entries(request.body as Record<string, unknown>)) {\n\t\t\t\t\t\tformData.append(key, value);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tformData.append('payload_json', JSON.stringify(request.body));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Set the final body to the form data\n\t\t\tfinalBody = formData;\n\n\t\t\t// eslint-disable-next-line no-eq-null, eqeqeq\n\t\t} else if (request.body != null) {\n\t\t\tif (request.passThroughBody) {\n\t\t\t\tfinalBody = request.body as BodyInit;\n\t\t\t} else {\n\t\t\t\t// Stringify the JSON data\n\t\t\t\tfinalBody = JSON.stringify(request.body);\n\t\t\t\t// Set the additional headers to specify the content-type\n\t\t\t\tadditionalHeaders = { 'Content-Type': 'application/json' };\n\t\t\t}\n\t\t}\n\n\t\tconst method = request.method.toUpperCase();\n\n\t\t// The non null assertions in the following block are due to exactOptionalPropertyTypes, they have been tested to work with undefined\n\t\tconst fetchOptions: RequestInit = {\n\t\t\t// Set body to null on get / head requests. This does not follow fetch spec (likely because it causes subtle bugs) but is aligned with what request was doing\n\t\t\tbody: ['GET', 'HEAD'].includes(method) ? null : finalBody!,\n\t\t\theaders: { ...request.headers, ...additionalHeaders, ...headers } as Record<string, string>,\n\t\t\tmethod,\n\t\t\t// Prioritize setting an agent per request, use the agent for this instance otherwise.\n\t\t\tdispatcher: request.dispatcher ?? this.agent ?? undefined!,\n\t\t};\n\n\t\treturn { url, fetchOptions };\n\t}\n\n\t/**\n\t * Stops the hash sweeping interval\n\t */\n\tpublic clearHashSweeper() {\n\t\tclearInterval(this.hashTimer);\n\t}\n\n\t/**\n\t * Stops the request handler sweeping interval\n\t */\n\tpublic clearHandlerSweeper() {\n\t\tclearInterval(this.handlerTimer);\n\t}\n\n\t/**\n\t * Generates route data for an endpoint:method\n\t *\n\t * @param endpoint - The raw endpoint to generalize\n\t * @param method - The HTTP method this endpoint is called without\n\t * @internal\n\t */\n\tprivate static generateRouteData(endpoint: RouteLike, method: RequestMethod): RouteData {\n\t\tif (endpoint.startsWith('/interactions/') && endpoint.endsWith('/callback')) {\n\t\t\treturn {\n\t\t\t\tmajorParameter: BurstHandlerMajorIdKey,\n\t\t\t\tbucketRoute: '/interactions/:id/:token/callback',\n\t\t\t\toriginal: endpoint,\n\t\t\t};\n\t\t}\n\n\t\tconst majorIdMatch = /^\\/(?:channels|guilds|webhooks)\\/(\\d{17,19})/.exec(endpoint);\n\n\t\t// Get the major id for this route - global otherwise\n\t\tconst majorId = majorIdMatch?.[1] ?? 'global';\n\n\t\tconst baseRoute = endpoint\n\t\t\t// Strip out all ids\n\t\t\t.replaceAll(/\\d{17,19}/g, ':id')\n\t\t\t// Strip out reaction as they fall under the same bucket\n\t\t\t.replace(/\\/reactions\\/(.*)/, '/reactions/:reaction');\n\n\t\tlet exceptions = '';\n\n\t\t// Hard-Code Old Message Deletion Exception (2 week+ old messages are a different bucket)\n\t\t// https://github.com/discord/discord-api-docs/issues/1295\n\t\tif (method === RequestMethod.Delete && baseRoute === '/channels/:id/messages/:id') {\n\t\t\tconst id = /\\d{17,19}$/.exec(endpoint)![0]!;\n\t\t\tconst timestamp = DiscordSnowflake.timestampFrom(id);\n\t\t\tif (Date.now() - timestamp > 1_000 * 60 * 60 * 24 * 14) {\n\t\t\t\texceptions += '/Delete Old Message';\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tmajorParameter: majorId,\n\t\t\tbucketRoute: baseRoute + exceptions,\n\t\t\toriginal: endpoint,\n\t\t};\n\t}\n}\n","import type { Readable } from 'node:stream';\nimport type { ReadableStream } from 'node:stream/web';\nimport type { Collection } from '@discordjs/collection';\nimport type { Agent, Dispatcher, RequestInit, BodyInit, Response } from 'undici';\nimport type { IHandler } from '../interfaces/Handler.js';\n\nexport interface RestEvents {\n\thandlerSweep: [sweptHandlers: Collection<string, IHandler>];\n\thashSweep: [sweptHashes: Collection<string, HashData>];\n\tinvalidRequestWarning: [invalidRequestInfo: InvalidRequestWarningData];\n\trateLimited: [rateLimitInfo: RateLimitData];\n\tresponse: [request: APIRequest, response: ResponseLike];\n\trestDebug: [info: string];\n}\n\nexport type RestEventsMap = {\n\t[K in keyof RestEvents]: RestEvents[K];\n};\n\n/**\n * Options to be passed when creating the REST instance\n */\nexport interface RESTOptions {\n\t/**\n\t * The agent to set globally\n\t */\n\tagent: Dispatcher | null;\n\t/**\n\t * The base api path, without version\n\t *\n\t * @defaultValue `'https://discord.com/api'`\n\t */\n\tapi: string;\n\t/**\n\t * The authorization prefix to use for requests, useful if you want to use\n\t * bearer tokens\n\t *\n\t * @defaultValue `'Bot'`\n\t */\n\tauthPrefix: 'Bearer' | 'Bot';\n\t/**\n\t * The cdn path\n\t *\n\t * @defaultValue `'https://cdn.discordapp.com'`\n\t */\n\tcdn: string;\n\t/**\n\t * How many requests to allow sending per second (Infinity for unlimited, 50 for the standard global limit used by Discord)\n\t *\n\t * @defaultValue `50`\n\t */\n\tglobalRequestsPerSecond: number;\n\t/**\n\t * The amount of time in milliseconds that passes between each hash sweep. (defaults to 1h)\n\t *\n\t * @defaultValue `3_600_000`\n\t */\n\thandlerSweepInterval: number;\n\t/**\n\t * The maximum amount of time a hash can exist in milliseconds without being hit with a request (defaults to 24h)\n\t *\n\t * @defaultValue `86_400_000`\n\t */\n\thashLifetime: number;\n\t/**\n\t * The amount of time in milliseconds that passes between each hash sweep. (defaults to 4h)\n\t *\n\t * @defaultValue `14_400_000`\n\t */\n\thashSweepInterval: number;\n\t/**\n\t * Additional headers to send for all API requests\n\t *\n\t * @defaultValue `{}`\n\t */\n\theaders: Record<string, string>;\n\t/**\n\t * The number of invalid REST requests (those that return 401, 403, or 429) in a 10 minute window between emitted warnings (0 for no warnings).\n\t * That is, if set to 500, warnings will be emitted at invalid request number 500, 1000, 1500, and so on.\n\t *\n\t * @defaultValue `0`\n\t */\n\tinvalidRequestWarningInterval: number;\n\t/**\n\t * The method called to perform the actual HTTP request given a url and web `fetch` options\n\t * For example, to use global fetch, simply provide `makeRequest: fetch`\n\t */\n\tmakeRequest(url: string, init: RequestInit): Promise<ResponseLike>;\n\t/**\n\t * The extra offset to add to rate limits in milliseconds\n\t *\n\t * @defaultValue `50`\n\t */\n\toffset: number;\n\t/**\n\t * Determines how rate limiting and pre-emptive throttling should be handled.\n\t * When an array of strings, each element is treated as a prefix for the request route\n\t * (e.g. `/channels` to match any route starting with `/channels` such as `/channels/:id/messages`)\n\t * for which to throw {@link RateLimitError}s. All other request routes will be queued normally\n\t *\n\t * @defaultValue `null`\n\t */\n\trejectOnRateLimit: RateLimitQueueFilter | string[] | null;\n\t/**\n\t * The number of retries for errors with the 500 code, or errors\n\t * that timeout\n\t *\n\t * @defaultValue `3`\n\t */\n\tretries: number;\n\t/**\n\t * The time to wait in milliseconds before a request is aborted\n\t *\n\t * @defaultValue `15_000`\n\t */\n\ttimeout: number;\n\t/**\n\t * Extra information to add to the user agent\n\t *\n\t * @defaultValue DefaultUserAgentAppendix\n\t */\n\tuserAgentAppendix: string;\n\t/**\n\t * The version of the API to use\n\t *\n\t * @defaultValue `'10'`\n\t */\n\tversion: string;\n}\n\n/**\n * Data emitted on `RESTEvents.RateLimited`\n */\nexport interface RateLimitData {\n\t/**\n\t * Whether the rate limit that was reached was the global limit\n\t */\n\tglobal: boolean;\n\t/**\n\t * The bucket hash for this request\n\t */\n\thash: string;\n\t/**\n\t * The amount of requests we can perform before locking requests\n\t */\n\tlimit: number;\n\t/**\n\t * The major parameter of the route\n\t *\n\t * For example, in `/channels/x`, this will be `x`.\n\t * If there is no major parameter (e.g: `/bot/gateway`) this will be `global`.\n\t */\n\tmajorParameter: string;\n\t/**\n\t * The HTTP method being performed\n\t */\n\tmethod: string;\n\t/**\n\t * The route being hit in this request\n\t */\n\troute: string;\n\t/**\n\t * The time, in milliseconds, until the request-lock is reset\n\t */\n\ttimeToReset: number;\n\t/**\n\t * The full URL for this request\n\t */\n\turl: string;\n}\n\n/**\n * A function that determines whether the rate limit hit should throw an Error\n */\nexport type RateLimitQueueFilter = (rateLimitData: RateLimitData) => Promise<boolean> | boolean;\n\nexport interface APIRequest {\n\t/**\n\t * The data that was used to form the body of this request\n\t */\n\tdata: HandlerRequestData;\n\t/**\n\t * The HTTP method used in this request\n\t */\n\tmethod: string;\n\t/**\n\t * Additional HTTP options for this request\n\t */\n\toptions: RequestInit;\n\t/**\n\t * The full path used to make the request\n\t */\n\tpath: RouteLike;\n\t/**\n\t * The number of times this request has been attempted\n\t */\n\tretries: number;\n\t/**\n\t * The API route identifying the ratelimit for this request\n\t */\n\troute: string;\n}\n\nexport interface ResponseLike\n\textends Pick<Response, 'arrayBuffer' | 'bodyUsed' | 'headers' | 'json' | 'ok' | 'status' | 'statusText' | 'text'> {\n\tbody: Readable | ReadableStream | null;\n}\n\nexport interface InvalidRequestWarningData {\n\t/**\n\t * Number of invalid requests that have been made in the window\n\t */\n\tcount: number;\n\t/**\n\t * Time in milliseconds remaining before the count resets\n\t */\n\tremainingTime: number;\n}\n\n/**\n * Represents a file to be added to the request\n */\nexport interface RawFile {\n\t/**\n\t * Content-Type of the file\n\t */\n\tcontentType?: string;\n\t/**\n\t * The actual data for the file\n\t */\n\tdata: Buffer | Uint8Array | boolean | number | string;\n\t/**\n\t * An explicit key to use for key of the formdata field for this file.\n\t * When not provided, the index of the file in the files array is used in the form `files[${index}]`.\n\t * If you wish to alter the placeholder snowflake, you must provide this property in the same form (`files[${placeholder}]`)\n\t */\n\tkey?: string;\n\t/**\n\t * The name of the file\n\t */\n\tname: string;\n}\n\n/**\n * Represents possible data to be given to an endpoint\n */\nexport interface RequestData {\n\t/**\n\t * Whether to append JSON data to form data instead of `payload_json` when sending files\n\t */\n\tappendToFormData?: boolean;\n\t/**\n\t * If this request needs the `Authorization` header\n\t *\n\t * @defaultValue `true`\n\t */\n\tauth?: boolean;\n\t/**\n\t * The authorization prefix to use for this request, useful if you use this with bearer tokens\n\t *\n\t * @defaultValue `'Bot'`\n\t */\n\tauthPrefix?: 'Bearer' | 'Bot';\n\t/**\n\t * The body to send to this request.\n\t * If providing as BodyInit, set `passThroughBody: true`\n\t */\n\tbody?: BodyInit | unknown;\n\t/**\n\t * The {@link https://undici.nodejs.org/#/docs/api/Agent | Agent} to use for the request.\n\t */\n\tdispatcher?: Agent;\n\t/**\n\t * Files to be attached to this request\n\t */\n\tfiles?: RawFile[] | undefined;\n\t/**\n\t * Additional headers to add to this request\n\t */\n\theaders?: Record<string, string>;\n\t/**\n\t * Whether to pass-through the body property directly to `fetch()`.\n\t * <warn>This only applies when files is NOT present</warn>\n\t */\n\tpassThroughBody?: boolean;\n\t/**\n\t * Query string parameters to append to the called endpoint\n\t */\n\tquery?: URLSearchParams;\n\t/**\n\t * Reason to show in the audit logs\n\t */\n\treason?: string | undefined;\n\t/**\n\t * The signal to abort the queue entry or the REST call, where applicable\n\t */\n\tsignal?: AbortSignal | undefined;\n\t/**\n\t * If this request should be versioned\n\t *\n\t * @defaultValue `true`\n\t */\n\tversioned?: boolean;\n}\n\n/**\n * Possible headers for an API call\n */\nexport interface RequestHeaders {\n\tAuthorization?: string;\n\t'User-Agent': string;\n\t'X-Audit-Log-Reason'?: string;\n}\n\n/**\n * Possible API methods to be used when doing requests\n */\nexport enum RequestMethod {\n\tDelete = 'DELETE',\n\tGet = 'GET',\n\tPatch = 'PATCH',\n\tPost = 'POST',\n\tPut = 'PUT',\n}\n\nexport type RouteLike = `/${string}`;\n\n/**\n * Internal request options\n *\n * @internal\n */\nexport interface InternalRequest extends RequestData {\n\tfullRoute: RouteLike;\n\tmethod: RequestMethod;\n}\n\nexport type HandlerRequestData = Pick<InternalRequest, 'auth' | 'body' | 'files' | 'signal'>;\n\n/**\n * Parsed route data for an endpoint\n *\n * @internal\n */\nexport interface RouteData {\n\tbucketRoute: string;\n\tmajorParameter: string;\n\toriginal: RouteLike;\n}\n\n/**\n * Represents a hash and its associated fields\n *\n * @internal\n */\nexport interface HashData {\n\tlastAccess: number;\n\tvalue: string;\n}\n","import type { RESTPatchAPIChannelJSONBody, Snowflake } from 'discord-api-types/v10';\nimport type { REST } from '../REST.js';\nimport { RateLimitError } from '../errors/RateLimitError.js';\nimport { RequestMethod, type RateLimitData, type ResponseLike } from './types.js';\n\nfunction serializeSearchParam(value: unknown): string | null {\n\tswitch (typeof value) {\n\t\tcase 'string':\n\t\t\treturn value;\n\t\tcase 'number':\n\t\tcase 'bigint':\n\t\tcase 'boolean':\n\t\t\treturn value.toString();\n\t\tcase 'object':\n\t\t\tif (value === null) return null;\n\t\t\tif (value instanceof Date) {\n\t\t\t\treturn Number.isNaN(value.getTime()) ? null : value.toISOString();\n\t\t\t}\n\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-base-to-string\n\t\t\tif (typeof value.toString === 'function' && value.toString !== Object.prototype.toString) return value.toString();\n\t\t\treturn null;\n\t\tdefault:\n\t\t\treturn null;\n\t}\n}\n\n/**\n * Creates and populates an URLSearchParams instance from an object, stripping\n * out null and undefined values, while also coercing non-strings to strings.\n *\n * @param options - The options to use\n * @returns A populated URLSearchParams instance\n */\nexport function makeURLSearchParams<T extends object>(options?: Readonly<T>) {\n\tconst params = new URLSearchParams();\n\tif (!options) return params;\n\n\tfor (const [key, value] of Object.entries(options)) {\n\t\tconst serialized = serializeSearchParam(value);\n\t\tif (serialized !== null) params.append(key, serialized);\n\t}\n\n\treturn params;\n}\n\n/**\n * Converts the response to usable data\n *\n * @param res - The fetch response\n */\nexport async function parseResponse(res: ResponseLike): Promise<unknown> {\n\tif (res.headers.get('Content-Type')?.startsWith('application/json')) {\n\t\treturn res.json();\n\t}\n\n\treturn res.arrayBuffer();\n}\n\n/**\n * Check whether a request falls under a sublimit\n *\n * @param bucketRoute - The buckets route identifier\n * @param body - The options provided as JSON data\n * @param method - The HTTP method that will be used to make the request\n * @returns Whether the request falls under a sublimit\n */\nexport function hasSublimit(bucketRoute: string, body?: unknown, method?: string): boolean {\n\t// TODO: Update for new sublimits\n\t// Currently known sublimits:\n\t// Editing channel `name` or `topic`\n\tif (bucketRoute === '/channels/:id') {\n\t\tif (typeof body !== 'object' || body === null) return false;\n\t\t// This should never be a POST body, but just in case\n\t\tif (method !== RequestMethod.Patch) return false;\n\t\tconst castedBody = body as RESTPatchAPIChannelJSONBody;\n\t\treturn ['name', 'topic'].some((key) => Reflect.has(castedBody, key));\n\t}\n\n\t// If we are checking if a request has a sublimit on a route not checked above, sublimit all requests to avoid a flood of 429s\n\treturn true;\n}\n\n/**\n * Check whether an error indicates that a retry can be attempted\n *\n * @param error - The error thrown by the network request\n * @returns Whether the error indicates a retry should be attempted\n */\nexport function shouldRetry(error: Error | NodeJS.ErrnoException) {\n\t// Retry for possible timed out requests\n\tif (error.name === 'AbortError') return true;\n\t// Downlevel ECONNRESET to retry as it may be recoverable\n\treturn ('code' in error && error.code === 'ECONNRESET') || error.message.includes('ECONNRESET');\n}\n\n/**\n * Determines whether the request should be queued or whether a RateLimitError should be thrown\n *\n * @internal\n */\nexport async function onRateLimit(manager: REST, rateLimitData: RateLimitData) {\n\tconst { options } = manager;\n\tif (!options.rejectOnRateLimit) return;\n\n\tconst shouldThrow =\n\t\ttypeof options.rejectOnRateLimit === 'function'\n\t\t\t? await options.rejectOnRateLimit(rateLimitData)\n\t\t\t: options.rejectOnRateLimit.some((route) => rateLimitData.route.startsWith(route.toLowerCase()));\n\tif (shouldThrow) {\n\t\tthrow new RateLimitError(rateLimitData);\n\t}\n}\n\n/**\n * Calculates the default avatar index for a given user id.\n *\n * @param userId - The user id to calculate the default avatar index for\n */\nexport function calculateUserDefaultAvatarIndex(userId: Snowflake) {\n\treturn Number(BigInt(userId) >> 22n) % 6;\n}\n\n/**\n * Sleeps for a given amount of time.\n *\n * @param ms - The amount of time (in milliseconds) to sleep for\n */\nexport async function sleep(ms: number): Promise<void> {\n\treturn new Promise<void>((resolve) => {\n\t\tsetTimeout(() => resolve(), ms);\n\t});\n}\n\n/**\n * Verifies that a value is a buffer-like object.\n *\n * @param value - The value to check\n */\nexport function isBufferLike(value: unknown): value is ArrayBuffer | Buffer | Uint8Array | Uint8ClampedArray {\n\treturn value instanceof ArrayBuffer || value instanceof Uint8Array || value instanceof Uint8ClampedArray;\n}\n","import type { RequestInit } from 'undici';\nimport type { REST } from '../REST.js';\nimport type { DiscordErrorData, OAuthErrorData } from '../errors/DiscordAPIError.js';\nimport { DiscordAPIError } from '../errors/DiscordAPIError.js';\nimport { HTTPError } from '../errors/HTTPError.js';\nimport { RESTEvents } from '../utils/constants.js';\nimport type { ResponseLike, HandlerRequestData, RouteData } from '../utils/types.js';\nimport { parseResponse, shouldRetry } from '../utils/utils.js';\n\n/**\n * Invalid request limiting is done on a per-IP basis, not a per-token basis.\n * The best we can do is track invalid counts process-wide (on the theory that\n * users could have multiple bots run from one process) rather than per-bot.\n * Therefore, store these at file scope here rather than in the client's\n * RESTManager object.\n */\nlet invalidCount = 0;\nlet invalidCountResetTime: number | null = null;\n\n/**\n * Increment the invalid request count and emit warning if necessary\n *\n * @internal\n */\nexport function incrementInvalidCount(manager: REST) {\n\tif (!invalidCountResetTime || invalidCountResetTime < Date.now()) {\n\t\tinvalidCountResetTime = Date.now() + 1_000 * 60 * 10;\n\t\tinvalidCount = 0;\n\t}\n\n\tinvalidCount++;\n\n\tconst emitInvalid =\n\t\tmanager.options.invalidRequestWarningInterval > 0 &&\n\t\tinvalidCount % manager.options.invalidRequestWarningInterval === 0;\n\tif (emitInvalid) {\n\t\t// Let library users know periodically about invalid requests\n\t\tmanager.emit(RESTEvents.InvalidRequestWarning, {\n\t\t\tcount: invalidCount,\n\t\t\tremainingTime: invalidCountResetTime - Date.now(),\n\t\t});\n\t}\n}\n\n/**\n * Performs the actual network request for a request handler\n *\n * @param manager - The manager that holds options and emits informational events\n * @param routeId - The generalized api route with literal ids for major parameters\n * @param url - The fully resolved url to make the request to\n * @param options - The fetch options needed to make the request\n * @param requestData - Extra data from the user's request needed for errors and additional processing\n * @param retries - The number of retries this request has already attempted (recursion occurs on the handler)\n * @returns The respond from the network or `null` when the request should be retried\n * @internal\n */\nexport async function makeNetworkRequest(\n\tmanager: REST,\n\trouteId: RouteData,\n\turl: string,\n\toptions: RequestInit,\n\trequestData: HandlerRequestData,\n\tretries: number,\n) {\n\tconst controller = new AbortController();\n\tconst timeout = setTimeout(() => controller.abort(), manager.options.timeout);\n\tif (requestData.signal) {\n\t\t// If the user signal was aborted, abort the controller, else abort the local signal.\n\t\t// The reason why we don't re-use the user's signal, is because users may use the same signal for multiple\n\t\t// requests, and we do not want to cause unexpected side-effects.\n\t\tif (requestData.signal.aborted) controller.abort();\n\t\telse requestData.signal.addEventListener('abort', () => controller.abort());\n\t}\n\n\tlet res: ResponseLike;\n\ttry {\n\t\tres = await manager.options.makeRequest(url, { ...options, signal: controller.signal });\n\t} catch (error: unknown) {\n\t\tif (!(error instanceof Error)) throw error;\n\t\t// Retry the specified number of times if needed\n\t\tif (shouldRetry(error) && retries !== manager.options.retries) {\n\t\t\t// Retry is handled by the handler upon receiving null\n\t\t\treturn null;\n\t\t}\n\n\t\tthrow error;\n\t} finally {\n\t\tclearTimeout(timeout);\n\t}\n\n\tif (manager.listenerCount(RESTEvents.Response)) {\n\t\tmanager.emit(\n\t\t\tRESTEvents.Response,\n\t\t\t{\n\t\t\t\tmethod: options.method ?? 'get',\n\t\t\t\tpath: routeId.original,\n\t\t\t\troute: routeId.bucketRoute,\n\t\t\t\toptions,\n\t\t\t\tdata: requestData,\n\t\t\t\tretries,\n\t\t\t},\n\t\t\tres instanceof Response ? res.clone() : { ...res },\n\t\t);\n\t}\n\n\treturn res;\n}\n\n/**\n * Handles 5xx and 4xx errors (not 429's) conventionally. 429's should be handled before calling this function\n *\n * @param manager - The manager that holds options and emits informational events\n * @param res - The response received from {@link makeNetworkRequest}\n * @param method - The method used to make the request\n * @param url - The fully resolved url to make the request to\n * @param requestData - Extra data from the user's request needed for errors and additional processing\n * @param retries - The number of retries this request has already attempted (recursion occurs on the handler)\n * @returns - The response if the status code is not handled or null to request a retry\n */\nexport async function handleErrors(\n\tmanager: REST,\n\tres: ResponseLike,\n\tmethod: string,\n\turl: string,\n\trequestData: HandlerRequestData,\n\tretries: number,\n) {\n\tconst status = res.status;\n\tif (status >= 500 && status < 600) {\n\t\t// Retry the specified number of times for possible server side issues\n\t\tif (retries !== manager.options.retries) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// We are out of retries, throw an error\n\t\tthrow new HTTPError(status, res.statusText, method, url, requestData);\n\t} else {\n\t\t// Handle possible malformed requests\n\t\tif (status >= 400 && status < 500) {\n\t\t\t// If we receive this status code, it means the token we had is no longer valid.\n\t\t\tif (status === 401 && requestData.auth) {\n\t\t\t\tmanager.setToken(null!);\n\t\t\t}\n\n\t\t\t// The request will not succeed for some reason, parse the error returned from the api\n\t\t\tconst data = (await parseResponse(res)) as DiscordErrorData | OAuthErrorData;\n\t\t\t// throw the API error\n\t\t\tthrow new DiscordAPIError(data, 'code' in data ? data.code : data.error, status, method, url, requestData);\n\t\t}\n\n\t\treturn res;\n\t}\n}\n","import type { RequestInit } from 'undici';\nimport type { REST } from '../REST.js';\nimport type { IHandler } from '../interfaces/Handler.js';\nimport { RESTEvents } from '../utils/constants.js';\nimport type { ResponseLike, HandlerRequestData, RouteData } from '../utils/types.js';\nimport { onRateLimit, sleep } from '../utils/utils.js';\nimport { handleErrors, incrementInvalidCount, makeNetworkRequest } from './Shared.js';\n\n/**\n * The structure used to handle burst requests for a given bucket.\n * Burst requests have no ratelimit handling but allow for pre- and post-processing\n * of data in the same manner as sequentially queued requests.\n *\n * @remarks\n * This queue may still emit a rate limit error if an unexpected 429 is hit\n */\nexport class BurstHandler implements IHandler {\n\t/**\n\t * {@inheritdoc IHandler.id}\n\t */\n\tpublic readonly id: string;\n\n\t/**\n\t * {@inheritDoc IHandler.inactive}\n\t */\n\tpublic inactive = false;\n\n\t/**\n\t * @param manager - The request manager\n\t * @param hash - The hash that this RequestHandler handles\n\t * @param majorParameter - The major parameter for this handler\n\t */\n\tpublic constructor(\n\t\tprivate readonly manager: REST,\n\t\tprivate readonly hash: string,\n\t\tprivate readonly majorParameter: string,\n\t) {\n\t\tthis.id = `${hash}:${majorParameter}`;\n\t}\n\n\t/**\n\t * Emits a debug message\n\t *\n\t * @param message - The message to debug\n\t */\n\tprivate debug(message: string) {\n\t\tthis.manager.emit(RESTEvents.Debug, `[REST ${this.id}] ${message}`);\n\t}\n\n\t/**\n\t * {@inheritDoc IHandler.queueRequest}\n\t */\n\tpublic async queueRequest(\n\t\trouteId: RouteData,\n\t\turl: string,\n\t\toptions: RequestInit,\n\t\trequestData: HandlerRequestData,\n\t): Promise<ResponseLike> {\n\t\treturn this.runRequest(routeId, url, options, requestData);\n\t}\n\n\t/**\n\t * The method that actually makes the request to the API, and updates info about the bucket accordingly\n\t *\n\t * @param routeId - The generalized API route with literal ids for major parameters\n\t * @param url - The fully resolved URL to make the request to\n\t * @param options - The fetch options needed to make the request\n\t * @param requestData - Extra data from the user's request needed for errors and additional processing\n\t * @param retries - The number of retries this request has already attempted (recursion)\n\t */\n\tprivate async runRequest(\n\t\trouteId: RouteData,\n\t\turl: string,\n\t\toptions: RequestInit,\n\t\trequestData: HandlerRequestData,\n\t\tretries = 0,\n\t): Promise<ResponseLike> {\n\t\tconst method = options.method ?? 'get';\n\n\t\tconst res = await makeNetworkRequest(this.manager, routeId, url, options, requestData, retries);\n\n\t\t// Retry requested\n\t\tif (res === null) {\n\t\t\t// eslint-disable-next-line no-param-reassign\n\t\t\treturn this.runRequest(routeId, url, options, requestData, ++retries);\n\t\t}\n\n\t\tconst status = res.status;\n\t\tlet retryAfter = 0;\n\t\tconst retry = res.headers.get('Retry-After');\n\n\t\t// Amount of time in milliseconds until we should retry if rate limited (globally or otherwise)\n\t\tif (retry) retryAfter = Number(retry) * 1_000 + this.manager.options.offset;\n\n\t\t// Count the invalid requests\n\t\tif (status === 401 || status === 403 || status === 429) {\n\t\t\tincrementInvalidCount(this.manager);\n\t\t}\n\n\t\tif (status >= 200 && status < 300) {\n\t\t\treturn res;\n\t\t} else if (status === 429) {\n\t\t\t// Unexpected ratelimit\n\t\t\tconst isGlobal = res.headers.has('X-RateLimit-Global');\n\t\t\tawait onRateLimit(this.manager, {\n\t\t\t\ttimeToReset: retryAfter,\n\t\t\t\tlimit: Number.POSITIVE_INFINITY,\n\t\t\t\tmethod,\n\t\t\t\thash: this.hash,\n\t\t\t\turl,\n\t\t\t\troute: routeId.bucketRoute,\n\t\t\t\tmajorParameter: this.majorParameter,\n\t\t\t\tglobal: isGlobal,\n\t\t\t});\n\t\t\tthis.debug(\n\t\t\t\t[\n\t\t\t\t\t'Encountered unexpected 429 rate limit',\n\t\t\t\t\t` Global : ${isGlobal}`,\n\t\t\t\t\t` Method : ${method}`,\n\t\t\t\t\t` URL : ${url}`,\n\t\t\t\t\t` Bucket : ${routeId.bucketRoute}`,\n\t\t\t\t\t` Major parameter: ${routeId.majorParameter}`,\n\t\t\t\t\t` Hash : ${this.hash}`,\n\t\t\t\t\t` Limit : ${Number.POSITIVE_INFINITY}`,\n\t\t\t\t\t` Retry After : ${retryAfter}ms`,\n\t\t\t\t\t` Sublimit : None`,\n\t\t\t\t].join('\\n'),\n\t\t\t);\n\n\t\t\t// We are bypassing all other limits, but an encountered limit should be respected (it's probably a non-punished rate limit anyways)\n\t\t\tawait sleep(retryAfter);\n\n\t\t\t// Since this is not a server side issue, the next request should pass, so we don't bump the retries counter\n\t\t\treturn this.runRequest(routeId, url, options, requestData, retries);\n\t\t} else {\n\t\t\tconst handled = await handleErrors(this.manager, res, method, url, requestData, retries);\n\t\t\tif (handled === null) {\n\t\t\t\t// eslint-disable-next-line no-param-reassign\n\t\t\t\treturn this.runRequest(routeId, url, options, requestData, ++retries);\n\t\t\t}\n\n\t\t\treturn handled;\n\t\t}\n\t}\n}\n","import { AsyncQueue } from '@sapphire/async-queue';\nimport type { RequestInit } from 'undici';\nimport type { REST } from '../REST.js';\nimport type { IHandler } from '../interfaces/Handler.js';\nimport { RESTEvents } from '../utils/constants.js';\nimport type { RateLimitData, ResponseLike, HandlerRequestData, RouteData } from '../utils/types.js';\nimport { hasSublimit, onRateLimit, sleep } from '../utils/utils.js';\nimport { handleErrors, incrementInvalidCount, makeNetworkRequest } from './Shared.js';\n\nconst enum QueueType {\n\tStandard,\n\tSublimit,\n}\n\n/**\n * The structure used to handle sequential requests for a given bucket\n */\nexport class SequentialHandler implements IHandler {\n\t/**\n\t * {@inheritDoc IHandler.id}\n\t */\n\tpublic readonly id: string;\n\n\t/**\n\t * The time this rate limit bucket will reset\n\t */\n\tprivate reset = -1;\n\n\t/**\n\t * The remaining requests that can be made before we are rate limited\n\t */\n\tprivate remaining = 1;\n\n\t/**\n\t * The total number of requests that can be made before we are rate limited\n\t */\n\tprivate limit = Number.POSITIVE_INFINITY;\n\n\t/**\n\t * The interface used to sequence async requests sequentially\n\t */\n\t#asyncQueue = new AsyncQueue();\n\n\t/**\n\t * The interface used to sequence sublimited async requests sequentially\n\t */\n\t#sublimitedQueue: AsyncQueue | null = null;\n\n\t/**\n\t * A promise wrapper for when the sublimited queue is finished being processed or null when not being processed\n\t */\n\t#sublimitPromise: { promise: Promise<void>; resolve(): void } | null = null;\n\n\t/**\n\t * Whether the sublimit queue needs to be shifted in the finally block\n\t */\n\t#shiftSublimit = false;\n\n\t/**\n\t * @param manager - The request manager\n\t * @param hash - The hash that this RequestHandler handles\n\t * @param majorParameter - The major parameter for this handler\n\t */\n\tpublic constructor(\n\t\tprivate readonly manager: REST,\n\t\tprivate readonly hash: string,\n\t\tprivate readonly majorParameter: string,\n\t) {\n\t\tthis.id = `${hash}:${majorParameter}`;\n\t}\n\n\t/**\n\t * {@inheritDoc IHandler.inactive}\n\t */\n\tpublic get inactive(): boolean {\n\t\treturn (\n\t\t\tthis.#asyncQueue.remaining === 0 &&\n\t\t\t(this.#sublimitedQueue === null || this.#sublimitedQueue.remaining === 0) &&\n\t\t\t!this.limited\n\t\t);\n\t}\n\n\t/**\n\t * If the rate limit bucket is currently limited by the global limit\n\t */\n\tprivate get globalLimited(): boolean {\n\t\treturn this.manager.globalRemaining <= 0 && Date.now() < this.manager.globalReset;\n\t}\n\n\t/**\n\t * If the rate limit bucket is currently limited by its limit\n\t */\n\tprivate get localLimited(): boolean {\n\t\treturn this.remaining <= 0 && Date.now() < this.reset;\n\t}\n\n\t/**\n\t * If the rate limit bucket is currently limited\n\t */\n\tprivate get limited(): boolean {\n\t\treturn this.globalLimited || this.localLimited;\n\t}\n\n\t/**\n\t * The time until queued requests can continue\n\t */\n\tprivate get timeToReset(): number {\n\t\treturn this.reset + this.manager.options.offset - Date.now();\n\t}\n\n\t/**\n\t * Emits a debug message\n\t *\n\t * @param message - The message to debug\n\t */\n\tprivate debug(message: string) {\n\t\tthis.manager.emit(RESTEvents.Debug, `[REST ${this.id}] ${message}`);\n\t}\n\n\t/**\n\t * Delay all requests for the specified amount of time, handling global rate limits\n\t *\n\t * @param time - The amount of time to delay all requests for\n\t */\n\tprivate async globalDelayFor(time: number): Promise<void> {\n\t\tawait sleep(time);\n\t\tthis.manager.globalDelay = null;\n\t}\n\n\t/**\n\t * {@inheritDoc IHandler.queueRequest}\n\t */\n\tpublic async queueRequest(\n\t\trouteId: RouteData,\n\t\turl: string,\n\t\toptions: RequestInit,\n\t\trequestData: HandlerRequestData,\n\t): Promise<ResponseLike> {\n\t\tlet queue = this.#asyncQueue;\n\t\tlet queueType = QueueType.Standard;\n\t\t// Separate sublimited requests when already sublimited\n\t\tif (this.#sublimitedQueue && hasSublimit(routeId.bucketRoute, requestData.body, options.method)) {\n\t\t\tqueue = this.#sublimitedQueue!;\n\t\t\tqueueType = QueueType.Sublimit;\n\t\t}\n\n\t\t// Wait for any previous requests to be completed before this one is run\n\t\tawait queue.wait({ signal: requestData.signal });\n\t\t// This set handles retroactively sublimiting requests\n\t\tif (queueType === QueueType.Standard) {\n\t\t\tif (this.#sublimitedQueue && hasSublimit(routeId.bucketRoute, requestData.body, options.method)) {\n\t\t\t\t/**\n\t\t\t\t * Remove the request from the standard queue, it should never be possible to get here while processing the\n\t\t\t\t * sublimit queue so there is no need to worry about shifting the wrong request\n\t\t\t\t */\n\t\t\t\tqueue = this.#sublimitedQueue!;\n\t\t\t\tconst wait = queue.wait();\n\t\t\t\tthis.#asyncQueue.shift();\n\t\t\t\tawait wait;\n\t\t\t} else if (this.#sublimitPromise) {\n\t\t\t\t// Stall requests while the sublimit queue gets processed\n\t\t\t\tawait this.#sublimitPromise.promise;\n\t\t\t}\n\t\t}\n\n\t\ttry {\n\t\t\t// Make the request, and return the results\n\t\t\treturn await this.runRequest(routeId, url, options, requestData);\n\t\t} finally {\n\t\t\t// Allow the next request to fire\n\t\t\tqueue.shift();\n\t\t\tif (this.#shiftSublimit) {\n\t\t\t\tthis.#shiftSublimit = false;\n\t\t\t\tthis.#sublimitedQueue?.shift();\n\t\t\t}\n\n\t\t\t// If this request is the last request in a sublimit\n\t\t\tif (this.#sublimitedQueue?.remaining === 0) {\n\t\t\t\tthis.#sublimitPromise?.resolve();\n\t\t\t\tthis.#sublimitedQueue = null;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * The method that actually makes the request to the api, and updates info about the bucket accordingly\n\t *\n\t * @param routeId - The generalized api route with literal ids for major parameters\n\t * @param url - The fully resolved url to make the request to\n\t * @param options - The fetch options needed to make the request\n\t * @param requestData - Extra data from the user's request needed for errors and additional processing\n\t * @param retries - The number of retries this request has already attempted (recursion)\n\t */\n\tprivate async runRequest(\n\t\trouteId: RouteData,\n\t\turl: string,\n\t\toptions: RequestInit,\n\t\trequestData: HandlerRequestData,\n\t\tretries = 0,\n\t): Promise<ResponseLike> {\n\t\t/*\n\t\t * After calculations have been done, pre-emptively stop further requests\n\t\t * Potentially loop until this task can run if e.g. the global rate limit is hit twice\n\t\t */\n\t\twhile (this.limited) {\n\t\t\tconst isGlobal = this.globalLimited;\n\t\t\tlet limit: number;\n\t\t\tlet timeout: number;\n\t\t\tlet delay: Promise<void>;\n\n\t\t\tif (isGlobal) {\n\t\t\t\t// Set RateLimitData based on the global limit\n\t\t\t\tlimit = this.manager.options.globalRequestsPerSecond;\n\t\t\t\ttimeout = this.manager.globalReset + this.manager.options.offset - Date.now();\n\t\t\t\t// If this is the first task to reach the global timeout, set the global delay\n\t\t\t\tif (!this.manager.globalDelay) {\n\t\t\t\t\t// The global delay function clears the global delay state when it is resolved\n\t\t\t\t\tthis.manager.globalDelay = this.globalDelayFor(timeout);\n\t\t\t\t}\n\n\t\t\t\tdelay = this.manager.globalDelay;\n\t\t\t} else {\n\t\t\t\t// Set RateLimitData based on the route-specific limit\n\t\t\t\tlimit = this.limit;\n\t\t\t\ttimeout = this.timeToReset;\n\t\t\t\tdelay = sleep(timeout);\n\t\t\t}\n\n\t\t\tconst rateLimitData: RateLimitData = {\n\t\t\t\ttimeToReset: timeout,\n\t\t\t\tlimit,\n\t\t\t\tmethod: options.method ?? 'get',\n\t\t\t\thash: this.hash,\n\t\t\t\turl,\n\t\t\t\troute: routeId.bucketRoute,\n\t\t\t\tmajorParameter: this.majorParameter,\n\t\t\t\tglobal: isGlobal,\n\t\t\t};\n\t\t\t// Let library users know they have hit a rate limit\n\t\t\tthis.manager.emit(RESTEvents.RateLimited, rateLimitData);\n\t\t\t// Determine whether a RateLimitError should be thrown\n\t\t\tawait onRateLimit(this.manager, rateLimitData);\n\t\t\t// When not erroring, emit debug for what is happening\n\t\t\tif (isGlobal) {\n\t\t\t\tthis.debug(`Global rate limit hit, blocking all requests for ${timeout}ms`);\n\t\t\t} else {\n\t\t\t\tthis.debug(`Waiting ${timeout}ms for rate limit to pass`);\n\t\t\t}\n\n\t\t\t// Wait the remaining time left before the rate limit resets\n\t\t\tawait delay;\n\t\t}\n\n\t\t// As the request goes out, update the global usage information\n\t\tif (!this.manager.globalReset || this.manager.globalReset < Date.now()) {\n\t\t\tthis.manager.globalReset = Date.now() + 1_000;\n\t\t\tthis.manager.globalRemaining = this.manager.options.globalRequestsPerSecond;\n\t\t}\n\n\t\tthis.manager.globalRemaining--;\n\n\t\tconst method = options.method ?? 'get';\n\n\t\tconst res = await makeNetworkRequest(this.manager, routeId, url, options, requestData, retries);\n\n\t\t// Retry requested\n\t\tif (res === null) {\n\t\t\t// eslint-disable-next-line no-param-reassign\n\t\t\treturn this.runRequest(routeId, url, options, requestData, ++retries);\n\t\t}\n\n\t\tconst status = res.status;\n\t\tlet retryAfter = 0;\n\n\t\tconst limit = res.headers.get('X-RateLimit-Limit');\n\t\tconst remaining = res.headers.get('X-RateLimit-Remaining');\n\t\tconst reset = res.headers.get('X-RateLimit-Reset-After');\n\t\tconst hash = res.headers.get('X-RateLimit-Bucket');\n\t\tconst retry = res.headers.get('Retry-After');\n\n\t\t// Update the total number of requests that can be made before the rate limit resets\n\t\tthis.limit = limit ? Number(limit) : Number.POSITIVE_INFINITY;\n\t\t// Update the number of remaining requests that can be made before the rate limit resets\n\t\tthis.remaining = remaining ? Number(remaining) : 1;\n\t\t// Update the time when this rate limit resets (reset-after is in seconds)\n\t\tthis.reset = reset ? Number(reset) * 1_000 + Date.now() + this.manager.options.offset : Date.now();\n\n\t\t// Amount of time in milliseconds until we should retry if rate limited (globally or otherwise)\n\t\tif (retry) retryAfter = Number(retry) * 1_000 + this.manager.options.offset;\n\n\t\t// Handle buckets via the hash header retroactively\n\t\tif (hash && hash !== this.hash) {\n\t\t\t// Let library users know when rate limit buckets have been updated\n\t\t\tthis.debug(['Received bucket hash update', ` Old Hash : ${this.hash}`, ` New Hash : ${hash}`].join('\\n'));\n\t\t\t// This queue will eventually be eliminated via attrition\n\t\t\tthis.manager.hashes.set(`${method}:${routeId.bucketRoute}`, { value: hash, lastAccess: Date.now() });\n\t\t} else if (hash) {\n\t\t\t// Handle the case where hash value doesn't change\n\t\t\t// Fetch the hash data from the manager\n\t\t\tconst hashData = this.manager.hashes.get(`${method}:${routeId.bucketRoute}`);\n\n\t\t\t// When fetched, update the last access of the hash\n\t\t\tif (hashData) {\n\t\t\t\thashData.lastAccess = Date.now();\n\t\t\t}\n\t\t}\n\n\t\t// Handle retryAfter, which means we have actually hit a rate limit\n\t\tlet sublimitTimeout: number | null = null;\n\t\tif (retryAfter > 0) {\n\t\t\tif (res.headers.has('X-RateLimit-Global')) {\n\t\t\t\tthis.manager.globalRemaining = 0;\n\t\t\t\tthis.manager.globalReset = Date.now() + retryAfter;\n\t\t\t} else if (!this.localLimited) {\n\t\t\t\t/*\n\t\t\t\t * This is a sublimit (e.g. 2 channel name changes/10 minutes) since the headers don't indicate a\n\t\t\t\t * route-wide rate limit. Don't update remaining or reset to avoid rate limiting the whole\n\t\t\t\t * endpoint, just set a reset time on the request itself to avoid retrying too soon.\n\t\t\t\t */\n\t\t\t\tsublimitTimeout = retryAfter;\n\t\t\t}\n\t\t}\n\n\t\t// Count the invalid requests\n\t\tif (status === 401 || status === 403 || status === 429) {\n\t\t\tincrementInvalidCount(this.manager);\n\t\t}\n\n\t\tif (res.ok) {\n\t\t\treturn res;\n\t\t} else if (status === 429) {\n\t\t\t// A rate limit was hit - this may happen if the route isn't associated with an official bucket hash yet, or when first globally rate limited\n\t\t\tconst isGlobal = this.globalLimited;\n\t\t\tlet limit: number;\n\t\t\tlet timeout: number;\n\n\t\t\tif (isGlobal) {\n\t\t\t\t// Set RateLimitData based on the global limit\n\t\t\t\tlimit = this.manager.options.globalRequestsPerSecond;\n\t\t\t\ttimeout = this.manager.globalReset + this.manager.options.offset - Date.now();\n\t\t\t} else {\n\t\t\t\t// Set RateLimitData based on the route-specific limit\n\t\t\t\tlimit = this.limit;\n\t\t\t\ttimeout = this.timeToReset;\n\t\t\t}\n\n\t\t\tawait onRateLimit(this.manager, {\n\t\t\t\ttimeToReset: timeout,\n\t\t\t\tlimit,\n\t\t\t\tmethod,\n\t\t\t\thash: this.hash,\n\t\t\t\turl,\n\t\t\t\troute: routeId.bucketRoute,\n\t\t\t\tmajorParameter: this.majorParameter,\n\t\t\t\tglobal: isGlobal,\n\t\t\t});\n\t\t\tthis.debug(\n\t\t\t\t[\n\t\t\t\t\t'Encountered unexpected 429 rate limit',\n\t\t\t\t\t` Global : ${isGlobal.toString()}`,\n\t\t\t\t\t` Method : ${method}`,\n\t\t\t\t\t` URL : ${url}`,\n\t\t\t\t\t` Bucket : ${routeId.bucketRoute}`,\n\t\t\t\t\t` Major parameter: ${routeId.majorParameter}`,\n\t\t\t\t\t` Hash : ${this.hash}`,\n\t\t\t\t\t` Limit : ${limit}`,\n\t\t\t\t\t` Retry After : ${retryAfter}ms`,\n\t\t\t\t\t` Sublimit : ${sublimitTimeout ? `${sublimitTimeout}ms` : 'None'}`,\n\t\t\t\t].join('\\n'),\n\t\t\t);\n\t\t\t// If caused by a sublimit, wait it out here so other requests on the route can be handled\n\t\t\tif (sublimitTimeout) {\n\t\t\t\t// Normally the sublimit queue will not exist, however, if a sublimit is hit while in the sublimit queue, it will\n\t\t\t\tconst firstSublimit = !this.#sublimitedQueue;\n\t\t\t\tif (firstSublimit) {\n\t\t\t\t\tthis.#sublimitedQueue = new AsyncQueue();\n\t\t\t\t\tvoid this.#sublimitedQueue.wait();\n\t\t\t\t\tthis.#asyncQueue.shift();\n\t\t\t\t}\n\n\t\t\t\tthis.#sublimitPromise?.resolve();\n\t\t\t\tthis.#sublimitPromise = null;\n\t\t\t\tawait sleep(sublimitTimeout);\n\t\t\t\tlet resolve: () => void;\n\t\t\t\t// eslint-disable-next-line promise/param-names, no-promise-executor-return\n\t\t\t\tconst promise = new Promise<void>((res) => (resolve = res));\n\t\t\t\tthis.#sublimitPromise = { promise, resolve: resolve! };\n\t\t\t\tif (firstSublimit) {\n\t\t\t\t\t// Re-queue this request so it can be shifted by the finally\n\t\t\t\t\tawait this.#asyncQueue.wait();\n\t\t\t\t\tthis.#shiftSublimit = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Since this is not a server side issue, the next request should pass, so we don't bump the retries counter\n\t\t\treturn this.runRequest(routeId, url, options, requestData, retries);\n\t\t} else {\n\t\t\tconst handled = await handleErrors(this.manager, res, method, url, requestData, retries);\n\t\t\tif (handled === null) {\n\t\t\t\t// eslint-disable-next-line no-param-reassign\n\t\t\t\treturn this.runRequest(routeId, url, options, requestData, ++retries);\n\t\t\t}\n\n\t\t\treturn handled;\n\t\t}\n\t}\n}\n","export * from './lib/CDN.js';\nexport * from './lib/errors/DiscordAPIError.js';\nexport * from './lib/errors/HTTPError.js';\nexport * from './lib/errors/RateLimitError.js';\nexport * from './lib/REST.js';\nexport * from './lib/utils/constants.js';\nexport * from './lib/utils/types.js';\nexport { calculateUserDefaultAvatarIndex, makeURLSearchParams, parseResponse } from './lib/utils/utils.js';\n\n/**\n * The {@link https://github.com/discordjs/discord.js/blob/main/packages/rest/#readme | @discordjs/rest} version\n * that you are currently using.\n */\n// This needs to explicitly be `string` so it is not typed as a \"const string\" that gets injected by esbuild\nexport const version = '2.0.1' as string;\n","import { setDefaultStrategy } from './environment.js';\n\nsetDefaultStrategy(fetch);\n\nexport * from './shared.js';\n"],"mappings":"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","names":["RESTEvents","RequestMethod","limit","res"]}
\ No newline at end of file |