cloudstorm
Advanced tools
Comparing version 0.10.3 to 0.10.4
@@ -1,2 +0,2 @@ | ||
var __create=Object.create;var __defProp=Object.defineProperty;var __getOwnPropDesc=Object.getOwnPropertyDescriptor;var __getOwnPropNames=Object.getOwnPropertyNames;var __getProtoOf=Object.getPrototypeOf;var __hasOwnProp=Object.prototype.hasOwnProperty;var __esm=(fn,res)=>function __init(){return fn&&(res=(0,fn[__getOwnPropNames(fn)[0]])(fn=0)),res};var __commonJS=(cb,mod)=>function __require(){return mod||(0,cb[__getOwnPropNames(cb)[0]])((mod={exports:{}}).exports,mod),mod.exports};var __export=(target,all2)=>{for(var name in all2)__defProp(target,name,{get:all2[name],enumerable:true})};var __copyProps=(to,from,except,desc)=>{if(from&&typeof from==="object"||typeof from==="function"){for(let key of __getOwnPropNames(from))if(!__hasOwnProp.call(to,key)&&key!==except)__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable})}return to};var __toESM=(mod,isNodeMode,target)=>(target=mod!=null?__create(__getProtoOf(mod)):{},__copyProps(isNodeMode||!mod||!mod.__esModule?__defProp(target,"default",{value:mod,enumerable:true}):target,mod));var __toCommonJS=mod=>__copyProps(__defProp({},"__esModule",{value:true}),mod);var require_package=__commonJS({"package.json"(exports2,module2){module2.exports={name:"cloudstorm",version:"0.10.3",description:"Minimalistic Discord Gateway library",main:"./dist/index.js",engines:{node:">=14.8.0"},types:"./dist/index.d.ts",scripts:{"build:src":"tsup src/index.ts --clean --dts --sourcemap --format cjs --target node14 --minify-whitespace","build:docs":"typedoc --name CloudStorm --excludeExternals --sort static-first --sort alphabetical"},author:"wolke <wolke@weeb.sh>",license:"MIT",dependencies:{"discord-api-types":"^0.37.67",snowtransfer:"^0.10.1"},devDependencies:{"@types/node":"20.11.7","@typescript-eslint/eslint-plugin":"^6.19.1","@typescript-eslint/parser":"^6.19.1",eslint:"^8.56.0",tsup:"^8.0.1",typedoc:"^0.25.7","typedoc-plugin-mdn-links":"^3.1.13",typescript:"^5.3.0"},files:["dist","README.md","LICENSE.md"]}}});var require_Constants=__commonJS({"src/Constants.ts"(exports2,module2){"use strict";var Constants2={GATEWAY_OP_CODES:{DISPATCH:0,HEARTBEAT:1,IDENTIFY:2,PRESENCE_UPDATE:3,VOICE_STATE_UPDATE:4,RESUME:6,RECONNECT:7,REQUEST_GUILD_MEMBERS:8,INVALID_SESSION:9,HELLO:10,HEARTBEAT_ACK:11},GATEWAY_VERSION:10};module2.exports=Constants2}});var require_BetterWs=__commonJS({"src/BetterWs.ts"(exports2,module2){"use strict";var import_events=require("events");var import_crypto=require("crypto");var import_zlib=require("zlib");var import_Constants=__toESM(require_Constants());var import_snowtransfer=require("snowtransfer");var https=require("https");var http=require("http");var util=require("util");var BetterWs=class extends import_events.EventEmitter{constructor(address,options){super();this.address=address;this.options=options;this.wsBucket=new import_snowtransfer.LocalBucket(120,6e4);this.presenceBucket=new import_snowtransfer.LocalBucket(5,6e4);this._socket=null;this._internal={openRejector:null,closePromise:null,zlib:null};this._connecting=false;this._lastCloseCode=null;this._lastCloseReason=null;this.encoding=options.encoding??"json";this.compress=options.compress??false}get status(){const internal=this._internal;if(this._connecting)return 2;if(internal.closePromise)return 3;if(!this._socket)return 4;return 1}connect(){if(this._socket||this._connecting)return Promise.resolve(void 0);this._connecting=true;const key=(0,import_crypto.randomBytes)(16).toString("base64");const url=new URL(this.address);const useHTTPS=url.protocol==="https:"||url.protocol==="wss:"||url.port==="443";const port=url.port||(useHTTPS?"443":"80");const req=(useHTTPS?https:http).request({hostname:url.hostname,path:`${url.pathname}${url.search}`,port,headers:{"Connection":"Upgrade","Upgrade":"websocket","Sec-WebSocket-Key":key,"Sec-WebSocket-Version":"13"}});let onErrorRef;let cameFromOnError=false;return new Promise((resolve2,reject)=>{this._internal.openRejector=reject;const upgrade=this._onUpgrade.bind(this,key,req,resolve2,reject);onErrorRef=e=>{this._internal.openRejector=null;cameFromOnError=true;this._connecting=false;req.removeListener("upgrade",upgrade);reject(e)};req.once("upgrade",upgrade);req.once("error",onErrorRef);req.end()}).catch(reason=>{if(onErrorRef&&!cameFromOnError){req.destroy();req.removeListener("error",onErrorRef);onErrorRef(reason)}return Promise.reject(reason)})}async close(code,reason){const internal=this._internal;if(internal.closePromise)return internal.closePromise;if(!this._socket)return Promise.resolve(void 0);let resolver;const promise=new Promise(resolve2=>{resolver=resolve2;const from=Buffer.from([code>>8,code&255]);this._write(reason?Buffer.concat([from,Buffer.from(reason)]):from,8)}).then(()=>{internal.closePromise=null});promise.resolve=resolver;internal.closePromise=promise;return promise}sendMessage(data){if(!isValidRequest(data))return Promise.reject(new Error("Invalid request"));return new Promise(res=>{const presence=data.op===import_Constants.GATEWAY_OP_CODES.PRESENCE_UPDATE;const sendMsg=()=>{this.wsBucket.queue(()=>{this.emit("ws_send",data);if(this.encoding==="json")this._write(Buffer.from(JSON.stringify(data)),1);else{const etf=writeETF(data);this._write(etf,2)}res(void 0)})};if(presence)this.presenceBucket.queue(sendMsg);else sendMsg()})}_write(packet,opcode){const socket=this._socket;if(!(socket==null?void 0:socket.writable))return;const length=packet.length;let frame;if(length<126){frame=Buffer.allocUnsafe(6+length);frame[1]=128+length}else if(length<1<<16){frame=Buffer.allocUnsafe(8+length);frame[1]=254;frame[2]=length>>8;frame[3]=length&255}else{frame=Buffer.allocUnsafe(14+length);frame[1]=255;frame.writeBigUInt64BE(BigInt(length),2)}frame[0]=128+opcode;frame.writeUInt32BE(0,frame.length-length-4);frame.set(packet,frame.length-length);socket.write(frame)}_onUpgrade(key,req,resolve2,reject,res,socket){this._internal.openRejector=null;const hash=(0,import_crypto.createHash)("sha1").update(key+"258EAFA5-E914-47DA-95CA-C5AB0DC85B11").digest("base64");const accept=res.headers["sec-websocket-accept"];if(hash!==accept){socket.end(()=>{this.emit("debug","Failed websocket-key validation");this._connecting=false;reject(new Error(`Invalid Sec-Websocket-Accept | expected: ${hash} | received: ${accept}`))});return}socket.once("error",this._onError.bind(this));socket.once("close",this._onClose.bind(this));socket.on("readable",this._onReadable.bind(this));this._socket=socket;this._connecting=false;if(this.compress){const z=(0,import_zlib.createInflate)();z._c=z.close;z._h=z._handle;z._hc=z._handle.close;z._v=()=>void 0;this._internal.zlib=z}this.emit("ws_open");resolve2(void 0);req.removeAllListeners("error")}_onError(error){if(!this._socket)return;this.emit("debug",util.inspect(error,true,1,false));this._write(Buffer.allocUnsafe(0),8)}_onClose(){const socket=this._socket;const internal=this._internal;if(!socket)return;socket.removeListener("data",this._onReadable);socket.removeListener("error",this._onError);this.wsBucket.dropQueue();this.presenceBucket.dropQueue();this._socket=null;this.emit("ws_close",this._lastCloseCode??1006,this._lastCloseReason??"Abnormal Closure");this._lastCloseCode=null;this._lastCloseReason=null;if(internal.zlib){internal.zlib.close();internal.zlib=null}if(internal.closePromise)internal.closePromise.resolve(void 0)}_onReadable(){const socket=this._socket;while(((socket==null?void 0:socket.readableLength)||0)>1){let length=readRange(socket,1,1)&127;let bytes=0;if(length>125){bytes=length===126?2:8;if(socket.readableLength<2+bytes)return;length=readRange(socket,2,bytes)}const frame=socket.read(2+bytes+length);if(!frame)return;const fin=frame[0]>>7;const opcode=frame[0]&15;if(fin!==1||opcode===0)this.emit("debug","discord actually does send messages with fin=0. if you see this error let me know");const payload=frame.subarray(2+bytes);this._processFrame(opcode,payload)}}_processFrame(opcode,message){const internal=this._internal;switch(opcode){case 1:{const packet=JSON.parse(message.toString());this.emit("ws_receive",packet);break}case 2:{let packet;if(this.compress){const z=internal.zlib;let error=null;let data=null;z.close=z._handle.close=z._v;try{data=z._processChunk(message,import_zlib.constants.Z_SYNC_FLUSH)}catch(e){error=e}const l=message.length;if(message[l-4]!==0||message[l-3]!==0||message[l-2]!==255||message[l-1]!==255)this.emit("debug","discord actually does send fragmented zlib messages. If you see this error let me know");z.close=z._c;z._handle=z._h;z._handle.close=z._hc;z._events.error=void 0;z._eventCount--;z.removeAllListeners("error");if(error){this.emit("debug","Zlib error processing chunk");this._write(Buffer.allocUnsafe(0),8);return}if(!data){this.emit("debug","Data from zlib processing was null. If you see this error let me know");return}packet=this.encoding==="json"?JSON.parse(String(data)):readETF(data,1)}else if(this.encoding==="json"){const data=(0,import_zlib.inflateSync)(message);packet=JSON.parse(data.toString())}else packet=readETF(message,1);this.emit("ws_receive",packet);break}case 8:{this._lastCloseCode=message.length>1?(message[0]<<8)+message[1]:0;this._lastCloseReason=message.length>2?message.subarray(2).toString():"";this._write(Buffer.from([this._lastCloseCode>>8,this._lastCloseCode&255]),8);break}case 9:{this._write(message,10);break}}}};function isValidRequest(value){return value&&typeof value==="object"&&Number.isInteger(value.op)&&typeof value.d!=="undefined"}function readRange(socket,index,bytes){let head=socket._readableState.buffer.head;let cursor=0;let read=0;let num=0;do{for(const element of head.data){if(++cursor>index){num*=256;num+=element;if(++read===bytes)return num}}}while(head=head.next);throw new Error("readRange failed?")}function readETF(data,start){let view;let x=start;const loop=()=>{const type=data[x++];switch(type){case 97:{return data[x++]}case 98:{const int=data.readInt32BE(x);x+=4;return int}case 100:{const length=data.readUInt16BE(x);let atom="";if(length>30){atom=data.latin1Slice(x+=2,x+length)}else{for(let i=x+=2;i<x+length;i++){atom+=String.fromCharCode(data[i])}}x+=length;if(!atom)return void 0;if(atom==="nil"||atom==="null")return null;if(atom==="true")return true;if(atom==="false")return false;return atom}case 108:case 106:{const array=[];if(type===108){const length=data.readUInt32BE(x);x+=4;for(let i=0;i<length;i++){array.push(loop())}x++}return array}case 107:{const array=[];const length=data.readUInt16BE(x);x+=2;for(let i=0;i<length;i++){array.push(data[x++])}return array}case 109:{const length=data.readUInt32BE(x);let str="";if(length>30){str=data.utf8Slice(x+=4,x+length)}else{let i=x+=4;const l=x+length;while(i<l){const byte=data[i++];if(byte<128)str+=String.fromCharCode(byte);else if(byte<224)str+=String.fromCharCode(((byte&31)<<6)+(data[i++]&63));else if(byte<240)str+=String.fromCharCode(((byte&15)<<12)+((data[i++]&63)<<6)+(data[i++]&63));else str+=String.fromCodePoint(((byte&7)<<18)+((data[i++]&63)<<12)+((data[i++]&63)<<6)+(data[i++]&63))}}x+=length;return str}case 110:{if(!view)view=new DataView(data.buffer,data.offset,data.byteLength);const length=data[x++];const sign=data[x++];let left=length;let num=BigInt(0);while(left>0){if(left>=8){num<<=BigInt(64);num+=view.getBigUint64(x+(left-=8),true)}else if(left>=4){num<<=BigInt(32);num+=BigInt(view.getUint32(x+(left-=4)),true)}else if(left>=2){num<<=BigInt(16);num+=BigInt(view.getUint16(x+(left-=2)),true)}else{num<<=BigInt(8);num+=BigInt(data[x]);left--}}x+=length;return(sign?-num:num).toString()}case 116:{const obj={};const length=data.readUInt32BE(x);x+=4;for(let i=0;i<length;i++){const key=loop();obj[key]=loop()}return obj}}throw new Error(`Missing etf type: ${type}`)};return loop()}function writeETF(data){const b=Buffer.allocUnsafe(1<<12);b[0]=131;let i=1;const loop=obj=>{const type=typeof obj;switch(type){case"boolean":{b[i++]=100;if(obj){b.writeUInt16BE(4,i);b.latin1Write("true",i+=2);i+=4}else{b.writeUInt16BE(5,i);b.latin1Write("false",i+=2);i+=5}break}case"string":{const length=Buffer.byteLength(obj);b[i++]=109;b.writeUInt32BE(length,i);b.utf8Write(obj,i+=4);i+=length;break}case"number":{if(Number.isInteger(obj)){const abs=Math.abs(obj);if(abs<2147483648){b[i++]=98;b.writeInt32BE(obj,i);i+=4}else if(abs<Number.MAX_SAFE_INTEGER){b[i++]=110;b[i++]=8;b[i++]=Number(obj<0);b.writeBigUInt64LE(BigInt(abs),i);i+=8;break}else{b[i++]=70;b.writeDoubleBE(obj,i);i+=8}}else{b[i++]=70;b.writeDoubleBE(obj,i);i+=8}break}case"bigint":{b[i++]=110;b[i++]=8;b[i++]=Number(obj<0);b.writeBigUInt64LE(obj,i);i+=8;break}case"object":{if(obj===null){b[i++]=100;b.writeUInt16BE(3,i);b.latin1Write("nil",i+=2);i+=3}else if(Array.isArray(obj)){if(obj.length){b[i++]=108;b.writeUInt32BE(obj.length,i);i+=4;for(const item of obj){loop(item)}}b[i++]=106}else{const entries=Object.entries(obj).filter(x=>typeof x[1]!=="undefined");b[i++]=116;b.writeUInt32BE(entries.length,i);i+=4;for(const[key,value]of entries){loop(key);loop(value)}}break}}};loop(data);return Buffer.from(b.subarray(0,i))}module2.exports=BetterWs}});var Intents_exports={};__export(Intents_exports,{all:()=>all,default:()=>Intents_default,flags:()=>flags,non_privileged:()=>non_privileged,privileged:()=>privileged,resolve:()=>resolve});function resolve(bit=0){if(typeof bit==="number"&&bit>=0)return bit;if(typeof bit==="string"&&flags[bit])return flags[bit]|0;if(Array.isArray(bit))return bit.map(p=>resolve(p)).reduce((prev,p)=>prev|p,0);throw new RangeError("BITFIELD_INVALID")}var flags,privileged,all,non_privileged,Intents_default;var init_Intents=__esm({"src/Intents.ts"(){"use strict";flags={GUILDS:1<<0,GUILD_MEMBERS:1<<1,GUILD_MODERATION:1<<2,GUILD_EMOJIS_AND_STICKERS:1<<3,GUILD_INTEGRATIONS:1<<4,GUILD_WEBHOOKS:1<<5,GUILD_INVITES:1<<6,GUILD_VOICE_STATES:1<<7,GUILD_PRESENCES:1<<8,GUILD_MESSAGES:1<<9,GUILD_MESSAGE_REACTIONS:1<<10,GUILD_MESSAGE_TYPING:1<<11,DIRECT_MESSAGES:1<<12,DIRECT_MESSAGE_REACTIONS:1<<13,DIRECT_MESSAGE_TYPING:1<<14,MESSAGE_CONTENT:1<<15,GUILD_SCHEDULED_EVENTS:1<<16,AUTO_MODERATION_CONFIGURATION:1<<20,AUTO_MODERATION_EXECUTION:1<<21};privileged=flags.GUILD_MEMBERS|flags.GUILD_PRESENCES|flags.MESSAGE_CONTENT;all=Object.values(flags).reduce((acc,p)=>acc|p,0);non_privileged=all&~privileged;Intents_default={flags,privileged,all,non_privileged,resolve}}});var require_DiscordConnector=__commonJS({"src/DiscordConnector.ts"(exports2,module2){"use strict";var import_events=require("events");var import_Constants=__toESM(require_Constants());var import_v10=require("discord-api-types/v10");var BetterWs=require_BetterWs();var Intents2=(init_Intents(),__toCommonJS(Intents_exports));var resumableCodes=[4008,4005,4003,4002,4001,4e3,1006,1001];var shouldntAttemptReconnectCodes=[4014,4013,4012,4011,4010,4004,1e3];var disconnectMessages={4014:"Disallowed Intents, check your client options and application page.",4013:"Invalid Intents data, check your client options.",4012:"Invalid API version.",4011:"Shard would be on over 2500 guilds. Add more shards.",4010:"Invalid sharding data, check your client options.",4009:"Session timed out.",4008:"You are being rate limited. Wait before sending more packets.",4007:"Invalid sequence. Reconnecting and starting a new session.",4005:"You sent more than one OP 2 IDENTIFY payload while the websocket was open.",4004:"Tried to connect with an invalid token.",4003:"You tried to send a packet before sending an OP 2 IDENTIFY or OP 6 RESUME.",4002:"You sent an invalid payload.",4001:"You sent an invalid opcode or invalid payload for an opcode."};var connectionError=new Error("WS took too long to connect. Is your internet okay?");var wsStatusTypes=["Whatever 0 is. Report if you see this","connected","connecting","closing","closed"];var DiscordConnector=class extends import_events.EventEmitter{constructor(id,client){super();this.id=id;this.client=client;this.heartbeatTimeout=null;this.heartbeatInterval=0;this._trace=null;this.seq=0;this.status="disconnected";this.sessionId=null;this.lastACKAt=0;this.lastHeartbeatSend=0;this.latency=0;this.resumeAddress=null;this.reconnecting=false;this._closing=false;this._closeCalled=false;this._openToHeartbeatTimeout=null;this._initialHeartbeatTimeout=null;this.options=client.options;this.reconnect=this.options.reconnect??true;this.identifyAddress=this.options.endpoint;this.betterWs=new BetterWs(this.identifyAddress,this.options.ws);this.betterWs.on("ws_open",()=>{this.status="connecting";this.emit("stateChange","connecting");this.reconnecting=false;this._openToHeartbeatTimeout=setTimeout(()=>{this.client.emit("debug",`Shard ${this.id} didn't receive a HELLO after the ws was opened in time`);this._reconnect(true)},1e4)});this.betterWs.on("ws_receive",msg=>this.messageAction(msg));this.betterWs.on("ws_close",(code,reason)=>this.handleWsClose(code,reason));this.betterWs.on("debug",event=>this.client.emit("error",event));this.betterWs.on("ws_send",data=>this.client.emit("rawSend",data))}async connect(){this._closing=false;this._closeCalled=false;this.client.emit("debug",`Shard ${this.id} connecting to gateway`);return this.betterWs.connect().catch(e=>{if(e===connectionError)return;setTimeout(()=>{if(!this._closeCalled)this.connect()},5e3)})}async disconnect(){this._closing=true;this._closeCalled=true;return this.betterWs.close(1e3,"Disconnected by User")}async messageAction(message){this.client.emit("rawReceive",message);const withShardID=Object.assign(message,{shard_id:this.id});this.client.emit("event",withShardID);switch(withShardID.op){case import_Constants.GATEWAY_OP_CODES.DISPATCH:this.handleDispatch(withShardID);break;case import_Constants.GATEWAY_OP_CODES.HEARTBEAT:this.heartbeat();break;case import_Constants.GATEWAY_OP_CODES.RECONNECT:this.client.emit("debug",`Gateway asked shard ${this.id} to reconnect`);if(this.options.reconnect)this._reconnect(true);else this.disconnect();break;case import_Constants.GATEWAY_OP_CODES.INVALID_SESSION:this.client.emit("debug",`Shard ${this.id}'s session was invalidated`);if(withShardID.d&&this.sessionId)this.resume();else{this.seq=0;this.sessionId="";this.emit("queueIdentify",this.id)}break;case import_Constants.GATEWAY_OP_CODES.HELLO:if(this._openToHeartbeatTimeout)clearTimeout(this._openToHeartbeatTimeout);this.client.emit("debug",`Shard ${this.id} received HELLO`);this.lastACKAt=Date.now();this.heartbeatInterval=withShardID.d.heartbeat_interval;this._initialHeartbeatTimeout=setTimeout(()=>this.heartbeat(),this.heartbeatInterval*Math.random());this._trace=withShardID.d._trace;this._onHello();break;case import_Constants.GATEWAY_OP_CODES.HEARTBEAT_ACK:this.lastACKAt=Date.now();this.latency=this.lastACKAt-this.lastHeartbeatSend;break;default:}}async _reconnect(resume=false){var _a,_b;(_b=(_a=this.betterWs._internal).openRejector)==null?void 0:_b.call(_a,connectionError);this.reconnecting=resume;await this.betterWs.close(resume?4e3:1012,"reconnecting");if(resume){this.clearHeartBeat();if(this.resumeAddress)this.betterWs.address=this.resumeAddress;else this.betterWs.address=this.identifyAddress}else{this.reset();this.betterWs.address=this.identifyAddress}this.connect()}reset(){this.sessionId=null;this.seq=0;this.lastACKAt=0;this._trace=null;this.clearHeartBeat()}setHeartBeat(){this.heartbeatTimeout=setInterval(()=>{if(this.lastACKAt<=Date.now()-(this.heartbeatInterval+5e3)){this.client.emit("debug",`Shard ${this.id} has not received a heartbeat ACK in ${this.heartbeatInterval+5e3}ms.`);if(this.options.reconnect)this._reconnect(true);else this.disconnect()}else this.heartbeat()},this.heartbeatInterval)}clearHeartBeat(){if(this.heartbeatTimeout)clearInterval(this.heartbeatTimeout);if(this._initialHeartbeatTimeout)clearTimeout(this._initialHeartbeatTimeout);this.heartbeatTimeout=null;this._initialHeartbeatTimeout=null;this.heartbeatInterval=0}_onHello(){if(this.sessionId)return void this.resume();else this.emit("queueIdentify",this.id)}async identify(){if(this.betterWs.status!==1){this.client.emit("error",`Shard ${this.id} was attempting to identify when the ws was not open. Was ${wsStatusTypes[this.betterWs.status]}`);return this._reconnect(true)}this.client.emit("debug",`Shard ${this.id} is identifying`);this.status="identifying";this.emit("stateChange","identifying");const data={op:import_Constants.GATEWAY_OP_CODES.IDENTIFY,d:{token:this.options.token,properties:{os:process.platform,browser:"CloudStorm",device:"CloudStorm"},large_threshold:this.options.largeGuildThreshold,shard:[this.id,this.options.totalShards??1],intents:this.options.intents?Intents2.resolve(this.options.intents):0}};if(this.options.initialPresence)data.d.presence=this._checkPresenceData(this.options.initialPresence);return this.betterWs.sendMessage(data)}async resume(){if(this.betterWs.status!==1){this.client.emit("error",`Shard ${this.id} was attempting to resume when the ws was not open. Was ${wsStatusTypes[this.betterWs.status]}`);return this._reconnect(true)}this.client.emit("debug",`Shard ${this.id} is resuming`);this.status="resuming";this.emit("stateChange","resuming");return this.betterWs.sendMessage({op:import_Constants.GATEWAY_OP_CODES.RESUME,d:{seq:this.seq,token:this.options.token,session_id:this.sessionId}})}heartbeat(){if(this.betterWs.status!==1){this.client.emit("error",`Shard ${this.id} was attempting to heartbeat when the ws was not open. Was ${wsStatusTypes[this.betterWs.status]}`);return void this._reconnect(true)}this.betterWs.sendMessage({op:import_Constants.GATEWAY_OP_CODES.HEARTBEAT,d:this.seq===0?null:this.seq});this.lastHeartbeatSend=Date.now();if(this._initialHeartbeatTimeout){clearTimeout(this._initialHeartbeatTimeout);this._initialHeartbeatTimeout=null}if(!this.heartbeatTimeout)this.setHeartBeat()}handleDispatch(message){var _a,_b;this.client.emit("dispatch",message);if(message.s){if(message.s>this.seq+1){this.client.emit("debug",`Shard ${this.id} invalid sequence: { current: ${this.seq} message: ${message.s} }`);this.seq=message.s;this.resume()}this.seq=message.s}switch(message.t){case"READY":case"RESUMED":if(message.t==="READY"){if(message.d.resume_gateway_url)this.resumeAddress=`${message.d.resume_gateway_url}?v=${import_Constants.GATEWAY_VERSION}&encoding=${((_a=this.options.ws)==null?void 0:_a.encoding)==="etf"?"etf":"json"}${((_b=this.options.ws)==null?void 0:_b.compress)?"&compress=zlib-stream":""}`;this.sessionId=message.d.session_id}this.status="ready";this.emit("stateChange","ready");this._trace=message.d._trace;this.emit("ready",message.t==="RESUMED");break;default:}}handleWsClose(code,reason){let gracefulClose=false;this.status="disconnected";this.emit("stateChange","disconnected");this.clearHeartBeat();const message=disconnectMessages[code];const isRecoverable=resumableCodes.includes(code);const shouldntReconnect=shouldntAttemptReconnectCodes.includes(code);if(isRecoverable&&this.resumeAddress)this.betterWs.address=this.resumeAddress;else this.betterWs.address=this.identifyAddress;if(message)this.client.emit("error",message);if(code===1e3&&this._closing||this.reconnecting)gracefulClose=true;if(!shouldntReconnect&&this.reconnect)this.connect();this._closing=false;this.emit("disconnect",code,reason,gracefulClose)}async presenceUpdate(data){return this.betterWs.sendMessage({op:import_Constants.GATEWAY_OP_CODES.PRESENCE_UPDATE,d:this._checkPresenceData(data)})}async voiceStateUpdate(data){if(!data)return Promise.resolve();return this.betterWs.sendMessage({op:import_Constants.GATEWAY_OP_CODES.VOICE_STATE_UPDATE,d:this._checkVoiceStateUpdateData(data)})}async requestGuildMembers(data){return this.betterWs.sendMessage({op:import_Constants.GATEWAY_OP_CODES.REQUEST_GUILD_MEMBERS,d:this._checkRequestGuildMembersData(data)})}_checkPresenceData(data){data.status=data.status??import_v10.PresenceUpdateStatus.Online;data.activities=data.activities&&Array.isArray(data.activities)?data.activities:[];if(data.activities){for(const activity of data.activities){const index=data.activities.indexOf(activity);if(activity.type===void 0)activity.type=activity.url?1:0;if(!activity.name){if(activity.state&&activity.type===4)activity.name="Custom Status";else data.activities.splice(index,1)}}}data.afk=data.afk??false;data.since=data.since??Date.now();return data}_checkVoiceStateUpdateData(data){data.channel_id=data.channel_id??null;data.self_mute=data.self_mute??false;data.self_deaf=data.self_deaf??false;return data}_checkRequestGuildMembersData(data){const withQuery=data;const withUserIDs=data;if(!withQuery.query&&!withUserIDs.user_ids)withQuery.query="";if(withQuery.query&&withUserIDs.user_ids)delete data.query;data.limit=data.limit??10;return data}};module2.exports=DiscordConnector}});var require_Shard=__commonJS({"src/Shard.ts"(exports2,module2){"use strict";var import_events=require("events");var DC=require_DiscordConnector();var Shard=class extends import_events.EventEmitter{constructor(id,client){super();this.id=id;this.client=client;this.ready=false;this.connector=new DC(id,client);this.connector.on("disconnect",(...args)=>{this.ready=false;this.emit("disconnect",...args)});this.connector.on("ready",resume=>this.emit("ready",resume));this.connector.on("queueIdentify",()=>this.emit("queueIdentify",this.id))}get latency(){return this.connector.latency}connect(){this.connector.connect()}disconnect(){return this.connector.disconnect()}presenceUpdate(data){return this.connector.presenceUpdate(data)}voiceStateUpdate(data){return this.connector.voiceStateUpdate(data)}requestGuildMembers(data){return this.connector.requestGuildMembers(data)}};module2.exports=Shard}});var require_ShardManager=__commonJS({"src/ShardManager.ts"(exports2,module2){"use strict";var import_snowtransfer=require("snowtransfer");var Shard=require_Shard();var ShardManager=class{constructor(client){this.client=client;this.shards={};this.identifyBucket=new import_snowtransfer.LocalBucket(1e3,1e3*60*60*24);this.concurrencyBucket=null;this.options=client.options}spawn(){if(!this.concurrencyBucket)throw new Error("Trying to spawn shards without calling Client.connect()");for(const id of this.options.shards==="auto"?Array(this.options.totalShards).fill(0).map((_,index)=>index):this.options.shards??[0]){this.client.emit("debug",`Spawned shard ${id}`);this.shards[id]=new Shard(id,this.client);this._addListener(this.shards[id]);this.shards[id].connector.connect()}}disconnect(){for(const shardKey in this.shards){this.shards[shardKey].disconnect()}}_addListener(shard){shard.on("ready",resume=>{shard.ready=true;this.client.emit("debug",`Shard ${shard.id} ${resume?"has resumed":"is ready"}`);this.client.emit("shardReady",{id:shard.id,ready:!resume});this._checkReady()});shard.on("queueIdentify",shardId=>{var _a;if(!this.shards[shardId])return this.client.emit("debug",`Received a queueIdentify event for shard ${shardId} but it does not exist. Was it removed?`);this.client.emit("debug",`Shard ${shardId} is ready to identify`);if(shard.connector.reconnecting)return shard.connector.resume();(_a=this.concurrencyBucket)==null?void 0:_a.queue(()=>{this.identifyBucket.queue(()=>this.shards[shardId].connector.identify())})});shard.on("disconnect",(code,reason,gracefulClose)=>{this.client.emit("debug",`Websocket of shard ${shard.id} closed with code ${code} and reason: ${reason??"None"}`);if(code===1e3&&gracefulClose)return this._checkDisconnect()})}_checkReady(){for(const shardId in this.shards){if(this.shards[shardId]){if(!this.shards[shardId].ready)return}}this.client.emit("ready")}_checkDisconnect(){for(const shardId in this.shards){if(this.shards[shardId]){if(this.shards[shardId].connector.status!=="disconnected")return}}this.client.emit("disconnected")}async presenceUpdate(data){for(const shardKey in this.shards){if(this.shards[shardKey]){const shard=this.shards[shardKey];this.shardPresenceUpdate(shard.id,data)}}}shardPresenceUpdate(shardId,data){return new Promise((res,rej)=>{const shard=this.shards[shardId];if(!shard)rej(new Error(`Shard ${shardId} does not exist`));if(!shard.ready)return;shard.presenceUpdate(data).then(result=>res(result)).catch(e=>rej(e))})}voiceStateUpdate(shardId,data){return new Promise((res,rej)=>{const shard=this.shards[shardId];if(!shard)rej(new Error(`Shard ${shardId} does not exist`));if(!shard.ready)return;shard.voiceStateUpdate(data).then(result=>res(result)).catch(e=>rej(e))})}requestGuildMembers(shardId,data){return new Promise((res,rej)=>{const shard=this.shards[shardId];if(!shard)rej(new Error(`Shard ${shardId} does not exist`));if(!shard.ready)return;shard.requestGuildMembers(data).then(result=>res(result)).catch(e=>rej(e))})}};module2.exports=ShardManager}});var require_Client=__commonJS({"src/Client.ts"(exports2,module2){"use strict";var import_events=require("events");var import_snowtransfer=require("snowtransfer");var version=require_package().version;var Constants2=require_Constants();var ShardManager=require_ShardManager();var Client=class extends import_events.EventEmitter{constructor(token,options={}){super();this.version=version;if(!token)throw new Error("Missing token!");this.options={largeGuildThreshold:250,shards:"auto",reconnect:true,intents:0,token:"",ws:{compress:true,encoding:"json"}};this._restClient=options.snowtransferInstance?options.snowtransferInstance:new import_snowtransfer.SnowTransfer(token);delete options.snowtransferInstance;this.token=token.startsWith("Bot ")?token.substring(4):token;Object.assign(this.options,options);this.options.token=token;this.shardManager=new ShardManager(this)}async connect(){const initial=await this.fetchConnectInfo();if(this.options.shards==="auto")this.options.totalShards=initial;this.shardManager.spawn()}async fetchConnectInfo(){var _a;const gateway=await this.getGatewayBot();this._updateEndpoint(gateway.url);const oldQueueConcurrency=[];const oldQueueIdentify=[];if((_a=this.shardManager.concurrencyBucket)==null?void 0:_a.fnQueue.length){oldQueueConcurrency.push(...this.shardManager.concurrencyBucket.fnQueue);this.shardManager.concurrencyBucket.dropQueue()}if(this.shardManager.identifyBucket.fnQueue.length)oldQueueIdentify.push(...this.shardManager.identifyBucket.fnQueue);this.shardManager.identifyBucket.dropQueue();this.shardManager.concurrencyBucket=new import_snowtransfer.LocalBucket(gateway.session_start_limit.max_concurrency,5e3);this.shardManager.identifyBucket.remaining=gateway.session_start_limit.remaining;this.shardManager.identifyBucket.reset=gateway.session_start_limit.reset_after;for(const fn of oldQueueConcurrency){this.shardManager.concurrencyBucket.queue(fn)}for(const fn of oldQueueIdentify){this.shardManager.identifyBucket.queue(fn)}return gateway.shards}async getGateway(){const gatewayData=await this._restClient.bot.getGateway();return gatewayData.url}async getGatewayBot(){return this._restClient.bot.getGatewayBot()}disconnect(){return this.shardManager.disconnect()}async presenceUpdate(data){return this.shardManager.presenceUpdate(data)}shardStatusUpdate(shardId,data){return this.shardManager.shardPresenceUpdate(shardId,data)}voiceStateUpdate(shardId,data){return this.shardManager.voiceStateUpdate(shardId,data)}requestGuildMembers(shardId,data){if(!data.guild_id)throw new Error("You need to pass a guild_id");return this.shardManager.requestGuildMembers(shardId,data)}_updateEndpoint(gatewayUrl){var _a,_b;this.options.endpoint=`${gatewayUrl}?v=${Constants2.GATEWAY_VERSION}&encoding=${((_a=this.options.ws)==null?void 0:_a.encoding)==="etf"?"etf":"json"}${((_b=this.options.ws)==null?void 0:_b.compress)?"&compress=zlib-stream":""}`}};module2.exports=Client}});var src_exports={};__export(src_exports,{BetterWs:()=>BetterWs2,Client:()=>Client2,Constants:()=>Constants,Intents:()=>Intents,Shard:()=>Shard2,ShardManager:()=>ShardManager2});module.exports=__toCommonJS(src_exports);var Client2=require_Client();var Constants=require_Constants();var Intents=(init_Intents(),__toCommonJS(Intents_exports));var Shard2=require_Shard();var ShardManager2=require_ShardManager();var BetterWs2=require_BetterWs();0&&(module.exports={BetterWs,Client,Constants,Intents,Shard,ShardManager}); | ||
var __create=Object.create;var __defProp=Object.defineProperty;var __getOwnPropDesc=Object.getOwnPropertyDescriptor;var __getOwnPropNames=Object.getOwnPropertyNames;var __getProtoOf=Object.getPrototypeOf;var __hasOwnProp=Object.prototype.hasOwnProperty;var __esm=(fn,res)=>function __init(){return fn&&(res=(0,fn[__getOwnPropNames(fn)[0]])(fn=0)),res};var __commonJS=(cb,mod)=>function __require(){return mod||(0,cb[__getOwnPropNames(cb)[0]])((mod={exports:{}}).exports,mod),mod.exports};var __export=(target,all2)=>{for(var name in all2)__defProp(target,name,{get:all2[name],enumerable:true})};var __copyProps=(to,from,except,desc)=>{if(from&&typeof from==="object"||typeof from==="function"){for(let key of __getOwnPropNames(from))if(!__hasOwnProp.call(to,key)&&key!==except)__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable})}return to};var __toESM=(mod,isNodeMode,target)=>(target=mod!=null?__create(__getProtoOf(mod)):{},__copyProps(isNodeMode||!mod||!mod.__esModule?__defProp(target,"default",{value:mod,enumerable:true}):target,mod));var __toCommonJS=mod=>__copyProps(__defProp({},"__esModule",{value:true}),mod);var require_package=__commonJS({"package.json"(exports2,module2){module2.exports={name:"cloudstorm",version:"0.10.4",description:"Minimalistic Discord Gateway library",main:"./dist/index.js",engines:{node:">=14.8.0"},types:"./dist/index.d.ts",scripts:{"build:src":"tsup src/index.ts --clean --dts --sourcemap --format cjs --target node14 --minify-whitespace","build:docs":"typedoc --name CloudStorm --excludeExternals --sort static-first --sort alphabetical"},author:"wolke <wolke@weeb.sh>",license:"MIT",dependencies:{"discord-api-types":"^0.37.67",snowtransfer:"^0.10.3"},devDependencies:{"@types/node":"20.11.7","@typescript-eslint/eslint-plugin":"^6.19.1","@typescript-eslint/parser":"^6.19.1",eslint:"^8.56.0",tsup:"^8.0.1",typedoc:"^0.25.7","typedoc-plugin-mdn-links":"^3.1.13",typescript:"^5.3.0"},files:["dist","README.md","LICENSE.md"]}}});var require_Constants=__commonJS({"src/Constants.ts"(exports2,module2){"use strict";var Constants2={GATEWAY_OP_CODES:{DISPATCH:0,HEARTBEAT:1,IDENTIFY:2,PRESENCE_UPDATE:3,VOICE_STATE_UPDATE:4,RESUME:6,RECONNECT:7,REQUEST_GUILD_MEMBERS:8,INVALID_SESSION:9,HELLO:10,HEARTBEAT_ACK:11},GATEWAY_VERSION:10};module2.exports=Constants2}});var require_BetterWs=__commonJS({"src/BetterWs.ts"(exports2,module2){"use strict";var import_events=require("events");var import_crypto=require("crypto");var import_zlib=require("zlib");var import_Constants=__toESM(require_Constants());var import_snowtransfer=require("snowtransfer");var https=require("https");var http=require("http");var util=require("util");var BetterWs=class extends import_events.EventEmitter{constructor(address,options){super();this.address=address;this.options=options;this.wsBucket=new import_snowtransfer.LocalBucket(120,6e4);this.presenceBucket=new import_snowtransfer.LocalBucket(5,6e4);this._socket=null;this._internal={openRejector:null,closePromise:null,zlib:null};this._connecting=false;this._lastCloseCode=null;this._lastCloseReason=null;this.encoding=options.encoding??"json";this.compress=options.compress??false}get status(){const internal=this._internal;if(this._connecting)return 2;if(internal.closePromise)return 3;if(!this._socket)return 4;return 1}connect(){if(this._socket||this._connecting)return Promise.resolve(void 0);this._connecting=true;const key=(0,import_crypto.randomBytes)(16).toString("base64");const url=new URL(this.address);const useHTTPS=url.protocol==="https:"||url.protocol==="wss:"||url.port==="443";const port=url.port||(useHTTPS?"443":"80");const req=(useHTTPS?https:http).request({hostname:url.hostname,path:`${url.pathname}${url.search}`,port,headers:{"Connection":"Upgrade","Upgrade":"websocket","Sec-WebSocket-Key":key,"Sec-WebSocket-Version":"13"}});let onErrorRef;let cameFromOnError=false;return new Promise((resolve2,reject)=>{this._internal.openRejector=reject;const upgrade=this._onUpgrade.bind(this,key,req,resolve2,reject);onErrorRef=e=>{this._internal.openRejector=null;cameFromOnError=true;this._connecting=false;req.removeListener("upgrade",upgrade);reject(e)};req.once("upgrade",upgrade);req.once("error",onErrorRef);req.end()}).catch(reason=>{if(onErrorRef&&!cameFromOnError){req.destroy();req.removeListener("error",onErrorRef);onErrorRef(reason)}return Promise.reject(reason)})}async close(code,reason){const internal=this._internal;if(internal.closePromise)return internal.closePromise;if(!this._socket)return Promise.resolve(void 0);let resolver;const promise=new Promise(resolve2=>{resolver=resolve2;const from=Buffer.from([code>>8,code&255]);this._write(reason?Buffer.concat([from,Buffer.from(reason)]):from,8)}).then(()=>{internal.closePromise=null});promise.resolve=resolver;internal.closePromise=promise;return promise}sendMessage(data){if(!isValidRequest(data))return Promise.reject(new Error("Invalid request"));return new Promise(res=>{const presence=data.op===import_Constants.GATEWAY_OP_CODES.PRESENCE_UPDATE;const sendMsg=()=>{this.wsBucket.queue(()=>{this.emit("ws_send",data);if(this.encoding==="json")this._write(Buffer.from(JSON.stringify(data)),1);else{const etf=writeETF(data);this._write(etf,2)}res(void 0)})};if(presence)this.presenceBucket.queue(sendMsg);else sendMsg()})}_write(packet,opcode){const socket=this._socket;if(!(socket==null?void 0:socket.writable))return;const length=packet.length;let frame;if(length<126){frame=Buffer.allocUnsafe(6+length);frame[1]=128+length}else if(length<1<<16){frame=Buffer.allocUnsafe(8+length);frame[1]=254;frame[2]=length>>8;frame[3]=length&255}else{frame=Buffer.allocUnsafe(14+length);frame[1]=255;frame.writeBigUInt64BE(BigInt(length),2)}frame[0]=128+opcode;frame.writeUInt32BE(0,frame.length-length-4);frame.set(packet,frame.length-length);socket.write(frame)}_onUpgrade(key,req,resolve2,reject,res,socket){this._internal.openRejector=null;const hash=(0,import_crypto.createHash)("sha1").update(key+"258EAFA5-E914-47DA-95CA-C5AB0DC85B11").digest("base64");const accept=res.headers["sec-websocket-accept"];if(hash!==accept){socket.end(()=>{this.emit("debug","Failed websocket-key validation");this._connecting=false;reject(new Error(`Invalid Sec-Websocket-Accept | expected: ${hash} | received: ${accept}`))});return}socket.once("error",this._onError.bind(this));socket.once("close",this._onClose.bind(this));socket.on("readable",this._onReadable.bind(this));this._socket=socket;this._connecting=false;if(this.compress){const z=(0,import_zlib.createInflate)();z._c=z.close;z._h=z._handle;z._hc=z._handle.close;z._v=()=>void 0;this._internal.zlib=z}this.emit("ws_open");resolve2(void 0);req.removeAllListeners("error")}_onError(error){if(!this._socket)return;this.emit("debug",util.inspect(error,true,1,false));this._write(Buffer.allocUnsafe(0),8)}_onClose(){const socket=this._socket;const internal=this._internal;if(!socket)return;socket.removeListener("data",this._onReadable);socket.removeListener("error",this._onError);this.wsBucket.dropQueue();this.presenceBucket.dropQueue();this._socket=null;this.emit("ws_close",this._lastCloseCode??1006,this._lastCloseReason??"Abnormal Closure");this._lastCloseCode=null;this._lastCloseReason=null;if(internal.zlib){internal.zlib.close();internal.zlib=null}if(internal.closePromise)internal.closePromise.resolve(void 0)}_onReadable(){const socket=this._socket;while(((socket==null?void 0:socket.readableLength)||0)>1){let length=readRange(socket,1,1)&127;let bytes=0;if(length>125){bytes=length===126?2:8;if(socket.readableLength<2+bytes)return;length=readRange(socket,2,bytes)}const frame=socket.read(2+bytes+length);if(!frame)return;const fin=frame[0]>>7;const opcode=frame[0]&15;if(fin!==1||opcode===0)this.emit("debug","discord actually does send messages with fin=0. if you see this error let me know");const payload=frame.subarray(2+bytes);this._processFrame(opcode,payload)}}_processFrame(opcode,message){const internal=this._internal;switch(opcode){case 1:{const packet=JSON.parse(message.toString());this.emit("ws_receive",packet);break}case 2:{let packet;if(this.compress){const z=internal.zlib;let error=null;let data=null;z.close=z._handle.close=z._v;try{data=z._processChunk(message,import_zlib.constants.Z_SYNC_FLUSH)}catch(e){error=e}const l=message.length;if(message[l-4]!==0||message[l-3]!==0||message[l-2]!==255||message[l-1]!==255)this.emit("debug","discord actually does send fragmented zlib messages. If you see this error let me know");z.close=z._c;z._handle=z._h;z._handle.close=z._hc;z._events.error=void 0;z._eventCount--;z.removeAllListeners("error");if(error){this.emit("debug","Zlib error processing chunk");this._write(Buffer.allocUnsafe(0),8);return}if(!data){this.emit("debug","Data from zlib processing was null. If you see this error let me know");return}packet=this.encoding==="json"?JSON.parse(String(data)):readETF(data,1)}else if(this.encoding==="json"){const data=(0,import_zlib.inflateSync)(message);packet=JSON.parse(data.toString())}else packet=readETF(message,1);this.emit("ws_receive",packet);break}case 8:{this._lastCloseCode=message.length>1?(message[0]<<8)+message[1]:0;this._lastCloseReason=message.length>2?message.subarray(2).toString():"";this._write(Buffer.from([this._lastCloseCode>>8,this._lastCloseCode&255]),8);break}case 9:{this._write(message,10);break}}}};function isValidRequest(value){return value&&typeof value==="object"&&Number.isInteger(value.op)&&typeof value.d!=="undefined"}function readRange(socket,index,bytes){let head=socket._readableState.buffer.head;let cursor=0;let read=0;let num=0;do{for(const element of head.data){if(++cursor>index){num*=256;num+=element;if(++read===bytes)return num}}}while(head=head.next);throw new Error("readRange failed?")}function readETF(data,start){let view;let x=start;const loop=()=>{const type=data[x++];switch(type){case 97:{return data[x++]}case 98:{const int=data.readInt32BE(x);x+=4;return int}case 100:{const length=data.readUInt16BE(x);let atom="";if(length>30){atom=data.latin1Slice(x+=2,x+length)}else{for(let i=x+=2;i<x+length;i++){atom+=String.fromCharCode(data[i])}}x+=length;if(!atom)return void 0;if(atom==="nil"||atom==="null")return null;if(atom==="true")return true;if(atom==="false")return false;return atom}case 108:case 106:{const array=[];if(type===108){const length=data.readUInt32BE(x);x+=4;for(let i=0;i<length;i++){array.push(loop())}x++}return array}case 107:{const array=[];const length=data.readUInt16BE(x);x+=2;for(let i=0;i<length;i++){array.push(data[x++])}return array}case 109:{const length=data.readUInt32BE(x);let str="";if(length>30){str=data.utf8Slice(x+=4,x+length)}else{let i=x+=4;const l=x+length;while(i<l){const byte=data[i++];if(byte<128)str+=String.fromCharCode(byte);else if(byte<224)str+=String.fromCharCode(((byte&31)<<6)+(data[i++]&63));else if(byte<240)str+=String.fromCharCode(((byte&15)<<12)+((data[i++]&63)<<6)+(data[i++]&63));else str+=String.fromCodePoint(((byte&7)<<18)+((data[i++]&63)<<12)+((data[i++]&63)<<6)+(data[i++]&63))}}x+=length;return str}case 110:{if(!view)view=new DataView(data.buffer,data.offset,data.byteLength);const length=data[x++];const sign=data[x++];let left=length;let num=BigInt(0);while(left>0){if(left>=8){num<<=BigInt(64);num+=view.getBigUint64(x+(left-=8),true)}else if(left>=4){num<<=BigInt(32);num+=BigInt(view.getUint32(x+(left-=4)),true)}else if(left>=2){num<<=BigInt(16);num+=BigInt(view.getUint16(x+(left-=2)),true)}else{num<<=BigInt(8);num+=BigInt(data[x]);left--}}x+=length;return(sign?-num:num).toString()}case 116:{const obj={};const length=data.readUInt32BE(x);x+=4;for(let i=0;i<length;i++){const key=loop();obj[key]=loop()}return obj}}throw new Error(`Missing etf type: ${type}`)};return loop()}function writeETF(data){const b=Buffer.allocUnsafe(1<<12);b[0]=131;let i=1;const loop=obj=>{const type=typeof obj;switch(type){case"boolean":{b[i++]=100;if(obj){b.writeUInt16BE(4,i);b.latin1Write("true",i+=2);i+=4}else{b.writeUInt16BE(5,i);b.latin1Write("false",i+=2);i+=5}break}case"string":{const length=Buffer.byteLength(obj);b[i++]=109;b.writeUInt32BE(length,i);b.utf8Write(obj,i+=4);i+=length;break}case"number":{if(Number.isInteger(obj)){const abs=Math.abs(obj);if(abs<2147483648){b[i++]=98;b.writeInt32BE(obj,i);i+=4}else if(abs<Number.MAX_SAFE_INTEGER){b[i++]=110;b[i++]=8;b[i++]=Number(obj<0);b.writeBigUInt64LE(BigInt(abs),i);i+=8;break}else{b[i++]=70;b.writeDoubleBE(obj,i);i+=8}}else{b[i++]=70;b.writeDoubleBE(obj,i);i+=8}break}case"bigint":{b[i++]=110;b[i++]=8;b[i++]=Number(obj<0);b.writeBigUInt64LE(obj,i);i+=8;break}case"object":{if(obj===null){b[i++]=100;b.writeUInt16BE(3,i);b.latin1Write("nil",i+=2);i+=3}else if(Array.isArray(obj)){if(obj.length){b[i++]=108;b.writeUInt32BE(obj.length,i);i+=4;for(const item of obj){loop(item)}}b[i++]=106}else{const entries=Object.entries(obj).filter(x=>typeof x[1]!=="undefined");b[i++]=116;b.writeUInt32BE(entries.length,i);i+=4;for(const[key,value]of entries){loop(key);loop(value)}}break}}};loop(data);return Buffer.from(b.subarray(0,i))}module2.exports=BetterWs}});var Intents_exports={};__export(Intents_exports,{all:()=>all,default:()=>Intents_default,flags:()=>flags,non_privileged:()=>non_privileged,privileged:()=>privileged,resolve:()=>resolve});function resolve(bit=0){if(typeof bit==="number"&&bit>=0)return bit;if(typeof bit==="string"&&flags[bit])return flags[bit]|0;if(Array.isArray(bit))return bit.map(p=>resolve(p)).reduce((prev,p)=>prev|p,0);throw new RangeError("BITFIELD_INVALID")}var flags,privileged,all,non_privileged,Intents_default;var init_Intents=__esm({"src/Intents.ts"(){"use strict";flags={GUILDS:1<<0,GUILD_MEMBERS:1<<1,GUILD_MODERATION:1<<2,GUILD_EMOJIS_AND_STICKERS:1<<3,GUILD_INTEGRATIONS:1<<4,GUILD_WEBHOOKS:1<<5,GUILD_INVITES:1<<6,GUILD_VOICE_STATES:1<<7,GUILD_PRESENCES:1<<8,GUILD_MESSAGES:1<<9,GUILD_MESSAGE_REACTIONS:1<<10,GUILD_MESSAGE_TYPING:1<<11,DIRECT_MESSAGES:1<<12,DIRECT_MESSAGE_REACTIONS:1<<13,DIRECT_MESSAGE_TYPING:1<<14,MESSAGE_CONTENT:1<<15,GUILD_SCHEDULED_EVENTS:1<<16,AUTO_MODERATION_CONFIGURATION:1<<20,AUTO_MODERATION_EXECUTION:1<<21};privileged=flags.GUILD_MEMBERS|flags.GUILD_PRESENCES|flags.MESSAGE_CONTENT;all=Object.values(flags).reduce((acc,p)=>acc|p,0);non_privileged=all&~privileged;Intents_default={flags,privileged,all,non_privileged,resolve}}});var require_DiscordConnector=__commonJS({"src/DiscordConnector.ts"(exports2,module2){"use strict";var import_events=require("events");var import_Constants=__toESM(require_Constants());var import_v10=require("discord-api-types/v10");var BetterWs=require_BetterWs();var Intents2=(init_Intents(),__toCommonJS(Intents_exports));var resumableCodes=[4008,4005,4003,4002,4001,4e3,1006,1001];var shouldntAttemptReconnectCodes=[4014,4013,4012,4011,4010,4004,1e3];var disconnectMessages={4014:"Disallowed Intents, check your client options and application page.",4013:"Invalid Intents data, check your client options.",4012:"Invalid API version.",4011:"Shard would be on over 2500 guilds. Add more shards.",4010:"Invalid sharding data, check your client options.",4009:"Session timed out.",4008:"You are being rate limited. Wait before sending more packets.",4007:"Invalid sequence. Reconnecting and starting a new session.",4005:"You sent more than one OP 2 IDENTIFY payload while the websocket was open.",4004:"Tried to connect with an invalid token.",4003:"You tried to send a packet before sending an OP 2 IDENTIFY or OP 6 RESUME.",4002:"You sent an invalid payload.",4001:"You sent an invalid opcode or invalid payload for an opcode."};var connectionError=new Error("WS took too long to connect. Is your internet okay?");var wsStatusTypes=["Whatever 0 is. Report if you see this","connected","connecting","closing","closed"];var DiscordConnector=class extends import_events.EventEmitter{constructor(id,client){super();this.id=id;this.client=client;this.heartbeatTimeout=null;this.heartbeatInterval=0;this._trace=null;this.seq=0;this.status="disconnected";this.sessionId=null;this.lastACKAt=0;this.lastHeartbeatSend=0;this.latency=0;this.resumeAddress=null;this.reconnecting=false;this._closing=false;this._closeCalled=false;this._openToHeartbeatTimeout=null;this._initialHeartbeatTimeout=null;this.options=client.options;this.reconnect=this.options.reconnect??true;this.identifyAddress=this.options.endpoint;this.betterWs=new BetterWs(this.identifyAddress,this.options.ws);this.betterWs.on("ws_open",()=>{this.status="connecting";this.emit("stateChange","connecting");this.reconnecting=false;this._openToHeartbeatTimeout=setTimeout(()=>{this.client.emit("debug",`Shard ${this.id} didn't receive a HELLO after the ws was opened in time`);this._reconnect(true)},1e4)});this.betterWs.on("ws_receive",msg=>this.messageAction(msg));this.betterWs.on("ws_close",(code,reason)=>this.handleWsClose(code,reason));this.betterWs.on("debug",event=>this.client.emit("error",event));this.betterWs.on("ws_send",data=>this.client.emit("rawSend",data))}async connect(){this._closing=false;this._closeCalled=false;this.client.emit("debug",`Shard ${this.id} connecting to gateway`);return this.betterWs.connect().catch(e=>{if(e===connectionError)return;setTimeout(()=>{if(!this._closeCalled)this.connect()},5e3)})}async disconnect(){this._closing=true;this._closeCalled=true;return this.betterWs.close(1e3,"Disconnected by User")}async messageAction(message){this.client.emit("rawReceive",message);const withShardID=Object.assign(message,{shard_id:this.id});this.client.emit("event",withShardID);switch(withShardID.op){case import_Constants.GATEWAY_OP_CODES.DISPATCH:this.handleDispatch(withShardID);break;case import_Constants.GATEWAY_OP_CODES.HEARTBEAT:this.heartbeat();break;case import_Constants.GATEWAY_OP_CODES.RECONNECT:this.client.emit("debug",`Gateway asked shard ${this.id} to reconnect`);if(this.options.reconnect)this._reconnect(true);else this.disconnect();break;case import_Constants.GATEWAY_OP_CODES.INVALID_SESSION:this.client.emit("debug",`Shard ${this.id}'s session was invalidated`);if(withShardID.d&&this.sessionId)this.resume();else{this.seq=0;this.sessionId="";this.emit("queueIdentify",this.id)}break;case import_Constants.GATEWAY_OP_CODES.HELLO:if(this._openToHeartbeatTimeout)clearTimeout(this._openToHeartbeatTimeout);this.client.emit("debug",`Shard ${this.id} received HELLO`);this.lastACKAt=Date.now();this.heartbeatInterval=withShardID.d.heartbeat_interval;this._initialHeartbeatTimeout=setTimeout(()=>this.heartbeat(),this.heartbeatInterval*Math.random());this._trace=withShardID.d._trace;this._onHello();break;case import_Constants.GATEWAY_OP_CODES.HEARTBEAT_ACK:this.lastACKAt=Date.now();this.latency=this.lastACKAt-this.lastHeartbeatSend;break;default:}}async _reconnect(resume=false){var _a,_b;(_b=(_a=this.betterWs._internal).openRejector)==null?void 0:_b.call(_a,connectionError);this.reconnecting=resume;await this.betterWs.close(resume?4e3:1012,"reconnecting");if(resume){this.clearHeartBeat();if(this.resumeAddress)this.betterWs.address=this.resumeAddress;else this.betterWs.address=this.identifyAddress}else{this.reset();this.betterWs.address=this.identifyAddress}this.connect()}reset(){this.sessionId=null;this.seq=0;this.lastACKAt=0;this._trace=null;this.clearHeartBeat()}setHeartBeat(){this.heartbeatTimeout=setInterval(()=>{if(this.lastACKAt<=Date.now()-(this.heartbeatInterval+5e3)){this.client.emit("debug",`Shard ${this.id} has not received a heartbeat ACK in ${this.heartbeatInterval+5e3}ms.`);if(this.options.reconnect)this._reconnect(true);else this.disconnect()}else this.heartbeat()},this.heartbeatInterval)}clearHeartBeat(){if(this.heartbeatTimeout)clearInterval(this.heartbeatTimeout);if(this._initialHeartbeatTimeout)clearTimeout(this._initialHeartbeatTimeout);this.heartbeatTimeout=null;this._initialHeartbeatTimeout=null;this.heartbeatInterval=0}_onHello(){if(this.sessionId)return void this.resume();else this.emit("queueIdentify",this.id)}async identify(){if(this.betterWs.status!==1){this.client.emit("error",`Shard ${this.id} was attempting to identify when the ws was not open. Was ${wsStatusTypes[this.betterWs.status]}`);return this._reconnect(true)}this.client.emit("debug",`Shard ${this.id} is identifying`);this.status="identifying";this.emit("stateChange","identifying");const data={op:import_Constants.GATEWAY_OP_CODES.IDENTIFY,d:{token:this.options.token,properties:{os:process.platform,browser:"CloudStorm",device:"CloudStorm"},large_threshold:this.options.largeGuildThreshold,shard:[this.id,this.options.totalShards??1],intents:this.options.intents?Intents2.resolve(this.options.intents):0}};if(this.options.initialPresence)data.d.presence=this._checkPresenceData(this.options.initialPresence);return this.betterWs.sendMessage(data)}async resume(){if(this.betterWs.status!==1){this.client.emit("error",`Shard ${this.id} was attempting to resume when the ws was not open. Was ${wsStatusTypes[this.betterWs.status]}`);return this._reconnect(true)}this.client.emit("debug",`Shard ${this.id} is resuming`);this.status="resuming";this.emit("stateChange","resuming");return this.betterWs.sendMessage({op:import_Constants.GATEWAY_OP_CODES.RESUME,d:{seq:this.seq,token:this.options.token,session_id:this.sessionId}})}heartbeat(){if(this.betterWs.status!==1){this.client.emit("error",`Shard ${this.id} was attempting to heartbeat when the ws was not open. Was ${wsStatusTypes[this.betterWs.status]}`);return void this._reconnect(true)}this.betterWs.sendMessage({op:import_Constants.GATEWAY_OP_CODES.HEARTBEAT,d:this.seq===0?null:this.seq});this.lastHeartbeatSend=Date.now();if(this._initialHeartbeatTimeout){clearTimeout(this._initialHeartbeatTimeout);this._initialHeartbeatTimeout=null}if(!this.heartbeatTimeout)this.setHeartBeat()}handleDispatch(message){var _a,_b;this.client.emit("dispatch",message);if(message.s){if(message.s>this.seq+1){this.client.emit("debug",`Shard ${this.id} invalid sequence: { current: ${this.seq} message: ${message.s} }`);this.seq=message.s;this.resume()}this.seq=message.s}switch(message.t){case"READY":case"RESUMED":if(message.t==="READY"){if(message.d.resume_gateway_url)this.resumeAddress=`${message.d.resume_gateway_url}?v=${import_Constants.GATEWAY_VERSION}&encoding=${((_a=this.options.ws)==null?void 0:_a.encoding)==="etf"?"etf":"json"}${((_b=this.options.ws)==null?void 0:_b.compress)?"&compress=zlib-stream":""}`;this.sessionId=message.d.session_id}this.status="ready";this.emit("stateChange","ready");this._trace=message.d._trace;this.emit("ready",message.t==="RESUMED");break;default:}}handleWsClose(code,reason){let gracefulClose=false;this.status="disconnected";this.emit("stateChange","disconnected");this.clearHeartBeat();const message=disconnectMessages[code];const isRecoverable=resumableCodes.includes(code);const shouldntReconnect=shouldntAttemptReconnectCodes.includes(code);if(isRecoverable&&this.resumeAddress)this.betterWs.address=this.resumeAddress;else this.betterWs.address=this.identifyAddress;if(message)this.client.emit("error",message);if(code===1e3&&this._closing||this.reconnecting)gracefulClose=true;if(!shouldntReconnect&&this.reconnect)this.connect();this._closing=false;this.emit("disconnect",code,reason,gracefulClose)}async presenceUpdate(data){return this.betterWs.sendMessage({op:import_Constants.GATEWAY_OP_CODES.PRESENCE_UPDATE,d:this._checkPresenceData(data)})}async voiceStateUpdate(data){if(!data)return Promise.resolve();return this.betterWs.sendMessage({op:import_Constants.GATEWAY_OP_CODES.VOICE_STATE_UPDATE,d:this._checkVoiceStateUpdateData(data)})}async requestGuildMembers(data){return this.betterWs.sendMessage({op:import_Constants.GATEWAY_OP_CODES.REQUEST_GUILD_MEMBERS,d:this._checkRequestGuildMembersData(data)})}_checkPresenceData(data){data.status=data.status??import_v10.PresenceUpdateStatus.Online;data.activities=data.activities&&Array.isArray(data.activities)?data.activities:[];if(data.activities){for(const activity of data.activities){const index=data.activities.indexOf(activity);if(activity.type===void 0)activity.type=activity.url?1:0;if(!activity.name){if(activity.state&&activity.type===4)activity.name="Custom Status";else data.activities.splice(index,1)}}}data.afk=data.afk??false;data.since=data.since??Date.now();return data}_checkVoiceStateUpdateData(data){data.channel_id=data.channel_id??null;data.self_mute=data.self_mute??false;data.self_deaf=data.self_deaf??false;return data}_checkRequestGuildMembersData(data){const withQuery=data;const withUserIDs=data;if(!withQuery.query&&!withUserIDs.user_ids)withQuery.query="";if(withQuery.query&&withUserIDs.user_ids)delete data.query;data.limit=data.limit??10;return data}};module2.exports=DiscordConnector}});var require_Shard=__commonJS({"src/Shard.ts"(exports2,module2){"use strict";var import_events=require("events");var DC=require_DiscordConnector();var Shard=class extends import_events.EventEmitter{constructor(id,client){super();this.id=id;this.client=client;this.ready=false;this.connector=new DC(id,client);this.connector.on("disconnect",(...args)=>{this.ready=false;this.emit("disconnect",...args)});this.connector.on("ready",resume=>this.emit("ready",resume));this.connector.on("queueIdentify",()=>this.emit("queueIdentify",this.id))}get latency(){return this.connector.latency}connect(){this.connector.connect()}disconnect(){return this.connector.disconnect()}presenceUpdate(data){return this.connector.presenceUpdate(data)}voiceStateUpdate(data){return this.connector.voiceStateUpdate(data)}requestGuildMembers(data){return this.connector.requestGuildMembers(data)}};module2.exports=Shard}});var require_ShardManager=__commonJS({"src/ShardManager.ts"(exports2,module2){"use strict";var import_snowtransfer=require("snowtransfer");var Shard=require_Shard();var ShardManager=class{constructor(client){this.client=client;this.shards={};this.identifyBucket=new import_snowtransfer.LocalBucket(1e3,1e3*60*60*24);this.concurrencyBucket=null;this.options=client.options}spawn(){if(!this.concurrencyBucket)throw new Error("Trying to spawn shards without calling Client.connect()");for(const id of this.options.shards==="auto"?Array(this.options.totalShards).fill(0).map((_,index)=>index):this.options.shards??[0]){this.client.emit("debug",`Spawned shard ${id}`);this.shards[id]=new Shard(id,this.client);this._addListener(this.shards[id]);this.shards[id].connector.connect()}}disconnect(){for(const shardKey in this.shards){this.shards[shardKey].disconnect()}}_addListener(shard){shard.on("ready",resume=>{shard.ready=true;this.client.emit("debug",`Shard ${shard.id} ${resume?"has resumed":"is ready"}`);this.client.emit("shardReady",{id:shard.id,ready:!resume});this._checkReady()});shard.on("queueIdentify",shardId=>{var _a;if(!this.shards[shardId])return this.client.emit("debug",`Received a queueIdentify event for shard ${shardId} but it does not exist. Was it removed?`);this.client.emit("debug",`Shard ${shardId} is ready to identify`);if(shard.connector.reconnecting)return shard.connector.resume();(_a=this.concurrencyBucket)==null?void 0:_a.queue(()=>{this.identifyBucket.queue(()=>this.shards[shardId].connector.identify())})});shard.on("disconnect",(code,reason,gracefulClose)=>{this.client.emit("debug",`Websocket of shard ${shard.id} closed with code ${code} and reason: ${reason??"None"}`);if(code===1e3&&gracefulClose)return this._checkDisconnect()})}_checkReady(){for(const shardId in this.shards){if(this.shards[shardId]){if(!this.shards[shardId].ready)return}}this.client.emit("ready")}_checkDisconnect(){for(const shardId in this.shards){if(this.shards[shardId]){if(this.shards[shardId].connector.status!=="disconnected")return}}this.client.emit("disconnected")}async presenceUpdate(data){for(const shardKey in this.shards){if(this.shards[shardKey]){const shard=this.shards[shardKey];this.shardPresenceUpdate(shard.id,data)}}}shardPresenceUpdate(shardId,data){return new Promise((res,rej)=>{const shard=this.shards[shardId];if(!shard)rej(new Error(`Shard ${shardId} does not exist`));if(!shard.ready)return;shard.presenceUpdate(data).then(result=>res(result)).catch(e=>rej(e))})}voiceStateUpdate(shardId,data){return new Promise((res,rej)=>{const shard=this.shards[shardId];if(!shard)rej(new Error(`Shard ${shardId} does not exist`));if(!shard.ready)return;shard.voiceStateUpdate(data).then(result=>res(result)).catch(e=>rej(e))})}requestGuildMembers(shardId,data){return new Promise((res,rej)=>{const shard=this.shards[shardId];if(!shard)rej(new Error(`Shard ${shardId} does not exist`));if(!shard.ready)return;shard.requestGuildMembers(data).then(result=>res(result)).catch(e=>rej(e))})}};module2.exports=ShardManager}});var require_Client=__commonJS({"src/Client.ts"(exports2,module2){"use strict";var import_events=require("events");var import_snowtransfer=require("snowtransfer");var version=require_package().version;var Constants2=require_Constants();var ShardManager=require_ShardManager();var Client=class extends import_events.EventEmitter{constructor(token,options={}){super();this.version=version;if(!token)throw new Error("Missing token!");this.options={largeGuildThreshold:250,shards:"auto",reconnect:true,intents:0,token:"",ws:{compress:true,encoding:"json"}};this._restClient=options.snowtransferInstance?options.snowtransferInstance:new import_snowtransfer.SnowTransfer(token);delete options.snowtransferInstance;this.token=token.startsWith("Bot ")?token.substring(4):token;Object.assign(this.options,options);this.options.token=token;this.shardManager=new ShardManager(this)}async connect(){const initial=await this.fetchConnectInfo();if(this.options.shards==="auto")this.options.totalShards=initial;this.shardManager.spawn()}async fetchConnectInfo(){var _a;const gateway=await this.getGatewayBot();this._updateEndpoint(gateway.url);const oldQueueConcurrency=[];const oldQueueIdentify=[];if((_a=this.shardManager.concurrencyBucket)==null?void 0:_a.fnQueue.length){oldQueueConcurrency.push(...this.shardManager.concurrencyBucket.fnQueue);this.shardManager.concurrencyBucket.dropQueue()}if(this.shardManager.identifyBucket.fnQueue.length)oldQueueIdentify.push(...this.shardManager.identifyBucket.fnQueue);this.shardManager.identifyBucket.dropQueue();this.shardManager.concurrencyBucket=new import_snowtransfer.LocalBucket(gateway.session_start_limit.max_concurrency,5e3);this.shardManager.identifyBucket.remaining=gateway.session_start_limit.remaining;this.shardManager.identifyBucket.reset=gateway.session_start_limit.reset_after;for(const fn of oldQueueConcurrency){this.shardManager.concurrencyBucket.queue(fn)}for(const fn of oldQueueIdentify){this.shardManager.identifyBucket.queue(fn)}return gateway.shards}async getGateway(){const gatewayData=await this._restClient.bot.getGateway();return gatewayData.url}async getGatewayBot(){return this._restClient.bot.getGatewayBot()}disconnect(){return this.shardManager.disconnect()}async presenceUpdate(data){return this.shardManager.presenceUpdate(data)}shardStatusUpdate(shardId,data){return this.shardManager.shardPresenceUpdate(shardId,data)}voiceStateUpdate(shardId,data){return this.shardManager.voiceStateUpdate(shardId,data)}requestGuildMembers(shardId,data){if(!data.guild_id)throw new Error("You need to pass a guild_id");return this.shardManager.requestGuildMembers(shardId,data)}_updateEndpoint(gatewayUrl){var _a,_b;this.options.endpoint=`${gatewayUrl}?v=${Constants2.GATEWAY_VERSION}&encoding=${((_a=this.options.ws)==null?void 0:_a.encoding)==="etf"?"etf":"json"}${((_b=this.options.ws)==null?void 0:_b.compress)?"&compress=zlib-stream":""}`}};module2.exports=Client}});var src_exports={};__export(src_exports,{BetterWs:()=>BetterWs2,Client:()=>Client2,Constants:()=>Constants,Intents:()=>Intents,Shard:()=>Shard2,ShardManager:()=>ShardManager2});module.exports=__toCommonJS(src_exports);var Client2=require_Client();var Constants=require_Constants();var Intents=(init_Intents(),__toCommonJS(Intents_exports));var Shard2=require_Shard();var ShardManager2=require_ShardManager();var BetterWs2=require_BetterWs();0&&(module.exports={BetterWs,Client,Constants,Intents,Shard,ShardManager}); | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "cloudstorm", | ||
"version": "0.10.3", | ||
"version": "0.10.4", | ||
"description": "Minimalistic Discord Gateway library", | ||
@@ -18,3 +18,3 @@ "main": "./dist/index.js", | ||
"discord-api-types": "^0.37.67", | ||
"snowtransfer": "^0.10.1" | ||
"snowtransfer": "^0.10.3" | ||
}, | ||
@@ -21,0 +21,0 @@ "devDependencies": { |
Sorry, the diff of this file is not supported yet
Updatedsnowtransfer@^0.10.3