@discordjs/rest
Advanced tools
Comparing version 0.2.0-canary.0 to 0.3.0
@@ -1,8 +0,8 @@ | ||
var fe=Object.create;var j=Object.defineProperty;var be=Object.getOwnPropertyDescriptor;var ye=Object.getOwnPropertyNames;var ve=Object.getPrototypeOf,Ee=Object.prototype.hasOwnProperty;var Le=(i,e,t)=>e in i?j(i,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):i[e]=t;var se=i=>j(i,"__esModule",{value:!0});var ke=(i,e)=>()=>(e||i((e={exports:{}}).exports,e),e.exports),xe=(i,e)=>{se(i);for(var t in e)j(i,t,{get:e[t],enumerable:!0})},De=(i,e,t)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of ye(e))!Ee.call(i,s)&&s!=="default"&&j(i,s,{get:()=>e[s],enumerable:!(t=be(e,s))||t.enumerable});return i},R=i=>De(se(j(i!=null?fe(ve(i)):{},"default",i&&i.__esModule&&"default"in i?{get:()=>i.default,enumerable:!0}:{value:i,enumerable:!0})),i);var l=(i,e,t)=>(Le(i,typeof e!="symbol"?e+"":e,t),t),ie=(i,e,t)=>{if(!e.has(i))throw TypeError("Cannot "+t)};var u=(i,e,t)=>(ie(i,e,"read from private field"),t?t.call(i):e.get(i)),D=(i,e,t)=>{if(e.has(i))throw TypeError("Cannot add the same private member more than once");e instanceof WeakSet?e.add(i):e.set(i,t)},b=(i,e,t,s)=>(ie(i,e,"write to private field"),s?s.call(i,t):e.set(i,t),t);var re=ke((Se,qe)=>{qe.exports={name:"@discordjs/rest",version:"0.1.1-canary.0",description:"The REST API for discord.js",scripts:{test:'echo "Error: run tests from root" && exit 1',build:"tsup && tsc --emitDeclarationOnly"},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-modules.git"},bugs:{url:"https://github.com/discordjs/discord.js-modules/issues"},homepage:"https://github.com/discordjs/discord.js-modules/tree/main/packages/rest",dependencies:{"@discordjs/collection":"^0.3.2","@sapphire/async-queue":"^1.1.9","@sapphire/snowflake":"^3.0.0","discord-api-types":"^0.25.2","form-data":"^4.0.0","node-fetch":"^2.6.5",tslib:"^2.3.1"},devDependencies:{"@types/node-fetch":"^2.5.10"},engines:{node:">=16.0.0"},publishConfig:{access:"public"}}});xe(exports,{ALLOWED_EXTENSIONS:()=>X,ALLOWED_SIZES:()=>N,ALLOWED_STICKER_EXTENSIONS:()=>G,CDN:()=>B,DefaultRestOptions:()=>q,DefaultUserAgent:()=>H,DiscordAPIError:()=>w,HTTPError:()=>K,REST:()=>pe,RESTEvents:()=>m,RateLimitError:()=>I,RequestManager:()=>_,RequestMethod:()=>p});var ne=R(require("discord-api-types/v9")),oe=re(),H=`DiscordBot (${oe.homepage}, ${oe.version})`,q={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},m;(function(r){r.Debug="restDebug",r.InvalidRequestWarning="invalidRequestWarning",r.RateLimited="rateLimited",r.Request="request",r.Response="response"})(m||(m={}));var X=["webp","png","jpg","jpeg","gif"],G=["png","json"],N=[16,32,64,128,256,512,1024,2048,4096];var B=class{constructor(e=q.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,n){return this.dynamicMakeURL(`/guilds/${e}/users/${t}/avatars/${s}`,s,n)}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})}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,{dynamic:s=!1,...n}={}){return this.makeURL(e,s&&t.startsWith("a_")?{...n,extension:"gif"}:n)}makeURL(e,{allowedExtensions:t=X,extension:s="png",size:n}={}){if(s=String(s).toLowerCase(),!t.includes(s))throw new RangeError(`Invalid extension provided: ${s} | ||
Must be one of: ${t.join(", ")}`);if(n&&!N.includes(n))throw new RangeError(`Invalid size provided: ${n} | ||
Must be one of: ${N.join(", ")}`);let r=new URL(`${this.base}${e}.${s}`);return n&&r.searchParams.set("size",String(n)),r.toString()}};function we(i){return Reflect.has(i,"_errors")}function $e(i){return typeof Reflect.get(i,"message")=="string"}var w=class extends Error{constructor(e,t,s,n,r,a){super(w.getMessage(e));this.rawError=e;this.code=t;this.status=s;this.method=n;this.url=r;l(this,"requestBody");this.requestBody={attachments:a.attachments,json:a.body}}get name(){return`${w.name}[${this.code}]`}static getMessage(e){let t="";return e.errors&&(t=[...this.flattenDiscordError(e.errors)].join(` | ||
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"}static*flattenDiscordError(e,t=""){if($e(e))return yield`${t.length?`${t}[${e.code}]`:`${e.code}`}: ${e.message}`.trim();for(let[s,n]of Object.entries(e)){let r=s.startsWith("_")?t:t?Number.isNaN(Number(s))?`${t}.${s}`:`${t}[${s}]`:s;if(typeof n=="string")yield n;else if(we(n))for(let a of n._errors)yield*this.flattenDiscordError(a,r);else yield*this.flattenDiscordError(n,r)}}};var K=class extends Error{constructor(e,t,s,n,r,a){super(e);this.name=t;this.status=s;this.method=n;this.url=r;l(this,"requestBody");this.requestBody={attachments:a.attachments,json:a.body}}};var I=class extends Error{constructor({timeToReset:e,limit:t,method:s,hash:n,url:r,route:a,majorParameter:g,global:x}){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=n,this.url=r,this.route=a,this.majorParameter=g,this.global=x}get name(){return`${I.name}[${this.route}]`}};var V=R(require("@discordjs/collection")),le=R(require("form-data")),ue=R(require("@sapphire/snowflake")),me=R(require("events")),ce=R(require("https"));var W=R(require("timers/promises")),J=R(require("@sapphire/async-queue")),ae=R(require("node-fetch"));function F(i){return i.headers.get("Content-Type")?.startsWith("application/json")?i.json():i.buffer()}function z(i,e,t){if(i==="/channels/:id"){if(typeof e!="object"||e===null||t!==p.Patch)return!1;let s=e;return["name","topic"].some(n=>Reflect.has(s,n))}return!1}var M=0,C=null,T;(function(t){t[t.Standard=0]="Standard",t[t.Sublimit=1]="Sublimit"})(T||(T={}));var k,d,v,S,Z=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);D(this,k,new J.AsyncQueue);D(this,d,null);D(this,v,null);D(this,S,!1);this.id=`${t}:${s}`}get inactive(){return u(this,k).remaining===0&&(u(this,d)===null||u(this,d).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(m.Debug,`[REST ${this.id}] ${e}`)}async globalDelayFor(e){await(0,W.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(n=>e.route.startsWith(n.toLowerCase())))throw new I(e)}async queueRequest(e,t,s,n){let r=u(this,k),a=0;if(u(this,d)&&z(e.bucketRoute,n.body,s.method)&&(r=u(this,d),a=1),await r.wait(),a===0)if(u(this,d)&&z(e.bucketRoute,n.body,s.method)){r=u(this,d);let g=r.wait();u(this,k).shift(),await g}else u(this,v)&&await u(this,v).promise;try{return await this.runRequest(e,t,s,n)}finally{r.shift(),u(this,S)&&(b(this,S,!1),u(this,d)?.shift()),u(this,d)?.remaining===0&&(u(this,v)?.resolve(),b(this,d,null))}}async runRequest(e,t,s,n,r=0){for(;this.limited;){let c=this.globalLimited,L,h,$;c?(L=this.manager.options.globalRequestsPerSecond,h=this.manager.globalReset+this.manager.options.offset-Date.now(),this.manager.globalDelay||(this.manager.globalDelay=this.globalDelayFor(h)),$=this.manager.globalDelay):(L=this.limit,h=this.timeToReset,$=(0,W.setTimeout)(h,void 0,{ref:!1}));let A={timeToReset:h,limit:L,method:s.method??"get",hash:this.hash,url:t,route:e.bucketRoute,majorParameter:this.majorParameter,global:c};this.manager.emit(m.RateLimited,A),await this.onRateLimit(A),c?this.debug(`Global rate limit hit, blocking all requests for ${h}ms`):this.debug(`Waiting ${h}ms for rate limit to pass`),await $}(!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(m.Request)&&this.manager.emit(m.Request,{method:a,path:e.original,route:e.bucketRoute,options:s,data:n,retries:r});let g=new AbortController,x=setTimeout(()=>g.abort(),this.manager.options.timeout).unref(),o;try{o=await(0,ae.default)(t,{...s,signal:g.signal})}catch(c){if(c instanceof Error&&c.name==="AbortError"&&r!==this.manager.options.retries)return this.runRequest(e,t,s,n,++r);throw c}finally{clearTimeout(x)}this.manager.listenerCount(m.Response)&&this.manager.emit(m.Response,{method:a,path:e.original,route:e.bucketRoute,options:s,data:n,retries:r},o.clone());let f=0,E=o.headers.get("X-RateLimit-Limit"),Y=o.headers.get("X-RateLimit-Remaining"),ee=o.headers.get("X-RateLimit-Reset-After"),U=o.headers.get("X-RateLimit-Bucket"),te=o.headers.get("Retry-After");this.limit=E?Number(E):1/0,this.remaining=Y?Number(Y):1,this.reset=ee?Number(ee)*1e3+Date.now()+this.manager.options.offset:Date.now(),te&&(f=Number(te)*1e3+this.manager.options.offset),U&&U!==this.hash&&(this.debug(["Received bucket hash update",` Old Hash : ${this.hash}`,` New Hash : ${U}`].join(` | ||
`)),this.manager.hashes.set(`${a}:${e.bucketRoute}`,U));let P=null;if(f>0&&(o.headers.get("X-RateLimit-Global")?(this.manager.globalRemaining=0,this.manager.globalReset=Date.now()+f):this.localLimited||(P=f)),(o.status===401||o.status===403||o.status===429)&&((!C||C<Date.now())&&(C=Date.now()+1e3*60*10,M=0),M++,this.manager.options.invalidRequestWarningInterval>0&&M%this.manager.options.invalidRequestWarningInterval==0&&this.manager.emit(m.InvalidRequestWarning,{count:M,remainingTime:C-Date.now()})),o.ok)return F(o);if(o.status===429){let c=this.globalLimited,L,h;if(c?(L=this.manager.options.globalRequestsPerSecond,h=this.manager.globalReset+this.manager.options.offset-Date.now()):(L=this.limit,h=this.timeToReset),await this.onRateLimit({timeToReset:h,limit:L,method:a,hash:this.hash,url:t,route:e.bucketRoute,majorParameter:this.majorParameter,global:c}),this.debug(["Encountered unexpected 429 rate limit",` Global : ${c.toString()}`,` Method : ${a}`,` URL : ${t}`,` Bucket : ${e.bucketRoute}`,` Major parameter: ${e.majorParameter}`,` Hash : ${this.hash}`,` Limit : ${L}`,` Retry After : ${f}ms`,` Sublimit : ${P?`${P}ms`:"None"}`].join(` | ||
`)),P){let $=!u(this,d);$&&(b(this,d,new J.AsyncQueue),u(this,d).wait(),u(this,k).shift()),u(this,v)?.resolve(),b(this,v,null),await(0,W.setTimeout)(P,void 0,{ref:!1});let A,he=new Promise(Re=>A=Re);b(this,v,{promise:he,resolve:A}),$&&(await u(this,k).wait(),b(this,S,!0))}return this.runRequest(e,t,s,n,r)}else if(o.status>=500&&o.status<600){if(r!==this.manager.options.retries)return this.runRequest(e,t,s,n,++r);throw new K(o.statusText,o.constructor.name,o.status,a,t,n)}else{if(o.status>=400&&o.status<500){o.status===401&&this.manager.setToken(null);let c=await F(o);throw new w(c,c.code,o.status,a,t,n)}return null}}};k=new WeakMap,d=new WeakMap,v=new WeakMap,S=new WeakMap;var de=null,p;(function(r){r.Delete="delete",r.Get="get",r.Patch="patch",r.Post="post",r.Put="put"})(p||(p={}));var O,Q=class extends me.EventEmitter{constructor(e){super();l(this,"globalRemaining");l(this,"globalDelay",null);l(this,"globalReset",-1);l(this,"hashes",new V.default);l(this,"handlers",new V.default);D(this,O,null);l(this,"options");this.options={...q,...e},this.options.offset=Math.max(0,this.options.offset),this.globalRemaining=this.options.globalRequestsPerSecond}setToken(e){return b(this,O,e),this}async queueRequest(e){let t=Q.generateRouteData(e.fullRoute,e.method),s=this.hashes.get(`${e.method}:${t.bucketRoute}`)??`Global(${e.method}:${t.bucketRoute})`,n=this.handlers.get(`${s}:${t.majorParameter}`)??this.createHandler(s,t.majorParameter),{url:r,fetchOptions:a}=this.resolveRequest(e);return n.queueRequest(t,r,a,{body:e.body,attachments:e.attachments})}createHandler(e,t){let s=new Z(this,e,t);return this.handlers.set(s.id,s),s}resolveRequest(e){let{options:t}=this;de??=new ce.Agent({...t.agent,keepAlive:!0});let s="";e.query&&(s=`?${e.query.toString()}`);let n={...this.options.headers,"User-Agent":`${H} ${t.userAgentAppendix}`.trim()};if(e.auth!==!1){if(!u(this,O))throw new Error("Expected token to be set for this request, but none was present");n.Authorization=`${e.authPrefix??"Bot"} ${u(this,O)}`}e.reason?.length&&(n["X-Audit-Log-Reason"]=encodeURIComponent(e.reason));let r=`${t.api}${e.versioned===!1?"":`/v${t.version}`}${e.fullRoute}${s}`,a,g={};if(e.attachments?.length){let o=new le.default;for(let[f,E]of e.attachments.entries())o.append(E.key??`files[${f}]`,E.rawBuffer,E.fileName);if(e.body!=null)if(e.appendToFormData)for(let[f,E]of Object.entries(e.body))o.append(f,E);else o.append("payload_json",JSON.stringify(e.body));a=o,g=o.getHeaders()}else e.body!=null&&(a=JSON.stringify(e.body),g={"Content-Type":"application/json"});let x={agent:de,body:a,headers:{...e.headers??{},...g,...n},method:e.method};return{url:r,fetchOptions:x}}static generateRouteData(e,t){let n=/^\/(?:channels|guilds|webhooks)\/(\d{16,19})/.exec(e)?.[1]??"global",r=e.replace(/\d{16,19}/g,":id").replace(/\/reactions\/(.*)/,"/reactions/:reaction"),a="";if(t===p.Delete&&r==="/channels/:id/messages/:id"){let g=/\d{16,19}$/.exec(e)[0],x=ue.DiscordSnowflake.deconstruct(g);Date.now()-Number(x.timestamp)>1e3*60*60*24*14&&(a+="/Delete Old Message")}return{majorParameter:n,bucketRoute:r+a,original:e}}},_=Q;O=new WeakMap;var ge=R(require("events"));var pe=class extends ge.EventEmitter{constructor(e={}){super();l(this,"cdn");l(this,"requestManager");this.cdn=new B(e.cdn??q.cdn),this.requestManager=new _(e).on(m.Debug,this.emit.bind(this,m.Debug)).on(m.RateLimited,this.emit.bind(this,m.RateLimited)).on(m.InvalidRequestWarning,this.emit.bind(this,m.InvalidRequestWarning)),this.on("newListener",(t,s)=>{(t===m.Request||t===m.Response)&&this.requestManager.on(t,s)}),this.on("removeListener",(t,s)=>{(t===m.Request||t===m.Response)&&this.requestManager.off(t,s)})}setToken(e){return this.requestManager.setToken(e),this}get(e,t={}){return this.request({...t,fullRoute:e,method:p.Get})}delete(e,t={}){return this.request({...t,fullRoute:e,method:p.Delete})}post(e,t={}){return this.request({...t,fullRoute:e,method:p.Post})}put(e,t={}){return this.request({...t,fullRoute:e,method:p.Put})}patch(e,t={}){return this.request({...t,fullRoute:e,method:p.Patch})}request(e){return this.requestManager.queueRequest(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 | ||
${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 |
import { ImageExtension, ImageSize, StickerExtension } from './utils/constants'; | ||
/** | ||
* The options used for image URLs | ||
*/ | ||
export interface BaseImageURLOptions { | ||
/** | ||
* The extension to use for the image URL | ||
* @default 'webp' | ||
*/ | ||
extension?: ImageExtension; | ||
/** | ||
* The size specified in the image URL | ||
*/ | ||
size?: ImageSize; | ||
} | ||
/** | ||
* The options used for image URLs with animated content | ||
*/ | ||
export interface ImageURLOptions extends BaseImageURLOptions { | ||
dynamic?: boolean; | ||
/** | ||
* Whether or not to prefer the static version of an image asset. | ||
*/ | ||
forceStatic?: boolean; | ||
} | ||
/** | ||
* The options to use when making a CDN URL | ||
*/ | ||
export interface MakeURLOptions { | ||
/** | ||
* The extension to use for the image URL | ||
* @default 'webp' | ||
*/ | ||
extension?: string | undefined; | ||
/** | ||
* The size specified in the image URL | ||
*/ | ||
size?: ImageSize; | ||
allowedExtensions?: readonly string[]; | ||
/** | ||
* The allowed extensions that can be used | ||
*/ | ||
allowedExtensions?: ReadonlyArray<string>; | ||
} | ||
@@ -14,0 +43,0 @@ /** |
@@ -1,2 +0,2 @@ | ||
import type { InternalRequest, RawAttachment } from '../RequestManager'; | ||
import type { InternalRequest, RawFile } from '../RequestManager'; | ||
interface DiscordErrorFieldInformation { | ||
@@ -17,4 +17,8 @@ code: string; | ||
} | ||
export interface OAuthErrorData { | ||
error: string; | ||
error_description?: string; | ||
} | ||
export interface RequestBody { | ||
attachments: RawAttachment[] | undefined; | ||
files: RawFile[] | undefined; | ||
json: unknown | undefined; | ||
@@ -27,4 +31,4 @@ } | ||
export declare class DiscordAPIError extends Error { | ||
rawError: DiscordErrorData; | ||
code: number; | ||
rawError: DiscordErrorData | OAuthErrorData; | ||
code: number | string; | ||
status: number; | ||
@@ -42,3 +46,3 @@ method: string; | ||
*/ | ||
constructor(rawError: DiscordErrorData, code: number, status: number, method: string, url: string, bodyData: Pick<InternalRequest, 'attachments' | 'body'>); | ||
constructor(rawError: DiscordErrorData | OAuthErrorData, code: number | string, status: number, method: string, url: string, bodyData: Pick<InternalRequest, 'files' | 'body'>); | ||
/** | ||
@@ -45,0 +49,0 @@ * The name of the error |
@@ -20,3 +20,3 @@ import type { InternalRequest } from '../RequestManager'; | ||
*/ | ||
constructor(message: string, name: string, status: number, method: string, url: string, bodyData: Pick<InternalRequest, 'attachments' | 'body'>); | ||
constructor(message: string, name: string, status: number, method: string, url: string, bodyData: Pick<InternalRequest, 'files' | 'body'>); | ||
} |
import type { RequestInit } from 'node-fetch'; | ||
import type { InternalRequest, RouteData } from '../RequestManager'; | ||
export interface IHandler { | ||
queueRequest(routeId: RouteData, url: string, options: RequestInit, bodyData: Pick<InternalRequest, 'attachments' | 'body'>): Promise<unknown>; | ||
queueRequest: (routeId: RouteData, url: string, options: RequestInit, bodyData: Pick<InternalRequest, 'files' | 'body'>) => Promise<unknown>; | ||
readonly inactive: boolean; | ||
readonly id: string; | ||
} |
@@ -72,3 +72,3 @@ import { RequestInit } from 'node-fetch'; | ||
*/ | ||
queueRequest(routeId: RouteData, url: string, options: RequestInit, bodyData: Pick<InternalRequest, 'attachments' | 'body'>): Promise<unknown>; | ||
queueRequest(routeId: RouteData, url: string, options: RequestInit, bodyData: Pick<InternalRequest, 'files' | 'body'>): Promise<unknown>; | ||
/** | ||
@@ -75,0 +75,0 @@ * The method that actually makes the request to the api, and updates info about the bucket accordingly |
/// <reference types="node" /> | ||
import Collection from '@discordjs/collection'; | ||
import { EventEmitter } from 'node:events'; | ||
import type { BodyInit } from 'node-fetch'; | ||
import type { IHandler } from './handlers/IHandler'; | ||
import type { RESTOptions, RestEvents } from './REST'; | ||
/** | ||
* Represents an attachment to be added to the request | ||
* Represents a file to be added to the request | ||
*/ | ||
export interface RawAttachment { | ||
export interface RawFile { | ||
/** | ||
@@ -15,4 +16,4 @@ * The name of the file | ||
/** | ||
* An explicit key to use for key of the formdata field for this attachment. | ||
* When not provided, the index of the file in the attachments array is used in the form `files[${index}]`. | ||
* 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}]`) | ||
@@ -22,5 +23,5 @@ */ | ||
/** | ||
* The actual data for the attachment | ||
* The actual data for the file | ||
*/ | ||
rawBuffer: Buffer; | ||
fileData: string | number | boolean | Buffer; | ||
} | ||
@@ -32,10 +33,6 @@ /** | ||
/** | ||
* Whether to append JSON data to form data instead of `payload_json` when sending attachments | ||
* Whether to append JSON data to form data instead of `payload_json` when sending files | ||
*/ | ||
appendToFormData?: boolean; | ||
/** | ||
* Files to be attached to this request | ||
*/ | ||
attachments?: RawAttachment[] | undefined; | ||
/** | ||
* If this request needs the `Authorization` header | ||
@@ -51,6 +48,11 @@ * @default true | ||
/** | ||
* The body to send to this request | ||
* The body to send to this request. | ||
* If providing as BodyInit, set `passThroughBody: true` | ||
*/ | ||
body?: unknown; | ||
body?: BodyInit | unknown; | ||
/** | ||
* Files to be attached to this request | ||
*/ | ||
files?: RawFile[] | undefined; | ||
/** | ||
* Additional headers to add to this request | ||
@@ -60,2 +62,7 @@ */ | ||
/** | ||
* 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 | ||
@@ -112,13 +119,17 @@ */ | ||
} | ||
/** | ||
* Represents a hash and its associated fields | ||
* | ||
* @internal | ||
*/ | ||
export interface HashData { | ||
value: string; | ||
lastAccess: number; | ||
} | ||
export interface RequestManager { | ||
on<K extends keyof RestEvents>(event: K, listener: (...args: RestEvents[K]) => void): this; | ||
on<S extends string | symbol>(event: Exclude<S, keyof RestEvents>, listener: (...args: any[]) => void): this; | ||
once<K extends keyof RestEvents>(event: K, listener: (...args: RestEvents[K]) => void): this; | ||
once<S extends string | symbol>(event: Exclude<S, keyof RestEvents>, listener: (...args: any[]) => void): this; | ||
emit<K extends keyof RestEvents>(event: K, ...args: RestEvents[K]): boolean; | ||
emit<S extends string | symbol>(event: Exclude<S, keyof RestEvents>, ...args: any[]): boolean; | ||
off<K extends keyof RestEvents>(event: K, listener: (...args: RestEvents[K]) => void): this; | ||
off<S extends string | symbol>(event: Exclude<S, keyof RestEvents>, listener: (...args: any[]) => void): this; | ||
removeAllListeners<K extends keyof RestEvents>(event?: K): this; | ||
removeAllListeners<S extends string | symbol>(event?: Exclude<S, keyof RestEvents>): this; | ||
on: (<K extends keyof RestEvents>(event: K, listener: (...args: RestEvents[K]) => void) => this) & (<S extends string | symbol>(event: Exclude<S, keyof RestEvents>, listener: (...args: any[]) => void) => this); | ||
once: (<K extends keyof RestEvents>(event: K, listener: (...args: RestEvents[K]) => void) => this) & (<S extends string | symbol>(event: Exclude<S, keyof RestEvents>, listener: (...args: any[]) => void) => this); | ||
emit: (<K extends keyof RestEvents>(event: K, ...args: RestEvents[K]) => boolean) & (<S extends string | symbol>(event: Exclude<S, keyof RestEvents>, ...args: any[]) => boolean); | ||
off: (<K extends keyof RestEvents>(event: K, listener: (...args: RestEvents[K]) => void) => this) & (<S extends string | symbol>(event: Exclude<S, keyof RestEvents>, listener: (...args: any[]) => void) => this); | ||
removeAllListeners: (<K extends keyof RestEvents>(event?: K) => this) & (<S extends string | symbol>(event?: Exclude<S, keyof RestEvents>) => this); | ||
} | ||
@@ -145,3 +156,3 @@ /** | ||
*/ | ||
readonly hashes: Collection<string, string>; | ||
readonly hashes: Collection<string, HashData>; | ||
/** | ||
@@ -151,4 +162,8 @@ * Request handlers created from the bucket hash and the major parameters | ||
readonly handlers: Collection<string, IHandler>; | ||
private hashTimer; | ||
private handlerTimer; | ||
private agent; | ||
readonly options: RESTOptions; | ||
constructor(options: Partial<RESTOptions>); | ||
private setupSweepers; | ||
/** | ||
@@ -178,2 +193,10 @@ * Sets the authorization token that should be used for requests | ||
/** | ||
* Stops the hash sweeping interval | ||
*/ | ||
clearHashSweeper(): void; | ||
/** | ||
* Stops the request handler sweeping interval | ||
*/ | ||
clearHandlerSweeper(): void; | ||
/** | ||
* Generates route data for an endpoint:method | ||
@@ -180,0 +203,0 @@ * @param endpoint The raw endpoint to generalize |
@@ -7,2 +7,5 @@ /// <reference types="node" /> | ||
import type { RequestInit, Response } from 'node-fetch'; | ||
import type { HashData } from './RequestManager'; | ||
import type Collection from '@discordjs/collection'; | ||
import type { IHandler } from './handlers/IHandler'; | ||
/** | ||
@@ -77,2 +80,17 @@ * Options to be passed when creating the REST instance | ||
version: string; | ||
/** | ||
* The amount of time in milliseconds that passes between each hash sweep. (defaults to 4h) | ||
* @default 14_400_000 | ||
*/ | ||
hashSweepInterval: number; | ||
/** | ||
* The maximum amount of time a hash can exist in milliseconds without being hit with a request (defaults to 24h) | ||
* @default 86_400_000 | ||
*/ | ||
hashLifetime: number; | ||
/** | ||
* The amount of time in milliseconds that passes between each hash sweep. (defaults to 1h) | ||
* @default 3_600_000 | ||
*/ | ||
handlerSweepInterval: number; | ||
} | ||
@@ -143,3 +161,3 @@ /** | ||
*/ | ||
data: Pick<InternalRequest, 'attachments' | 'body'>; | ||
data: Pick<InternalRequest, 'files' | 'body'>; | ||
/** | ||
@@ -156,3 +174,3 @@ * The number of times this request has been attempted | ||
/** | ||
* Time in ms remaining before the count resets | ||
* Time in milliseconds remaining before the count resets | ||
*/ | ||
@@ -169,14 +187,11 @@ remainingTime: number; | ||
removeListener: [name: string, listener: (...args: any) => void]; | ||
hashSweep: [sweptHashes: Collection<string, HashData>]; | ||
handlerSweep: [sweptHandlers: Collection<string, IHandler>]; | ||
} | ||
export interface REST { | ||
on<K extends keyof RestEvents>(event: K, listener: (...args: RestEvents[K]) => void): this; | ||
on<S extends string | symbol>(event: Exclude<S, keyof RestEvents>, listener: (...args: any[]) => void): this; | ||
once<K extends keyof RestEvents>(event: K, listener: (...args: RestEvents[K]) => void): this; | ||
once<S extends string | symbol>(event: Exclude<S, keyof RestEvents>, listener: (...args: any[]) => void): this; | ||
emit<K extends keyof RestEvents>(event: K, ...args: RestEvents[K]): boolean; | ||
emit<S extends string | symbol>(event: Exclude<S, keyof RestEvents>, ...args: any[]): boolean; | ||
off<K extends keyof RestEvents>(event: K, listener: (...args: RestEvents[K]) => void): this; | ||
off<S extends string | symbol>(event: Exclude<S, keyof RestEvents>, listener: (...args: any[]) => void): this; | ||
removeAllListeners<K extends keyof RestEvents>(event?: K): this; | ||
removeAllListeners<S extends string | symbol>(event?: Exclude<S, keyof RestEvents>): this; | ||
on: (<K extends keyof RestEvents>(event: K, listener: (...args: RestEvents[K]) => void) => this) & (<S extends string | symbol>(event: Exclude<S, keyof RestEvents>, listener: (...args: any[]) => void) => this); | ||
once: (<K extends keyof RestEvents>(event: K, listener: (...args: RestEvents[K]) => void) => this) & (<S extends string | symbol>(event: Exclude<S, keyof RestEvents>, listener: (...args: any[]) => void) => this); | ||
emit: (<K extends keyof RestEvents>(event: K, ...args: RestEvents[K]) => boolean) & (<S extends string | symbol>(event: Exclude<S, keyof RestEvents>, ...args: any[]) => boolean); | ||
off: (<K extends keyof RestEvents>(event: K, listener: (...args: RestEvents[K]) => void) => this) & (<S extends string | symbol>(event: Exclude<S, keyof RestEvents>, listener: (...args: any[]) => void) => this); | ||
removeAllListeners: (<K extends keyof RestEvents>(event?: K) => this) & (<S extends string | symbol>(event?: Exclude<S, keyof RestEvents>) => this); | ||
} | ||
@@ -183,0 +198,0 @@ export declare class REST extends EventEmitter { |
@@ -12,3 +12,5 @@ import type { RESTOptions } from '../REST'; | ||
Request = "request", | ||
Response = "response" | ||
Response = "response", | ||
HashSweep = "hashSweep", | ||
HandlerSweep = "handlerSweep" | ||
} | ||
@@ -15,0 +17,0 @@ export declare const ALLOWED_EXTENSIONS: readonly ["webp", "png", "jpg", "jpeg", "gif"]; |
{ | ||
"name": "@discordjs/rest", | ||
"version": "0.2.0-canary.0", | ||
"version": "0.3.0", | ||
"description": "The REST API for discord.js", | ||
"scripts": { | ||
"test": "echo \"Error: run tests from root\" && exit 1", | ||
"build": "tsup && tsc --emitDeclarationOnly" | ||
"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/*'" | ||
}, | ||
@@ -40,13 +45,13 @@ "main": "./dist/index.js", | ||
"type": "git", | ||
"url": "git+https://github.com/discordjs/discord.js-modules.git" | ||
"url": "git+https://github.com/discordjs/discord.js.git" | ||
}, | ||
"bugs": { | ||
"url": "https://github.com/discordjs/discord.js-modules/issues" | ||
"url": "https://github.com/discordjs/discord.js/issues" | ||
}, | ||
"homepage": "https://github.com/discordjs/discord.js-modules/tree/main/packages/rest", | ||
"homepage": "https://discord.js.org", | ||
"dependencies": { | ||
"@discordjs/collection": "^0.3.2", | ||
"@discordjs/collection": "^0.4.0", | ||
"@sapphire/async-queue": "^1.1.9", | ||
"@sapphire/snowflake": "^3.0.0", | ||
"discord-api-types": "^0.25.2", | ||
"@sapphire/snowflake": "^3.0.1", | ||
"discord-api-types": "^0.26.1", | ||
"form-data": "^4.0.0", | ||
@@ -57,11 +62,30 @@ "node-fetch": "^2.6.5", | ||
"devDependencies": { | ||
"@types/node-fetch": "^2.5.10" | ||
"@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.0.0" | ||
"node": ">=16.9.0" | ||
}, | ||
"publishConfig": { | ||
"access": "public" | ||
}, | ||
"gitHead": "d006f270fd911e178b0b6f83cbfa88aa2ef626b7" | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
233191
21
966
21
+ Added@discordjs/collection@0.4.0(transitive)
+ Addeddiscord-api-types@0.26.1(transitive)
- Removed@discordjs/collection@0.3.2(transitive)
- Removeddiscord-api-types@0.25.2(transitive)
Updated@discordjs/collection@^0.4.0
Updated@sapphire/snowflake@^3.0.1
Updateddiscord-api-types@^0.26.1