@discordjs/rest 0.4.0-dev.1648166871.cedd053 → 0.4.0-dev.1649030897-5748dbe

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,8 +1,928 @@
1
- var be=Object.create;var I=Object.defineProperty;var ye=Object.getOwnPropertyDescriptor;var ve=Object.getOwnPropertyNames;var we=Object.getPrototypeOf,Ee=Object.prototype.hasOwnProperty;var Le=(r,e,t)=>e in r?I(r,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):r[e]=t;var ie=r=>I(r,"__esModule",{value:!0}),d=(r,e)=>I(r,"name",{value:e,configurable:!0});var xe=(r,e)=>()=>(e||r((e={exports:{}}).exports,e),e.exports),De=(r,e)=>{for(var t in e)I(r,t,{get:e[t],enumerable:!0})},re=(r,e,t,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of ve(e))!Ee.call(r,i)&&(t||i!=="default")&&I(r,i,{get:()=>e[i],enumerable:!(s=ye(e,i))||s.enumerable});return r},F=(r,e)=>re(ie(I(r!=null?be(we(r)):{},"default",!e&&r&&r.__esModule?{get:()=>r.default,enumerable:!0}:{value:r,enumerable:!0})),r),Se=(r=>(e,t)=>r&&r.get(e)||(t=re(ie({}),e,1),r&&r.set(e,t),t))(typeof WeakMap!="undefined"?new WeakMap:0);var l=(r,e,t)=>(Le(r,typeof e!="symbol"?e+"":e,t),t),ne=(r,e,t)=>{if(!e.has(r))throw TypeError("Cannot "+t)};var u=(r,e,t)=>(ne(r,e,"read from private field"),t?t.call(r):e.get(r)),x=(r,e,t)=>{if(e.has(r))throw TypeError("Cannot add the same private member more than once");e instanceof WeakSet?e.add(r):e.set(r,t)},f=(r,e,t,s)=>(ne(r,e,"write to private field"),s?s.call(r,t):e.set(r,t),t);var ae=xe((Ae,ke)=>{ke.exports={name:"@discordjs/rest",version:"0.4.0-dev",description:"The REST API for discord.js",scripts:{build:"tsup && tsc --emitDeclarationOnly --incremental",test:"jest --pass-with-no-tests --collect-coverage",lint:"prettier --check . && eslint src __tests__ --ext mjs,js,ts",format:"prettier --write . && eslint src __tests__ --ext mjs,js,ts --fix",docs:"typedoc --json docs/typedoc-out.json src/index.ts && node scripts/docs.mjs",prepublishOnly:"yarn build && yarn lint && yarn test",changelog:"git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/rest/*'"},main:"./dist/index.js",module:"./dist/index.mjs",typings:"./dist/index.d.ts",exports:{import:"./dist/index.mjs",require:"./dist/index.js",types:"./dist/index.d.ts"},directories:{lib:"src",test:"__tests__"},files:["dist"],contributors:["Crawl <icrawltogo@gmail.com>","Amish Shah <amishshah.2k@gmail.com>","SpaceEEC <spaceeec@yahoo.com>","Vlad Frangu <kingdgrizzle@gmail.com>","Antonio Roman <kyradiscord@gmail.com>"],license:"Apache-2.0",keywords:["discord","api","rest","discordapp","discordjs"],repository:{type:"git",url:"git+https://github.com/discordjs/discord.js.git"},bugs:{url:"https://github.com/discordjs/discord.js/issues"},homepage:"https://discord.js.org",dependencies:{"@discordjs/collection":"workspace:^","@sapphire/async-queue":"^1.2.0","@sapphire/snowflake":"^3.1.0","@types/node-fetch":"^2.5.12","discord-api-types":"^0.29.0","form-data":"^4.0.0","node-fetch":"^2.6.7",tslib:"^2.3.1"},devDependencies:{"@babel/core":"^7.17.2","@babel/plugin-proposal-decorators":"^7.17.2","@babel/preset-env":"^7.16.11","@babel/preset-typescript":"^7.16.7","@discordjs/ts-docgen":"^0.3.4","@types/jest":"^27.4.0","@typescript-eslint/eslint-plugin":"^5.11.0","@typescript-eslint/parser":"^5.11.0","babel-plugin-const-enum":"^1.2.0","babel-plugin-transform-typescript-metadata":"^0.3.2",eslint:"^8.9.0","eslint-config-marine":"^9.3.2","eslint-config-prettier":"^8.3.0","eslint-plugin-prettier":"^4.0.0",jest:"^27.5.1",nock:"^13.2.4",prettier:"^2.5.1",tsup:"^5.11.13",typedoc:"^0.22.11",typescript:"^4.5.5"},engines:{node:">=16.9.0"},publishConfig:{access:"public"}}});var qe={};De(qe,{ALLOWED_EXTENSIONS:()=>X,ALLOWED_SIZES:()=>_,ALLOWED_STICKER_EXTENSIONS:()=>z,CDN:()=>P,DefaultRestOptions:()=>D,DefaultUserAgent:()=>G,DiscordAPIError:()=>w,HTTPError:()=>U,REST:()=>Y,RESTEvents:()=>T,RateLimitError:()=>S,RequestManager:()=>B,RequestMethod:()=>M});var oe=require("discord-api-types/v10"),le=ae(),G=`DiscordBot (${le.homepage}, ${le.version})`,D={agent:{},api:"https://discord.com/api",cdn:"https://cdn.discordapp.com",headers:{},invalidRequestWarningInterval:0,globalRequestsPerSecond:50,offset:50,rejectOnRateLimit:null,retries:3,timeout:15e3,userAgentAppendix:`Node.js ${process.version}`,version:oe.APIVersion,hashSweepInterval:144e5,hashLifetime:864e5,handlerSweepInterval:36e5},T=(m=>(m.Debug="restDebug",m.InvalidRequestWarning="invalidRequestWarning",m.RateLimited="rateLimited",m.Request="request",m.Response="response",m.HashSweep="hashSweep",m.HandlerSweep="handlerSweep",m))(T||{}),X=["webp","png","jpg","jpeg","gif"],z=["png","json"],_=[16,32,64,128,256,512,1024,2048,4096];var P=class{constructor(e=D.cdn){this.base=e}appAsset(e,t,s){return this.makeURL(`/app-assets/${e}/${t}`,s)}appIcon(e,t,s){return this.makeURL(`/app-icons/${e}/${t}`,s)}avatar(e,t,s){return this.dynamicMakeURL(`/avatars/${e}/${t}`,t,s)}banner(e,t,s){return this.dynamicMakeURL(`/banners/${e}/${t}`,t,s)}channelIcon(e,t,s){return this.makeURL(`/channel-icons/${e}/${t}`,s)}defaultAvatar(e){return this.makeURL(`/embed/avatars/${e}`,{extension:"png"})}discoverySplash(e,t,s){return this.makeURL(`/discovery-splashes/${e}/${t}`,s)}emoji(e,t){return this.makeURL(`/emojis/${e}`,{extension:t})}guildMemberAvatar(e,t,s,i){return this.dynamicMakeURL(`/guilds/${e}/users/${t}/avatars/${s}`,s,i)}icon(e,t,s){return this.dynamicMakeURL(`/icons/${e}/${t}`,t,s)}roleIcon(e,t,s){return this.makeURL(`/role-icons/${e}/${t}`,s)}splash(e,t,s){return this.makeURL(`/splashes/${e}/${t}`,s)}sticker(e,t){return this.makeURL(`/stickers/${e}`,{allowedExtensions:z,extension:t??"png"})}stickerPackBanner(e,t){return this.makeURL(`/app-assets/710982414301790216/store/${e}`,t)}teamIcon(e,t,s){return this.makeURL(`/team-icons/${e}/${t}`,s)}guildScheduledEventCover(e,t,s){return this.makeURL(`/guild-events/${e}/${t}`,s)}dynamicMakeURL(e,t,{forceStatic:s=!1,...i}={}){return this.makeURL(e,!s&&t.startsWith("a_")?{...i,extension:"gif"}:i)}makeURL(e,{allowedExtensions:t=X,extension:s="webp",size:i}={}){if(s=String(s).toLowerCase(),!t.includes(s))throw new RangeError(`Invalid extension provided: ${s}
2
- Must be one of: ${t.join(", ")}`);if(i&&!_.includes(i))throw new RangeError(`Invalid size provided: ${i}
3
- Must be one of: ${_.join(", ")}`);let n=new URL(`${this.base}${e}.${s}`);return i&&n.searchParams.set("size",String(i)),n.toString()}};d(P,"CDN");function Ie(r){return Reflect.has(r,"_errors")}d(Ie,"isErrorGroupWrapper");function $e(r){return typeof Reflect.get(r,"message")=="string"}d($e,"isErrorResponse");var w=class extends Error{constructor(e,t,s,i,n,a){super(w.getMessage(e));this.rawError=e;this.code=t;this.status=s;this.method=i;this.url=n;l(this,"requestBody");this.requestBody={files:a.files,json:a.body}}get name(){return`${w.name}[${this.code}]`}static getMessage(e){let t="";return"code"in e?(e.errors&&(t=[...this.flattenDiscordError(e.errors)].join(`
4
- `)),e.message&&t?`${e.message}
5
- ${t}`:e.message||t||"Unknown Error"):e.error_description??"No Description"}static*flattenDiscordError(e,t=""){if($e(e))return yield`${t.length?`${t}[${e.code}]`:`${e.code}`}: ${e.message}`.trim();for(let[s,i]of Object.entries(e)){let n=s.startsWith("_")?t:t?Number.isNaN(Number(s))?`${t}.${s}`:`${t}[${s}]`:s;if(typeof i=="string")yield i;else if(Ie(i))for(let a of i._errors)yield*this.flattenDiscordError(a,n);else yield*this.flattenDiscordError(i,n)}}};d(w,"DiscordAPIError");var U=class extends Error{constructor(e,t,s,i,n,a){super(e);this.name=t;this.status=s;this.method=i;this.url=n;l(this,"requestBody");this.requestBody={files:a.files,json:a.body}}};d(U,"HTTPError");var S=class extends Error{constructor({timeToReset:e,limit:t,method:s,hash:i,url:n,route:a,majorParameter:m,global:L}){super();l(this,"timeToReset");l(this,"limit");l(this,"method");l(this,"hash");l(this,"url");l(this,"route");l(this,"majorParameter");l(this,"global");this.timeToReset=e,this.limit=t,this.method=s,this.hash=i,this.url=n,this.route=a,this.majorParameter=m,this.global=L}get name(){return`${S.name}[${this.route}]`}};d(S,"RateLimitError");var H=F(require("@discordjs/collection")),me=F(require("form-data")),pe=require("@sapphire/snowflake"),de=require("events"),ce=require("https"),he=require("http");var K=require("timers/promises"),Z=require("@sapphire/async-queue"),ue=F(require("node-fetch"));function J(r){return r.headers.get("Content-Type")?.startsWith("application/json")?r.json():r.arrayBuffer()}d(J,"parseResponse");function Q(r,e,t){if(r==="/channels/:id"){if(typeof e!="object"||e===null||t!=="patch")return!1;let s=e;return["name","topic"].some(i=>Reflect.has(s,i))}return!0}d(Q,"hasSublimit");var N=0,W=null;var E,c,b,$,C=class{constructor(e,t,s){this.manager=e;this.hash=t;this.majorParameter=s;l(this,"id");l(this,"reset",-1);l(this,"remaining",1);l(this,"limit",1/0);x(this,E,new Z.AsyncQueue);x(this,c,null);x(this,b,null);x(this,$,!1);this.id=`${t}:${s}`}get inactive(){return u(this,E).remaining===0&&(u(this,c)===null||u(this,c).remaining===0)&&!this.limited}get globalLimited(){return this.manager.globalRemaining<=0&&Date.now()<this.manager.globalReset}get localLimited(){return this.remaining<=0&&Date.now()<this.reset}get limited(){return this.globalLimited||this.localLimited}get timeToReset(){return this.reset+this.manager.options.offset-Date.now()}debug(e){this.manager.emit("restDebug",`[REST ${this.id}] ${e}`)}async globalDelayFor(e){await(0,K.setTimeout)(e,void 0,{ref:!1}),this.manager.globalDelay=null}async onRateLimit(e){let{options:t}=this.manager;if(!t.rejectOnRateLimit)return;if(typeof t.rejectOnRateLimit=="function"?await t.rejectOnRateLimit(e):t.rejectOnRateLimit.some(i=>e.route.startsWith(i.toLowerCase())))throw new S(e)}async queueRequest(e,t,s,i){let n=u(this,E),a=0;if(u(this,c)&&Q(e.bucketRoute,i.body,s.method)&&(n=u(this,c),a=1),await n.wait(),a===0)if(u(this,c)&&Q(e.bucketRoute,i.body,s.method)){n=u(this,c);let m=n.wait();u(this,E).shift(),await m}else u(this,b)&&await u(this,b).promise;try{return await this.runRequest(e,t,s,i)}finally{n.shift(),u(this,$)&&(f(this,$,!1),u(this,c)?.shift()),u(this,c)?.remaining===0&&(u(this,b)?.resolve(),f(this,c,null))}}async runRequest(e,t,s,i,n=0){for(;this.limited;){let p=this.globalLimited,v,h,k;p?(v=this.manager.options.globalRequestsPerSecond,h=this.manager.globalReset+this.manager.options.offset-Date.now(),this.manager.globalDelay||(this.manager.globalDelay=this.globalDelayFor(h)),k=this.manager.globalDelay):(v=this.limit,h=this.timeToReset,k=(0,K.setTimeout)(h));let j={timeToReset:h,limit:v,method:s.method??"get",hash:this.hash,url:t,route:e.bucketRoute,majorParameter:this.majorParameter,global:p};this.manager.emit("rateLimited",j),await this.onRateLimit(j),p?this.debug(`Global rate limit hit, blocking all requests for ${h}ms`):this.debug(`Waiting ${h}ms for rate limit to pass`),await k}(!this.manager.globalReset||this.manager.globalReset<Date.now())&&(this.manager.globalReset=Date.now()+1e3,this.manager.globalRemaining=this.manager.options.globalRequestsPerSecond),this.manager.globalRemaining--;let a=s.method??"get";this.manager.listenerCount("request")&&this.manager.emit("request",{method:a,path:e.original,route:e.bucketRoute,options:s,data:i,retries:n});let m=new AbortController,L=setTimeout(()=>m.abort(),this.manager.options.timeout).unref(),o;try{o=await(0,ue.default)(t,{...s,signal:m.signal})}catch(p){if(p instanceof Error&&p.name==="AbortError"&&n!==this.manager.options.retries)return await this.runRequest(e,t,s,i,++n);throw p}finally{clearTimeout(L)}this.manager.listenerCount("response")&&this.manager.emit("response",{method:a,path:e.original,route:e.bucketRoute,options:s,data:i,retries:n},o.clone());let g=0,y=o.headers.get("X-RateLimit-Limit"),ee=o.headers.get("X-RateLimit-Remaining"),te=o.headers.get("X-RateLimit-Reset-After"),O=o.headers.get("X-RateLimit-Bucket"),se=o.headers.get("Retry-After");if(this.limit=y?Number(y):1/0,this.remaining=ee?Number(ee):1,this.reset=te?Number(te)*1e3+Date.now()+this.manager.options.offset:Date.now(),se&&(g=Number(se)*1e3+this.manager.options.offset),O&&O!==this.hash)this.debug(["Received bucket hash update",` Old Hash : ${this.hash}`,` New Hash : ${O}`].join(`
6
- `)),this.manager.hashes.set(`${a}:${e.bucketRoute}`,{value:O,lastAccess:Date.now()});else if(O){let p=this.manager.hashes.get(`${a}:${e.bucketRoute}`);p&&(p.lastAccess=Date.now())}let A=null;if(g>0&&(o.headers.get("X-RateLimit-Global")?(this.manager.globalRemaining=0,this.manager.globalReset=Date.now()+g):this.localLimited||(A=g)),(o.status===401||o.status===403||o.status===429)&&((!W||W<Date.now())&&(W=Date.now()+1e3*60*10,N=0),N++,this.manager.options.invalidRequestWarningInterval>0&&N%this.manager.options.invalidRequestWarningInterval===0&&this.manager.emit("invalidRequestWarning",{count:N,remainingTime:W-Date.now()})),o.ok)return J(o);if(o.status===429){let p=this.globalLimited,v,h;if(p?(v=this.manager.options.globalRequestsPerSecond,h=this.manager.globalReset+this.manager.options.offset-Date.now()):(v=this.limit,h=this.timeToReset),await this.onRateLimit({timeToReset:h,limit:v,method:a,hash:this.hash,url:t,route:e.bucketRoute,majorParameter:this.majorParameter,global:p}),this.debug(["Encountered unexpected 429 rate limit",` Global : ${p.toString()}`,` Method : ${a}`,` URL : ${t}`,` Bucket : ${e.bucketRoute}`,` Major parameter: ${e.majorParameter}`,` Hash : ${this.hash}`,` Limit : ${v}`,` Retry After : ${g}ms`,` Sublimit : ${A?`${A}ms`:"None"}`].join(`
7
- `)),A){let k=!u(this,c);k&&(f(this,c,new Z.AsyncQueue),u(this,c).wait(),u(this,E).shift()),u(this,b)?.resolve(),f(this,b,null),await(0,K.setTimeout)(A,void 0,{ref:!1});let j,fe=new Promise(Re=>j=Re);f(this,b,{promise:fe,resolve:j}),k&&(await u(this,E).wait(),f(this,$,!0))}return this.runRequest(e,t,s,i,n)}else if(o.status>=500&&o.status<600){if(n!==this.manager.options.retries)return this.runRequest(e,t,s,i,++n);throw new U(o.statusText,o.constructor.name,o.status,a,t,i)}else{if(o.status>=400&&o.status<500){o.status===401&&i.auth&&this.manager.setToken(null);let p=await J(o);throw new w(p,"code"in p?p.code:p.error,o.status,a,t,i)}return null}}};d(C,"SequentialHandler"),E=new WeakMap,c=new WeakMap,b=new WeakMap,$=new WeakMap;var M=(n=>(n.Delete="delete",n.Get="get",n.Patch="patch",n.Post="post",n.Put="put",n))(M||{}),q,V=class extends de.EventEmitter{constructor(e){super();l(this,"globalRemaining");l(this,"globalDelay",null);l(this,"globalReset",-1);l(this,"hashes",new H.default);l(this,"handlers",new H.default);x(this,q,null);l(this,"hashTimer");l(this,"handlerTimer");l(this,"agent",null);l(this,"options");this.options={...D,...e},this.options.offset=Math.max(0,this.options.offset),this.globalRemaining=this.options.globalRequestsPerSecond,this.setupSweepers()}setupSweepers(){let e=d(t=>{if(t>144e5)throw new Error("Cannot set an interval greater than 4 hours")},"validateMaxInterval");this.options.hashSweepInterval!==0&&this.options.hashSweepInterval!==1/0&&(e(this.options.hashSweepInterval),this.hashTimer=setInterval(()=>{let t=new H.default,s=Date.now();this.hashes.sweep((i,n)=>{if(i.lastAccess===-1)return!1;let a=Math.floor(s-i.lastAccess)>this.options.hashLifetime;return a&&t.set(n,i),this.emit("restDebug",`Hash ${i.value} for ${n} swept due to lifetime being exceeded`),a}),this.emit("hashSweep",t)},this.options.hashSweepInterval).unref()),this.options.handlerSweepInterval!==0&&this.options.handlerSweepInterval!==1/0&&(e(this.options.handlerSweepInterval),this.handlerTimer=setInterval(()=>{let t=new H.default;this.handlers.sweep((s,i)=>{let{inactive:n}=s;return n&&t.set(i,s),this.emit("restDebug",`Handler ${s.id} for ${i} swept due to being inactive`),n}),this.emit("handlerSweep",t)},this.options.handlerSweepInterval).unref())}setToken(e){return f(this,q,e),this}async queueRequest(e){let t=V.generateRouteData(e.fullRoute,e.method),s=this.hashes.get(`${e.method}:${t.bucketRoute}`)??{value:`Global(${e.method}:${t.bucketRoute})`,lastAccess:-1},i=this.handlers.get(`${s.value}:${t.majorParameter}`)??this.createHandler(s.value,t.majorParameter),{url:n,fetchOptions:a}=this.resolveRequest(e);return i.queueRequest(t,n,a,{body:e.body,files:e.files,auth:e.auth!==!1})}createHandler(e,t){let s=new C(this,e,t);return this.handlers.set(s.id,s),s}resolveRequest(e){let{options:t}=this;this.agent??=t.api.startsWith("https")?new ce.Agent({...t.agent,keepAlive:!0}):new he.Agent({...t.agent,keepAlive:!0});let s="";if(e.query){let o=e.query.toString();o!==""&&(s=`?${o}`)}let i={...this.options.headers,"User-Agent":`${G} ${t.userAgentAppendix}`.trim()};if(e.auth!==!1){if(!u(this,q))throw new Error("Expected token to be set for this request, but none was present");i.Authorization=`${e.authPrefix??"Bot"} ${u(this,q)}`}e.reason?.length&&(i["X-Audit-Log-Reason"]=encodeURIComponent(e.reason));let n=`${t.api}${e.versioned===!1?"":`/v${t.version}`}${e.fullRoute}${s}`,a,m={};if(e.files?.length){let o=new me.default;for(let[g,y]of e.files.entries())o.append(y.key??`files[${g}]`,y.data,y.name);if(e.body!=null)if(e.appendToFormData)for(let[g,y]of Object.entries(e.body))o.append(g,y);else o.append("payload_json",JSON.stringify(e.body));a=o,m=o.getHeaders()}else e.body!=null&&(e.passThroughBody?a=e.body:(a=JSON.stringify(e.body),m={"Content-Type":"application/json"}));let L={agent:this.agent,body:a,headers:{...e.headers??{},...m,...i},method:e.method};return{url:n,fetchOptions:L}}clearHashSweeper(){clearInterval(this.hashTimer)}clearHandlerSweeper(){clearInterval(this.handlerTimer)}static generateRouteData(e,t){let i=/^\/(?:channels|guilds|webhooks)\/(\d{16,19})/.exec(e)?.[1]??"global",n=e.replace(/\d{16,19}/g,":id").replace(/\/reactions\/(.*)/,"/reactions/:reaction"),a="";if(t==="delete"&&n==="/channels/:id/messages/:id"){let m=/\d{16,19}$/.exec(e)[0],L=pe.DiscordSnowflake.timestampFrom(m);Date.now()-L>1e3*60*60*24*14&&(a+="/Delete Old Message")}return{majorParameter:i,bucketRoute:n+a,original:e}}},B=V;d(B,"RequestManager"),q=new WeakMap;var ge=require("events");var Y=class extends ge.EventEmitter{constructor(e={}){super();l(this,"cdn");l(this,"requestManager");this.cdn=new P(e.cdn??D.cdn),this.requestManager=new B(e).on("restDebug",this.emit.bind(this,"restDebug")).on("rateLimited",this.emit.bind(this,"rateLimited")).on("invalidRequestWarning",this.emit.bind(this,"invalidRequestWarning")).on("hashSweep",this.emit.bind(this,"hashSweep")),this.on("newListener",(t,s)=>{(t==="request"||t==="response")&&this.requestManager.on(t,s)}),this.on("removeListener",(t,s)=>{(t==="request"||t==="response")&&this.requestManager.off(t,s)})}setToken(e){return this.requestManager.setToken(e),this}get(e,t={}){return this.request({...t,fullRoute:e,method:"get"})}delete(e,t={}){return this.request({...t,fullRoute:e,method:"delete"})}post(e,t={}){return this.request({...t,fullRoute:e,method:"post"})}put(e,t={}){return this.request({...t,fullRoute:e,method:"put"})}patch(e,t={}){return this.request({...t,fullRoute:e,method:"patch"})}request(e){return this.requestManager.queueRequest(e)}};d(Y,"REST");module.exports=Se(qe);0&&(module.exports={ALLOWED_EXTENSIONS,ALLOWED_SIZES,ALLOWED_STICKER_EXTENSIONS,CDN,DefaultRestOptions,DefaultUserAgent,DiscordAPIError,HTTPError,REST,RESTEvents,RateLimitError,RequestManager,RequestMethod});
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
9
+ var __markAsModule = (target) => __defProp(target, "__esModule", { value: true });
10
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
11
+ var __commonJS = (cb, mod) => function __require() {
12
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
13
+ };
14
+ var __export = (target, all) => {
15
+ for (var name in all)
16
+ __defProp(target, name, { get: all[name], enumerable: true });
17
+ };
18
+ var __reExport = (target, module2, copyDefault, desc) => {
19
+ if (module2 && typeof module2 === "object" || typeof module2 === "function") {
20
+ for (let key of __getOwnPropNames(module2))
21
+ if (!__hasOwnProp.call(target, key) && (copyDefault || key !== "default"))
22
+ __defProp(target, key, { get: () => module2[key], enumerable: !(desc = __getOwnPropDesc(module2, key)) || desc.enumerable });
23
+ }
24
+ return target;
25
+ };
26
+ var __toESM = (module2, isNodeMode) => {
27
+ return __reExport(__markAsModule(__defProp(module2 != null ? __create(__getProtoOf(module2)) : {}, "default", !isNodeMode && module2 && module2.__esModule ? { get: () => module2.default, enumerable: true } : { value: module2, enumerable: true })), module2);
28
+ };
29
+ var __toCommonJS = /* @__PURE__ */ ((cache) => {
30
+ return (module2, temp) => {
31
+ return cache && cache.get(module2) || (temp = __reExport(__markAsModule({}), module2, 1), cache && cache.set(module2, temp), temp);
32
+ };
33
+ })(typeof WeakMap !== "undefined" ? /* @__PURE__ */ new WeakMap() : 0);
34
+ var __publicField = (obj, key, value) => {
35
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
36
+ return value;
37
+ };
38
+ var __accessCheck = (obj, member, msg) => {
39
+ if (!member.has(obj))
40
+ throw TypeError("Cannot " + msg);
41
+ };
42
+ var __privateGet = (obj, member, getter) => {
43
+ __accessCheck(obj, member, "read from private field");
44
+ return getter ? getter.call(obj) : member.get(obj);
45
+ };
46
+ var __privateAdd = (obj, member, value) => {
47
+ if (member.has(obj))
48
+ throw TypeError("Cannot add the same private member more than once");
49
+ member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
50
+ };
51
+ var __privateSet = (obj, member, value, setter) => {
52
+ __accessCheck(obj, member, "write to private field");
53
+ setter ? setter.call(obj, value) : member.set(obj, value);
54
+ return value;
55
+ };
56
+
57
+ // package.json
58
+ var require_package = __commonJS({
59
+ "package.json"(exports, module2) {
60
+ module2.exports = {
61
+ name: "@discordjs/rest",
62
+ version: "0.4.0-dev",
63
+ description: "The REST API for discord.js",
64
+ scripts: {
65
+ build: "tsup && tsc --emitDeclarationOnly --incremental",
66
+ test: "jest --pass-with-no-tests --collect-coverage",
67
+ lint: "prettier --check . && eslint src __tests__ --ext mjs,js,ts",
68
+ format: "prettier --write . && eslint src __tests__ --ext mjs,js,ts --fix",
69
+ docs: "typedoc --json docs/typedoc-out.json src/index.ts && node scripts/docs.mjs",
70
+ prepublishOnly: "yarn build && yarn lint && yarn test",
71
+ changelog: "git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/rest/*'"
72
+ },
73
+ main: "./dist/index.js",
74
+ module: "./dist/index.mjs",
75
+ typings: "./dist/index.d.ts",
76
+ exports: {
77
+ import: "./dist/index.mjs",
78
+ require: "./dist/index.js",
79
+ types: "./dist/index.d.ts"
80
+ },
81
+ directories: {
82
+ lib: "src",
83
+ test: "__tests__"
84
+ },
85
+ files: [
86
+ "dist"
87
+ ],
88
+ contributors: [
89
+ "Crawl <icrawltogo@gmail.com>",
90
+ "Amish Shah <amishshah.2k@gmail.com>",
91
+ "SpaceEEC <spaceeec@yahoo.com>",
92
+ "Vlad Frangu <kingdgrizzle@gmail.com>",
93
+ "Antonio Roman <kyradiscord@gmail.com>"
94
+ ],
95
+ license: "Apache-2.0",
96
+ keywords: [
97
+ "discord",
98
+ "api",
99
+ "rest",
100
+ "discordapp",
101
+ "discordjs"
102
+ ],
103
+ repository: {
104
+ type: "git",
105
+ url: "git+https://github.com/discordjs/discord.js.git"
106
+ },
107
+ bugs: {
108
+ url: "https://github.com/discordjs/discord.js/issues"
109
+ },
110
+ homepage: "https://discord.js.org",
111
+ dependencies: {
112
+ "@discordjs/collection": "workspace:^",
113
+ "@sapphire/async-queue": "^1.2.0",
114
+ "@sapphire/snowflake": "^3.1.0",
115
+ "@types/node-fetch": "^2.5.12",
116
+ "discord-api-types": "^0.29.0",
117
+ "form-data": "^4.0.0",
118
+ "node-fetch": "^2.6.7",
119
+ tslib: "^2.3.1"
120
+ },
121
+ devDependencies: {
122
+ "@babel/core": "^7.17.2",
123
+ "@babel/plugin-proposal-decorators": "^7.17.2",
124
+ "@babel/preset-env": "^7.16.11",
125
+ "@babel/preset-typescript": "^7.16.7",
126
+ "@discordjs/ts-docgen": "^0.3.4",
127
+ "@types/jest": "^27.4.0",
128
+ "@typescript-eslint/eslint-plugin": "^5.11.0",
129
+ "@typescript-eslint/parser": "^5.11.0",
130
+ "babel-plugin-const-enum": "^1.2.0",
131
+ "babel-plugin-transform-typescript-metadata": "^0.3.2",
132
+ eslint: "^8.9.0",
133
+ "eslint-config-marine": "^9.3.2",
134
+ "eslint-config-prettier": "^8.3.0",
135
+ "eslint-plugin-prettier": "^4.0.0",
136
+ jest: "^27.5.1",
137
+ nock: "^13.2.4",
138
+ prettier: "^2.5.1",
139
+ tsup: "^5.11.13",
140
+ typedoc: "^0.22.11",
141
+ typescript: "^4.5.5"
142
+ },
143
+ engines: {
144
+ node: ">=16.9.0"
145
+ },
146
+ publishConfig: {
147
+ access: "public"
148
+ }
149
+ };
150
+ }
151
+ });
152
+
153
+ // src/index.ts
154
+ var src_exports = {};
155
+ __export(src_exports, {
156
+ ALLOWED_EXTENSIONS: () => ALLOWED_EXTENSIONS,
157
+ ALLOWED_SIZES: () => ALLOWED_SIZES,
158
+ ALLOWED_STICKER_EXTENSIONS: () => ALLOWED_STICKER_EXTENSIONS,
159
+ CDN: () => CDN,
160
+ DefaultRestOptions: () => DefaultRestOptions,
161
+ DefaultUserAgent: () => DefaultUserAgent,
162
+ DiscordAPIError: () => DiscordAPIError,
163
+ HTTPError: () => HTTPError,
164
+ REST: () => REST,
165
+ RESTEvents: () => RESTEvents,
166
+ RateLimitError: () => RateLimitError,
167
+ RequestManager: () => RequestManager,
168
+ RequestMethod: () => RequestMethod
169
+ });
170
+
171
+ // src/lib/utils/constants.ts
172
+ var import_v10 = require("discord-api-types/v10");
173
+ var Package = require_package();
174
+ var DefaultUserAgent = `DiscordBot (${Package.homepage}, ${Package.version})`;
175
+ var DefaultRestOptions = {
176
+ agent: {},
177
+ api: "https://discord.com/api",
178
+ cdn: "https://cdn.discordapp.com",
179
+ headers: {},
180
+ invalidRequestWarningInterval: 0,
181
+ globalRequestsPerSecond: 50,
182
+ offset: 50,
183
+ rejectOnRateLimit: null,
184
+ retries: 3,
185
+ timeout: 15e3,
186
+ userAgentAppendix: `Node.js ${process.version}`,
187
+ version: import_v10.APIVersion,
188
+ hashSweepInterval: 144e5,
189
+ hashLifetime: 864e5,
190
+ handlerSweepInterval: 36e5
191
+ };
192
+ var RESTEvents = /* @__PURE__ */ ((RESTEvents2) => {
193
+ RESTEvents2["Debug"] = "restDebug";
194
+ RESTEvents2["InvalidRequestWarning"] = "invalidRequestWarning";
195
+ RESTEvents2["RateLimited"] = "rateLimited";
196
+ RESTEvents2["Request"] = "request";
197
+ RESTEvents2["Response"] = "response";
198
+ RESTEvents2["HashSweep"] = "hashSweep";
199
+ RESTEvents2["HandlerSweep"] = "handlerSweep";
200
+ return RESTEvents2;
201
+ })(RESTEvents || {});
202
+ var ALLOWED_EXTENSIONS = ["webp", "png", "jpg", "jpeg", "gif"];
203
+ var ALLOWED_STICKER_EXTENSIONS = ["png", "json"];
204
+ var ALLOWED_SIZES = [16, 32, 64, 128, 256, 512, 1024, 2048, 4096];
205
+
206
+ // src/lib/CDN.ts
207
+ var CDN = class {
208
+ constructor(base = DefaultRestOptions.cdn) {
209
+ this.base = base;
210
+ }
211
+ appAsset(clientId, assetHash, options) {
212
+ return this.makeURL(`/app-assets/${clientId}/${assetHash}`, options);
213
+ }
214
+ appIcon(clientId, iconHash, options) {
215
+ return this.makeURL(`/app-icons/${clientId}/${iconHash}`, options);
216
+ }
217
+ avatar(id, avatarHash, options) {
218
+ return this.dynamicMakeURL(`/avatars/${id}/${avatarHash}`, avatarHash, options);
219
+ }
220
+ banner(id, bannerHash, options) {
221
+ return this.dynamicMakeURL(`/banners/${id}/${bannerHash}`, bannerHash, options);
222
+ }
223
+ channelIcon(channelId, iconHash, options) {
224
+ return this.makeURL(`/channel-icons/${channelId}/${iconHash}`, options);
225
+ }
226
+ defaultAvatar(discriminator) {
227
+ return this.makeURL(`/embed/avatars/${discriminator}`, { extension: "png" });
228
+ }
229
+ discoverySplash(guildId, splashHash, options) {
230
+ return this.makeURL(`/discovery-splashes/${guildId}/${splashHash}`, options);
231
+ }
232
+ emoji(emojiId, extension) {
233
+ return this.makeURL(`/emojis/${emojiId}`, { extension });
234
+ }
235
+ guildMemberAvatar(guildId, userId, avatarHash, options) {
236
+ return this.dynamicMakeURL(`/guilds/${guildId}/users/${userId}/avatars/${avatarHash}`, avatarHash, options);
237
+ }
238
+ icon(id, iconHash, options) {
239
+ return this.dynamicMakeURL(`/icons/${id}/${iconHash}`, iconHash, options);
240
+ }
241
+ roleIcon(roleId, roleIconHash, options) {
242
+ return this.makeURL(`/role-icons/${roleId}/${roleIconHash}`, options);
243
+ }
244
+ splash(guildId, splashHash, options) {
245
+ return this.makeURL(`/splashes/${guildId}/${splashHash}`, options);
246
+ }
247
+ sticker(stickerId, extension) {
248
+ return this.makeURL(`/stickers/${stickerId}`, {
249
+ allowedExtensions: ALLOWED_STICKER_EXTENSIONS,
250
+ extension: extension ?? "png"
251
+ });
252
+ }
253
+ stickerPackBanner(bannerId, options) {
254
+ return this.makeURL(`/app-assets/710982414301790216/store/${bannerId}`, options);
255
+ }
256
+ teamIcon(teamId, iconHash, options) {
257
+ return this.makeURL(`/team-icons/${teamId}/${iconHash}`, options);
258
+ }
259
+ guildScheduledEventCover(scheduledEventId, coverHash, options) {
260
+ return this.makeURL(`/guild-events/${scheduledEventId}/${coverHash}`, options);
261
+ }
262
+ dynamicMakeURL(route, hash, { forceStatic = false, ...options } = {}) {
263
+ return this.makeURL(route, !forceStatic && hash.startsWith("a_") ? { ...options, extension: "gif" } : options);
264
+ }
265
+ makeURL(route, { allowedExtensions = ALLOWED_EXTENSIONS, extension = "webp", size } = {}) {
266
+ extension = String(extension).toLowerCase();
267
+ if (!allowedExtensions.includes(extension)) {
268
+ throw new RangeError(`Invalid extension provided: ${extension}
269
+ Must be one of: ${allowedExtensions.join(", ")}`);
270
+ }
271
+ if (size && !ALLOWED_SIZES.includes(size)) {
272
+ throw new RangeError(`Invalid size provided: ${size}
273
+ Must be one of: ${ALLOWED_SIZES.join(", ")}`);
274
+ }
275
+ const url = new URL(`${this.base}${route}.${extension}`);
276
+ if (size) {
277
+ url.searchParams.set("size", String(size));
278
+ }
279
+ return url.toString();
280
+ }
281
+ };
282
+ __name(CDN, "CDN");
283
+
284
+ // src/lib/errors/DiscordAPIError.ts
285
+ function isErrorGroupWrapper(error) {
286
+ return Reflect.has(error, "_errors");
287
+ }
288
+ __name(isErrorGroupWrapper, "isErrorGroupWrapper");
289
+ function isErrorResponse(error) {
290
+ return typeof Reflect.get(error, "message") === "string";
291
+ }
292
+ __name(isErrorResponse, "isErrorResponse");
293
+ var DiscordAPIError = class extends Error {
294
+ constructor(rawError, code, status, method, url, bodyData) {
295
+ super(DiscordAPIError.getMessage(rawError));
296
+ this.rawError = rawError;
297
+ this.code = code;
298
+ this.status = status;
299
+ this.method = method;
300
+ this.url = url;
301
+ __publicField(this, "requestBody");
302
+ this.requestBody = { files: bodyData.files, json: bodyData.body };
303
+ }
304
+ get name() {
305
+ return `${DiscordAPIError.name}[${this.code}]`;
306
+ }
307
+ static getMessage(error) {
308
+ let flattened = "";
309
+ if ("code" in error) {
310
+ if (error.errors) {
311
+ flattened = [...this.flattenDiscordError(error.errors)].join("\n");
312
+ }
313
+ return error.message && flattened ? `${error.message}
314
+ ${flattened}` : error.message || flattened || "Unknown Error";
315
+ }
316
+ return error.error_description ?? "No Description";
317
+ }
318
+ static *flattenDiscordError(obj, key = "") {
319
+ if (isErrorResponse(obj)) {
320
+ return yield `${key.length ? `${key}[${obj.code}]` : `${obj.code}`}: ${obj.message}`.trim();
321
+ }
322
+ for (const [k, v] of Object.entries(obj)) {
323
+ const nextKey = k.startsWith("_") ? key : key ? Number.isNaN(Number(k)) ? `${key}.${k}` : `${key}[${k}]` : k;
324
+ if (typeof v === "string") {
325
+ yield v;
326
+ } else if (isErrorGroupWrapper(v)) {
327
+ for (const error of v._errors) {
328
+ yield* this.flattenDiscordError(error, nextKey);
329
+ }
330
+ } else {
331
+ yield* this.flattenDiscordError(v, nextKey);
332
+ }
333
+ }
334
+ }
335
+ };
336
+ __name(DiscordAPIError, "DiscordAPIError");
337
+
338
+ // src/lib/errors/HTTPError.ts
339
+ var HTTPError = class extends Error {
340
+ constructor(message, name, status, method, url, bodyData) {
341
+ super(message);
342
+ this.name = name;
343
+ this.status = status;
344
+ this.method = method;
345
+ this.url = url;
346
+ __publicField(this, "requestBody");
347
+ this.requestBody = { files: bodyData.files, json: bodyData.body };
348
+ }
349
+ };
350
+ __name(HTTPError, "HTTPError");
351
+
352
+ // src/lib/errors/RateLimitError.ts
353
+ var RateLimitError = class extends Error {
354
+ constructor({ timeToReset, limit, method, hash, url, route, majorParameter, global }) {
355
+ super();
356
+ __publicField(this, "timeToReset");
357
+ __publicField(this, "limit");
358
+ __publicField(this, "method");
359
+ __publicField(this, "hash");
360
+ __publicField(this, "url");
361
+ __publicField(this, "route");
362
+ __publicField(this, "majorParameter");
363
+ __publicField(this, "global");
364
+ this.timeToReset = timeToReset;
365
+ this.limit = limit;
366
+ this.method = method;
367
+ this.hash = hash;
368
+ this.url = url;
369
+ this.route = route;
370
+ this.majorParameter = majorParameter;
371
+ this.global = global;
372
+ }
373
+ get name() {
374
+ return `${RateLimitError.name}[${this.route}]`;
375
+ }
376
+ };
377
+ __name(RateLimitError, "RateLimitError");
378
+
379
+ // src/lib/RequestManager.ts
380
+ var import_collection = __toESM(require("@discordjs/collection"));
381
+ var import_form_data = __toESM(require("form-data"));
382
+ var import_snowflake = require("@sapphire/snowflake");
383
+ var import_node_events = require("events");
384
+ var import_node_https = require("https");
385
+ var import_node_http = require("http");
386
+
387
+ // src/lib/handlers/SequentialHandler.ts
388
+ var import_promises = require("timers/promises");
389
+ var import_async_queue = require("@sapphire/async-queue");
390
+ var import_node_fetch = __toESM(require("node-fetch"));
391
+
392
+ // src/lib/utils/utils.ts
393
+ function parseResponse(res) {
394
+ if (res.headers.get("Content-Type")?.startsWith("application/json")) {
395
+ return res.json();
396
+ }
397
+ return res.arrayBuffer();
398
+ }
399
+ __name(parseResponse, "parseResponse");
400
+ function hasSublimit(bucketRoute, body, method) {
401
+ if (bucketRoute === "/channels/:id") {
402
+ if (typeof body !== "object" || body === null)
403
+ return false;
404
+ if (method !== "patch" /* Patch */)
405
+ return false;
406
+ const castedBody = body;
407
+ return ["name", "topic"].some((key) => Reflect.has(castedBody, key));
408
+ }
409
+ return true;
410
+ }
411
+ __name(hasSublimit, "hasSublimit");
412
+
413
+ // src/lib/handlers/SequentialHandler.ts
414
+ var invalidCount = 0;
415
+ var invalidCountResetTime = null;
416
+ var _asyncQueue, _sublimitedQueue, _sublimitPromise, _shiftSublimit;
417
+ var SequentialHandler = class {
418
+ constructor(manager, hash, majorParameter) {
419
+ this.manager = manager;
420
+ this.hash = hash;
421
+ this.majorParameter = majorParameter;
422
+ __publicField(this, "id");
423
+ __publicField(this, "reset", -1);
424
+ __publicField(this, "remaining", 1);
425
+ __publicField(this, "limit", Infinity);
426
+ __privateAdd(this, _asyncQueue, new import_async_queue.AsyncQueue());
427
+ __privateAdd(this, _sublimitedQueue, null);
428
+ __privateAdd(this, _sublimitPromise, null);
429
+ __privateAdd(this, _shiftSublimit, false);
430
+ this.id = `${hash}:${majorParameter}`;
431
+ }
432
+ get inactive() {
433
+ return __privateGet(this, _asyncQueue).remaining === 0 && (__privateGet(this, _sublimitedQueue) === null || __privateGet(this, _sublimitedQueue).remaining === 0) && !this.limited;
434
+ }
435
+ get globalLimited() {
436
+ return this.manager.globalRemaining <= 0 && Date.now() < this.manager.globalReset;
437
+ }
438
+ get localLimited() {
439
+ return this.remaining <= 0 && Date.now() < this.reset;
440
+ }
441
+ get limited() {
442
+ return this.globalLimited || this.localLimited;
443
+ }
444
+ get timeToReset() {
445
+ return this.reset + this.manager.options.offset - Date.now();
446
+ }
447
+ debug(message) {
448
+ this.manager.emit("restDebug" /* Debug */, `[REST ${this.id}] ${message}`);
449
+ }
450
+ async globalDelayFor(time) {
451
+ await (0, import_promises.setTimeout)(time, void 0, { ref: false });
452
+ this.manager.globalDelay = null;
453
+ }
454
+ async onRateLimit(rateLimitData) {
455
+ const { options } = this.manager;
456
+ if (!options.rejectOnRateLimit)
457
+ return;
458
+ const shouldThrow = typeof options.rejectOnRateLimit === "function" ? await options.rejectOnRateLimit(rateLimitData) : options.rejectOnRateLimit.some((route) => rateLimitData.route.startsWith(route.toLowerCase()));
459
+ if (shouldThrow) {
460
+ throw new RateLimitError(rateLimitData);
461
+ }
462
+ }
463
+ async queueRequest(routeId, url, options, requestData) {
464
+ let queue = __privateGet(this, _asyncQueue);
465
+ let queueType = 0 /* Standard */;
466
+ if (__privateGet(this, _sublimitedQueue) && hasSublimit(routeId.bucketRoute, requestData.body, options.method)) {
467
+ queue = __privateGet(this, _sublimitedQueue);
468
+ queueType = 1 /* Sublimit */;
469
+ }
470
+ await queue.wait();
471
+ if (queueType === 0 /* Standard */) {
472
+ if (__privateGet(this, _sublimitedQueue) && hasSublimit(routeId.bucketRoute, requestData.body, options.method)) {
473
+ queue = __privateGet(this, _sublimitedQueue);
474
+ const wait = queue.wait();
475
+ __privateGet(this, _asyncQueue).shift();
476
+ await wait;
477
+ } else if (__privateGet(this, _sublimitPromise)) {
478
+ await __privateGet(this, _sublimitPromise).promise;
479
+ }
480
+ }
481
+ try {
482
+ return await this.runRequest(routeId, url, options, requestData);
483
+ } finally {
484
+ queue.shift();
485
+ if (__privateGet(this, _shiftSublimit)) {
486
+ __privateSet(this, _shiftSublimit, false);
487
+ __privateGet(this, _sublimitedQueue)?.shift();
488
+ }
489
+ if (__privateGet(this, _sublimitedQueue)?.remaining === 0) {
490
+ __privateGet(this, _sublimitPromise)?.resolve();
491
+ __privateSet(this, _sublimitedQueue, null);
492
+ }
493
+ }
494
+ }
495
+ async runRequest(routeId, url, options, requestData, retries = 0) {
496
+ while (this.limited) {
497
+ const isGlobal = this.globalLimited;
498
+ let limit2;
499
+ let timeout2;
500
+ let delay;
501
+ if (isGlobal) {
502
+ limit2 = this.manager.options.globalRequestsPerSecond;
503
+ timeout2 = this.manager.globalReset + this.manager.options.offset - Date.now();
504
+ if (!this.manager.globalDelay) {
505
+ this.manager.globalDelay = this.globalDelayFor(timeout2);
506
+ }
507
+ delay = this.manager.globalDelay;
508
+ } else {
509
+ limit2 = this.limit;
510
+ timeout2 = this.timeToReset;
511
+ delay = (0, import_promises.setTimeout)(timeout2);
512
+ }
513
+ const rateLimitData = {
514
+ timeToReset: timeout2,
515
+ limit: limit2,
516
+ method: options.method ?? "get",
517
+ hash: this.hash,
518
+ url,
519
+ route: routeId.bucketRoute,
520
+ majorParameter: this.majorParameter,
521
+ global: isGlobal
522
+ };
523
+ this.manager.emit("rateLimited" /* RateLimited */, rateLimitData);
524
+ await this.onRateLimit(rateLimitData);
525
+ if (isGlobal) {
526
+ this.debug(`Global rate limit hit, blocking all requests for ${timeout2}ms`);
527
+ } else {
528
+ this.debug(`Waiting ${timeout2}ms for rate limit to pass`);
529
+ }
530
+ await delay;
531
+ }
532
+ if (!this.manager.globalReset || this.manager.globalReset < Date.now()) {
533
+ this.manager.globalReset = Date.now() + 1e3;
534
+ this.manager.globalRemaining = this.manager.options.globalRequestsPerSecond;
535
+ }
536
+ this.manager.globalRemaining--;
537
+ const method = options.method ?? "get";
538
+ if (this.manager.listenerCount("request" /* Request */)) {
539
+ this.manager.emit("request" /* Request */, {
540
+ method,
541
+ path: routeId.original,
542
+ route: routeId.bucketRoute,
543
+ options,
544
+ data: requestData,
545
+ retries
546
+ });
547
+ }
548
+ const controller = new AbortController();
549
+ const timeout = setTimeout(() => controller.abort(), this.manager.options.timeout).unref();
550
+ let res;
551
+ try {
552
+ res = await (0, import_node_fetch.default)(url, { ...options, signal: controller.signal });
553
+ } catch (error) {
554
+ if (error instanceof Error && error.name === "AbortError" && retries !== this.manager.options.retries) {
555
+ return await this.runRequest(routeId, url, options, requestData, ++retries);
556
+ }
557
+ throw error;
558
+ } finally {
559
+ clearTimeout(timeout);
560
+ }
561
+ if (this.manager.listenerCount("response" /* Response */)) {
562
+ this.manager.emit("response" /* Response */, {
563
+ method,
564
+ path: routeId.original,
565
+ route: routeId.bucketRoute,
566
+ options,
567
+ data: requestData,
568
+ retries
569
+ }, res.clone());
570
+ }
571
+ let retryAfter = 0;
572
+ const limit = res.headers.get("X-RateLimit-Limit");
573
+ const remaining = res.headers.get("X-RateLimit-Remaining");
574
+ const reset = res.headers.get("X-RateLimit-Reset-After");
575
+ const hash = res.headers.get("X-RateLimit-Bucket");
576
+ const retry = res.headers.get("Retry-After");
577
+ this.limit = limit ? Number(limit) : Infinity;
578
+ this.remaining = remaining ? Number(remaining) : 1;
579
+ this.reset = reset ? Number(reset) * 1e3 + Date.now() + this.manager.options.offset : Date.now();
580
+ if (retry)
581
+ retryAfter = Number(retry) * 1e3 + this.manager.options.offset;
582
+ if (hash && hash !== this.hash) {
583
+ this.debug(["Received bucket hash update", ` Old Hash : ${this.hash}`, ` New Hash : ${hash}`].join("\n"));
584
+ this.manager.hashes.set(`${method}:${routeId.bucketRoute}`, { value: hash, lastAccess: Date.now() });
585
+ } else if (hash) {
586
+ const hashData = this.manager.hashes.get(`${method}:${routeId.bucketRoute}`);
587
+ if (hashData) {
588
+ hashData.lastAccess = Date.now();
589
+ }
590
+ }
591
+ let sublimitTimeout = null;
592
+ if (retryAfter > 0) {
593
+ if (res.headers.get("X-RateLimit-Global")) {
594
+ this.manager.globalRemaining = 0;
595
+ this.manager.globalReset = Date.now() + retryAfter;
596
+ } else if (!this.localLimited) {
597
+ sublimitTimeout = retryAfter;
598
+ }
599
+ }
600
+ if (res.status === 401 || res.status === 403 || res.status === 429) {
601
+ if (!invalidCountResetTime || invalidCountResetTime < Date.now()) {
602
+ invalidCountResetTime = Date.now() + 1e3 * 60 * 10;
603
+ invalidCount = 0;
604
+ }
605
+ invalidCount++;
606
+ const emitInvalid = this.manager.options.invalidRequestWarningInterval > 0 && invalidCount % this.manager.options.invalidRequestWarningInterval === 0;
607
+ if (emitInvalid) {
608
+ this.manager.emit("invalidRequestWarning" /* InvalidRequestWarning */, {
609
+ count: invalidCount,
610
+ remainingTime: invalidCountResetTime - Date.now()
611
+ });
612
+ }
613
+ }
614
+ if (res.ok) {
615
+ return parseResponse(res);
616
+ } else if (res.status === 429) {
617
+ const isGlobal = this.globalLimited;
618
+ let limit2;
619
+ let timeout2;
620
+ if (isGlobal) {
621
+ limit2 = this.manager.options.globalRequestsPerSecond;
622
+ timeout2 = this.manager.globalReset + this.manager.options.offset - Date.now();
623
+ } else {
624
+ limit2 = this.limit;
625
+ timeout2 = this.timeToReset;
626
+ }
627
+ await this.onRateLimit({
628
+ timeToReset: timeout2,
629
+ limit: limit2,
630
+ method,
631
+ hash: this.hash,
632
+ url,
633
+ route: routeId.bucketRoute,
634
+ majorParameter: this.majorParameter,
635
+ global: isGlobal
636
+ });
637
+ this.debug([
638
+ "Encountered unexpected 429 rate limit",
639
+ ` Global : ${isGlobal.toString()}`,
640
+ ` Method : ${method}`,
641
+ ` URL : ${url}`,
642
+ ` Bucket : ${routeId.bucketRoute}`,
643
+ ` Major parameter: ${routeId.majorParameter}`,
644
+ ` Hash : ${this.hash}`,
645
+ ` Limit : ${limit2}`,
646
+ ` Retry After : ${retryAfter}ms`,
647
+ ` Sublimit : ${sublimitTimeout ? `${sublimitTimeout}ms` : "None"}`
648
+ ].join("\n"));
649
+ if (sublimitTimeout) {
650
+ const firstSublimit = !__privateGet(this, _sublimitedQueue);
651
+ if (firstSublimit) {
652
+ __privateSet(this, _sublimitedQueue, new import_async_queue.AsyncQueue());
653
+ void __privateGet(this, _sublimitedQueue).wait();
654
+ __privateGet(this, _asyncQueue).shift();
655
+ }
656
+ __privateGet(this, _sublimitPromise)?.resolve();
657
+ __privateSet(this, _sublimitPromise, null);
658
+ await (0, import_promises.setTimeout)(sublimitTimeout, void 0, { ref: false });
659
+ let resolve;
660
+ const promise = new Promise((res2) => resolve = res2);
661
+ __privateSet(this, _sublimitPromise, { promise, resolve });
662
+ if (firstSublimit) {
663
+ await __privateGet(this, _asyncQueue).wait();
664
+ __privateSet(this, _shiftSublimit, true);
665
+ }
666
+ }
667
+ return this.runRequest(routeId, url, options, requestData, retries);
668
+ } else if (res.status >= 500 && res.status < 600) {
669
+ if (retries !== this.manager.options.retries) {
670
+ return this.runRequest(routeId, url, options, requestData, ++retries);
671
+ }
672
+ throw new HTTPError(res.statusText, res.constructor.name, res.status, method, url, requestData);
673
+ } else {
674
+ if (res.status >= 400 && res.status < 500) {
675
+ if (res.status === 401 && requestData.auth) {
676
+ this.manager.setToken(null);
677
+ }
678
+ const data = await parseResponse(res);
679
+ throw new DiscordAPIError(data, "code" in data ? data.code : data.error, res.status, method, url, requestData);
680
+ }
681
+ return null;
682
+ }
683
+ }
684
+ };
685
+ __name(SequentialHandler, "SequentialHandler");
686
+ _asyncQueue = new WeakMap();
687
+ _sublimitedQueue = new WeakMap();
688
+ _sublimitPromise = new WeakMap();
689
+ _shiftSublimit = new WeakMap();
690
+
691
+ // src/lib/RequestManager.ts
692
+ var RequestMethod = /* @__PURE__ */ ((RequestMethod2) => {
693
+ RequestMethod2["Delete"] = "delete";
694
+ RequestMethod2["Get"] = "get";
695
+ RequestMethod2["Patch"] = "patch";
696
+ RequestMethod2["Post"] = "post";
697
+ RequestMethod2["Put"] = "put";
698
+ return RequestMethod2;
699
+ })(RequestMethod || {});
700
+ var _token;
701
+ var _RequestManager = class extends import_node_events.EventEmitter {
702
+ constructor(options) {
703
+ super();
704
+ __publicField(this, "globalRemaining");
705
+ __publicField(this, "globalDelay", null);
706
+ __publicField(this, "globalReset", -1);
707
+ __publicField(this, "hashes", new import_collection.default());
708
+ __publicField(this, "handlers", new import_collection.default());
709
+ __privateAdd(this, _token, null);
710
+ __publicField(this, "hashTimer");
711
+ __publicField(this, "handlerTimer");
712
+ __publicField(this, "agent", null);
713
+ __publicField(this, "options");
714
+ this.options = { ...DefaultRestOptions, ...options };
715
+ this.options.offset = Math.max(0, this.options.offset);
716
+ this.globalRemaining = this.options.globalRequestsPerSecond;
717
+ this.setupSweepers();
718
+ }
719
+ setupSweepers() {
720
+ const validateMaxInterval = /* @__PURE__ */ __name((interval) => {
721
+ if (interval > 144e5) {
722
+ throw new Error("Cannot set an interval greater than 4 hours");
723
+ }
724
+ }, "validateMaxInterval");
725
+ if (this.options.hashSweepInterval !== 0 && this.options.hashSweepInterval !== Infinity) {
726
+ validateMaxInterval(this.options.hashSweepInterval);
727
+ this.hashTimer = setInterval(() => {
728
+ const sweptHashes = new import_collection.default();
729
+ const currentDate = Date.now();
730
+ this.hashes.sweep((v, k) => {
731
+ if (v.lastAccess === -1)
732
+ return false;
733
+ const shouldSweep = Math.floor(currentDate - v.lastAccess) > this.options.hashLifetime;
734
+ if (shouldSweep) {
735
+ sweptHashes.set(k, v);
736
+ }
737
+ this.emit("restDebug" /* Debug */, `Hash ${v.value} for ${k} swept due to lifetime being exceeded`);
738
+ return shouldSweep;
739
+ });
740
+ this.emit("hashSweep" /* HashSweep */, sweptHashes);
741
+ }, this.options.hashSweepInterval).unref();
742
+ }
743
+ if (this.options.handlerSweepInterval !== 0 && this.options.handlerSweepInterval !== Infinity) {
744
+ validateMaxInterval(this.options.handlerSweepInterval);
745
+ this.handlerTimer = setInterval(() => {
746
+ const sweptHandlers = new import_collection.default();
747
+ this.handlers.sweep((v, k) => {
748
+ const { inactive } = v;
749
+ if (inactive) {
750
+ sweptHandlers.set(k, v);
751
+ }
752
+ this.emit("restDebug" /* Debug */, `Handler ${v.id} for ${k} swept due to being inactive`);
753
+ return inactive;
754
+ });
755
+ this.emit("handlerSweep" /* HandlerSweep */, sweptHandlers);
756
+ }, this.options.handlerSweepInterval).unref();
757
+ }
758
+ }
759
+ setToken(token) {
760
+ __privateSet(this, _token, token);
761
+ return this;
762
+ }
763
+ async queueRequest(request) {
764
+ const routeId = _RequestManager.generateRouteData(request.fullRoute, request.method);
765
+ const hash = this.hashes.get(`${request.method}:${routeId.bucketRoute}`) ?? {
766
+ value: `Global(${request.method}:${routeId.bucketRoute})`,
767
+ lastAccess: -1
768
+ };
769
+ const handler = this.handlers.get(`${hash.value}:${routeId.majorParameter}`) ?? this.createHandler(hash.value, routeId.majorParameter);
770
+ const { url, fetchOptions } = this.resolveRequest(request);
771
+ return handler.queueRequest(routeId, url, fetchOptions, {
772
+ body: request.body,
773
+ files: request.files,
774
+ auth: request.auth !== false
775
+ });
776
+ }
777
+ createHandler(hash, majorParameter) {
778
+ const queue = new SequentialHandler(this, hash, majorParameter);
779
+ this.handlers.set(queue.id, queue);
780
+ return queue;
781
+ }
782
+ resolveRequest(request) {
783
+ const { options } = this;
784
+ this.agent ??= options.api.startsWith("https") ? new import_node_https.Agent({ ...options.agent, keepAlive: true }) : new import_node_http.Agent({ ...options.agent, keepAlive: true });
785
+ let query = "";
786
+ if (request.query) {
787
+ const resolvedQuery = request.query.toString();
788
+ if (resolvedQuery !== "") {
789
+ query = `?${resolvedQuery}`;
790
+ }
791
+ }
792
+ const headers = {
793
+ ...this.options.headers,
794
+ "User-Agent": `${DefaultUserAgent} ${options.userAgentAppendix}`.trim()
795
+ };
796
+ if (request.auth !== false) {
797
+ if (!__privateGet(this, _token)) {
798
+ throw new Error("Expected token to be set for this request, but none was present");
799
+ }
800
+ headers.Authorization = `${request.authPrefix ?? "Bot"} ${__privateGet(this, _token)}`;
801
+ }
802
+ if (request.reason?.length) {
803
+ headers["X-Audit-Log-Reason"] = encodeURIComponent(request.reason);
804
+ }
805
+ const url = `${options.api}${request.versioned === false ? "" : `/v${options.version}`}${request.fullRoute}${query}`;
806
+ let finalBody;
807
+ let additionalHeaders = {};
808
+ if (request.files?.length) {
809
+ const formData = new import_form_data.default();
810
+ for (const [index, file] of request.files.entries()) {
811
+ formData.append(file.key ?? `files[${index}]`, file.data, file.name);
812
+ }
813
+ if (request.body != null) {
814
+ if (request.appendToFormData) {
815
+ for (const [key, value] of Object.entries(request.body)) {
816
+ formData.append(key, value);
817
+ }
818
+ } else {
819
+ formData.append("payload_json", JSON.stringify(request.body));
820
+ }
821
+ }
822
+ finalBody = formData;
823
+ additionalHeaders = formData.getHeaders();
824
+ } else if (request.body != null) {
825
+ if (request.passThroughBody) {
826
+ finalBody = request.body;
827
+ } else {
828
+ finalBody = JSON.stringify(request.body);
829
+ additionalHeaders = { "Content-Type": "application/json" };
830
+ }
831
+ }
832
+ const fetchOptions = {
833
+ agent: this.agent,
834
+ body: finalBody,
835
+ headers: { ...request.headers ?? {}, ...additionalHeaders, ...headers },
836
+ method: request.method
837
+ };
838
+ return { url, fetchOptions };
839
+ }
840
+ clearHashSweeper() {
841
+ clearInterval(this.hashTimer);
842
+ }
843
+ clearHandlerSweeper() {
844
+ clearInterval(this.handlerTimer);
845
+ }
846
+ static generateRouteData(endpoint, method) {
847
+ const majorIdMatch = /^\/(?:channels|guilds|webhooks)\/(\d{16,19})/.exec(endpoint);
848
+ const majorId = majorIdMatch?.[1] ?? "global";
849
+ const baseRoute = endpoint.replace(/\d{16,19}/g, ":id").replace(/\/reactions\/(.*)/, "/reactions/:reaction");
850
+ let exceptions = "";
851
+ if (method === "delete" /* Delete */ && baseRoute === "/channels/:id/messages/:id") {
852
+ const id = /\d{16,19}$/.exec(endpoint)[0];
853
+ const timestamp = import_snowflake.DiscordSnowflake.timestampFrom(id);
854
+ if (Date.now() - timestamp > 1e3 * 60 * 60 * 24 * 14) {
855
+ exceptions += "/Delete Old Message";
856
+ }
857
+ }
858
+ return {
859
+ majorParameter: majorId,
860
+ bucketRoute: baseRoute + exceptions,
861
+ original: endpoint
862
+ };
863
+ }
864
+ };
865
+ var RequestManager = _RequestManager;
866
+ __name(RequestManager, "RequestManager");
867
+ _token = new WeakMap();
868
+
869
+ // src/lib/REST.ts
870
+ var import_node_events2 = require("events");
871
+ var REST = class extends import_node_events2.EventEmitter {
872
+ constructor(options = {}) {
873
+ super();
874
+ __publicField(this, "cdn");
875
+ __publicField(this, "requestManager");
876
+ this.cdn = new CDN(options.cdn ?? DefaultRestOptions.cdn);
877
+ this.requestManager = new RequestManager(options).on("restDebug" /* Debug */, this.emit.bind(this, "restDebug" /* Debug */)).on("rateLimited" /* RateLimited */, this.emit.bind(this, "rateLimited" /* RateLimited */)).on("invalidRequestWarning" /* InvalidRequestWarning */, this.emit.bind(this, "invalidRequestWarning" /* InvalidRequestWarning */)).on("hashSweep" /* HashSweep */, this.emit.bind(this, "hashSweep" /* HashSweep */));
878
+ this.on("newListener", (name, listener) => {
879
+ if (name === "request" /* Request */ || name === "response" /* Response */)
880
+ this.requestManager.on(name, listener);
881
+ });
882
+ this.on("removeListener", (name, listener) => {
883
+ if (name === "request" /* Request */ || name === "response" /* Response */)
884
+ this.requestManager.off(name, listener);
885
+ });
886
+ }
887
+ setToken(token) {
888
+ this.requestManager.setToken(token);
889
+ return this;
890
+ }
891
+ get(fullRoute, options = {}) {
892
+ return this.request({ ...options, fullRoute, method: "get" /* Get */ });
893
+ }
894
+ delete(fullRoute, options = {}) {
895
+ return this.request({ ...options, fullRoute, method: "delete" /* Delete */ });
896
+ }
897
+ post(fullRoute, options = {}) {
898
+ return this.request({ ...options, fullRoute, method: "post" /* Post */ });
899
+ }
900
+ put(fullRoute, options = {}) {
901
+ return this.request({ ...options, fullRoute, method: "put" /* Put */ });
902
+ }
903
+ patch(fullRoute, options = {}) {
904
+ return this.request({ ...options, fullRoute, method: "patch" /* Patch */ });
905
+ }
906
+ request(options) {
907
+ return this.requestManager.queueRequest(options);
908
+ }
909
+ };
910
+ __name(REST, "REST");
911
+ module.exports = __toCommonJS(src_exports);
912
+ // Annotate the CommonJS export names for ESM import in node:
913
+ 0 && (module.exports = {
914
+ ALLOWED_EXTENSIONS,
915
+ ALLOWED_SIZES,
916
+ ALLOWED_STICKER_EXTENSIONS,
917
+ CDN,
918
+ DefaultRestOptions,
919
+ DefaultUserAgent,
920
+ DiscordAPIError,
921
+ HTTPError,
922
+ REST,
923
+ RESTEvents,
924
+ RateLimitError,
925
+ RequestManager,
926
+ RequestMethod
927
+ });
8
928
  //# sourceMappingURL=index.js.map