index.js 18.3 KB
var Re=Object.create;var A=Object.defineProperty;var be=Object.getOwnPropertyDescriptor;var ye=Object.getOwnPropertyNames;var ve=Object.getPrototypeOf,we=Object.prototype.hasOwnProperty;var Ee=(r,e,t)=>e in r?A(r,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):r[e]=t;var te=r=>A(r,"__esModule",{value:!0});var Le=(r,e)=>()=>(e||r((e={exports:{}}).exports,e),e.exports),Se=(r,e)=>{for(var t in e)A(r,t,{get:e[t],enumerable:!0})},se=(r,e,t,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of ye(e))!we.call(r,i)&&(t||i!=="default")&&A(r,i,{get:()=>e[i],enumerable:!(s=be(e,i))||s.enumerable});return r},W=(r,e)=>se(te(A(r!=null?Re(ve(r)):{},"default",!e&&r&&r.__esModule?{get:()=>r.default,enumerable:!0}:{value:r,enumerable:!0})),r),xe=(r=>(e,t)=>r&&r.get(e)||(t=se(te({}),e,1),r&&r.set(e,t),t))(typeof WeakMap!="undefined"?new WeakMap:0);var l=(r,e,t)=>(Ee(r,typeof e!="symbol"?e+"":e,t),t),ie=(r,e,t)=>{if(!e.has(r))throw TypeError("Cannot "+t)};var u=(r,e,t)=>(ie(r,e,"read from private field"),t?t.call(r):e.get(r)),E=(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)},g=(r,e,t,s)=>(ie(r,e,"write to private field"),s?s.call(r,t):e.set(r,t),t);var re=Le((Oe,De)=>{De.exports={name:"@discordjs/rest",version:"0.3.0",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"},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":"^0.4.0","@sapphire/async-queue":"^1.1.9","@sapphire/snowflake":"^3.0.1","discord-api-types":"^0.26.1","form-data":"^4.0.0","node-fetch":"^2.6.5",tslib:"^2.3.1"},devDependencies:{"@babel/core":"^7.16.12","@babel/plugin-proposal-decorators":"^7.16.7","@babel/preset-env":"^7.16.11","@babel/preset-typescript":"^7.16.7","@discordjs/ts-docgen":"^0.3.4","@types/jest":"^27.4.0","@types/node-fetch":"^2.5.10","@typescript-eslint/eslint-plugin":"^5.10.0","@typescript-eslint/parser":"^5.10.0","babel-plugin-const-enum":"^1.2.0","babel-plugin-transform-typescript-metadata":"^0.3.2",eslint:"^8.7.0","eslint-config-marine":"^9.3.2","eslint-config-prettier":"^8.3.0","eslint-plugin-prettier":"^4.0.0",jest:"^27.4.7",nock:"^13.2.2",prettier:"^2.5.1",tsup:"^5.11.11",typedoc:"^0.22.11",typescript:"^4.5.5"},engines:{node:">=16.9.0"},publishConfig:{access:"public"}}});var $e={};Se($e,{ALLOWED_EXTENSIONS:()=>F,ALLOWED_SIZES:()=>P,ALLOWED_STICKER_EXTENSIONS:()=>G,CDN:()=>U,DefaultRestOptions:()=>L,DefaultUserAgent:()=>C,DiscordAPIError:()=>S,HTTPError:()=>_,REST:()=>de,RESTEvents:()=>j,RateLimitError:()=>D,RequestManager:()=>K,RequestMethod:()=>N});var ne=require("discord-api-types/v9"),ae=re(),C=`DiscordBot (${ae.homepage}, ${ae.version})`,L={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:ne.APIVersion,hashSweepInterval:144e5,hashLifetime:864e5,handlerSweepInterval:36e5},j=(m=>(m.Debug="restDebug",m.InvalidRequestWarning="invalidRequestWarning",m.RateLimited="rateLimited",m.Request="request",m.Response="response",m.HashSweep="hashSweep",m.HandlerSweep="handlerSweep",m))(j||{}),F=["webp","png","jpg","jpeg","gif"],G=["png","json"],P=[16,32,64,128,256,512,1024,2048,4096];var U=class{constructor(e=L.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}`)}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:G,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)}dynamicMakeURL(e,t,{forceStatic:s=!1,...i}={}){return this.makeURL(e,!s&&t.startsWith("a_")?{...i,extension:"gif"}:i)}makeURL(e,{allowedExtensions:t=F,extension:s="webp",size:i}={}){if(s=String(s).toLowerCase(),!t.includes(s))throw new RangeError(`Invalid extension provided: ${s}
Must be one of: ${t.join(", ")}`);if(i&&!P.includes(i))throw new RangeError(`Invalid size provided: ${i}
Must be one of: ${P.join(", ")}`);let n=new URL(`${this.base}${e}.${s}`);return i&&n.searchParams.set("size",String(i)),n.toString()}};function ke(r){return Reflect.has(r,"_errors")}function Ie(r){return typeof Reflect.get(r,"message")=="string"}var S=class extends Error{constructor(e,t,s,i,n,a){super(S.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`${S.name}[${this.code}]`}static getMessage(e){let t="";return"code"in e?(e.errors&&(t=[...this.flattenDiscordError(e.errors)].join(`
`)),e.message&&t?`${e.message}
${t}`:e.message||t||"Unknown Error"):e.error_description??"No Description"}static*flattenDiscordError(e,t=""){if(Ie(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(ke(i))for(let a of i._errors)yield*this.flattenDiscordError(a,n);else yield*this.flattenDiscordError(i,n)}}};var _=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}}};var D=class extends Error{constructor({timeToReset:e,limit:t,method:s,hash:i,url:n,route:a,majorParameter:m,global:w}){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=w}get name(){return`${D.name}[${this.route}]`}};var T=W(require("@discordjs/collection")),le=W(require("form-data")),ue=require("@sapphire/snowflake"),me=require("events"),pe=require("https"),ce=require("http");var B=require("timers/promises"),J=require("@sapphire/async-queue"),oe=W(require("node-fetch"));function X(r){return r.headers.get("Content-Type")?.startsWith("application/json")?r.json():r.buffer()}function z(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!1}var M=0,H=null;var v,c,R,k,Q=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);E(this,v,new J.AsyncQueue);E(this,c,null);E(this,R,null);E(this,k,!1);this.id=`${t}:${s}`}get inactive(){return u(this,v).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,B.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 D(e)}async queueRequest(e,t,s,i){let n=u(this,v),a=0;if(u(this,c)&&z(e.bucketRoute,i.body,s.method)&&(n=u(this,c),a=1),await n.wait(),a===0)if(u(this,c)&&z(e.bucketRoute,i.body,s.method)){n=u(this,c);let m=n.wait();u(this,v).shift(),await m}else u(this,R)&&await u(this,R).promise;try{return await this.runRequest(e,t,s,i)}finally{n.shift(),u(this,k)&&(g(this,k,!1),u(this,c)?.shift()),u(this,c)?.remaining===0&&(u(this,R)?.resolve(),g(this,c,null))}}async runRequest(e,t,s,i,n=0){for(;this.limited;){let p=this.globalLimited,y,h,x;p?(y=this.manager.options.globalRequestsPerSecond,h=this.manager.globalReset+this.manager.options.offset-Date.now(),this.manager.globalDelay||(this.manager.globalDelay=this.globalDelayFor(h)),x=this.manager.globalDelay):(y=this.limit,h=this.timeToReset,x=(0,B.setTimeout)(h));let O={timeToReset:h,limit:y,method:s.method??"get",hash:this.hash,url:t,route:e.bucketRoute,majorParameter:this.majorParameter,global:p};this.manager.emit("rateLimited",O),await this.onRateLimit(O),p?this.debug(`Global rate limit hit, blocking all requests for ${h}ms`):this.debug(`Waiting ${h}ms for rate limit to pass`),await x}(!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,w=setTimeout(()=>m.abort(),this.manager.options.timeout).unref(),o;try{o=await(0,oe.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(w)}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 d=0,b=o.headers.get("X-RateLimit-Limit"),V=o.headers.get("X-RateLimit-Remaining"),Y=o.headers.get("X-RateLimit-Reset-After"),$=o.headers.get("X-RateLimit-Bucket"),ee=o.headers.get("Retry-After");if(this.limit=b?Number(b):1/0,this.remaining=V?Number(V):1,this.reset=Y?Number(Y)*1e3+Date.now()+this.manager.options.offset:Date.now(),ee&&(d=Number(ee)*1e3+this.manager.options.offset),$&&$!==this.hash)this.debug(["Received bucket hash update",`  Old Hash  : ${this.hash}`,`  New Hash  : ${$}`].join(`
`)),this.manager.hashes.set(`${a}:${e.bucketRoute}`,{value:$,lastAccess:Date.now()});else if($){let p=this.manager.hashes.get(`${a}:${e.bucketRoute}`);p&&(p.lastAccess=Date.now())}let q=null;if(d>0&&(o.headers.get("X-RateLimit-Global")?(this.manager.globalRemaining=0,this.manager.globalReset=Date.now()+d):this.localLimited||(q=d)),(o.status===401||o.status===403||o.status===429)&&((!H||H<Date.now())&&(H=Date.now()+1e3*60*10,M=0),M++,this.manager.options.invalidRequestWarningInterval>0&&M%this.manager.options.invalidRequestWarningInterval===0&&this.manager.emit("invalidRequestWarning",{count:M,remainingTime:H-Date.now()})),o.ok)return X(o);if(o.status===429){let p=this.globalLimited,y,h;if(p?(y=this.manager.options.globalRequestsPerSecond,h=this.manager.globalReset+this.manager.options.offset-Date.now()):(y=this.limit,h=this.timeToReset),await this.onRateLimit({timeToReset:h,limit:y,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          : ${y}`,`  Retry After    : ${d}ms`,`  Sublimit       : ${q?`${q}ms`:"None"}`].join(`
`)),q){let x=!u(this,c);x&&(g(this,c,new J.AsyncQueue),u(this,c).wait(),u(this,v).shift()),u(this,R)?.resolve(),g(this,R,null),await(0,B.setTimeout)(q,void 0,{ref:!1});let O,ge=new Promise(fe=>O=fe);g(this,R,{promise:ge,resolve:O}),x&&(await u(this,v).wait(),g(this,k,!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 _(o.statusText,o.constructor.name,o.status,a,t,i)}else{if(o.status>=400&&o.status<500){o.status===401&&this.manager.setToken(null);let p=await X(o);throw new S(p,"code"in p?p.code:p.error,o.status,a,t,i)}return null}}};v=new WeakMap,c=new WeakMap,R=new WeakMap,k=new WeakMap;var N=(n=>(n.Delete="delete",n.Get="get",n.Patch="patch",n.Post="post",n.Put="put",n))(N||{}),I,Z=class extends me.EventEmitter{constructor(e){super();l(this,"globalRemaining");l(this,"globalDelay",null);l(this,"globalReset",-1);l(this,"hashes",new T.default);l(this,"handlers",new T.default);E(this,I,null);l(this,"hashTimer");l(this,"handlerTimer");l(this,"agent",null);l(this,"options");this.options={...L,...e},this.options.offset=Math.max(0,this.options.offset),this.globalRemaining=this.options.globalRequestsPerSecond,this.setupSweepers()}setupSweepers(){let e=t=>{if(t>144e5)throw new Error("Cannot set an interval greater than 4 hours")};this.options.hashSweepInterval!==0&&this.options.hashSweepInterval!==1/0&&(e(this.options.hashSweepInterval),this.hashTimer=setInterval(()=>{let t=new T.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 T.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 g(this,I,e),this}async queueRequest(e){let t=Z.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})}createHandler(e,t){let s=new Q(this,e,t);return this.handlers.set(s.id,s),s}resolveRequest(e){let{options:t}=this;this.agent??=t.api.startsWith("https")?new pe.Agent({...t.agent,keepAlive:!0}):new ce.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":`${C} ${t.userAgentAppendix}`.trim()};if(e.auth!==!1){if(!u(this,I))throw new Error("Expected token to be set for this request, but none was present");i.Authorization=`${e.authPrefix??"Bot"} ${u(this,I)}`}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 le.default;for(let[d,b]of e.files.entries())o.append(b.key??`files[${d}]`,b.fileData,b.fileName);if(e.body!=null)if(e.appendToFormData)for(let[d,b]of Object.entries(e.body))o.append(d,b);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 w={agent:this.agent,body:a,headers:{...e.headers??{},...m,...i},method:e.method};return{url:n,fetchOptions:w}}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],w=ue.DiscordSnowflake.deconstruct(m);Date.now()-Number(w.timestamp)>1e3*60*60*24*14&&(a+="/Delete Old Message")}return{majorParameter:i,bucketRoute:n+a,original:e}}},K=Z;I=new WeakMap;var he=require("events");var de=class extends he.EventEmitter{constructor(e={}){super();l(this,"cdn");l(this,"requestManager");this.cdn=new U(e.cdn??L.cdn),this.requestManager=new K(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)}};module.exports=xe($e);0&&(module.exports={ALLOWED_EXTENSIONS,ALLOWED_SIZES,ALLOWED_STICKER_EXTENSIONS,CDN,DefaultRestOptions,DefaultUserAgent,DiscordAPIError,HTTPError,REST,RESTEvents,RateLimitError,RequestManager,RequestMethod});
//# sourceMappingURL=index.js.map