cloudstorm
Advanced tools
Comparing version 0.4.0 to 0.4.1
@@ -7,9 +7,2 @@ "use strict"; | ||
const events_1 = require("events"); | ||
let Erlpack; | ||
try { | ||
Erlpack = require("erlpack"); | ||
} | ||
catch (e) { | ||
Erlpack = null; | ||
} | ||
const Constants_1 = __importDefault(require("./Constants")); | ||
@@ -28,5 +21,4 @@ const snowtransfer_1 = require("snowtransfer"); | ||
super(); | ||
if (!token) { | ||
if (!token) | ||
throw new Error("Missing token!"); | ||
} | ||
this.options = { | ||
@@ -42,3 +34,3 @@ largeGuildThreshold: 250, | ||
compress: true, | ||
socket: undefined | ||
encoding: "json" | ||
} | ||
@@ -101,4 +93,3 @@ }; | ||
async presenceUpdate(data) { | ||
await this.shardManager.presenceUpdate(data); | ||
void undefined; | ||
return this.shardManager.presenceUpdate(data); | ||
} | ||
@@ -166,5 +157,4 @@ /** | ||
requestGuildMembers(shardId, data) { | ||
if (!data.guild_id) { | ||
if (!data.guild_id) | ||
throw new Error("You need to pass a guild_id"); | ||
} | ||
return this.shardManager.requestGuildMembers(shardId, data); | ||
@@ -177,4 +167,4 @@ } | ||
_updateEndpoint(gatewayUrl) { | ||
var _a; | ||
this.options.endpoint = `${gatewayUrl}?v=${Constants_1.default.GATEWAY_VERSION}&encoding=${Erlpack ? "etf" : "json"}${((_a = this.options.ws) === null || _a === void 0 ? void 0 : _a.compress) ? "&compress=zlib-stream" : ""}`; | ||
var _a, _b; | ||
this.options.endpoint = `${gatewayUrl}?v=${Constants_1.default.GATEWAY_VERSION}&encoding=${((_a = this.options.ws) === null || _a === void 0 ? void 0 : _a.encoding) === "etf" ? "etf" : "json"}${((_b = this.options.ws) === null || _b === void 0 ? void 0 : _b.compress) ? "&compress=zlib-stream" : ""}`; | ||
} | ||
@@ -181,0 +171,0 @@ } |
@@ -8,4 +8,4 @@ /// <reference types="node" /> | ||
ready: [boolean]; | ||
error: [string]; | ||
disconnect: [number, string, boolean]; | ||
stateChange: ["connecting" | "identifying" | "resuming" | "ready" | "disconnected"]; | ||
} | ||
@@ -37,3 +37,3 @@ interface DiscordConnector { | ||
reconnect: boolean; | ||
betterWs: BetterWs | null; | ||
betterWs: BetterWs; | ||
heartbeatTimeout: NodeJS.Timeout | null; | ||
@@ -43,3 +43,3 @@ heartbeatInterval: number; | ||
seq: number; | ||
status: string; | ||
status: "connecting" | "identifying" | "resuming" | "ready" | "disconnected"; | ||
sessionId: string | null; | ||
@@ -59,3 +59,3 @@ lastACKAt: number; | ||
*/ | ||
connect(): void; | ||
connect(): Promise<void>; | ||
/** | ||
@@ -62,0 +62,0 @@ * Close the websocket connection and disconnect. |
@@ -9,3 +9,2 @@ "use strict"; | ||
const Intents_1 = __importDefault(require("../Intents")); | ||
const ws_1 = __importDefault(require("ws")); | ||
let reconnecting = false; | ||
@@ -25,3 +24,2 @@ /** | ||
super(); | ||
this.betterWs = null; | ||
this.heartbeatTimeout = null; | ||
@@ -31,3 +29,3 @@ this.heartbeatInterval = 0; | ||
this.seq = 0; | ||
this.status = "init"; | ||
this.status = "disconnected"; | ||
this.sessionId = null; | ||
@@ -41,16 +39,6 @@ this.lastACKAt = 0; | ||
this.reconnect = this.options.reconnect || true; | ||
} | ||
/** | ||
* Connect to Discord. | ||
*/ | ||
connect() { | ||
if (!this.betterWs) { | ||
this.betterWs = new BetterWs_1.default(this.options.endpoint, this.options.ws); | ||
} | ||
else { | ||
this.betterWs.removeAllListeners(); | ||
this.betterWs.recreateWs(this.options.endpoint, this.options.ws); | ||
} | ||
this.betterWs = new BetterWs_1.default(this.options.endpoint, this.options.ws); | ||
this.betterWs.on("ws_open", () => { | ||
this.status = "connecting"; | ||
this.emit("stateChange", "connecting"); | ||
reconnecting = false; | ||
@@ -60,15 +48,16 @@ }); | ||
this.betterWs.on("ws_close", (code, reason) => this.handleWsClose(code, reason)); | ||
this.betterWs.on("debug", event => { | ||
this.client.emit("debug", event); | ||
}); | ||
this.betterWs.on("debug_send", data => { | ||
this.client.emit("rawSend", data); | ||
}); | ||
this.betterWs.on("debug", event => this.client.emit("debug", event)); | ||
this.betterWs.on("debug_send", data => this.client.emit("rawSend", data)); | ||
} | ||
/** | ||
* Connect to Discord. | ||
*/ | ||
connect() { | ||
return this.betterWs.connect(); | ||
} | ||
/** | ||
* Close the websocket connection and disconnect. | ||
*/ | ||
async disconnect() { | ||
var _a; | ||
return (_a = this.betterWs) === null || _a === void 0 ? void 0 : _a.close(1000, "Disconnected by User"); | ||
return this.betterWs.close(); | ||
} | ||
@@ -104,5 +93,4 @@ /** | ||
case Constants_1.GATEWAY_OP_CODES.INVALID_SESSION: | ||
if (message.d && this.sessionId) { | ||
if (message.d && this.sessionId) | ||
this.resume(); | ||
} | ||
else { | ||
@@ -125,5 +113,4 @@ this.seq = 0; | ||
} | ||
else { | ||
else | ||
this.heartbeat(); | ||
} | ||
}, this.heartbeatInterval); | ||
@@ -147,20 +134,11 @@ this._trace = message.d._trace; | ||
async _reconnect(resume = false) { | ||
var _a, _b, _c; | ||
if (resume) | ||
reconnecting = true; | ||
if (((_a = this.betterWs) === null || _a === void 0 ? void 0 : _a.ws.readyState) === ws_1.default.CONNECTING) { | ||
this.emit("error", `Client was attempting to ${resume ? "resume" : "reconnect"} while the WebSocket was still in the connecting state. This should never happen.${this.options.reconnect ? " Restarting the connect loop." : ""}`); | ||
this.reset(); | ||
if (this.options.reconnect) | ||
this.connect(); | ||
} | ||
// This is for instances where the gateway asks the client to reconnect. The ws would be closed by the time the code reaches here. | ||
if (((_b = this.betterWs) === null || _b === void 0 ? void 0 : _b.ws.readyState) === ws_1.default.OPEN) | ||
await ((_c = this.betterWs) === null || _c === void 0 ? void 0 : _c.close(resume ? 4000 : 1012, "reconnecting")); | ||
if (resume) { | ||
if (this.betterWs.status === 2) | ||
void this.client.emit("error", `Client was attempting to ${resume ? "resume" : "reconnect"} while the WebSocket was still in the connecting state. This should never happen.`); | ||
await this.betterWs.close(); | ||
if (resume) | ||
this.clearHeartBeat(); | ||
} | ||
else { | ||
else | ||
this.reset(); | ||
} | ||
this.connect(); | ||
@@ -192,6 +170,8 @@ } | ||
async identify(force) { | ||
var _a; | ||
if (this.sessionId && !force) { | ||
if (this.betterWs.status !== 1) | ||
void this.client.emit("debug", "Client was attempting to identify when the ws was not open"); | ||
if (this.sessionId && !force) | ||
return this.resume(); | ||
} | ||
this.status = "identifying"; | ||
this.emit("stateChange", "identifying"); | ||
const data = { | ||
@@ -213,3 +193,3 @@ op: Constants_1.GATEWAY_OP_CODES.IDENTIFY, | ||
Object.assign(data.d, { presence: this._checkPresenceData(this.options.initialPresence) }); | ||
return (_a = this.betterWs) === null || _a === void 0 ? void 0 : _a.sendMessage(data); | ||
return this.betterWs.sendMessage(data); | ||
} | ||
@@ -220,4 +200,7 @@ /** | ||
async resume() { | ||
var _a; | ||
return (_a = this.betterWs) === null || _a === void 0 ? void 0 : _a.sendMessage({ | ||
if (this.betterWs.status !== 1) | ||
void this.client.emit("debug", "Client was attempting to resume when the ws was not open"); | ||
this.status = "resuming"; | ||
this.emit("stateChange", "resuming"); | ||
return this.betterWs.sendMessage({ | ||
op: Constants_1.GATEWAY_OP_CODES.RESUME, | ||
@@ -231,6 +214,5 @@ d: { seq: this.seq, token: this.options.token, session_id: this.sessionId } | ||
heartbeat() { | ||
var _a, _b; | ||
if (((_a = this.betterWs) === null || _a === void 0 ? void 0 : _a.ws.readyState) !== ws_1.default.OPEN) | ||
return; | ||
(_b = this.betterWs) === null || _b === void 0 ? void 0 : _b.sendMessage({ op: Constants_1.GATEWAY_OP_CODES.HEARTBEAT, d: this.seq }); | ||
if (this.betterWs.status !== 1) | ||
void this.client.emit("debug", "Client was attempting to heartbeat when the ws was not open"); | ||
this.betterWs.sendMessage({ op: Constants_1.GATEWAY_OP_CODES.HEARTBEAT, d: this.seq }); | ||
this.lastHeartbeatSend = Date.now(); | ||
@@ -246,6 +228,6 @@ } | ||
case "RESUMED": | ||
if (message.t === "READY") { | ||
if (message.t === "READY") | ||
this.sessionId = message.d.session_id; | ||
} | ||
this.status = "ready"; | ||
this.emit("stateChange", "ready"); | ||
this._trace = message.d._trace; | ||
@@ -265,29 +247,24 @@ this.emit("ready", message.t === "RESUMED"); | ||
handleWsClose(code, reason) { | ||
var _a; | ||
let gracefulClose = false; | ||
this.status = "disconnected"; | ||
this.emit("stateChange", "disconnected"); | ||
// Disallowed Intents. | ||
if (code === 4014) { | ||
this.emit("error", "Disallowed Intents, check your client options and application page."); | ||
} | ||
if (code === 4014) | ||
this.client.emit("error", "Disallowed Intents, check your client options and application page."); | ||
// Invalid Intents. | ||
if (code === 4013) { | ||
this.emit("error", "Invalid Intents data, check your client options."); | ||
} | ||
if (code === 4013) | ||
this.client.emit("error", "Invalid Intents data, check your client options."); | ||
// Invalid API version. | ||
if (code === 4012) { | ||
this.emit("error", "Invalid API version."); | ||
} | ||
if (code === 4012) | ||
this.client.emit("error", "Invalid API version."); | ||
// Sharding required. | ||
if (code === 4011) { | ||
this.emit("error", "Shard would be on over 2500 guilds. Add more shards."); | ||
} | ||
if (code === 4011) | ||
this.client.emit("error", "Shard would be on over 2500 guilds. Add more shards."); | ||
// Invalid shard. | ||
if (code === 4010) { | ||
this.emit("error", "Invalid sharding data, check your client options."); | ||
} | ||
if (code === 4010) | ||
this.client.emit("error", "Invalid sharding data, check your client options."); | ||
// Session timed out. | ||
// force identify if the session is marked as invalid. | ||
if (code === 4009) { | ||
this.emit("error", "Session timed out."); | ||
this.client.emit("error", "Session timed out."); | ||
this.clearHeartBeat(); | ||
@@ -298,3 +275,3 @@ this.connect(); | ||
if (code === 4008) { | ||
this.emit("error", "You are being rate limited. Wait before sending more packets."); | ||
this.client.emit("error", "You are being rate limited. Wait before sending more packets."); | ||
this.clearHeartBeat(); | ||
@@ -305,3 +282,3 @@ this.connect(); | ||
if (code === 4007) { | ||
this.emit("error", "Invalid sequence. Reconnecting and starting a new session."); | ||
this.client.emit("error", "Invalid sequence. Reconnecting and starting a new session."); | ||
this.reset(); | ||
@@ -312,3 +289,3 @@ this.connect(); | ||
if (code === 4005) { | ||
this.emit("error", "You sent more than one OP 2 IDENTIFY payload while the websocket was open."); | ||
this.client.emit("error", "You sent more than one OP 2 IDENTIFY payload while the websocket was open."); | ||
this.clearHeartBeat(); | ||
@@ -318,8 +295,7 @@ this.connect(); | ||
// Authentication failed. | ||
if (code === 4004) { | ||
this.emit("error", "Tried to connect with an invalid token"); | ||
} | ||
if (code === 4004) | ||
this.client.emit("error", "Tried to connect with an invalid token"); | ||
// Not authenticated. | ||
if (code === 4003) { | ||
this.emit("error", "You tried to send a packet before sending an OP 2 IDENTIFY or OP 6 RESUME."); | ||
this.client.emit("error", "You tried to send a packet before sending an OP 2 IDENTIFY or OP 6 RESUME."); | ||
this.clearHeartBeat(); | ||
@@ -330,3 +306,3 @@ this.connect(); | ||
if (code === 4002) { | ||
this.emit("error", "You sent an invalid payload"); | ||
this.client.emit("error", "You sent an invalid payload"); | ||
this.clearHeartBeat(); | ||
@@ -337,3 +313,3 @@ this.connect(); | ||
if (code === 4001) { | ||
this.emit("error", "You sent an invalid opcode or invalid payload for an opcode"); | ||
this.client.emit("error", "You sent an invalid opcode or invalid payload for an opcode"); | ||
this.clearHeartBeat(); | ||
@@ -344,7 +320,6 @@ this.connect(); | ||
if (code === 4000) { | ||
if (reconnecting) { | ||
if (reconnecting) | ||
gracefulClose = true; | ||
} | ||
else { | ||
this.emit("error", "Error code 4000 received. Attempting to resume"); | ||
this.client.emit("error", "Error code 4000 received. Attempting to resume"); | ||
this.clearHeartBeat(); | ||
@@ -355,8 +330,7 @@ this.connect(); | ||
// Don't try to reconnect when true | ||
if (code === 1000 && reason === "Disconnected by User") { | ||
if (code === 1000 && reason === "Disconnected by User") | ||
gracefulClose = true; | ||
} | ||
if (gracefulClose) { | ||
this.clearHeartBeat(); | ||
(_a = this.betterWs) === null || _a === void 0 ? void 0 : _a.removeAllListeners(); | ||
this.betterWs.removeAllListeners(); | ||
} | ||
@@ -370,4 +344,3 @@ this.emit("disconnect", code, reason, gracefulClose); | ||
async presenceUpdate(data) { | ||
var _a; | ||
return (_a = this.betterWs) === null || _a === void 0 ? void 0 : _a.sendMessage({ op: Constants_1.GATEWAY_OP_CODES.PRESENCE_UPDATE, d: this._checkPresenceData(data) }); | ||
return this.betterWs.sendMessage({ op: Constants_1.GATEWAY_OP_CODES.PRESENCE_UPDATE, d: this._checkPresenceData(data) }); | ||
} | ||
@@ -379,7 +352,5 @@ /** | ||
async voiceStateUpdate(data) { | ||
var _a; | ||
if (!data) { | ||
if (!data) | ||
return Promise.resolve(); | ||
} | ||
return (_a = this.betterWs) === null || _a === void 0 ? void 0 : _a.sendMessage({ op: Constants_1.GATEWAY_OP_CODES.VOICE_STATE_UPDATE, d: this._checkVoiceStateUpdateData(data) }); | ||
return this.betterWs.sendMessage({ op: Constants_1.GATEWAY_OP_CODES.VOICE_STATE_UPDATE, d: this._checkVoiceStateUpdateData(data) }); | ||
} | ||
@@ -391,4 +362,3 @@ /** | ||
async requestGuildMembers(data) { | ||
var _a; | ||
return (_a = this.betterWs) === null || _a === void 0 ? void 0 : _a.sendMessage({ op: Constants_1.GATEWAY_OP_CODES.REQUEST_GUILD_MEMBERS, d: this._checkRequestGuildMembersData(data) }); | ||
return this.betterWs.sendMessage({ op: Constants_1.GATEWAY_OP_CODES.REQUEST_GUILD_MEMBERS, d: this._checkRequestGuildMembersData(data) }); | ||
} | ||
@@ -395,0 +365,0 @@ /** |
@@ -17,2 +17,3 @@ export declare const flags: { | ||
DIRECT_MESSAGE_TYPING: number; | ||
MESSAGE_CONTENT: number; | ||
}; | ||
@@ -19,0 +20,0 @@ export declare const privileged: number; |
@@ -20,4 +20,5 @@ "use strict"; | ||
DIRECT_MESSAGE_TYPING: 1 << 14, | ||
MESSAGE_CONTENT: 1 << 15, | ||
}; | ||
exports.privileged = exports.flags.GUILD_MEMBERS | exports.flags.GUILD_PRESENCES | exports.flags.GUILD_MESSAGES; | ||
exports.privileged = exports.flags.GUILD_MEMBERS | exports.flags.GUILD_PRESENCES | exports.flags.GUILD_MESSAGES | exports.flags.MESSAGE_CONTENT; | ||
exports.all = Object.values(exports.flags).reduce((acc, p) => acc | p, 0); | ||
@@ -24,0 +25,0 @@ exports.non_privileged = exports.all & ~exports.privileged; |
@@ -6,3 +6,2 @@ /// <reference types="node" /> | ||
disconnect: [number, string, boolean]; | ||
error: [string]; | ||
ready: [boolean]; | ||
@@ -9,0 +8,0 @@ queueIdentify: [number]; |
@@ -43,11 +43,4 @@ "use strict"; | ||
}); | ||
this.connector.on("error", (err) => { | ||
this.emit("error", err); | ||
}); | ||
this.connector.on("ready", (resume) => { | ||
this.emit("ready", resume); | ||
}); | ||
this.connector.on("queueIdentify", () => { | ||
this.emit("queueIdentify", this.id); | ||
}); | ||
this.connector.on("ready", (resume) => this.emit("ready", resume)); | ||
this.connector.on("queueIdentify", () => this.emit("queueIdentify", this.id)); | ||
} | ||
@@ -54,0 +47,0 @@ /** |
@@ -18,5 +18,4 @@ "use strict"; | ||
this.options = client.options; | ||
if (!this.options.connectQueueInterval) { | ||
if (!this.options.connectQueueInterval) | ||
this.options.connectQueueInterval = 1000 * 5; | ||
} | ||
this.shards = {}; | ||
@@ -96,5 +95,2 @@ this.connectQueue = []; | ||
}); | ||
shard.on("error", (error) => { | ||
this.client.emit("error", error); | ||
}); | ||
shard.on("disconnect", (code, reason, gracefulClose) => { | ||
@@ -122,5 +118,4 @@ this.client.emit("debug", `Websocket of shard ${shard.id} closed with code ${code} and reason: ${reason ? reason : "None"}`); | ||
if (this.shards[shardId]) { | ||
if (!this.shards[shardId].ready) { | ||
if (!this.shards[shardId].ready) | ||
return; | ||
} | ||
} | ||
@@ -136,5 +131,4 @@ } | ||
if (this.shards[shardId]) { | ||
if (this.shards[shardId].connector.status !== "disconnected") { | ||
if (this.shards[shardId].connector.status !== "disconnected") | ||
return; | ||
} | ||
} | ||
@@ -164,10 +158,6 @@ } | ||
const shard = this.shards[shardId]; | ||
if (!shard) { | ||
if (!shard) | ||
rej(new Error(`Shard ${shardId} does not exist`)); | ||
} | ||
if (!shard.ready) { | ||
shard.once("ready", () => { | ||
shard.presenceUpdate(data).then(result => res(result)).catch(e => rej(e)); | ||
}); | ||
} | ||
if (!shard.ready) | ||
shard.once("ready", () => shard.presenceUpdate(data).then(result => res(result)).catch(e => rej(e))); | ||
shard.presenceUpdate(data).then(result => res(result)).catch(e => rej(e)); | ||
@@ -184,10 +174,6 @@ }); | ||
const shard = this.shards[shardId]; | ||
if (!shard) { | ||
if (!shard) | ||
rej(new Error(`Shard ${shardId} does not exist`)); | ||
} | ||
if (!shard.ready) { | ||
shard.once("ready", () => { | ||
shard.voiceStateUpdate(data).then(result => res(result)).catch(e => rej(e)); | ||
}); | ||
} | ||
if (!shard.ready) | ||
shard.once("ready", () => shard.voiceStateUpdate(data).then(result => res(result)).catch(e => rej(e))); | ||
shard.voiceStateUpdate(data).then(result => res(result)).catch(e => rej(e)); | ||
@@ -204,10 +190,6 @@ }); | ||
const shard = this.shards[shardId]; | ||
if (!shard) { | ||
if (!shard) | ||
rej(new Error(`Shard ${shardId} does not exist`)); | ||
} | ||
if (!shard.ready) { | ||
shard.once("ready", () => { | ||
shard.requestGuildMembers(data).then(result => res(result)).catch(e => rej(e)); | ||
}); | ||
} | ||
if (!shard.ready) | ||
shard.once("ready", () => shard.requestGuildMembers(data).then(result => res(result)).catch(e => rej(e))); | ||
shard.requestGuildMembers(data).then(result => res(result)).catch(e => rej(e)); | ||
@@ -214,0 +196,0 @@ }); |
/// <reference types="node" /> | ||
import { EventEmitter } from "events"; | ||
import zlib from "zlib-sync"; | ||
import WebSocket from "ws"; | ||
import RatelimitBucket from "./RatelimitBucket"; | ||
interface BWSEvents { | ||
error: [Error | string]; | ||
ws_open: []; | ||
@@ -33,56 +30,22 @@ ws_close: [number, string]; | ||
declare class BetterWs extends EventEmitter { | ||
ws: WebSocket; | ||
encoding: "etf" | "json"; | ||
compress: boolean; | ||
address: string; | ||
options: import("../Types").IClientWSOptions; | ||
wsBucket: RatelimitBucket; | ||
presenceBucket: RatelimitBucket; | ||
zlibInflate: zlib.Inflate | null; | ||
options: import("../Types").IClientWSOptions; | ||
compress: boolean; | ||
static readonly default: typeof BetterWs; | ||
/** | ||
* Create a new BetterWs instance. | ||
*/ | ||
constructor(address: string, options?: import("../Types").IClientWSOptions); | ||
/** | ||
* Get the raw websocket connection currently used. | ||
*/ | ||
get rawWs(): WebSocket; | ||
/** | ||
* Add eventlisteners to a passed websocket connection. | ||
* @param ws Websocket. | ||
*/ | ||
private bindWs; | ||
/** | ||
* Create a new websocket connection if the old one was closed/destroyed. | ||
* @param address Address to connect to. | ||
* @param options Options used by the websocket connection. | ||
*/ | ||
recreateWs(address: string, options?: import("../Types").IClientWSOptions): void; | ||
/** | ||
* Called upon opening of the websocket connection. | ||
*/ | ||
private onOpen; | ||
/** | ||
* Called once a websocket message is received, | ||
* uncompresses the message using zlib and parses it via Erlpack or JSON.parse. | ||
* @param message Message received by websocket. | ||
*/ | ||
private onMessage; | ||
/** | ||
* Called when the websocket connection closes for some reason. | ||
* @param code Websocket close code. | ||
* @param reason Reason of the close if any. | ||
*/ | ||
private onClose; | ||
/** | ||
* Send a message to the Discord gateway. | ||
* @param data Data to send. | ||
*/ | ||
sendMessage(data: any): Promise<void>; | ||
/** | ||
* Close the current websocket connection. | ||
* @param code Websocket close code to use. | ||
* @param reason Reason of the disconnect. | ||
*/ | ||
close(code?: number, reason?: string): Promise<void>; | ||
private _socket; | ||
private _internal; | ||
private _connecting; | ||
constructor(address: string, options: import("../Types").IClientWSOptions); | ||
get status(): 1 | 2 | 3 | 4; | ||
connect(): Promise<void>; | ||
close(): Promise<void>; | ||
sendMessage(data: import("../Types").IWSMessage): Promise<void>; | ||
private _write; | ||
private _onError; | ||
private _onClose; | ||
private _onReadable; | ||
private _processFrame; | ||
} | ||
export = BetterWs; |
@@ -6,12 +6,8 @@ "use strict"; | ||
const events_1 = require("events"); | ||
const zlib_sync_1 = __importDefault(require("zlib-sync")); | ||
let Erlpack; | ||
try { | ||
Erlpack = require("erlpack"); | ||
} | ||
catch (e) { | ||
Erlpack = null; | ||
} | ||
const crypto_1 = require("crypto"); | ||
const zlib_1 = require("zlib"); | ||
const https_1 = require("https"); | ||
const util_1 = __importDefault(require("util")); | ||
const Z_SYNC_FLUSH = zlib_1.constants.Z_SYNC_FLUSH; | ||
const Constants_1 = require("../Constants"); | ||
const ws_1 = __importDefault(require("ws")); | ||
const RatelimitBucket_1 = __importDefault(require("./RatelimitBucket")); | ||
@@ -22,175 +18,525 @@ /** | ||
class BetterWs extends events_1.EventEmitter { | ||
/** | ||
* Create a new BetterWs instance. | ||
*/ | ||
constructor(address, options = {}) { | ||
constructor(address, options) { | ||
super(); | ||
this.zlibInflate = null; | ||
this.ws = new ws_1.default(address, options.socket); | ||
this.bindWs(this.ws); | ||
this.wsBucket = new RatelimitBucket_1.default(120, 60000); | ||
this.presenceBucket = new RatelimitBucket_1.default(5, 20000); | ||
if (options.compress) { | ||
this.zlibInflate = new zlib_sync_1.default.Inflate({ chunkSize: 65535 }); | ||
this.compress = true; | ||
} | ||
else | ||
this.compress = false; | ||
this.presenceBucket = new RatelimitBucket_1.default(5, 60000); | ||
this._connecting = false; | ||
this.encoding = options.encoding === "etf" ? "etf" : "json"; | ||
this.compress = options.compress || false; | ||
this.address = address; | ||
this.options = options; | ||
this._socket = null; | ||
this._internal = { | ||
closePromise: null, | ||
zlib: null, | ||
}; | ||
} | ||
/** | ||
* Get the raw websocket connection currently used. | ||
*/ | ||
get rawWs() { | ||
return this.ws; | ||
get status() { | ||
const internal = this._internal; | ||
if (this._connecting) | ||
return 2; | ||
if (internal.closePromise) | ||
return 3; // closing | ||
if (!this._socket) | ||
return 4; // closed | ||
return 1; // connected | ||
} | ||
/** | ||
* Add eventlisteners to a passed websocket connection. | ||
* @param ws Websocket. | ||
*/ | ||
bindWs(ws) { | ||
ws.on("message", (msg) => { | ||
this.onMessage(msg); | ||
connect() { | ||
if (this._socket) | ||
return Promise.resolve(void 0); | ||
const key = (0, crypto_1.randomBytes)(16).toString("base64"); | ||
this.emit("debug", "Creating connection"); | ||
const url = new URL(this.address); | ||
const req = (0, https_1.request)({ | ||
hostname: url.hostname, | ||
path: `${url.pathname}${url.search}`, | ||
headers: { | ||
"Connection": "Upgrade", | ||
"Upgrade": "websocket", | ||
"Sec-WebSocket-Key": key, | ||
"Sec-WebSocket-Version": "13", | ||
} | ||
}); | ||
ws.on("close", (code, reason) => this.onClose(code, reason.toString())); | ||
ws.on("error", (err) => { | ||
this.emit("error", err); | ||
this._connecting = true; | ||
return new Promise((resolve, reject) => { | ||
req.on("upgrade", (res, socket) => { | ||
const hash = (0, crypto_1.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.on("error", this._onError.bind(this)); | ||
socket.on("close", this._onClose.bind(this)); | ||
socket.on("readable", this._onReadable.bind(this)); | ||
this._socket = socket; | ||
this._connecting = false; | ||
if (this.compress) { | ||
const z = (0, zlib_1.createInflate)(); | ||
// @ts-ignore | ||
z._c = z.close; | ||
// @ts-ignore | ||
z._h = z._handle; | ||
// @ts-ignore | ||
z._hc = z._handle.close; | ||
// @ts-ignore | ||
z._v = () => void 0; | ||
this._internal.zlib = z; | ||
} | ||
this.emit("ws_open"); | ||
resolve(void 0); | ||
}); | ||
req.on("error", e => { | ||
this._connecting = false; | ||
reject(e); | ||
}); | ||
req.end(); | ||
}); | ||
ws.on("open", () => this.onOpen()); | ||
} | ||
/** | ||
* Create a new websocket connection if the old one was closed/destroyed. | ||
* @param address Address to connect to. | ||
* @param options Options used by the websocket connection. | ||
*/ | ||
recreateWs(address, options = {}) { | ||
this.ws.removeAllListeners(); | ||
if (options.compress) { | ||
this.zlibInflate = new zlib_sync_1.default.Inflate({ chunkSize: 65535 }); | ||
this.compress = true; | ||
async close() { | ||
const internal = this._internal; | ||
if (internal.closePromise) | ||
return internal.closePromise; | ||
if (!this._socket) | ||
return Promise.resolve(void 0); | ||
let resolver; | ||
const promise = new Promise(resolve => { | ||
resolver = resolve; | ||
this._write(Buffer.allocUnsafe(0), 8); | ||
}).then(() => { | ||
internal.closePromise = null; | ||
}); | ||
// @ts-ignore | ||
promise.resolve = resolver; | ||
internal.closePromise = promise; | ||
} | ||
sendMessage(data) { | ||
if (!isValidRequest(data)) | ||
return Promise.reject(new Error("Invalid request")); | ||
return new Promise(res => { | ||
const presence = data.op === Constants_1.GATEWAY_OP_CODES.PRESENCE_UPDATE; | ||
const sendMsg = () => { | ||
this.wsBucket.queue(() => { | ||
this.emit("debug_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 || !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 { | ||
this.zlibInflate = null; | ||
this.compress = false; | ||
frame = Buffer.allocUnsafe(14 + length); | ||
frame[1] = 255; | ||
frame.writeBigUInt64BE(BigInt(length), 2); | ||
} | ||
this.ws = new ws_1.default(address, options.socket); | ||
this.options = options; | ||
frame[0] = 128 + opcode; | ||
frame.writeUInt32BE(0, frame.length - length - 4); | ||
frame.set(packet, frame.length - length); | ||
socket.write(frame); | ||
} | ||
_onError(error) { | ||
if (!this._socket) | ||
return; | ||
this.emit("debug", util_1.default.inspect(error, true, 1, false)); | ||
this._write(Buffer.allocUnsafe(0), 8); | ||
} | ||
_onClose() { | ||
const socket = this._socket; | ||
const internal = this._internal; | ||
if (!socket) | ||
return; | ||
this.emit("debug", "Connection closed"); | ||
socket.removeListener("data", this._onReadable); | ||
socket.removeListener("error", this._onError); | ||
socket.removeListener("close", this._onClose); | ||
this.wsBucket.dropQueue(); | ||
this.presenceBucket.dropQueue(); | ||
this.wsBucket = new RatelimitBucket_1.default(120, 60000); | ||
this.presenceBucket = new RatelimitBucket_1.default(5, 60000); | ||
this.bindWs(this.ws); | ||
this._socket = null; | ||
if (internal.zlib) { | ||
internal.zlib.close(); | ||
internal.zlib = null; | ||
} | ||
if (internal.closePromise) { | ||
// @ts-ignore | ||
internal.closePromise.resolve(void 0); | ||
} | ||
} | ||
/** | ||
* Called upon opening of the websocket connection. | ||
*/ | ||
onOpen() { | ||
this.emit("ws_open"); | ||
} | ||
/** | ||
* Called once a websocket message is received, | ||
* uncompresses the message using zlib and parses it via Erlpack or JSON.parse. | ||
* @param message Message received by websocket. | ||
*/ | ||
onMessage(message) { | ||
let parsed; | ||
try { | ||
let msg; | ||
if (this.compress && this.zlibInflate) { | ||
const length = message.length; | ||
const flush = length >= 4 && | ||
message[length - 4] === 0x00 && | ||
message[length - 3] === 0x00 && | ||
message[length - 2] === 0xFF && | ||
message[length - 1] === 0xFF; | ||
this.zlibInflate.push(message, flush ? zlib_sync_1.default.Z_SYNC_FLUSH : false); | ||
if (!flush) | ||
_onReadable() { | ||
const socket = this._socket; | ||
while (socket.readableLength > 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; | ||
msg = this.zlibInflate.result; | ||
length = readRange(socket, 2, bytes); | ||
} | ||
else | ||
msg = message; | ||
if (Erlpack) { | ||
parsed = Erlpack.unpack(msg); | ||
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.slice(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_message", packet); | ||
break; | ||
} | ||
else { | ||
parsed = JSON.parse(String(msg)); | ||
case 2: { | ||
let packet; | ||
if (this.compress) { | ||
const z = internal.zlib; | ||
let error = null; | ||
let data = null; | ||
// @ts-ignore | ||
z.close = z._handle.close = z._v; | ||
try { | ||
// @ts-ignore | ||
data = z._processChunk(message, 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"); | ||
// @ts-ignore | ||
z.close = z._c; | ||
// @ts-ignore | ||
z._handle = z._h; | ||
// @ts-ignore | ||
z._handle.close = z._hc; | ||
// @ts-ignore | ||
z._events.error = void 0; | ||
// @ts-ignore | ||
z._eventCount--; | ||
z.removeAllListeners("error"); | ||
if (error) { | ||
this.emit("debug", "Zlib error"); | ||
this._write(Buffer.allocUnsafe(0), 8); | ||
return; | ||
} | ||
if (!data) | ||
return; // This should never run, but TS is lame | ||
packet = this.encoding === "json" ? JSON.parse(String(data)) : readETF(data, 1); | ||
} | ||
else if (this.encoding === "json") { | ||
const data = (0, zlib_1.inflateSync)(message); | ||
packet = JSON.parse(data.toString()); | ||
} | ||
else | ||
packet = readETF(message, 1); | ||
this.emit("ws_message", packet); | ||
break; | ||
} | ||
case 8: { | ||
const code = message.length > 1 ? (message[0] << 8) + message[1] : 0; | ||
const reason = message.length > 2 ? message.slice(2).toString() : ""; | ||
this.emit("ws_close", code, reason); | ||
this._write(Buffer.from([code >> 8, code & 255]), 8); | ||
break; | ||
} | ||
case 9: { | ||
this._write(message, 10); | ||
break; | ||
} | ||
} | ||
catch (e) { | ||
this.emit("error", `Message: ${message} was not parseable`); | ||
return; | ||
} | ||
} | ||
function isValidRequest(value) { | ||
return value && typeof value === "object" && Number.isInteger(value.op) && typeof value.d !== "undefined"; | ||
} | ||
function readRange(socket, index, bytes) { | ||
// @ts-ignore | ||
let head = socket._readableState.buffer.head; | ||
let cursor = 0; | ||
let read = 0; | ||
let num = 0; | ||
do { | ||
for (let i = 0; i < head.data.length; i++) { | ||
if (++cursor > index) { | ||
num *= 256; | ||
num += head.data[i]; | ||
if (++read === bytes) | ||
return num; | ||
} | ||
} | ||
this.emit("ws_message", parsed); | ||
} | ||
/** | ||
* Called when the websocket connection closes for some reason. | ||
* @param code Websocket close code. | ||
* @param reason Reason of the close if any. | ||
*/ | ||
onClose(code, reason) { | ||
this.emit("ws_close", code, reason); | ||
} | ||
/** | ||
* Send a message to the Discord gateway. | ||
* @param data Data to send. | ||
*/ | ||
sendMessage(data) { | ||
if (this.ws.readyState !== ws_1.default.OPEN) | ||
return Promise.reject(new Error("WS is not open")); | ||
this.emit("debug_send", data); | ||
return new Promise((res, rej) => { | ||
const presence = data.op === Constants_1.GATEWAY_OP_CODES.PRESENCE_UPDATE; | ||
try { | ||
if (Erlpack) { | ||
data = Erlpack.pack(data); | ||
} 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) { | ||
// @ts-ignore | ||
atom = data.latin1Slice(x += 2, x + length); | ||
} | ||
else { | ||
data = JSON.stringify(data); | ||
for (let i = x += 2; i < x + length; i++) { | ||
atom += String.fromCharCode(data[i]); | ||
} | ||
} | ||
x += length; | ||
if (!atom) | ||
return undefined; | ||
if (atom === "nil" || atom === "null") | ||
return null; | ||
if (atom === "true") | ||
return true; | ||
if (atom === "false") | ||
return false; | ||
return atom; | ||
} | ||
catch (e) { | ||
return rej(e); | ||
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; | ||
} | ||
const sendMsg = () => { | ||
// The promise from wsBucket is ignored, since the method passed to it does not return a promise | ||
this.wsBucket.queue(() => { | ||
this.ws.send(data, {}, (e) => { | ||
if (e) { | ||
return rej(e); | ||
} | ||
res(); | ||
}); | ||
}); | ||
}; | ||
if (presence) { | ||
// same here | ||
this.presenceBucket.queue(sendMsg); | ||
case 107: { | ||
const array = []; | ||
const length = data.readUInt16BE(x); | ||
x += 2; | ||
for (let i = 0; i < length; i++) { | ||
array.push(data[x++]); | ||
} | ||
return array; | ||
} | ||
else { | ||
sendMsg(); | ||
case 109: { | ||
const length = data.readUInt32BE(x); | ||
let str = ""; | ||
if (length > 30) { | ||
// @ts-ignore | ||
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; | ||
} | ||
}); | ||
} | ||
/** | ||
* Close the current websocket connection. | ||
* @param code Websocket close code to use. | ||
* @param reason Reason of the disconnect. | ||
*/ | ||
close(code = 1000, reason = "Unknown") { | ||
if (this.ws.readyState === ws_1.default.CLOSING || this.ws.readyState === ws_1.default.CLOSED) | ||
return Promise.reject(new Error("WS is already closing or is closed")); | ||
return new Promise((res, rej) => { | ||
const timeout = setTimeout(() => { | ||
return rej("Websocket not closed within 5 seconds"); | ||
}, 5 * 1000); | ||
this.ws.once("close", () => { | ||
clearTimeout(timeout); | ||
return res(); | ||
}); | ||
this.ws.close(code, reason); | ||
}); | ||
} | ||
case 110: { | ||
// @ts-ignore | ||
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); | ||
// @ts-ignore | ||
num += BigInt(view.getUint32(x + (left -= 4)), true); | ||
} | ||
else if (left >= 2) { | ||
num <<= BigInt(16); | ||
// @ts-ignore | ||
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(); | ||
// @ts-ignore | ||
obj[key] = loop(); | ||
} | ||
return obj; | ||
} | ||
} | ||
throw new Error(`Missing etf type: ${type}`); | ||
}; | ||
return loop(); | ||
} | ||
BetterWs.default = BetterWs; | ||
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); | ||
// @ts-ignore | ||
b.latin1Write("true", i += 2); | ||
i += 4; | ||
} | ||
else { | ||
b.writeUInt16BE(5, i); | ||
// @ts-ignore | ||
b.latin1Write("false", i += 2); | ||
i += 5; | ||
} | ||
break; | ||
} | ||
case "string": { | ||
const length = Buffer.byteLength(obj); | ||
b[i++] = 109; | ||
b.writeUInt32BE(length, i); | ||
// @ts-ignore | ||
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); | ||
// @ts-ignore | ||
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.slice(0, i)); | ||
} | ||
module.exports = BetterWs; |
@@ -39,5 +39,4 @@ "use strict"; | ||
} | ||
if (this.remaining !== 0) { | ||
if (this.remaining !== 0) | ||
this.checkQueue().catch(rej); | ||
} | ||
if (fn instanceof Promise) { | ||
@@ -56,10 +55,7 @@ return fn.then(res).catch((e) => { | ||
if (this.remaining === 0) { | ||
this.fnQueue.push({ | ||
fn, callback: wrapFn, error | ||
}); | ||
this.fnQueue.push({ fn, callback: wrapFn, error }); | ||
this.checkQueue().catch(rej); | ||
} | ||
else { | ||
else | ||
wrapFn(); | ||
} | ||
}); | ||
@@ -66,0 +62,0 @@ } |
@@ -1,2 +0,1 @@ | ||
import Constants from "./Constants"; | ||
export interface IntentFlags { | ||
@@ -21,6 +20,6 @@ GUILDS: number; | ||
export interface IWSMessage { | ||
op: typeof Constants["GATEWAY_OP_CODES"][keyof typeof Constants.GATEWAY_OP_CODES]; | ||
op: import("discord-typings").GatewayOpcode; | ||
d?: any; | ||
s?: number; | ||
t?: string; | ||
t?: import("discord-typings").GatewayEvent; | ||
} | ||
@@ -30,13 +29,2 @@ export interface IGatewayMessage extends IWSMessage { | ||
} | ||
export interface IPresenceActivity { | ||
name: string; | ||
type?: 0 | 1 | 2 | 3 | 5; | ||
url?: string; | ||
} | ||
export interface IPresence { | ||
status?: "online" | "idle" | "dnd" | "offline"; | ||
afk?: boolean; | ||
since?: boolean; | ||
activities?: Array<IPresenceActivity> | null; | ||
} | ||
export interface IClientOptions { | ||
@@ -48,3 +36,3 @@ largeGuildThreshold?: number; | ||
reconnect?: boolean; | ||
initialPresence?: IPresence; | ||
initialPresence?: import("discord-typings").GatewayPresenceUpdate; | ||
intents?: IntentResolvable; | ||
@@ -55,20 +43,5 @@ connectQueueInterval?: number; | ||
} | ||
export interface IVoiceStateUpdate { | ||
guild_id: string; | ||
channel_id?: string | null; | ||
self_mute?: boolean; | ||
self_deaf?: boolean; | ||
} | ||
export interface IRequestGuildMembers { | ||
guild_id: string; | ||
query?: string | null; | ||
limit?: number; | ||
} | ||
export interface IShardReady { | ||
id: number; | ||
ready: boolean; | ||
} | ||
export interface IClientWSOptions { | ||
compress?: boolean; | ||
socket?: import("ws").ClientOptions; | ||
encoding?: "etf" | "json"; | ||
} |
{ | ||
"name": "cloudstorm", | ||
"version": "0.4.0", | ||
"version": "0.4.1", | ||
"description": "Minimalistic Discord Gateway library", | ||
@@ -17,20 +17,15 @@ "main": "./dist/index.js", | ||
"dependencies": { | ||
"snowtransfer": "^0.4.x", | ||
"ws": "^8.5.0", | ||
"zlib-sync": "^0.1.7" | ||
"snowtransfer": "^0.4.x" | ||
}, | ||
"devDependencies": { | ||
"@types/node": "16.7.1", | ||
"@types/ws": "^8.2.3", | ||
"@typescript-eslint/eslint-plugin": "^5.12.0", | ||
"@typescript-eslint/parser": "^5.12.0", | ||
"eslint": "^8.9.0", | ||
"typedoc": "^0.22.12", | ||
"@types/centra": "^2.2.0", | ||
"@types/node": "17.0.23", | ||
"@typescript-eslint/eslint-plugin": "^5.16.0", | ||
"@typescript-eslint/parser": "^5.16.0", | ||
"eslint": "^8.11.0", | ||
"typedoc": "^0.22.13", | ||
"typedoc-plugin-mdn-links": "^1.0.5", | ||
"typedoc-plugin-missing-exports": "^0.22.6", | ||
"typescript": "^4.5.5" | ||
"typescript": "^4.6.2" | ||
}, | ||
"optionalDependencies": { | ||
"erlpack": "github:discordapp/erlpack" | ||
}, | ||
"files": [ | ||
@@ -37,0 +32,0 @@ "dist", |
@@ -20,5 +20,3 @@ # A minimal discord gateway library | ||
await bot.connect(); | ||
bot.on("ready", () => { | ||
console.log("Bot received ready event"); | ||
}); | ||
bot.on("ready", () => console.log("Bot received ready event");); | ||
}; | ||
@@ -48,3 +46,3 @@ startup().catch(e => { | ||
"user": { | ||
"id": "id" | ||
"id": "id" | ||
} | ||
@@ -51,0 +49,0 @@ } |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
115723
1
2257
60
1
- Removedws@^8.5.0
- Removedzlib-sync@^0.1.7
- Removednan@2.22.0(transitive)
- Removedws@8.18.0(transitive)
- Removedzlib-sync@0.1.9(transitive)