summaryrefslogtreecommitdiff
path: root/desktop/node_modules/@xhayper/discord-rpc
diff options
context:
space:
mode:
authorRaindropsSys <raindrops@equestria.dev>2023-10-27 22:29:56 +0200
committerRaindropsSys <raindrops@equestria.dev>2023-10-27 22:29:56 +0200
commit4d4308c46d4f7801c657cc79d2243e1a81831334 (patch)
treea2e392e0af92b9a3ca3d1b5afb841640276e2294 /desktop/node_modules/@xhayper/discord-rpc
parent9f9d66afebc59c6c265c4424f7b8fb36d8876541 (diff)
downloadmist-4d4308c46d4f7801c657cc79d2243e1a81831334.tar.gz
mist-4d4308c46d4f7801c657cc79d2243e1a81831334.tar.bz2
mist-4d4308c46d4f7801c657cc79d2243e1a81831334.zip
Updated 32 files, added 279 files, deleted 3 files and renamed 14 files (automated)
Diffstat (limited to 'desktop/node_modules/@xhayper/discord-rpc')
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/LICENSE8
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/README.md66
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/dist/Client.d.ts151
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/dist/Client.js282
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/dist/index.d.ts11
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/dist/index.js26
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/dist/structures/Base.d.ts8
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/dist/structures/Base.js13
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/dist/structures/CertifiedDevice.d.ts66
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/dist/structures/CertifiedDevice.js58
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/dist/structures/Channel.d.ts47
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/dist/structures/Channel.js62
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/dist/structures/ClientUser.d.ts168
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/dist/structures/ClientUser.js261
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/dist/structures/Guild.d.ts25
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/dist/structures/Guild.js34
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/dist/structures/Lobby.d.ts31
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/dist/structures/Lobby.js68
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/dist/structures/Message.d.ts73
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/dist/structures/Message.js96
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/dist/structures/Transport.d.ts152
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/dist/structures/Transport.js118
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/dist/structures/User.d.ts54
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/dist/structures/User.js70
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/dist/structures/VoiceSettings.d.ts119
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/dist/structures/VoiceSettings.js68
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/dist/transport/IPC.d.ts23
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/dist/transport/IPC.js193
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/dist/transport/WebSocket.d.ts9
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/dist/transport/WebSocket.js74
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/dist/utils/RPCError.d.ts7
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/dist/utils/RPCError.js17
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/dist/utils/TypedEventEmitter.d.ts36
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/dist/utils/TypedEventEmitter.js25
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/LICENSE20
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/README.md536
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/browser.js8
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/index.js13
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/buffer-util.js131
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/constants.js12
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/event-target.js292
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/extension.js203
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/limiter.js55
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/permessage-deflate.js514
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/receiver.js679
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/sender.js477
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/stream.js159
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/subprotocol.js62
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/validation.js130
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/websocket-server.js531
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/websocket.js1319
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/package.json68
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/wrapper.mjs8
-rw-r--r--desktop/node_modules/@xhayper/discord-rpc/package.json40
54 files changed, 7776 insertions, 0 deletions
diff --git a/desktop/node_modules/@xhayper/discord-rpc/LICENSE b/desktop/node_modules/@xhayper/discord-rpc/LICENSE
new file mode 100644
index 0000000..0132782
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/LICENSE
@@ -0,0 +1,8 @@
+ISC License
+
+Copyright 2023 xhayper
+Copyright 2022 devsnek
+
+Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/desktop/node_modules/@xhayper/discord-rpc/README.md b/desktop/node_modules/@xhayper/discord-rpc/README.md
new file mode 100644
index 0000000..1a33d5f
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/README.md
@@ -0,0 +1,66 @@
+<!-- markdownlint-disable -->
+<div align="center">
+ <br />
+ <h3>@xhayper/discord-rpc</h3>
+ <br />
+ <p>
+ <a href="https://www.npmjs.com/package/@xhayper/discord-rpc" target="_blank"><img src="https://img.shields.io/npm/v/@xhayper/discord-rpc.svg" alt="npm version"/></a>
+ <a href="https://discord.com/invite/xTAR8nUs2g" target="_blank"><img src="https://img.shields.io/discord/965168309731487805.svg" alt="discord"/></a>
+ <a href="https://github.com/xhayper/discord-rpc/blob/main/LICENSE" target="_blank"><img src="https://img.shields.io/github/license/xhayper/discord-rpc.svg" alt="license"/></a>
+ </p>
+</div>
+<!-- markdownlint-enable -->
+
+## About
+
+`@xhayper/discord-rpc` is a fork of [discordjs/RPC](https://github.com/discordjs/RPC) with type safety and some additional features.
+
+Looking for Deno version? Check out [discord_rpc_deno](https://github.com/xhayper/discord-rpc-deno)!
+
+## Features
+
+- flatpak / snap support
+- Low dependencies count
+- Proper error exception
+- Up-To-Date with Discord's IPC command / event list
+- Less than 100kb bundle size
+
+## Optional packages (when using WebSocket)
+
+- [bufferutil](https://www.npmjs.com/package/bufferutil)
+- [utf-8-validate](https://www.npmjs.com/package/utf-8-validate)
+
+## Example
+
+```ts
+import { Client } from "@xhayper/discord-rpc";
+
+const client = new Client({
+ clientId: "123456789012345678"
+});
+
+client.on("ready", () => {
+ client.user?.setActivity({
+ state: "Hello, world!"
+ });
+});
+
+client.login();
+```
+
+## Compatibility
+
+| OS | Normal | snap | flatpak |
+| ------- | ------ | ---- | ------- |
+| Windows | Y | - | - |
+| macOS | Y | - | - |
+| Linux | Y | Y | Y |
+
+- Linux is tested on Kubuntu 22.04
+
+## Credits
+
+- [discordjs](https://github.com/discordjs): Making [discordjs/RPC](https://github.com/discordjs/RPC)
+- [JakeMakesStuff](https://github.com/JakeMakesStuff): [snap support](https://github.com/discordjs/RPC/pull/152)
+- [Snazzah](https://github.com/Snazzah): [snap + flatpak support](https://github.com/Snazzah/SublimeDiscordRP/blob/c13e60cdbc5de8147881bb232f2339722c2b46b4/discord_ipc/__init__.py#L208)
+- [leonardssh](https://github.com/leonardssh): Making [coc-discord-rpc](https://github.com/leonardssh/coc-discord-rpc) which inspried me to make this package due to how old [discordjs/RPC](https://github.com/discordjs/RPC) is
diff --git a/desktop/node_modules/@xhayper/discord-rpc/dist/Client.d.ts b/desktop/node_modules/@xhayper/discord-rpc/dist/Client.d.ts
new file mode 100644
index 0000000..3651588
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/dist/Client.d.ts
@@ -0,0 +1,151 @@
+import type { APIApplication, OAuth2Scopes } from "discord-api-types/v10";
+import { type FormatFunction } from "./transport/IPC";
+import type { TypedEventEmitter } from "./utils/TypedEventEmitter";
+import { type AxiosResponse, type Method } from "axios";
+import { ClientUser } from "./structures/ClientUser";
+import { type RPC_CMD, type CommandIncoming, type RPC_EVT, type Transport, type TransportOptions } from "./structures/Transport";
+export type AuthorizeOptions = {
+ scopes: (OAuth2Scopes | `${OAuth2Scopes}`)[];
+ redirect_uri?: string;
+ prompt?: "consent" | "none";
+ useRPCToken?: boolean;
+};
+export interface ClientOptions {
+ /**
+ * application id
+ */
+ clientId: string;
+ /**
+ * application secret
+ */
+ clientSecret?: string;
+ /**
+ * pipe id
+ */
+ pipeId?: number;
+ /**
+ * transport configs
+ */
+ transport?: {
+ /**
+ * transport type
+ */
+ type?: "ipc" | "websocket" | {
+ new (options: TransportOptions): Transport;
+ };
+ /**
+ * ipc transport's path list
+ */
+ pathList?: FormatFunction[];
+ };
+}
+export type ClientEvents = {
+ /**
+ * fired when the client is ready
+ */
+ ready: () => void;
+ /**
+ * fired when the client is connected to local rpc server
+ */
+ connected: () => void;
+ /**
+ * fired when the client is disconnected from the local rpc server
+ */
+ disconnected: () => void;
+ /**
+ * fired when the client is have debug message
+ */
+ debug: (...data: any[]) => void;
+} & {
+ [K in Exclude<RPC_EVT, "READY">]: (...args: unknown[]) => void;
+};
+declare const Client_base: new () => TypedEventEmitter<ClientEvents>;
+export declare class Client extends Client_base {
+ /**
+ * application id
+ */
+ clientId: string;
+ /**
+ * application secret
+ */
+ clientSecret?: string;
+ /**
+ * pipe id
+ */
+ pipeId?: number;
+ private accessToken?;
+ private refreshToken?;
+ private tokenType;
+ /**
+ * transport instance
+ */
+ readonly transport: Transport;
+ /**
+ * current user
+ */
+ user?: ClientUser;
+ /**
+ * current application
+ */
+ application?: APIApplication;
+ /**
+ * @hidden
+ */
+ cdnHost: string;
+ /**
+ * @hidden
+ */
+ origin: string;
+ get isConnected(): boolean;
+ private refreshTimeout?;
+ private connectionPromise?;
+ private _nonceMap;
+ constructor(options: ClientOptions);
+ /**
+ * For RPC event, make sure to subscribe to the event.
+ */
+ on<E extends keyof ClientEvents>(event: E, listener: ClientEvents[E]): this;
+ /**
+ * For RPC event, make sure to subscribe to the event.
+ */
+ once<E extends keyof ClientEvents>(event: E, listener: ClientEvents[E]): this;
+ /**
+ * @hidden
+ */
+ fetch<R = any>(method: Method | string, path: string, req?: {
+ data?: any;
+ query?: string;
+ headers?: any;
+ }): Promise<AxiosResponse<R>>;
+ /**
+ * @hidden
+ */
+ request<A = any, D = any>(cmd: RPC_CMD, args?: any, evt?: RPC_EVT): Promise<CommandIncoming<A, D>>;
+ private authenticate;
+ private refreshAccessToken;
+ private hanleAccessTokenResponse;
+ private authorize;
+ /**
+ * Used to subscribe to events. `evt` of the payload should be set to the event being subscribed to. `args` of the payload should be set to the args needed for the event.
+ * @param event event name now subscribed to
+ * @param args args for the event
+ * @returns an object to unsubscribe from the event
+ */
+ subscribe(event: Exclude<RPC_EVT, "READY" | "ERROR">, args?: any): Promise<{
+ unsubscribe: () => void;
+ }>;
+ /**
+ * connect to the local rpc server
+ */
+ connect(): Promise<void>;
+ /**
+ * will try to authorize if a scope is specified, else it's the same as `connect()`
+ * @param options options for the authorization
+ */
+ login(options?: AuthorizeOptions): Promise<void>;
+ /**
+ * disconnects from the local rpc server
+ */
+ destroy(): Promise<void>;
+}
+export {};
diff --git a/desktop/node_modules/@xhayper/discord-rpc/dist/Client.js b/desktop/node_modules/@xhayper/discord-rpc/dist/Client.js
new file mode 100644
index 0000000..22aff23
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/dist/Client.js
@@ -0,0 +1,282 @@
+"use strict";
+var __importDefault = (this && this.__importDefault) || function (mod) {
+ return (mod && mod.__esModule) ? mod : { "default": mod };
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.Client = void 0;
+const IPC_1 = require("./transport/IPC");
+const axios_1 = __importDefault(require("axios"));
+const WebSocket_1 = require("./transport/WebSocket");
+const ClientUser_1 = require("./structures/ClientUser");
+const RPCError_1 = require("./utils/RPCError");
+const node_events_1 = require("node:events");
+const node_crypto_1 = __importDefault(require("node:crypto"));
+const Transport_1 = require("./structures/Transport");
+class Client extends node_events_1.EventEmitter {
+ /**
+ * application id
+ */
+ clientId;
+ /**
+ * application secret
+ */
+ clientSecret;
+ /**
+ * pipe id
+ */
+ pipeId;
+ accessToken;
+ refreshToken;
+ tokenType = "Bearer";
+ /**
+ * transport instance
+ */
+ transport;
+ /**
+ * current user
+ */
+ user;
+ /**
+ * current application
+ */
+ application;
+ /**
+ * @hidden
+ */
+ cdnHost = "https://cdn.discordapp.com";
+ /**
+ * @hidden
+ */
+ origin = "https://localhost";
+ get isConnected() {
+ return this.transport.isConnected;
+ }
+ refreshTimeout;
+ connectionPromise;
+ _nonceMap = new Map();
+ constructor(options) {
+ super();
+ this.clientId = options.clientId;
+ this.clientSecret = options.clientSecret;
+ this.pipeId = options.pipeId;
+ this.transport =
+ options.transport?.type === undefined || options.transport.type === "ipc"
+ ? new IPC_1.IPCTransport({
+ client: this,
+ pathList: options.transport?.pathList
+ })
+ : new (options.transport.type === "websocket" ? WebSocket_1.WebSocketTransport : options.transport.type)({
+ client: this
+ });
+ this.transport.on("message", (message) => {
+ if (message.cmd === "DISPATCH" && message.evt === "READY") {
+ if (message.data.user)
+ this.user = new ClientUser_1.ClientUser(this, message.data.user);
+ if (message.data.config && message.data.config.cdn_host)
+ this.cdnHost = `https://${message.data.config.cdn_host}`;
+ this.emit("connected");
+ }
+ else {
+ if (message.nonce && this._nonceMap.has(message.nonce)) {
+ const nonceObj = this._nonceMap.get(message.nonce);
+ if (message.evt === "ERROR") {
+ nonceObj.error.code = message.data.code;
+ nonceObj.error.message = message.data.message;
+ nonceObj?.reject(nonceObj.error);
+ }
+ else
+ nonceObj?.resolve(message);
+ this._nonceMap.delete(message.nonce);
+ }
+ this.emit(message.evt, message.data);
+ }
+ });
+ }
+ /**
+ * For RPC event, make sure to subscribe to the event.
+ */
+ on(event, listener) {
+ return super.on(event, listener);
+ }
+ /**
+ * For RPC event, make sure to subscribe to the event.
+ */
+ once(event, listener) {
+ return super.once(event, listener);
+ }
+ // #region Request Handlers
+ /**
+ * @hidden
+ */
+ async fetch(method, path, req) {
+ const url = new URL(`https://discord.com/api${path}`);
+ if (req?.query)
+ for (const [key, value] of req.query)
+ url.searchParams.append(key, value);
+ return await (0, axios_1.default)({
+ url: url.toString(),
+ method,
+ data: req?.data ?? undefined,
+ headers: {
+ ...(req?.headers ?? {}),
+ ...(this.accessToken ? { Authorization: `${this.tokenType} ${this.accessToken}` } : {})
+ }
+ });
+ }
+ /**
+ * @hidden
+ */
+ async request(cmd, args, evt) {
+ const error = new RPCError_1.RPCError(Transport_1.RPC_ERROR_CODE.RPC_UNKNOWN_ERROR);
+ RPCError_1.RPCError.captureStackTrace(error, this.request);
+ return new Promise((resolve, reject) => {
+ const nonce = node_crypto_1.default.randomUUID();
+ this.transport.send({ cmd, args, evt, nonce });
+ this._nonceMap.set(nonce, { resolve, reject, error });
+ });
+ }
+ // #endregion
+ // #region Authorization handlers
+ async authenticate() {
+ const { application, user } = (await this.request("AUTHENTICATE", { access_token: this.accessToken ?? "" }))
+ .data;
+ this.application = application;
+ this.user = new ClientUser_1.ClientUser(this, user);
+ this.emit("ready");
+ }
+ async refreshAccessToken() {
+ this.emit("debug", "CLIENT | Refreshing access token!");
+ this.hanleAccessTokenResponse((await this.fetch("POST", "/oauth2/token", {
+ data: new URLSearchParams({
+ client_id: this.clientId,
+ client_secret: this.clientSecret ?? "",
+ grant_type: "refresh_token",
+ refresh_token: this.refreshToken ?? ""
+ }),
+ headers: {
+ "content-type": "application/x-www-form-urlencoded"
+ }
+ })).data);
+ }
+ hanleAccessTokenResponse(data) {
+ if (!("access_token" in data) ||
+ !("refresh_token" in data) ||
+ !("expires_in" in data) ||
+ !("token_type" in data))
+ throw new TypeError(`Invalid access token response!\nData: ${JSON.stringify(data, null, 2)}`);
+ this.accessToken = data.access_token;
+ this.refreshToken = data.refresh_token;
+ this.tokenType = data.token_type;
+ this.refreshTimeout = setTimeout(() => void this.refreshAccessToken(), data.expires_in);
+ }
+ async authorize(options) {
+ let rpcToken;
+ if (options.useRPCToken) {
+ rpcToken = (await this.fetch("POST", "/oauth2/token/rpc", {
+ data: new URLSearchParams({
+ client_id: this.clientId,
+ client_secret: this.clientSecret ?? ""
+ }),
+ headers: {
+ "content-type": "application/x-www-form-urlencoded"
+ }
+ })).data.rpc_token;
+ }
+ const { code } = (await this.request("AUTHORIZE", {
+ scopes: options.scopes,
+ client_id: this.clientId,
+ rpc_token: options.useRPCToken ? rpcToken : undefined,
+ redirect_uri: options.redirect_uri ?? undefined,
+ prompt: options.prompt ?? "consent"
+ })).data;
+ this.hanleAccessTokenResponse((await this.fetch("POST", "/oauth2/token", {
+ data: new URLSearchParams({
+ client_id: this.clientId,
+ client_secret: this.clientSecret ?? "",
+ redirect_uri: options.redirect_uri ?? "",
+ grant_type: "authorization_code",
+ code
+ }),
+ headers: {
+ "content-type": "application/x-www-form-urlencoded"
+ }
+ })).data);
+ }
+ // #endregion
+ /**
+ * Used to subscribe to events. `evt` of the payload should be set to the event being subscribed to. `args` of the payload should be set to the args needed for the event.
+ * @param event event name now subscribed to
+ * @param args args for the event
+ * @returns an object to unsubscribe from the event
+ */
+ async subscribe(event, args) {
+ await this.request("SUBSCRIBE", args, event);
+ return {
+ /**
+ * Unsubscribes from the event
+ */
+ unsubscribe: () => this.request("UNSUBSCRIBE", args, event)
+ };
+ }
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+ /**
+ * connect to the local rpc server
+ */
+ async connect() {
+ if (this.connectionPromise)
+ return this.connectionPromise;
+ const error = new RPCError_1.RPCError(Transport_1.RPC_ERROR_CODE.RPC_UNKNOWN_ERROR);
+ RPCError_1.RPCError.captureStackTrace(error, this.connect);
+ this.connectionPromise = new Promise((resolve, reject) => {
+ const timeout = setTimeout(() => {
+ this.connectionPromise = undefined;
+ error.code = Transport_1.CUSTOM_RPC_ERROR_CODE.RPC_CONNECTION_TIMEOUT;
+ error.message = "Connection timed out";
+ reject(error);
+ }, 10e3);
+ timeout.unref();
+ this.once("connected", () => {
+ this.connectionPromise = undefined;
+ this.transport.once("close", (reason) => {
+ this._nonceMap.forEach((promise) => {
+ promise.error.code =
+ typeof reason === "object" ? reason.code : Transport_1.CUSTOM_RPC_ERROR_CODE.RPC_CONNECTION_ENDED;
+ promise.error.message =
+ typeof reason === "object" ? reason.message : reason ?? "Connection ended";
+ promise.reject(promise.error);
+ });
+ this.emit("disconnected");
+ });
+ clearTimeout(timeout);
+ resolve();
+ });
+ this.transport.connect().catch(reject);
+ });
+ return this.connectionPromise;
+ }
+ /**
+ * will try to authorize if a scope is specified, else it's the same as `connect()`
+ * @param options options for the authorization
+ */
+ async login(options) {
+ await this.connect();
+ if (!options || !options.scopes) {
+ this.emit("ready");
+ return;
+ }
+ await this.authorize(options);
+ await this.authenticate();
+ }
+ /**
+ * disconnects from the local rpc server
+ */
+ async destroy() {
+ if (this.refreshTimeout) {
+ clearTimeout(this.refreshTimeout);
+ this.refreshTimeout = undefined;
+ this.refreshToken = undefined;
+ }
+ await this.transport.close();
+ }
+}
+exports.Client = Client;
diff --git a/desktop/node_modules/@xhayper/discord-rpc/dist/index.d.ts b/desktop/node_modules/@xhayper/discord-rpc/dist/index.d.ts
new file mode 100644
index 0000000..0f78beb
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/dist/index.d.ts
@@ -0,0 +1,11 @@
+export * from "./Client";
+export * from "./structures/ClientUser";
+export * from "./structures/CertifiedDevice";
+export * from "./structures/Channel";
+export * from "./structures/Guild";
+export * from "./structures/Lobby";
+export * from "./structures/User";
+export * from "./structures/VoiceSettings";
+export * from "./structures/Transport";
+export * from "./structures/Message";
+export { type FormatFunction } from "./transport/IPC";
diff --git a/desktop/node_modules/@xhayper/discord-rpc/dist/index.js b/desktop/node_modules/@xhayper/discord-rpc/dist/index.js
new file mode 100644
index 0000000..b820663
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/dist/index.js
@@ -0,0 +1,26 @@
+"use strict";
+var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = { enumerable: true, get: function() { return m[k]; } };
+ }
+ Object.defineProperty(o, k2, desc);
+}) : (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+}));
+var __exportStar = (this && this.__exportStar) || function(m, exports) {
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+__exportStar(require("./Client"), exports);
+__exportStar(require("./structures/ClientUser"), exports);
+__exportStar(require("./structures/CertifiedDevice"), exports);
+__exportStar(require("./structures/Channel"), exports);
+__exportStar(require("./structures/Guild"), exports);
+__exportStar(require("./structures/Lobby"), exports);
+__exportStar(require("./structures/User"), exports);
+__exportStar(require("./structures/VoiceSettings"), exports);
+__exportStar(require("./structures/Transport"), exports);
+__exportStar(require("./structures/Message"), exports);
diff --git a/desktop/node_modules/@xhayper/discord-rpc/dist/structures/Base.d.ts b/desktop/node_modules/@xhayper/discord-rpc/dist/structures/Base.d.ts
new file mode 100644
index 0000000..4bab6c5
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/dist/structures/Base.d.ts
@@ -0,0 +1,8 @@
+import type { Client } from "../Client";
+export declare class Base {
+ /**
+ * the client instance
+ */
+ client: Client;
+ constructor(client: Client);
+}
diff --git a/desktop/node_modules/@xhayper/discord-rpc/dist/structures/Base.js b/desktop/node_modules/@xhayper/discord-rpc/dist/structures/Base.js
new file mode 100644
index 0000000..9ddbc84
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/dist/structures/Base.js
@@ -0,0 +1,13 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.Base = void 0;
+class Base {
+ /**
+ * the client instance
+ */
+ client;
+ constructor(client) {
+ this.client = client;
+ }
+}
+exports.Base = Base;
diff --git a/desktop/node_modules/@xhayper/discord-rpc/dist/structures/CertifiedDevice.d.ts b/desktop/node_modules/@xhayper/discord-rpc/dist/structures/CertifiedDevice.d.ts
new file mode 100644
index 0000000..ec477df
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/dist/structures/CertifiedDevice.d.ts
@@ -0,0 +1,66 @@
+import type { Client } from "../Client";
+import { Base } from "./Base";
+export declare enum DeviceType {
+ AUDIO_INPUT = "audioinput",
+ AUDIO_OUTPUT = "audiooutput",
+ VIDEO_INPUT = "videoinput"
+}
+export interface Vendor {
+ /**
+ * name of the vendor
+ */
+ name: string;
+ /**
+ * url for the vendor
+ */
+ url: string;
+}
+export interface Model {
+ /**
+ * name of the model
+ */
+ name: string;
+ /**
+ * url for the model
+ */
+ url: string;
+}
+export declare class CertifiedDevice extends Base {
+ /**
+ * the type of device
+ */
+ type: DeviceType;
+ /**
+ * the device's Windows UUID
+ */
+ id: string;
+ /**
+ * the hardware vendor
+ */
+ vendor: Vendor;
+ /**
+ * the model of the product
+ */
+ model: Model;
+ /**
+ * UUIDs of related devices
+ */
+ related: string[];
+ /**
+ * if the device's native echo cancellation is enabled
+ */
+ echo_cancellation?: boolean;
+ /**
+ * if the device's native noise suppression is enabled
+ */
+ noise_suppression?: boolean;
+ /**
+ * if the device's native automatic gain control is enabled
+ */
+ automatic_gain_control?: boolean;
+ /**
+ * if the device is hardware muted
+ */
+ hardware_mute?: boolean;
+ constructor(client: Client, props: Record<string, any>);
+}
diff --git a/desktop/node_modules/@xhayper/discord-rpc/dist/structures/CertifiedDevice.js b/desktop/node_modules/@xhayper/discord-rpc/dist/structures/CertifiedDevice.js
new file mode 100644
index 0000000..71248c2
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/dist/structures/CertifiedDevice.js
@@ -0,0 +1,58 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.CertifiedDevice = exports.DeviceType = void 0;
+const Base_1 = require("./Base");
+var DeviceType;
+(function (DeviceType) {
+ DeviceType["AUDIO_INPUT"] = "audioinput";
+ DeviceType["AUDIO_OUTPUT"] = "audiooutput";
+ DeviceType["VIDEO_INPUT"] = "videoinput";
+})(DeviceType || (exports.DeviceType = DeviceType = {}));
+class CertifiedDevice extends Base_1.Base {
+ /**
+ * the type of device
+ */
+ type;
+ /**
+ * the device's Windows UUID
+ */
+ id;
+ /**
+ * the hardware vendor
+ */
+ vendor;
+ /**
+ * the model of the product
+ */
+ model;
+ /**
+ * UUIDs of related devices
+ */
+ related;
+ /**
+ * if the device's native echo cancellation is enabled
+ */
+ echo_cancellation;
+ /**
+ * if the device's native noise suppression is enabled
+ */
+ noise_suppression;
+ /**
+ * if the device's native automatic gain control is enabled
+ */
+ automatic_gain_control;
+ /**
+ * if the device is hardware muted
+ */
+ hardware_mute;
+ constructor(client, props) {
+ super(client);
+ Object.assign(this, props);
+ this.type = props.type;
+ this.id = props.id;
+ this.vendor = props.vendor;
+ this.model = props.model;
+ this.related = props.related;
+ }
+}
+exports.CertifiedDevice = CertifiedDevice;
diff --git a/desktop/node_modules/@xhayper/discord-rpc/dist/structures/Channel.d.ts b/desktop/node_modules/@xhayper/discord-rpc/dist/structures/Channel.d.ts
new file mode 100644
index 0000000..a12534b
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/dist/structures/Channel.d.ts
@@ -0,0 +1,47 @@
+import type { ChannelType, GatewayVoiceState } from "discord-api-types/v10";
+import type { Client } from "../Client";
+import { Message } from "./Message";
+import { Base } from "./Base";
+export declare class Channel extends Base {
+ /**
+ * channel id
+ */
+ id: string;
+ /**
+ * channel's guild id
+ */
+ guild_id?: string;
+ /**
+ * channel name
+ */
+ name: string;
+ /**
+ * channel type (guild text: 0, guild voice: 2, dm: 1, group dm: 3)
+ */
+ type: ChannelType;
+ /**
+ * (text) channel topic
+ */
+ topic?: string;
+ /**
+ * (voice) bitrate of voice channel
+ */
+ bitrate?: number;
+ /**
+ * (voice) user limit of voice channel (0 for none)
+ */
+ user_limit?: number;
+ /**
+ * position of channel in channel list
+ */
+ position?: number;
+ /**
+ * (voice) channel's voice states
+ */
+ voice_states?: GatewayVoiceState[];
+ /**
+ * (text) channel's messages
+ */
+ messages?: Message[];
+ constructor(client: Client, props: Record<string, any>);
+}
diff --git a/desktop/node_modules/@xhayper/discord-rpc/dist/structures/Channel.js b/desktop/node_modules/@xhayper/discord-rpc/dist/structures/Channel.js
new file mode 100644
index 0000000..0bff393
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/dist/structures/Channel.js
@@ -0,0 +1,62 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.Channel = void 0;
+const Message_1 = require("./Message");
+const Base_1 = require("./Base");
+class Channel extends Base_1.Base {
+ /**
+ * channel id
+ */
+ id;
+ /**
+ * channel's guild id
+ */
+ guild_id;
+ /**
+ * channel name
+ */
+ name;
+ /**
+ * channel type (guild text: 0, guild voice: 2, dm: 1, group dm: 3)
+ */
+ type;
+ /**
+ * (text) channel topic
+ */
+ topic;
+ /**
+ * (voice) bitrate of voice channel
+ */
+ bitrate;
+ /**
+ * (voice) user limit of voice channel (0 for none)
+ */
+ user_limit;
+ /**
+ * position of channel in channel list
+ */
+ position;
+ /**
+ * (voice) channel's voice states
+ */
+ voice_states;
+ /**
+ * (text) channel's messages
+ */
+ messages;
+ constructor(client, props) {
+ super(client);
+ Object.assign(this, props);
+ this.id = props.id;
+ this.guild_id = props.guild_id;
+ this.name = props.name;
+ this.type = props.type;
+ this.topic = props.topic;
+ this.bitrate = props.bitrate;
+ this.user_limit = props.user_limit;
+ this.position = props.position;
+ this.voice_states = props.voice_states;
+ this.messages = props.messages?.map((messgeData) => new Message_1.Message(client, messgeData));
+ }
+}
+exports.Channel = Channel;
diff --git a/desktop/node_modules/@xhayper/discord-rpc/dist/structures/ClientUser.d.ts b/desktop/node_modules/@xhayper/discord-rpc/dist/structures/ClientUser.d.ts
new file mode 100644
index 0000000..df31bcd
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/dist/structures/ClientUser.d.ts
@@ -0,0 +1,168 @@
+import type { ActivityType, GatewayActivityButton } from "discord-api-types/v10";
+import type { CertifiedDevice } from "./CertifiedDevice";
+import { VoiceSettings } from "./VoiceSettings";
+import { Lobby, type LobbyType } from "./Lobby";
+import { Channel } from "./Channel";
+import { Guild } from "./Guild";
+import { User } from "./User";
+export type SetActivity = {
+ state?: string;
+ details?: string;
+ startTimestamp?: number | Date;
+ endTimestamp?: number | Date;
+ largeImageKey?: string;
+ smallImageKey?: string;
+ largeImageText?: string;
+ smallImageText?: string;
+ partyId?: string;
+ partySize?: number;
+ partyMax?: number;
+ matchSecret?: string;
+ joinSecret?: string;
+ spectateSecret?: string;
+ instance?: boolean;
+ buttons?: Array<GatewayActivityButton>;
+ type?: ActivityType.Playing | ActivityType.Watching | number;
+};
+export type SetActivityResponse = {
+ state?: string;
+ buttons?: string[];
+ name: string;
+ application_id: string;
+ type: number;
+ metadata: {
+ button_urls?: string[];
+ };
+};
+export declare class ClientUser extends User {
+ fetchUser(userId: string): Promise<User>;
+ /**
+ * Used to get a guild the client is in.
+ *
+ * @param guildId - id of the guild to get
+ * @param timeout - asynchronously get guild with time to wait before timing out
+ * @returns partial guild
+ */
+ fetchGuild(guildId: string, timeout?: number): Promise<Guild>;
+ /**
+ * Used to get a list of guilds the client is in.
+ * @returns the guilds the user is in
+ */
+ fetchGuilds(): Promise<Guild[]>;
+ /**
+ * Used to get a channel the client is in.
+ * @param channelId - id of the channel to get
+ * @returns partial channel
+ */
+ fetchChannel(channelId: string): Promise<Channel>;
+ /**
+ * Used to get a guild's channels the client is in.
+ * @param guildId - id of the guild to get channels for
+ * @returns guild channels the user is in
+ */
+ fetchChannels(guildId: string): Promise<Channel>;
+ /**
+ * Used to get the client's current voice channel. There are no arguments for this command. Returns the [Get Channel](https://discord.com/developers/docs/topics/rpc#getchannel) response, or `null` if none.
+ * @returns the client's current voice channel, `null` if none
+ */
+ getSelectedVoiceChannel(): Promise<Channel | null>;
+ /**
+ * Used to join voice channels, group dms, or dms. Returns the [Get Channel](https://discord.com/developers/docs/topics/rpc#getchannel) response, `null` if none.
+ * @param channelId - channel id to join
+ * @param timeout - asynchronously join channel with time to wait before timing out
+ * @param force - forces a user to join a voice channel
+ * @returns the channel that the user joined, `null` if none
+ */
+ selectVoiceChannel(channelId: string, timeout?: number, force?: boolean): Promise<Channel>;
+ /**
+ * Used to leave voice channels, group dms, or dms
+ * @param timeout - asynchronously join channel with time to wait before timing out
+ * @param force - forces a user to join a voice channel
+ */
+ leaveVoiceChannel(timeout?: number, force?: boolean): Promise<void>;
+ /**
+ * Used to get current client's voice settings
+ * @returns the voice setting
+ */
+ getVoiceSettings(): Promise<VoiceSettings>;
+ /**
+ * Used to change voice settings of users in voice channels
+ * @param voiceSettings - the settings
+ * @returns the settings that have been set
+ */
+ setVoiceSettings(voiceSettings: Partial<VoiceSettings>): Promise<VoiceSettings>;
+ /**
+ * Used by hardware manufacturers to send information about the current state of their certified devices that are connected to Discord.
+ * @param devices - a list of devices for your manufacturer, in order of priority
+ * @returns
+ */
+ setCeritfiedDevices(devices: CertifiedDevice[]): Promise<void>;
+ /**
+ * Used to accept an Ask to Join request.
+ * @param userId - the id of the requesting user
+ */
+ sendJoinInvite(userId: string): Promise<void>;
+ /**
+ * Used to reject an Ask to Join request.
+ * @param userId - the id of the requesting user
+ */
+ closeJoinRequest(userId: string): Promise<void>;
+ /**
+ * Used to join text channels, group dms, or dms. Returns the [Get Channel](https://discord.com/developers/docs/topics/rpc#getchannel) response, or `null` if none.
+ * @param channelId - channel id to join
+ * @param timeout - asynchronously join channel with time to wait before timing out
+ * @returns the text channel that user joined
+ */
+ selectTextChannel(channelId: string, timeout?: number): Promise<Channel | null>;
+ /**
+ * Used to leave text channels, group dms, or dms.
+ * @param timeout - asynchronously join channel with time to wait before timing out
+ */
+ leaveTextChannel(timeout?: number): Promise<void>;
+ getRelationships(): Promise<Array<User>>;
+ /**
+ * Used to update a user's Rich Presence.
+ *
+ * @param activity - the rich presence to assign to the user
+ * @param pid - the application's process id
+ * @returns The activity that have been set
+ */
+ setActivity(activity: SetActivity, pid?: number): Promise<SetActivityResponse>;
+ /**
+ * Used to clear a user's Rich Presence.
+ *
+ * @param pid - the application's process id
+ */
+ clearActivity(pid?: number): Promise<void>;
+ /**
+ * Create a new lobby
+ * @param type - lobby type
+ * @param capacity - lobby size
+ * @param locked - is lobby locked
+ * @param metadata - additional data?
+ * @returns lobby that user created
+ */
+ createLobby(type: LobbyType, capacity?: number, locked?: boolean, metadata?: any): Promise<Lobby>;
+ /**
+ * Used to join a new lobby.
+ * @param lobbyId - the id of the lobby to join
+ * @param secret - the secret of the lobby to join
+ * @returns the lobby that the user joined
+ */
+ connectToLobby(lobbyId: string, secret: string): Promise<Lobby>;
+ /**
+ * Used to join a new lobby.
+ * @param lobbyId - the id of the lobby to join
+ * @param data - additional data to send to lobby
+ * @returns the lobby that the user joined
+ */
+ sendToLobby(lobbyId: string, data: string): Promise<Lobby>;
+ /**
+ * Used to get a user's avatar
+ * @param userId - id of the user to get the avatar of
+ * @param format - image format
+ * @param size - image size
+ * @return base64 encoded image data
+ */
+ getImage(userId: string, format?: "png" | "webp" | "jpg", size?: 16 | 32 | 64 | 128 | 256 | 512 | 1024): Promise<string>;
+}
diff --git a/desktop/node_modules/@xhayper/discord-rpc/dist/structures/ClientUser.js b/desktop/node_modules/@xhayper/discord-rpc/dist/structures/ClientUser.js
new file mode 100644
index 0000000..0e85785
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/dist/structures/ClientUser.js
@@ -0,0 +1,261 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.ClientUser = void 0;
+const VoiceSettings_1 = require("./VoiceSettings");
+const Lobby_1 = require("./Lobby");
+const Channel_1 = require("./Channel");
+const Guild_1 = require("./Guild");
+const User_1 = require("./User");
+class ClientUser extends User_1.User {
+ // #region Helper function
+ async fetchUser(userId) {
+ return new User_1.User(this.client, (await this.client.request("GET_USER", { id: userId })).data);
+ }
+ /**
+ * Used to get a guild the client is in.
+ *
+ * @param guildId - id of the guild to get
+ * @param timeout - asynchronously get guild with time to wait before timing out
+ * @returns partial guild
+ */
+ async fetchGuild(guildId, timeout) {
+ return new Guild_1.Guild(this.client, (await this.client.request("GET_GUILD", { guild_id: guildId, timeout })).data);
+ }
+ /**
+ * Used to get a list of guilds the client is in.
+ * @returns the guilds the user is in
+ */
+ async fetchGuilds() {
+ return (await this.client.request("GET_GUILDS")).data.guilds.map((guildData) => new Guild_1.Guild(this.client, guildData));
+ }
+ /**
+ * Used to get a channel the client is in.
+ * @param channelId - id of the channel to get
+ * @returns partial channel
+ */
+ async fetchChannel(channelId) {
+ return new Channel_1.Channel(this.client, (await this.client.request("GET_CHANNEL", { channel_id: channelId })).data);
+ }
+ /**
+ * Used to get a guild's channels the client is in.
+ * @param guildId - id of the guild to get channels for
+ * @returns guild channels the user is in
+ */
+ async fetchChannels(guildId) {
+ return (await this.client.request("GET_CHANNELS", { guild_id: guildId })).data.channels.map((channelData) => new Channel_1.Channel(this.client, channelData));
+ }
+ /**
+ * Used to get the client's current voice channel. There are no arguments for this command. Returns the [Get Channel](https://discord.com/developers/docs/topics/rpc#getchannel) response, or `null` if none.
+ * @returns the client's current voice channel, `null` if none
+ */
+ async getSelectedVoiceChannel() {
+ const response = await this.client.request("GET_SELECTED_VOICE_CHANNEL");
+ return response.data !== null ? new Channel_1.Channel(this.client, response.data) : null;
+ }
+ /**
+ * Used to join voice channels, group dms, or dms. Returns the [Get Channel](https://discord.com/developers/docs/topics/rpc#getchannel) response, `null` if none.
+ * @param channelId - channel id to join
+ * @param timeout - asynchronously join channel with time to wait before timing out
+ * @param force - forces a user to join a voice channel
+ * @returns the channel that the user joined, `null` if none
+ */
+ async selectVoiceChannel(channelId, timeout, force) {
+ return new Channel_1.Channel(this.client, (await this.client.request("SELECT_VOICE_CHANNEL", {
+ channel_id: channelId,
+ timeout,
+ force
+ })).data);
+ }
+ /**
+ * Used to leave voice channels, group dms, or dms
+ * @param timeout - asynchronously join channel with time to wait before timing out
+ * @param force - forces a user to join a voice channel
+ */
+ async leaveVoiceChannel(timeout, force) {
+ await this.client.request("SELECT_VOICE_CHANNEL", {
+ channel_id: null,
+ timeout,
+ force
+ });
+ }
+ /**
+ * Used to get current client's voice settings
+ * @returns the voice setting
+ */
+ async getVoiceSettings() {
+ return new VoiceSettings_1.VoiceSettings(this.client, (await this.client.request("GET_VOICE_SETTINGS")).data);
+ }
+ /**
+ * Used to change voice settings of users in voice channels
+ * @param voiceSettings - the settings
+ * @returns the settings that have been set
+ */
+ async setVoiceSettings(voiceSettings) {
+ return new VoiceSettings_1.VoiceSettings(this.client, (await this.client.request("SET_VOICE_SETTINGS", voiceSettings)).data);
+ }
+ /**
+ * Used by hardware manufacturers to send information about the current state of their certified devices that are connected to Discord.
+ * @param devices - a list of devices for your manufacturer, in order of priority
+ * @returns
+ */
+ async setCeritfiedDevices(devices) {
+ await this.client.request("SET_CERTIFIED_DEVICES", { devices });
+ }
+ /**
+ * Used to accept an Ask to Join request.
+ * @param userId - the id of the requesting user
+ */
+ async sendJoinInvite(userId) {
+ await this.client.request("SEND_ACTIVITY_JOIN_INVITE", { user_id: userId });
+ }
+ /**
+ * Used to reject an Ask to Join request.
+ * @param userId - the id of the requesting user
+ */
+ async closeJoinRequest(userId) {
+ await this.client.request("CLOSE_ACTIVITY_JOIN_REQUEST", { user_id: userId });
+ }
+ /**
+ * Used to join text channels, group dms, or dms. Returns the [Get Channel](https://discord.com/developers/docs/topics/rpc#getchannel) response, or `null` if none.
+ * @param channelId - channel id to join
+ * @param timeout - asynchronously join channel with time to wait before timing out
+ * @returns the text channel that user joined
+ */
+ async selectTextChannel(channelId, timeout) {
+ return new Channel_1.Channel(this.client, (await this.client.request("SELECT_TEXT_CHANNEL", { channel_id: channelId, timeout })).data);
+ }
+ /**
+ * Used to leave text channels, group dms, or dms.
+ * @param timeout - asynchronously join channel with time to wait before timing out
+ */
+ async leaveTextChannel(timeout) {
+ await this.client.request("SELECT_TEXT_CHANNEL", { channel_id: null, timeout });
+ }
+ async getRelationships() {
+ return (await this.client.request("GET_RELATIONSHIPS")).data.relationships.map((data) => {
+ return new User_1.User(this.client, { ...data.user, presence: data.presence });
+ });
+ }
+ /**
+ * Used to update a user's Rich Presence.
+ *
+ * @param activity - the rich presence to assign to the user
+ * @param pid - the application's process id
+ * @returns The activity that have been set
+ */
+ async setActivity(activity, pid) {
+ const formattedAcitivity = {
+ ...activity,
+ assets: {},
+ timestamps: {},
+ party: {},
+ secrets: {}
+ };
+ if (activity.startTimestamp instanceof Date) {
+ formattedAcitivity.timestamps.start = Math.round(activity.startTimestamp.getTime());
+ }
+ else if (typeof activity.startTimestamp === "number") {
+ formattedAcitivity.timestamps.start = activity.startTimestamp;
+ }
+ if (activity.endTimestamp instanceof Date) {
+ formattedAcitivity.timestamps.end = Math.round(activity.endTimestamp.getTime());
+ }
+ else if (typeof activity.endTimestamp === "number") {
+ formattedAcitivity.timestamps.end = activity.endTimestamp;
+ }
+ if (activity.largeImageKey)
+ formattedAcitivity.assets.large_image = activity.largeImageKey;
+ if (activity.smallImageKey)
+ formattedAcitivity.assets.small_image = activity.smallImageKey;
+ if (activity.largeImageText)
+ formattedAcitivity.assets.large_text = activity.largeImageText;
+ if (activity.smallImageText)
+ formattedAcitivity.assets.small_text = activity.smallImageText;
+ if (activity.partyId)
+ formattedAcitivity.party.id = activity.partyId;
+ if (activity.partySize && activity.partyMax)
+ formattedAcitivity.party.size = [activity.partySize, activity.partyMax];
+ if (activity.joinSecret)
+ formattedAcitivity.secrets.join = activity.joinSecret;
+ if (activity.spectateSecret)
+ formattedAcitivity.secrets.spectate = activity.spectateSecret;
+ if (activity.matchSecret)
+ formattedAcitivity.secrets.match = activity.matchSecret;
+ if (Object.keys(formattedAcitivity.assets).length === 0)
+ delete formattedAcitivity["assets"];
+ if (Object.keys(formattedAcitivity.timestamps).length === 0)
+ delete formattedAcitivity["timestamps"];
+ if (Object.keys(formattedAcitivity.party).length === 0)
+ delete formattedAcitivity["party"];
+ if (Object.keys(formattedAcitivity.secrets).length === 0)
+ delete formattedAcitivity["secrets"];
+ formattedAcitivity.instance = !!activity.instance;
+ // Clean-up
+ delete formattedAcitivity["startTimestamp"];
+ delete formattedAcitivity["endTimestamp"];
+ delete formattedAcitivity["largeImageKey"];
+ delete formattedAcitivity["smallImageKey"];
+ delete formattedAcitivity["largeImageText"];
+ delete formattedAcitivity["smallImageText"];
+ delete formattedAcitivity["partyId"];
+ delete formattedAcitivity["partySize"];
+ delete formattedAcitivity["partyMax"];
+ delete formattedAcitivity["joinSecret"];
+ delete formattedAcitivity["spectateSecret"];
+ delete formattedAcitivity["matchSecret"];
+ return (await this.client.request("SET_ACTIVITY", {
+ pid: pid ?? process ? process.pid ?? 0 : 0,
+ activity: formattedAcitivity
+ })).data;
+ }
+ /**
+ * Used to clear a user's Rich Presence.
+ *
+ * @param pid - the application's process id
+ */
+ async clearActivity(pid) {
+ await this.client.request("SET_ACTIVITY", { pid: pid ?? process ? process.pid ?? 0 : 0 });
+ }
+ // #region Undocumented
+ // This region holds method that are not documented by Discord BUT does exist
+ /**
+ * Create a new lobby
+ * @param type - lobby type
+ * @param capacity - lobby size
+ * @param locked - is lobby locked
+ * @param metadata - additional data?
+ * @returns lobby that user created
+ */
+ async createLobby(type, capacity, locked, metadata) {
+ return new Lobby_1.Lobby(this.client, (await this.client.request("CREATE_LOBBY", { type, capacity, locked, metadata })).data);
+ }
+ /**
+ * Used to join a new lobby.
+ * @param lobbyId - the id of the lobby to join
+ * @param secret - the secret of the lobby to join
+ * @returns the lobby that the user joined
+ */
+ async connectToLobby(lobbyId, secret) {
+ return new Lobby_1.Lobby(this.client, (await this.client.request("CONNECT_TO_LOBBY", { id: lobbyId, secret })).data);
+ }
+ /**
+ * Used to join a new lobby.
+ * @param lobbyId - the id of the lobby to join
+ * @param data - additional data to send to lobby
+ * @returns the lobby that the user joined
+ */
+ async sendToLobby(lobbyId, data) {
+ return new Lobby_1.Lobby(this.client, (await this.client.request("SEND_TO_LOBBY", { lobby_id: lobbyId, data })).data);
+ }
+ /**
+ * Used to get a user's avatar
+ * @param userId - id of the user to get the avatar of
+ * @param format - image format
+ * @param size - image size
+ * @return base64 encoded image data
+ */
+ async getImage(userId, format = "png", size = 1024) {
+ return (await this.client.request("GET_IMAGE", { type: "user", id: userId, format, size })).data.data_url;
+ }
+}
+exports.ClientUser = ClientUser;
diff --git a/desktop/node_modules/@xhayper/discord-rpc/dist/structures/Guild.d.ts b/desktop/node_modules/@xhayper/discord-rpc/dist/structures/Guild.d.ts
new file mode 100644
index 0000000..02ce38f
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/dist/structures/Guild.d.ts
@@ -0,0 +1,25 @@
+import type { Client } from "../Client";
+import { type User } from "./User";
+import { Base } from "./Base";
+export declare class Guild extends Base {
+ /**
+ * guild id
+ */
+ id: string;
+ /**
+ * guild name (2-100 characters, excluding trailing and leading whitespace)
+ */
+ name: string;
+ icon_url: string | null;
+ /**
+ * guild member list
+ * (always an empty array)
+ * @deprecated
+ */
+ members: User[];
+ /**
+ * the vanity url code for the guild
+ */
+ vanity_url_code: string | null;
+ constructor(client: Client, props: Record<string, any>);
+}
diff --git a/desktop/node_modules/@xhayper/discord-rpc/dist/structures/Guild.js b/desktop/node_modules/@xhayper/discord-rpc/dist/structures/Guild.js
new file mode 100644
index 0000000..3014fa9
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/dist/structures/Guild.js
@@ -0,0 +1,34 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.Guild = void 0;
+const Base_1 = require("./Base");
+class Guild extends Base_1.Base {
+ /**
+ * guild id
+ */
+ id;
+ /**
+ * guild name (2-100 characters, excluding trailing and leading whitespace)
+ */
+ name;
+ icon_url;
+ /**
+ * guild member list
+ * (always an empty array)
+ * @deprecated
+ */
+ members = []; // Always an empty array
+ /**
+ * the vanity url code for the guild
+ */
+ vanity_url_code;
+ constructor(client, props) {
+ super(client);
+ Object.assign(this, props);
+ this.id = props.id;
+ this.name = props.name;
+ this.icon_url = props.icon_url;
+ this.vanity_url_code = props.vanity_url_code;
+ }
+}
+exports.Guild = Guild;
diff --git a/desktop/node_modules/@xhayper/discord-rpc/dist/structures/Lobby.d.ts b/desktop/node_modules/@xhayper/discord-rpc/dist/structures/Lobby.d.ts
new file mode 100644
index 0000000..23872c3
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/dist/structures/Lobby.d.ts
@@ -0,0 +1,31 @@
+import type { GatewayVoiceState } from "discord-api-types/v10";
+import type { Client } from "../Client";
+import { type User } from "./User";
+import { Base } from "./Base";
+export declare enum LobbyType {
+ PRIVATE = 1,
+ PUBLIC = 2
+}
+export declare class Lobby extends Base {
+ application_id: string;
+ capacity: number;
+ id: string;
+ locked: boolean;
+ members: {
+ metadata: any;
+ user: User;
+ }[];
+ metadata: any;
+ owner_id: string;
+ region: string;
+ secret: string;
+ type: LobbyType;
+ voice_states: GatewayVoiceState;
+ constructor(client: Client, props: Record<string, any>);
+ joinVoice(): Promise<void>;
+ leaveVoice(): Promise<void>;
+ update(type?: LobbyType, owner_id?: string, capacity?: number, locked?: boolean, metadata?: any): Promise<void>;
+ updateMember(userId: string, metadata?: any): Promise<void>;
+ disconnect(): Promise<void>;
+ delete(): Promise<void>;
+}
diff --git a/desktop/node_modules/@xhayper/discord-rpc/dist/structures/Lobby.js b/desktop/node_modules/@xhayper/discord-rpc/dist/structures/Lobby.js
new file mode 100644
index 0000000..1c6b96d
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/dist/structures/Lobby.js
@@ -0,0 +1,68 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.Lobby = exports.LobbyType = void 0;
+const Base_1 = require("./Base");
+var LobbyType;
+(function (LobbyType) {
+ LobbyType[LobbyType["PRIVATE"] = 1] = "PRIVATE";
+ LobbyType[LobbyType["PUBLIC"] = 2] = "PUBLIC";
+})(LobbyType || (exports.LobbyType = LobbyType = {}));
+class Lobby extends Base_1.Base {
+ application_id;
+ capacity;
+ id;
+ locked;
+ members;
+ metadata;
+ owner_id;
+ region;
+ secret;
+ type;
+ voice_states;
+ constructor(client, props) {
+ super(client);
+ Object.assign(this, props);
+ this.application_id = props.application_id;
+ this.capacity = props.capacity;
+ this.id = props.id;
+ this.locked = props.locked;
+ this.members = props.members;
+ this.metadata = props.metadata;
+ this.owner_id = props.owner_id;
+ this.region = props.region;
+ this.secret = props.secret;
+ this.type = props.type;
+ this.voice_states = props.voice_states;
+ }
+ async joinVoice() {
+ await this.client.request("CONNECT_TO_LOBBY_VOICE", { id: this.id });
+ }
+ async leaveVoice() {
+ await this.client.request("DISCONNECT_FROM_LOBBY_VOICE", { id: this.id });
+ }
+ async update(type, owner_id, capacity, locked, metadata) {
+ this.type = type ?? this.type;
+ this.owner_id = owner_id ?? this.owner_id;
+ this.capacity = capacity ?? this.capacity;
+ this.locked = locked ?? this.locked;
+ this.metadata = metadata ?? this.metadata;
+ await this.client.request("UPDATE_LOBBY", {
+ id: this.id,
+ type,
+ owner_id,
+ capacity,
+ locked,
+ metadata
+ });
+ }
+ async updateMember(userId, metadata) {
+ await this.client.request("UPDATE_LOBBY_MEMBER", { lobby_id: this.id, user_id: userId, metadata });
+ }
+ async disconnect() {
+ await this.client.request("DISCONNECT_FROM_LOBBY", { id: this.id });
+ }
+ async delete() {
+ await this.client.request("DELETE_LOBBY", { id: this.id });
+ }
+}
+exports.Lobby = Lobby;
diff --git a/desktop/node_modules/@xhayper/discord-rpc/dist/structures/Message.d.ts b/desktop/node_modules/@xhayper/discord-rpc/dist/structures/Message.d.ts
new file mode 100644
index 0000000..4c6b127
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/dist/structures/Message.d.ts
@@ -0,0 +1,73 @@
+import type { APIEmbed, APIAttachment, MessageType } from "discord-api-types/v10";
+import type { Client } from "../Client";
+import { Base } from "./Base";
+import { User } from "./User";
+export declare class Message extends Base {
+ /**
+ * id of the message
+ */
+ id: string;
+ /**
+ * if the message's author is blocked
+ */
+ blocked: boolean;
+ /**
+ * if the message is sent by a bot
+ */
+ bot: boolean;
+ /**
+ * contents of the message
+ */
+ content: string;
+ content_parsed: any[];
+ /**
+ * author's server nickname
+ */
+ nick: string;
+ author_color: string;
+ /**
+ * when this message was edited (or null if never)
+ */
+ edited_timestamp: string | null;
+ /**
+ * when this message was sent
+ */
+ timestamp: string;
+ /**
+ * whether this was a TTS message
+ */
+ tts: boolean;
+ /**
+ * users specifically mentioned in the message
+ */
+ mentions: User[];
+ /**
+ * whether this message mentions everyone
+ */
+ mention_everyone: boolean;
+ /**
+ * roles specifically mentioned in this message
+ */
+ mention_roles: string[];
+ /**
+ * any embedded content
+ */
+ embeds: APIEmbed[];
+ /**
+ * any attached files
+ */
+ attachments: APIAttachment[];
+ /**
+ * the author of this message
+ */
+ author: User;
+ /**
+ * whether this message is pinned
+ */
+ pinned: boolean;
+ /**
+ * [type of message](https://discord.com/developers/docs/resources/channel#message-object-message-types)
+ */
+ type: MessageType;
+ constructor(client: Client, props: Record<string, any>);
+}
diff --git a/desktop/node_modules/@xhayper/discord-rpc/dist/structures/Message.js b/desktop/node_modules/@xhayper/discord-rpc/dist/structures/Message.js
new file mode 100644
index 0000000..ec08fdf
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/dist/structures/Message.js
@@ -0,0 +1,96 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.Message = void 0;
+const Base_1 = require("./Base");
+const User_1 = require("./User");
+class Message extends Base_1.Base {
+ /**
+ * id of the message
+ */
+ id;
+ /**
+ * if the message's author is blocked
+ */
+ blocked;
+ /**
+ * if the message is sent by a bot
+ */
+ bot;
+ /**
+ * contents of the message
+ */
+ content;
+ content_parsed;
+ /**
+ * author's server nickname
+ */
+ nick;
+ author_color;
+ /**
+ * when this message was edited (or null if never)
+ */
+ edited_timestamp;
+ /**
+ * when this message was sent
+ */
+ timestamp;
+ /**
+ * whether this was a TTS message
+ */
+ tts;
+ /**
+ * users specifically mentioned in the message
+ */
+ mentions;
+ /**
+ * whether this message mentions everyone
+ */
+ mention_everyone;
+ /**
+ * roles specifically mentioned in this message
+ */
+ mention_roles;
+ /**
+ * any embedded content
+ */
+ embeds;
+ /**
+ * any attached files
+ */
+ attachments;
+ /**
+ * the author of this message
+ */
+ author;
+ /**
+ * whether this message is pinned
+ */
+ pinned;
+ /**
+ * [type of message](https://discord.com/developers/docs/resources/channel#message-object-message-types)
+ */
+ type;
+ constructor(client, props) {
+ super(client);
+ Object.assign(this, props);
+ this.id = props.id;
+ this.blocked = props.blocked;
+ this.bot = props.bot;
+ this.content = props.content;
+ this.content_parsed = props.content_parsed;
+ this.nick = props.nick;
+ this.author_color = props.author_color;
+ this.edited_timestamp = props.edited_timestamp;
+ this.timestamp = props.timestamp;
+ this.tts = props.tts;
+ this.mentions = props.mentions.map((mentionData) => new User_1.User(client, mentionData));
+ this.mention_everyone = props.mention_everyone;
+ this.mention_roles = props.mention_roles;
+ this.embeds = props.embeds;
+ this.attachments = props.attachments;
+ this.author = new User_1.User(client, props.author);
+ this.pinned = props.pinned;
+ this.type = props.type;
+ }
+}
+exports.Message = Message;
diff --git a/desktop/node_modules/@xhayper/discord-rpc/dist/structures/Transport.d.ts b/desktop/node_modules/@xhayper/discord-rpc/dist/structures/Transport.d.ts
new file mode 100644
index 0000000..06f757a
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/dist/structures/Transport.d.ts
@@ -0,0 +1,152 @@
+import { type TypedEventEmitter } from "../utils/TypedEventEmitter";
+import type { Client } from "../Client";
+export declare enum RPC_CLOSE_CODE {
+ RPC_CLOSE_NORMAL = 1000,
+ RPC_CLOSE_UNSUPPORTED = 1003,
+ RPC_CLOSE_ABNORMAL = 1006,
+ /**
+ * You connected to the RPC server with an invalid client ID.
+ */
+ RPC_CLOSE_INVALID_CLIENT_ID = 4000,
+ /**
+ * You connected to the RPC server with an invalid origin.
+ */
+ RPC_CLOSE_INVALID_ORIGIN = 4001,
+ /**
+ * You are being rate limited.
+ */
+ RPC_CLOSE_RATE_LIMITED = 4002,
+ /**
+ * The OAuth2 token associated with a connection was revoked, get a new one!
+ */
+ RPC_CLOSE_TOKEN_REVOKED = 4003,
+ /**
+ * The RPC Server version specified in the connection string was not valid.
+ */
+ RPC_CLOSE_INVALID_VERSION = 4004,
+ /**
+ * The encoding specified in the connection string was not valid
+ */
+ RPC_CLOSE_INVALID_ENCODING = 4005
+}
+export declare enum RPC_ERROR_CODE {
+ /**
+ * An unknown error occurred.
+ */
+ RPC_UNKNOWN_ERROR = 1000,
+ /**
+ * You sent an invalid payload.
+ */
+ RPC_INVALID_PAYLOAD = 4000,
+ /**
+ * Invalid command name specified.
+ */
+ RPC_INVALID_COMMAND = 4002,
+ /**
+ * Invalid guild ID specified.
+ */
+ RPC_INVALID_GUILD = 4003,
+ /**
+ * Invalid event name specified.
+ */
+ RPC_INVALID_EVENT = 4004,
+ /**
+ * Invalid channel ID specified.
+ */
+ RPC_INVALID_CHANNEL = 4005,
+ /**
+ * You lack permissions to access the given resource.
+ */
+ RPC_INVALID_PERMISSION = 4006,
+ /**
+ * An invalid OAuth2 application ID was used to authorize or authenticate with.
+ */
+ RPC_INVALID_CLIENT_ID = 4007,
+ /**
+ * An invalid OAuth2 application origin was used to authorize or authenticate with.
+ */
+ RPC_INVALID_ORIGIN = 4008,
+ /**
+ * An invalid OAuth2 token was used to authorize or authenticate with.
+ */
+ RPC_INVALID_TOKEN = 4009,
+ /**
+ * The specified user ID was invalid.
+ */
+ RPC_INVALID_USER = 4010,
+ /**
+ * A standard OAuth2 error occurred; check the data object for the OAuth2 error details.
+ */
+ RPC_OAUTH2_ERROR = 5000,
+ /**
+ * An asynchronous `SELECT_TEXT_CHANNEL`/`SELECT_VOICE_CHANNEL` command timed out.
+ */
+ RPC_SELECT_CHANNEL_TIMEOUT = 5001,
+ /**
+ * An asynchronous `GET_GUILD` command timed out.
+ */
+ RPC_GET_GUILD_TIMEOUT = 5002,
+ /**
+ * You tried to join a user to a voice channel but the user was already in one.
+ */
+ RPC_SELECT_VOICE_FORCE_REQUIRED = 5003,
+ /**
+ * You tried to capture more than one shortcut key at once.
+ */
+ RPC_CAPTURE_SHORTCUT_ALREADY_LISTENING = 5004
+}
+export declare enum CUSTOM_RPC_ERROR_CODE {
+ RPC_CONNECTION_ENDED = 0,
+ RPC_CONNECTION_TIMEOUT = 1,
+ RPC_COULD_NOT_CONNECT = 2
+}
+export type RPC_CMD = "DISPATCH" | "SET_CONFIG" | "AUTHORIZE" | "AUTHENTICATE" | "GET_GUILD" | "GET_GUILDS" | "GET_CHANNEL" | "GET_CHANNELS" | "CREATE_CHANNEL_INVITE" | "GET_RELATIONSHIPS" | "GET_USER" | "SUBSCRIBE" | "UNSUBSCRIBE" | "SET_USER_VOICE_SETTINGS" | "SET_USER_VOICE_SETTINGS_2" | "SELECT_VOICE_CHANNEL" | "GET_SELECTED_VOICE_CHANNEL" | "SELECT_TEXT_CHANNEL" | "GET_VOICE_SETTINGS" | "SET_VOICE_SETTINGS_2" | "SET_VOICE_SETTINGS" | "SET_ACTIVITY" | "SEND_ACTIVITY_JOIN_INVITE" | "CLOSE_ACTIVITY_JOIN_REQUEST" | "ACTIVITY_INVITE_USER" | "ACCEPT_ACTIVITY_INVITE" | "OPEN_INVITE_DIALOG" | "INVITE_BROWSER" | "DEEP_LINK" | "CONNECTIONS_CALLBACK" | "BILLING_POPUP_BRIDGE_CALLBACK" | "BRAINTREE_POPUP_BRIDGE_CALLBACK" | "GIFT_CODE_BROWSER" | "GUILD_TEMPLATE_BROWSER" | "OVERLAY" | "BROWSER_HANDOFF" | "SET_CERTIFIED_DEVICES" | "GET_IMAGE" | "CREATE_LOBBY" | "UPDATE_LOBBY" | "DELETE_LOBBY" | "UPDATE_LOBBY_MEMBER" | "CONNECT_TO_LOBBY" | "DISCONNECT_FROM_LOBBY" | "SEND_TO_LOBBY" | "SEARCH_LOBBIES" | "CONNECT_TO_LOBBY_VOICE" | "DISCONNECT_FROM_LOBBY_VOICE" | "SET_OVERLAY_LOCKED" | "OPEN_OVERLAY_ACTIVITY_INVITE" | "OPEN_OVERLAY_GUILD_INVITE" | "OPEN_OVERLAY_VOICE_SETTINGS" | "VALIDATE_APPLICATION" | "GET_ENTITLEMENT_TICKET" | "GET_APPLICATION_TICKET" | "START_PURCHASE" | "START_PREMIUM_PURCHASE" | "GET_SKUS" | "GET_ENTITLEMENTS" | "GET_NETWORKING_CONFIG" | "NETWORKING_SYSTEM_METRICS" | "NETWORKING_PEER_METRICS" | "NETWORKING_CREATE_TOKEN" | "SET_USER_ACHIEVEMENT" | "GET_USER_ACHIEVEMENTS" | "USER_SETTINGS_GET_LOCALE" | "GET_ACTIVITY_JOIN_TICKET" | "SEND_GENERIC_EVENT" | "SEND_ANALYTICS_EVENT" | "OPEN_EXTERNAL_LINK" | "CAPTURE_LOG" | "ENCOURAGE_HW_ACCELERATION" | "SET_ORIENTATION_LOCK_STATE";
+export type RPC_EVT = "CURRENT_USER_UPDATE" | "GUILD_STATUS" | "GUILD_CREATE" | "CHANNEL_CREATE" | "RELATIONSHIP_UPDATE" | "VOICE_CHANNEL_SELECT" | "VOICE_STATE_CREATE" | "VOICE_STATE_DELETE" | "VOICE_STATE_UPDATE" | "VOICE_SETTINGS_UPDATE" | "VOICE_SETTINGS_UPDATE_2" | "VOICE_CONNECTION_STATUS" | "SPEAKING_START" | "SPEAKING_STOP" | "GAME_JOIN" | "GAME_SPECTATE" | "ACTIVITY_JOIN" | "ACTIVITY_JOIN_REQUEST" | "ACTIVITY_SPECTATE" | "ACTIVITY_INVITE" | "ACTIVITY_PIP_MODE_UPDATE" | "NOTIFICATION_CREATE" | "MESSAGE_CREATE" | "MESSAGE_UPDATE" | "MESSAGE_DELETE" | "LOBBY_DELETE" | "LOBBY_UPDATE" | "LOBBY_MEMBER_CONNECT" | "LOBBY_MEMBER_DISCONNECT" | "LOBBY_MEMBER_UPDATE" | "LOBBY_MESSAGE" | "OVERLAY" | "OVERLAY_UPDATE" | "ENTITLEMENT_CREATE" | "ENTITLEMENT_DELETE" | "USER_ACHIEVEMENT_UPDATE" | "VOICE_CHANNEL_EFFECT_SEND" | "THERMAL_STATE_UPDATE" | "READY" | "ERROR";
+export interface CommandOutgoing<A = any> {
+ cmd: RPC_CMD;
+ nonce: string | null;
+ args: A;
+ evt?: RPC_EVT;
+}
+export interface CommandIncoming<A = any, D = any> {
+ cmd: RPC_CMD;
+ nonce: string | null;
+ args?: A;
+ data: D;
+ evt?: RPC_EVT;
+}
+export type TransportEvents = {
+ /**
+ * @event
+ */
+ message: (message: CommandIncoming) => void;
+ /**
+ * @event
+ */
+ ping: () => void;
+ /**
+ * @event
+ */
+ open: () => void;
+ /**
+ * @event
+ */
+ close: (reason?: string | {
+ code: number;
+ message: string;
+ }) => void;
+};
+export type TransportOptions = {
+ client: Client;
+};
+declare const Transport_base: new () => TypedEventEmitter<TransportEvents>;
+export declare abstract class Transport extends Transport_base {
+ readonly client: Client;
+ get isConnected(): boolean;
+ constructor(options: TransportOptions);
+ abstract connect(): Promise<void>;
+ abstract send(data?: any): void;
+ abstract ping(): void;
+ abstract close(): Promise<void>;
+}
+export {};
diff --git a/desktop/node_modules/@xhayper/discord-rpc/dist/structures/Transport.js b/desktop/node_modules/@xhayper/discord-rpc/dist/structures/Transport.js
new file mode 100644
index 0000000..c5594af
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/dist/structures/Transport.js
@@ -0,0 +1,118 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.Transport = exports.CUSTOM_RPC_ERROR_CODE = exports.RPC_ERROR_CODE = exports.RPC_CLOSE_CODE = void 0;
+const node_events_1 = require("node:events");
+var RPC_CLOSE_CODE;
+(function (RPC_CLOSE_CODE) {
+ RPC_CLOSE_CODE[RPC_CLOSE_CODE["RPC_CLOSE_NORMAL"] = 1000] = "RPC_CLOSE_NORMAL";
+ RPC_CLOSE_CODE[RPC_CLOSE_CODE["RPC_CLOSE_UNSUPPORTED"] = 1003] = "RPC_CLOSE_UNSUPPORTED";
+ RPC_CLOSE_CODE[RPC_CLOSE_CODE["RPC_CLOSE_ABNORMAL"] = 1006] = "RPC_CLOSE_ABNORMAL";
+ /**
+ * You connected to the RPC server with an invalid client ID.
+ */
+ RPC_CLOSE_CODE[RPC_CLOSE_CODE["RPC_CLOSE_INVALID_CLIENT_ID"] = 4000] = "RPC_CLOSE_INVALID_CLIENT_ID";
+ /**
+ * You connected to the RPC server with an invalid origin.
+ */
+ RPC_CLOSE_CODE[RPC_CLOSE_CODE["RPC_CLOSE_INVALID_ORIGIN"] = 4001] = "RPC_CLOSE_INVALID_ORIGIN";
+ /**
+ * You are being rate limited.
+ */
+ RPC_CLOSE_CODE[RPC_CLOSE_CODE["RPC_CLOSE_RATE_LIMITED"] = 4002] = "RPC_CLOSE_RATE_LIMITED";
+ /**
+ * The OAuth2 token associated with a connection was revoked, get a new one!
+ */
+ RPC_CLOSE_CODE[RPC_CLOSE_CODE["RPC_CLOSE_TOKEN_REVOKED"] = 4003] = "RPC_CLOSE_TOKEN_REVOKED";
+ /**
+ * The RPC Server version specified in the connection string was not valid.
+ */
+ RPC_CLOSE_CODE[RPC_CLOSE_CODE["RPC_CLOSE_INVALID_VERSION"] = 4004] = "RPC_CLOSE_INVALID_VERSION";
+ /**
+ * The encoding specified in the connection string was not valid
+ */
+ RPC_CLOSE_CODE[RPC_CLOSE_CODE["RPC_CLOSE_INVALID_ENCODING"] = 4005] = "RPC_CLOSE_INVALID_ENCODING";
+})(RPC_CLOSE_CODE || (exports.RPC_CLOSE_CODE = RPC_CLOSE_CODE = {}));
+var RPC_ERROR_CODE;
+(function (RPC_ERROR_CODE) {
+ /**
+ * An unknown error occurred.
+ */
+ RPC_ERROR_CODE[RPC_ERROR_CODE["RPC_UNKNOWN_ERROR"] = 1000] = "RPC_UNKNOWN_ERROR";
+ /**
+ * You sent an invalid payload.
+ */
+ RPC_ERROR_CODE[RPC_ERROR_CODE["RPC_INVALID_PAYLOAD"] = 4000] = "RPC_INVALID_PAYLOAD";
+ /**
+ * Invalid command name specified.
+ */
+ RPC_ERROR_CODE[RPC_ERROR_CODE["RPC_INVALID_COMMAND"] = 4002] = "RPC_INVALID_COMMAND";
+ /**
+ * Invalid guild ID specified.
+ */
+ RPC_ERROR_CODE[RPC_ERROR_CODE["RPC_INVALID_GUILD"] = 4003] = "RPC_INVALID_GUILD";
+ /**
+ * Invalid event name specified.
+ */
+ RPC_ERROR_CODE[RPC_ERROR_CODE["RPC_INVALID_EVENT"] = 4004] = "RPC_INVALID_EVENT";
+ /**
+ * Invalid channel ID specified.
+ */
+ RPC_ERROR_CODE[RPC_ERROR_CODE["RPC_INVALID_CHANNEL"] = 4005] = "RPC_INVALID_CHANNEL";
+ /**
+ * You lack permissions to access the given resource.
+ */
+ RPC_ERROR_CODE[RPC_ERROR_CODE["RPC_INVALID_PERMISSION"] = 4006] = "RPC_INVALID_PERMISSION";
+ /**
+ * An invalid OAuth2 application ID was used to authorize or authenticate with.
+ */
+ RPC_ERROR_CODE[RPC_ERROR_CODE["RPC_INVALID_CLIENT_ID"] = 4007] = "RPC_INVALID_CLIENT_ID";
+ /**
+ * An invalid OAuth2 application origin was used to authorize or authenticate with.
+ */
+ RPC_ERROR_CODE[RPC_ERROR_CODE["RPC_INVALID_ORIGIN"] = 4008] = "RPC_INVALID_ORIGIN";
+ /**
+ * An invalid OAuth2 token was used to authorize or authenticate with.
+ */
+ RPC_ERROR_CODE[RPC_ERROR_CODE["RPC_INVALID_TOKEN"] = 4009] = "RPC_INVALID_TOKEN";
+ /**
+ * The specified user ID was invalid.
+ */
+ RPC_ERROR_CODE[RPC_ERROR_CODE["RPC_INVALID_USER"] = 4010] = "RPC_INVALID_USER";
+ /**
+ * A standard OAuth2 error occurred; check the data object for the OAuth2 error details.
+ */
+ RPC_ERROR_CODE[RPC_ERROR_CODE["RPC_OAUTH2_ERROR"] = 5000] = "RPC_OAUTH2_ERROR";
+ /**
+ * An asynchronous `SELECT_TEXT_CHANNEL`/`SELECT_VOICE_CHANNEL` command timed out.
+ */
+ RPC_ERROR_CODE[RPC_ERROR_CODE["RPC_SELECT_CHANNEL_TIMEOUT"] = 5001] = "RPC_SELECT_CHANNEL_TIMEOUT";
+ /**
+ * An asynchronous `GET_GUILD` command timed out.
+ */
+ RPC_ERROR_CODE[RPC_ERROR_CODE["RPC_GET_GUILD_TIMEOUT"] = 5002] = "RPC_GET_GUILD_TIMEOUT";
+ /**
+ * You tried to join a user to a voice channel but the user was already in one.
+ */
+ RPC_ERROR_CODE[RPC_ERROR_CODE["RPC_SELECT_VOICE_FORCE_REQUIRED"] = 5003] = "RPC_SELECT_VOICE_FORCE_REQUIRED";
+ /**
+ * You tried to capture more than one shortcut key at once.
+ */
+ RPC_ERROR_CODE[RPC_ERROR_CODE["RPC_CAPTURE_SHORTCUT_ALREADY_LISTENING"] = 5004] = "RPC_CAPTURE_SHORTCUT_ALREADY_LISTENING";
+})(RPC_ERROR_CODE || (exports.RPC_ERROR_CODE = RPC_ERROR_CODE = {}));
+var CUSTOM_RPC_ERROR_CODE;
+(function (CUSTOM_RPC_ERROR_CODE) {
+ CUSTOM_RPC_ERROR_CODE[CUSTOM_RPC_ERROR_CODE["RPC_CONNECTION_ENDED"] = 0] = "RPC_CONNECTION_ENDED";
+ CUSTOM_RPC_ERROR_CODE[CUSTOM_RPC_ERROR_CODE["RPC_CONNECTION_TIMEOUT"] = 1] = "RPC_CONNECTION_TIMEOUT";
+ CUSTOM_RPC_ERROR_CODE[CUSTOM_RPC_ERROR_CODE["RPC_COULD_NOT_CONNECT"] = 2] = "RPC_COULD_NOT_CONNECT";
+})(CUSTOM_RPC_ERROR_CODE || (exports.CUSTOM_RPC_ERROR_CODE = CUSTOM_RPC_ERROR_CODE = {}));
+class Transport extends node_events_1.EventEmitter {
+ client;
+ get isConnected() {
+ return false;
+ }
+ constructor(options) {
+ super();
+ this.client = options.client;
+ }
+}
+exports.Transport = Transport;
diff --git a/desktop/node_modules/@xhayper/discord-rpc/dist/structures/User.d.ts b/desktop/node_modules/@xhayper/discord-rpc/dist/structures/User.d.ts
new file mode 100644
index 0000000..a608875
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/dist/structures/User.d.ts
@@ -0,0 +1,54 @@
+import type { UserFlags, UserPremiumType, PresenceUpdateStatus, GatewayActivity } from "discord-api-types/v10";
+import type { Client } from "../Client";
+import { Base } from "./Base";
+export declare class User extends Base {
+ /**
+ * the user's id
+ */
+ id: string;
+ /**
+ * the user's username, not unique across the platform
+ */
+ username: string;
+ /**
+ * the user's 4-digit discord-tag
+ */
+ discriminator: string;
+ /**
+ * the user's [avatar hash](https://discord.com/developers/docs/reference#image-formatting)
+ */
+ avatar: string | null;
+ /**
+ * the [flags](https://discord.com/developers/docs/resources/user#user-object-user-flags) on a user's account
+ */
+ flags?: UserFlags | undefined;
+ /**
+ * the [type of Nitro subscription](https://discord.com/developers/docs/resources/user#user-object-premium-types) on a user's account
+ */
+ premium_type?: UserPremiumType | undefined;
+ /**
+ * the public [flags](https://discord.com/developers/docs/resources/user#user-object-user-flags) on a user's account
+ */
+ public_flags?: UserFlags | undefined;
+ /**
+ * user's rich presence
+ */
+ presence?: {
+ status?: PresenceUpdateStatus;
+ activities?: GatewayActivity[];
+ } | undefined;
+ avatar_decoration?: string | null;
+ constructor(client: Client, props: Record<string, any>);
+ /**
+ * The URL to the user's avatar.
+ */
+ get avatarUrl(): string;
+ /**
+ * The URL to the user's default avatar. (avatar that is used when user have no avatar)
+ */
+ get defaultAvatarUrl(): string;
+ /**
+ * User's tag
+ */
+ get tag(): string;
+}
diff --git a/desktop/node_modules/@xhayper/discord-rpc/dist/structures/User.js b/desktop/node_modules/@xhayper/discord-rpc/dist/structures/User.js
new file mode 100644
index 0000000..8e313cb
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/dist/structures/User.js
@@ -0,0 +1,70 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.User = void 0;
+const Base_1 = require("./Base");
+class User extends Base_1.Base {
+ /**
+ * the user's id
+ */
+ id;
+ /**
+ * the user's username, not unique across the platform
+ */
+ username;
+ /**
+ * the user's 4-digit discord-tag
+ */
+ discriminator;
+ /**
+ * the user's [avatar hash](https://discord.com/developers/docs/reference#image-formatting)
+ */
+ avatar;
+ /**
+ * the [flags](https://discord.com/developers/docs/resources/user#user-object-user-flags) on a user's account
+ */
+ flags;
+ /**
+ * the [type of Nitro subscription](https://discord.com/developers/docs/resources/user#user-object-premium-types) on a user's account
+ */
+ premium_type;
+ /**
+ * the public [flags](https://discord.com/developers/docs/resources/user#user-object-user-flags) on a user's account
+ */
+ public_flags;
+ /**
+ * user's rich presence
+ */
+ presence;
+ avatar_decoration;
+ constructor(client, props) {
+ super(client);
+ Object.assign(this, props);
+ // word can't explains how much i hate this
+ this.id = props.id;
+ this.username = props.username;
+ this.discriminator = props.discriminator;
+ this.avatar = props.avatar;
+ }
+ /**
+ * The URL to the user's avatar.
+ */
+ get avatarUrl() {
+ const isAnimated = this.avatar && this.avatar.startsWith("a_");
+ return this.avatar
+ ? `${this.client.cdnHost}/avatars/${this.id}/${this.avatar}${isAnimated ? ".gif" : ".png"}`
+ : this.defaultAvatarUrl;
+ }
+ /**
+ * The URL to the user's default avatar. (avatar that is used when user have no avatar)
+ */
+ get defaultAvatarUrl() {
+ return `${this.client.cdnHost}/embed/avatars/${parseInt(this.discriminator.substring(1)) % 5}.png`;
+ }
+ /**
+ * User's tag
+ */
+ get tag() {
+ return `${this.username}#${this.discriminator}`;
+ }
+}
+exports.User = User;
diff --git a/desktop/node_modules/@xhayper/discord-rpc/dist/structures/VoiceSettings.d.ts b/desktop/node_modules/@xhayper/discord-rpc/dist/structures/VoiceSettings.d.ts
new file mode 100644
index 0000000..5d7c1af
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/dist/structures/VoiceSettings.d.ts
@@ -0,0 +1,119 @@
+import type { Client } from "../Client";
+import { Base } from "./Base";
+export declare enum KEY_TYPE {
+ KEYBOARD_KEY = 0,
+ MOUSE_BUTTON = 1,
+ KEYBOARD_MODIFIER_KEY = 2,
+ GAMEPAD_BUTTON = 3
+}
+export interface ShortcutKeyCombo {
+ /**
+ * see [key types](https://discord.com/developers/docs/topics/rpc#getvoicesettings-key-types)
+ */
+ type: KEY_TYPE;
+ /**
+ * key code
+ */
+ code: number;
+ /**
+ * key name
+ */
+ name: string;
+}
+export interface Device {
+ id: string;
+ name: string;
+}
+export interface VoiceInput {
+ /**
+ * device id
+ */
+ device_id: string;
+ /**
+ * input voice level (min: 0, max: 100)
+ */
+ volume: number;
+ /**
+ * array of read-only device objects containing `id` and `name` string keys
+ */
+ readonly available_devices: Device[];
+}
+export interface VoiceOutput {
+ /**
+ * device id
+ */
+ device_id: string;
+ /**
+ * output voice level (min: 0, max: 200)
+ */
+ volume: number;
+ /**
+ * array of read-only device objects containing `id` and `name` string keys
+ */
+ readonly available_devices: Device[];
+}
+export interface VoiceMode {
+ /**
+ * voice setting mode type (can be `PUSH_TO_TALK` or `VOICE_ACTIVITY`)
+ */
+ type: "PUSH_TO_TALK" | "VOICE_ACTIVITY";
+ /**
+ * voice activity threshold automatically sets its threshold
+ */
+ auto_threshold: boolean;
+ /**
+ * threshold for voice activity (in dB) (min: -100, max: 0)
+ */
+ threshold: number;
+ /**
+ * shortcut key combos for PTT
+ */
+ shortcut: ShortcutKeyCombo[];
+ /**
+ * the PTT release delay (in ms) (min: 0, max: 2000)
+ */
+ delay: number;
+}
+export declare class VoiceSettings extends Base {
+ /**
+ * input settings
+ */
+ input: VoiceInput;
+ /**
+ * output settings
+ */
+ output: VoiceOutput;
+ /**
+ * voice mode settings
+ */
+ mode: any;
+ /**
+ * state of automatic gain control
+ */
+ automatic_gain_control: boolean;
+ /**
+ * state of echo cancellation
+ */
+ echo_cancellation: boolean;
+ /**
+ * state of noise suppression
+ */
+ noise_suppression: boolean;
+ /**
+ * state of voice quality of service
+ */
+ qos: boolean;
+ /**
+ * state of silence warning notice
+ */
+ silence_warning: boolean;
+ /**
+ * state of self-deafen
+ */
+ deaf: boolean;
+ /**
+ * state of self-mute
+ */
+ mute: boolean;
+ constructor(client: Client, props: Record<string, any>);
+}
diff --git a/desktop/node_modules/@xhayper/discord-rpc/dist/structures/VoiceSettings.js b/desktop/node_modules/@xhayper/discord-rpc/dist/structures/VoiceSettings.js
new file mode 100644
index 0000000..0e67894
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/dist/structures/VoiceSettings.js
@@ -0,0 +1,68 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.VoiceSettings = exports.KEY_TYPE = void 0;
+const Base_1 = require("./Base");
+var KEY_TYPE;
+(function (KEY_TYPE) {
+ KEY_TYPE[KEY_TYPE["KEYBOARD_KEY"] = 0] = "KEYBOARD_KEY";
+ KEY_TYPE[KEY_TYPE["MOUSE_BUTTON"] = 1] = "MOUSE_BUTTON";
+ KEY_TYPE[KEY_TYPE["KEYBOARD_MODIFIER_KEY"] = 2] = "KEYBOARD_MODIFIER_KEY";
+ KEY_TYPE[KEY_TYPE["GAMEPAD_BUTTON"] = 3] = "GAMEPAD_BUTTON";
+})(KEY_TYPE || (exports.KEY_TYPE = KEY_TYPE = {}));
+class VoiceSettings extends Base_1.Base {
+ /**
+ * input settings
+ */
+ input;
+ /**
+ * output settings
+ */
+ output;
+ /**
+ * voice mode settings
+ */
+ mode;
+ /**
+ * state of automatic gain control
+ */
+ automatic_gain_control;
+ /**
+ * state of echo cancellation
+ */
+ echo_cancellation;
+ /**
+ * state of noise suppression
+ */
+ noise_suppression;
+ /**
+ * state of voice quality of service
+ */
+ qos;
+ /**
+ * state of silence warning notice
+ */
+ silence_warning;
+ /**
+ * state of self-deafen
+ */
+ deaf;
+ /**
+ * state of self-mute
+ */
+ mute;
+ constructor(client, props) {
+ super(client);
+ Object.assign(this, props);
+ this.input = props.input;
+ this.output = props.output;
+ this.mode = props.mode;
+ this.automatic_gain_control = props.automatic_gain_control;
+ this.echo_cancellation = props.echo_cancellation;
+ this.noise_suppression = props.noise_suppression;
+ this.qos = props.qos;
+ this.silence_warning = props.silence_warning;
+ this.deaf = props.deaf;
+ this.mute = props.mute;
+ }
+}
+exports.VoiceSettings = VoiceSettings;
diff --git a/desktop/node_modules/@xhayper/discord-rpc/dist/transport/IPC.d.ts b/desktop/node_modules/@xhayper/discord-rpc/dist/transport/IPC.d.ts
new file mode 100644
index 0000000..848788a
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/dist/transport/IPC.d.ts
@@ -0,0 +1,23 @@
+import { Transport, type TransportOptions } from "../structures/Transport";
+export declare enum IPC_OPCODE {
+ HANDSHAKE = 0,
+ FRAME = 1,
+ CLOSE = 2,
+ PING = 3,
+ PONG = 4
+}
+export type FormatFunction = (id: number) => string | undefined;
+export type IPCTransportOptions = {
+ pathList?: FormatFunction[];
+} & TransportOptions;
+export declare class IPCTransport extends Transport {
+ pathList: FormatFunction[];
+ private socket?;
+ get isConnected(): boolean;
+ constructor(options: IPCTransportOptions);
+ private getSocket;
+ connect(): Promise<void>;
+ send(message?: any, op?: IPC_OPCODE): void;
+ ping(): void;
+ close(): Promise<void>;
+}
diff --git a/desktop/node_modules/@xhayper/discord-rpc/dist/transport/IPC.js b/desktop/node_modules/@xhayper/discord-rpc/dist/transport/IPC.js
new file mode 100644
index 0000000..0361265
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/dist/transport/IPC.js
@@ -0,0 +1,193 @@
+"use strict";
+var __importDefault = (this && this.__importDefault) || function (mod) {
+ return (mod && mod.__esModule) ? mod : { "default": mod };
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.IPCTransport = exports.IPC_OPCODE = void 0;
+const Transport_1 = require("../structures/Transport");
+const RPCError_1 = require("../utils/RPCError");
+const node_crypto_1 = __importDefault(require("node:crypto"));
+const node_path_1 = __importDefault(require("node:path"));
+const node_net_1 = __importDefault(require("node:net"));
+const node_fs_1 = __importDefault(require("node:fs"));
+var IPC_OPCODE;
+(function (IPC_OPCODE) {
+ IPC_OPCODE[IPC_OPCODE["HANDSHAKE"] = 0] = "HANDSHAKE";
+ IPC_OPCODE[IPC_OPCODE["FRAME"] = 1] = "FRAME";
+ IPC_OPCODE[IPC_OPCODE["CLOSE"] = 2] = "CLOSE";
+ IPC_OPCODE[IPC_OPCODE["PING"] = 3] = "PING";
+ IPC_OPCODE[IPC_OPCODE["PONG"] = 4] = "PONG";
+})(IPC_OPCODE || (exports.IPC_OPCODE = IPC_OPCODE = {}));
+const defaultPathList = [
+ (id) => {
+ // Windows path
+ const isWindows = process.platform === "win32";
+ return isWindows ? `\\\\?\\pipe\\discord-ipc-${id}` : undefined;
+ },
+ (id) => {
+ // macOS / Linux path
+ if (process.platform === "win32")
+ return;
+ const { env: { XDG_RUNTIME_DIR, TMPDIR, TMP, TEMP } } = process;
+ const prefix = node_fs_1.default.realpathSync(XDG_RUNTIME_DIR ?? TMPDIR ?? TMP ?? TEMP ?? `${node_path_1.default.sep}tmp`);
+ return node_path_1.default.join(prefix, `discord-ipc-${id}`);
+ },
+ (id) => {
+ // snap
+ if (process.platform === "win32")
+ return;
+ const { env: { XDG_RUNTIME_DIR, TMPDIR, TMP, TEMP } } = process;
+ const prefix = node_fs_1.default.realpathSync(XDG_RUNTIME_DIR ?? TMPDIR ?? TMP ?? TEMP ?? `${node_path_1.default.sep}tmp`);
+ return node_path_1.default.join(prefix, "snap.discord", `discord-ipc-${id}`);
+ },
+ (id) => {
+ // flatpak
+ if (process.platform === "win32")
+ return;
+ const { env: { XDG_RUNTIME_DIR, TMPDIR, TMP, TEMP } } = process;
+ const prefix = node_fs_1.default.realpathSync(XDG_RUNTIME_DIR ?? TMPDIR ?? TMP ?? TEMP ?? `${node_path_1.default.sep}tmp`);
+ return node_path_1.default.join(prefix, "app", "com.discordapp.Discord", `discord-ipc-${id}`);
+ }
+];
+const createSocket = async (path) => {
+ return new Promise((resolve, reject) => {
+ const onError = () => {
+ socket.removeListener("conect", onConnect);
+ reject();
+ };
+ const onConnect = () => {
+ socket.removeListener("error", onError);
+ resolve(socket);
+ };
+ const socket = node_net_1.default.createConnection(path);
+ socket.once("connect", onConnect);
+ socket.once("error", onError);
+ });
+};
+class IPCTransport extends Transport_1.Transport {
+ pathList = defaultPathList;
+ socket;
+ get isConnected() {
+ return this.socket !== undefined && this.socket.readyState === "open";
+ }
+ constructor(options) {
+ super(options);
+ this.pathList = options.pathList ?? this.pathList;
+ }
+ async getSocket() {
+ if (this.socket)
+ return this.socket;
+ const pathList = this.pathList;
+ return new Promise(async (resolve, reject) => {
+ for (const formatFunc of pathList) {
+ const tryCreateSocket = async (path) => {
+ const socket = await createSocket(path).catch(() => undefined);
+ return socket;
+ };
+ const handleSocketId = async (id) => {
+ const socketPath = formatFunc(id);
+ if (!socketPath || socketPath.trim() === "")
+ return;
+ if (process.platform !== "win32" && !node_fs_1.default.existsSync(node_path_1.default.dirname(socketPath)))
+ return;
+ const socket = await tryCreateSocket(socketPath);
+ return socket;
+ };
+ if (this.client.pipeId) {
+ const socket = await handleSocketId(this.client.pipeId);
+ if (socket) {
+ return resolve(socket);
+ }
+ }
+ else {
+ for (let i = 0; i < 10; i++) {
+ const socket = await handleSocketId(i);
+ if (socket) {
+ return resolve(socket);
+ }
+ }
+ }
+ }
+ reject(new RPCError_1.RPCError(Transport_1.CUSTOM_RPC_ERROR_CODE.RPC_COULD_NOT_CONNECT, "Could not connect"));
+ });
+ }
+ async connect() {
+ if (!this.socket)
+ this.socket = await this.getSocket();
+ this.emit("open");
+ this.send({
+ v: 1,
+ client_id: this.client.clientId
+ }, IPC_OPCODE.HANDSHAKE);
+ this.socket.on("readable", () => {
+ let data = this.socket?.read();
+ if (!data)
+ return;
+ this.client.emit("debug", `SERVER => CLIENT | ${data
+ .toString("hex")
+ .match(/.{1,2}/g)
+ ?.join(" ")
+ .toUpperCase()}`);
+ do {
+ const chunk = this.socket?.read();
+ if (!chunk)
+ break;
+ this.client.emit("debug", `SERVER => CLIENT | ${chunk
+ .toString("hex")
+ .match(/.{1,2}/g)
+ ?.join(" ")
+ .toUpperCase()}`);
+ data = Buffer.concat([data, chunk]);
+ } while (true);
+ const op = data.readUInt32LE(0);
+ const length = data.readUInt32LE(4);
+ const parsedData = JSON.parse(data.subarray(8, length + 8).toString());
+ this.client.emit("debug", `SERVER => CLIENT | OPCODE.${IPC_OPCODE[op]} |`, parsedData);
+ switch (op) {
+ case IPC_OPCODE.FRAME: {
+ if (!data)
+ break;
+ this.emit("message", parsedData);
+ break;
+ }
+ case IPC_OPCODE.CLOSE: {
+ this.emit("close", parsedData);
+ break;
+ }
+ case IPC_OPCODE.PING: {
+ this.send(parsedData, IPC_OPCODE.PONG);
+ this.emit("ping");
+ break;
+ }
+ }
+ });
+ this.socket.on("close", () => {
+ this.socket = undefined;
+ this.emit("close", "Closed by Discord");
+ });
+ }
+ send(message, op = IPC_OPCODE.FRAME) {
+ this.client.emit("debug", `CLIENT => SERVER | OPCODE.${IPC_OPCODE[op]} |`, message);
+ const dataBuffer = message ? Buffer.from(JSON.stringify(message)) : Buffer.alloc(0);
+ const packet = Buffer.alloc(8);
+ packet.writeUInt32LE(op, 0);
+ packet.writeUInt32LE(dataBuffer.length, 4);
+ this.socket?.write(Buffer.concat([packet, dataBuffer]));
+ }
+ ping() {
+ this.send(node_crypto_1.default.randomUUID(), IPC_OPCODE.PING);
+ }
+ close() {
+ if (!this.socket)
+ return new Promise((resolve) => void resolve());
+ return new Promise((resolve) => {
+ this.socket.once("close", () => {
+ this.emit("close", "Closed by client");
+ this.socket = undefined;
+ resolve();
+ });
+ this.socket.end();
+ });
+ }
+}
+exports.IPCTransport = IPCTransport;
diff --git a/desktop/node_modules/@xhayper/discord-rpc/dist/transport/WebSocket.d.ts b/desktop/node_modules/@xhayper/discord-rpc/dist/transport/WebSocket.d.ts
new file mode 100644
index 0000000..4fe4b10
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/dist/transport/WebSocket.d.ts
@@ -0,0 +1,9 @@
+import { Transport } from "../structures/Transport";
+export declare class WebSocketTransport extends Transport {
+ private ws?;
+ get isConnected(): boolean;
+ connect(): Promise<void>;
+ send(data?: object | undefined): void;
+ ping(): void;
+ close(): Promise<void>;
+}
diff --git a/desktop/node_modules/@xhayper/discord-rpc/dist/transport/WebSocket.js b/desktop/node_modules/@xhayper/discord-rpc/dist/transport/WebSocket.js
new file mode 100644
index 0000000..9ec75a1
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/dist/transport/WebSocket.js
@@ -0,0 +1,74 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.WebSocketTransport = void 0;
+const Transport_1 = require("../structures/Transport");
+const RPCError_1 = require("../utils/RPCError");
+const ws_1 = require("ws");
+class WebSocketTransport extends Transport_1.Transport {
+ ws;
+ get isConnected() {
+ return this.ws !== undefined && this.ws.readyState === 1;
+ }
+ connect() {
+ return new Promise(async (resolve, reject) => {
+ for (let i = 0; i < 10; i++) {
+ const ws = await new Promise((resolve, reject) => {
+ const socket = new ws_1.WebSocket(`ws://127.0.0.1:${6463 + i}/?v=1&client_id=${this.client.clientId}&encoding=json`, {
+ origin: this.client.origin
+ });
+ socket.onopen = () => {
+ socket.onclose = null;
+ socket.onopen = null;
+ resolve(socket);
+ };
+ socket.onerror = () => {
+ socket.onclose = null;
+ socket.onopen = null;
+ reject();
+ };
+ }).catch(() => undefined);
+ if (ws) {
+ this.ws = ws;
+ resolve();
+ break;
+ }
+ }
+ if (!this.ws)
+ reject(new RPCError_1.RPCError(Transport_1.CUSTOM_RPC_ERROR_CODE.RPC_COULD_NOT_CONNECT, "Failed to connect to websocket"));
+ this.ws.onmessage = (event) => {
+ this.emit("message", JSON.parse(event.data.toString()));
+ };
+ this.ws.onclose = (event) => {
+ if (!event.wasClean)
+ return;
+ this.ws = undefined;
+ this.emit("close", event.reason);
+ };
+ this.ws.onerror = (event) => {
+ try {
+ this.ws?.close();
+ }
+ catch { }
+ throw event.error;
+ };
+ this.emit("open");
+ });
+ }
+ send(data) {
+ this.ws?.send(JSON.stringify(data));
+ }
+ ping() { }
+ close() {
+ if (!this.ws)
+ return new Promise((resolve) => void resolve());
+ return new Promise((resolve) => {
+ this.ws.once("close", () => {
+ this.emit("close", "Closed by client");
+ this.ws = undefined;
+ resolve();
+ });
+ this.ws.close();
+ });
+ }
+}
+exports.WebSocketTransport = WebSocketTransport;
diff --git a/desktop/node_modules/@xhayper/discord-rpc/dist/utils/RPCError.d.ts b/desktop/node_modules/@xhayper/discord-rpc/dist/utils/RPCError.d.ts
new file mode 100644
index 0000000..35985c9
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/dist/utils/RPCError.d.ts
@@ -0,0 +1,7 @@
+import { CUSTOM_RPC_ERROR_CODE, RPC_ERROR_CODE } from "../structures/Transport";
+export declare class RPCError extends Error {
+ code: RPC_ERROR_CODE | CUSTOM_RPC_ERROR_CODE;
+ message: string;
+ get name(): string;
+ constructor(errorCode: CUSTOM_RPC_ERROR_CODE | RPC_ERROR_CODE, message?: string, options?: ErrorOptions);
+}
diff --git a/desktop/node_modules/@xhayper/discord-rpc/dist/utils/RPCError.js b/desktop/node_modules/@xhayper/discord-rpc/dist/utils/RPCError.js
new file mode 100644
index 0000000..162e325
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/dist/utils/RPCError.js
@@ -0,0 +1,17 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.RPCError = void 0;
+const Transport_1 = require("../structures/Transport");
+class RPCError extends Error {
+ code;
+ message = "";
+ get name() {
+ return `${{ ...Transport_1.CUSTOM_RPC_ERROR_CODE, ...Transport_1.RPC_ERROR_CODE }[this.code]}`;
+ }
+ constructor(errorCode, message, options) {
+ super(message, options);
+ this.code = errorCode;
+ this.message = message ?? this.message;
+ }
+}
+exports.RPCError = RPCError;
diff --git a/desktop/node_modules/@xhayper/discord-rpc/dist/utils/TypedEventEmitter.d.ts b/desktop/node_modules/@xhayper/discord-rpc/dist/utils/TypedEventEmitter.d.ts
new file mode 100644
index 0000000..acdb3a2
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/dist/utils/TypedEventEmitter.d.ts
@@ -0,0 +1,36 @@
+export type EventMap = {
+ [key: string]: (...args: any[]) => void;
+};
+/**
+ * Type-safe event emitter.
+ *
+ * Use it like this:
+ *
+ * ```typescript
+ * type MyEvents = {
+ * error: (error: Error) => void;
+ * message: (from: string, content: string) => void;
+ * }
+ *
+ * const myEmitter = new EventEmitter() as TypedEmitter<MyEvents>;
+ *
+ * myEmitter.emit("error", "x") // <- Will catch this type error;
+ * ```
+ */
+export interface TypedEventEmitter<Events extends EventMap> {
+ addListener<E extends keyof Events>(event: E, listener: Events[E]): this;
+ on<E extends keyof Events>(event: E, listener: Events[E]): this;
+ once<E extends keyof Events>(event: E, listener: Events[E]): this;
+ prependListener<E extends keyof Events>(event: E, listener: Events[E]): this;
+ prependOnceListener<E extends keyof Events>(event: E, listener: Events[E]): this;
+ off<E extends keyof Events>(event: E, listener: Events[E]): this;
+ removeAllListeners<E extends keyof Events>(event?: E): this;
+ removeListener<E extends keyof Events>(event: E, listener: Events[E]): this;
+ emit<E extends keyof Events>(event: E, ...args: Parameters<Events[E]>): boolean;
+ eventNames(): (keyof Events | string | symbol)[];
+ rawListeners<E extends keyof Events>(event: E): Events[E][];
+ listeners<E extends keyof Events>(event: E): Events[E][];
+ listenerCount<E extends keyof Events>(event: E): number;
+ getMaxListeners(): number;
+ setMaxListeners(maxListeners: number): this;
+}
diff --git a/desktop/node_modules/@xhayper/discord-rpc/dist/utils/TypedEventEmitter.js b/desktop/node_modules/@xhayper/discord-rpc/dist/utils/TypedEventEmitter.js
new file mode 100644
index 0000000..b8771a7
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/dist/utils/TypedEventEmitter.js
@@ -0,0 +1,25 @@
+"use strict";
+/*
+ The MIT License (MIT)
+
+ Copyright (c) 2018 Andy Wermke
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+Object.defineProperty(exports, "__esModule", { value: true });
diff --git a/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/LICENSE b/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/LICENSE
new file mode 100644
index 0000000..1da5b96
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2011 Einar Otto Stangvik <einaros@gmail.com>
+Copyright (c) 2013 Arnout Kazemier and contributors
+Copyright (c) 2016 Luigi Pinca and contributors
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/README.md b/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/README.md
new file mode 100644
index 0000000..a550ca1
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/README.md
@@ -0,0 +1,536 @@
+# ws: a Node.js WebSocket library
+
+[![Version npm](https://img.shields.io/npm/v/ws.svg?logo=npm)](https://www.npmjs.com/package/ws)
+[![CI](https://img.shields.io/github/actions/workflow/status/websockets/ws/ci.yml?branch=master&label=CI&logo=github)](https://github.com/websockets/ws/actions?query=workflow%3ACI+branch%3Amaster)
+[![Coverage Status](https://img.shields.io/coveralls/websockets/ws/master.svg?logo=coveralls)](https://coveralls.io/github/websockets/ws)
+
+ws is a simple to use, blazing fast, and thoroughly tested WebSocket client and
+server implementation.
+
+Passes the quite extensive Autobahn test suite: [server][server-report],
+[client][client-report].
+
+**Note**: This module does not work in the browser. The client in the docs is a
+reference to a back end with the role of a client in the WebSocket
+communication. Browser clients must use the native
+[`WebSocket`](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket)
+object. To make the same code work seamlessly on Node.js and the browser, you
+can use one of the many wrappers available on npm, like
+[isomorphic-ws](https://github.com/heineiuo/isomorphic-ws).
+
+## Table of Contents
+
+- [Protocol support](#protocol-support)
+- [Installing](#installing)
+ - [Opt-in for performance](#opt-in-for-performance)
+- [API docs](#api-docs)
+- [WebSocket compression](#websocket-compression)
+- [Usage examples](#usage-examples)
+ - [Sending and receiving text data](#sending-and-receiving-text-data)
+ - [Sending binary data](#sending-binary-data)
+ - [Simple server](#simple-server)
+ - [External HTTP/S server](#external-https-server)
+ - [Multiple servers sharing a single HTTP/S server](#multiple-servers-sharing-a-single-https-server)
+ - [Client authentication](#client-authentication)
+ - [Server broadcast](#server-broadcast)
+ - [Round-trip time](#round-trip-time)
+ - [Use the Node.js streams API](#use-the-nodejs-streams-api)
+ - [Other examples](#other-examples)
+- [FAQ](#faq)
+ - [How to get the IP address of the client?](#how-to-get-the-ip-address-of-the-client)
+ - [How to detect and close broken connections?](#how-to-detect-and-close-broken-connections)
+ - [How to connect via a proxy?](#how-to-connect-via-a-proxy)
+- [Changelog](#changelog)
+- [License](#license)
+
+## Protocol support
+
+- **HyBi drafts 07-12** (Use the option `protocolVersion: 8`)
+- **HyBi drafts 13-17** (Current default, alternatively option
+ `protocolVersion: 13`)
+
+## Installing
+
+```
+npm install ws
+```
+
+### Opt-in for performance
+
+There are 2 optional modules that can be installed along side with the ws
+module. These modules are binary addons that improve the performance of certain
+operations. Prebuilt binaries are available for the most popular platforms so
+you don't necessarily need to have a C++ compiler installed on your machine.
+
+- `npm install --save-optional bufferutil`: Allows to efficiently perform
+ operations such as masking and unmasking the data payload of the WebSocket
+ frames.
+- `npm install --save-optional utf-8-validate`: Allows to efficiently check if a
+ message contains valid UTF-8.
+
+To not even try to require and use these modules, use the
+[`WS_NO_BUFFER_UTIL`](./doc/ws.md#ws_no_buffer_util) and
+[`WS_NO_UTF_8_VALIDATE`](./doc/ws.md#ws_no_utf_8_validate) environment
+variables. These might be useful to enhance security in systems where a user can
+put a package in the package search path of an application of another user, due
+to how the Node.js resolver algorithm works.
+
+The `utf-8-validate` module is not needed and is not required, even if it is
+already installed, regardless of the value of the `WS_NO_UTF_8_VALIDATE`
+environment variable, if [`buffer.isUtf8()`][] is available.
+
+## API docs
+
+See [`/doc/ws.md`](./doc/ws.md) for Node.js-like documentation of ws classes and
+utility functions.
+
+## WebSocket compression
+
+ws supports the [permessage-deflate extension][permessage-deflate] which enables
+the client and server to negotiate a compression algorithm and its parameters,
+and then selectively apply it to the data payloads of each WebSocket message.
+
+The extension is disabled by default on the server and enabled by default on the
+client. It adds a significant overhead in terms of performance and memory
+consumption so we suggest to enable it only if it is really needed.
+
+Note that Node.js has a variety of issues with high-performance compression,
+where increased concurrency, especially on Linux, can lead to [catastrophic
+memory fragmentation][node-zlib-bug] and slow performance. If you intend to use
+permessage-deflate in production, it is worthwhile to set up a test
+representative of your workload and ensure Node.js/zlib will handle it with
+acceptable performance and memory usage.
+
+Tuning of permessage-deflate can be done via the options defined below. You can
+also use `zlibDeflateOptions` and `zlibInflateOptions`, which is passed directly
+into the creation of [raw deflate/inflate streams][node-zlib-deflaterawdocs].
+
+See [the docs][ws-server-options] for more options.
+
+```js
+import WebSocket, { WebSocketServer } from 'ws';
+
+const wss = new WebSocketServer({
+ port: 8080,
+ perMessageDeflate: {
+ zlibDeflateOptions: {
+ // See zlib defaults.
+ chunkSize: 1024,
+ memLevel: 7,
+ level: 3
+ },
+ zlibInflateOptions: {
+ chunkSize: 10 * 1024
+ },
+ // Other options settable:
+ clientNoContextTakeover: true, // Defaults to negotiated value.
+ serverNoContextTakeover: true, // Defaults to negotiated value.
+ serverMaxWindowBits: 10, // Defaults to negotiated value.
+ // Below options specified as default values.
+ concurrencyLimit: 10, // Limits zlib concurrency for perf.
+ threshold: 1024 // Size (in bytes) below which messages
+ // should not be compressed if context takeover is disabled.
+ }
+});
+```
+
+The client will only use the extension if it is supported and enabled on the
+server. To always disable the extension on the client set the
+`perMessageDeflate` option to `false`.
+
+```js
+import WebSocket from 'ws';
+
+const ws = new WebSocket('ws://www.host.com/path', {
+ perMessageDeflate: false
+});
+```
+
+## Usage examples
+
+### Sending and receiving text data
+
+```js
+import WebSocket from 'ws';
+
+const ws = new WebSocket('ws://www.host.com/path');
+
+ws.on('error', console.error);
+
+ws.on('open', function open() {
+ ws.send('something');
+});
+
+ws.on('message', function message(data) {
+ console.log('received: %s', data);
+});
+```
+
+### Sending binary data
+
+```js
+import WebSocket from 'ws';
+
+const ws = new WebSocket('ws://www.host.com/path');
+
+ws.on('error', console.error);
+
+ws.on('open', function open() {
+ const array = new Float32Array(5);
+
+ for (var i = 0; i < array.length; ++i) {
+ array[i] = i / 2;
+ }
+
+ ws.send(array);
+});
+```
+
+### Simple server
+
+```js
+import { WebSocketServer } from 'ws';
+
+const wss = new WebSocketServer({ port: 8080 });
+
+wss.on('connection', function connection(ws) {
+ ws.on('error', console.error);
+
+ ws.on('message', function message(data) {
+ console.log('received: %s', data);
+ });
+
+ ws.send('something');
+});
+```
+
+### External HTTP/S server
+
+```js
+import { createServer } from 'https';
+import { readFileSync } from 'fs';
+import { WebSocketServer } from 'ws';
+
+const server = createServer({
+ cert: readFileSync('/path/to/cert.pem'),
+ key: readFileSync('/path/to/key.pem')
+});
+const wss = new WebSocketServer({ server });
+
+wss.on('connection', function connection(ws) {
+ ws.on('error', console.error);
+
+ ws.on('message', function message(data) {
+ console.log('received: %s', data);
+ });
+
+ ws.send('something');
+});
+
+server.listen(8080);
+```
+
+### Multiple servers sharing a single HTTP/S server
+
+```js
+import { createServer } from 'http';
+import { parse } from 'url';
+import { WebSocketServer } from 'ws';
+
+const server = createServer();
+const wss1 = new WebSocketServer({ noServer: true });
+const wss2 = new WebSocketServer({ noServer: true });
+
+wss1.on('connection', function connection(ws) {
+ ws.on('error', console.error);
+
+ // ...
+});
+
+wss2.on('connection', function connection(ws) {
+ ws.on('error', console.error);
+
+ // ...
+});
+
+server.on('upgrade', function upgrade(request, socket, head) {
+ const { pathname } = parse(request.url);
+
+ if (pathname === '/foo') {
+ wss1.handleUpgrade(request, socket, head, function done(ws) {
+ wss1.emit('connection', ws, request);
+ });
+ } else if (pathname === '/bar') {
+ wss2.handleUpgrade(request, socket, head, function done(ws) {
+ wss2.emit('connection', ws, request);
+ });
+ } else {
+ socket.destroy();
+ }
+});
+
+server.listen(8080);
+```
+
+### Client authentication
+
+```js
+import { createServer } from 'http';
+import { WebSocketServer } from 'ws';
+
+function onSocketError(err) {
+ console.error(err);
+}
+
+const server = createServer();
+const wss = new WebSocketServer({ noServer: true });
+
+wss.on('connection', function connection(ws, request, client) {
+ ws.on('error', console.error);
+
+ ws.on('message', function message(data) {
+ console.log(`Received message ${data} from user ${client}`);
+ });
+});
+
+server.on('upgrade', function upgrade(request, socket, head) {
+ socket.on('error', onSocketError);
+
+ // This function is not defined on purpose. Implement it with your own logic.
+ authenticate(request, function next(err, client) {
+ if (err || !client) {
+ socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n');
+ socket.destroy();
+ return;
+ }
+
+ socket.removeListener('error', onSocketError);
+
+ wss.handleUpgrade(request, socket, head, function done(ws) {
+ wss.emit('connection', ws, request, client);
+ });
+ });
+});
+
+server.listen(8080);
+```
+
+Also see the provided [example][session-parse-example] using `express-session`.
+
+### Server broadcast
+
+A client WebSocket broadcasting to all connected WebSocket clients, including
+itself.
+
+```js
+import WebSocket, { WebSocketServer } from 'ws';
+
+const wss = new WebSocketServer({ port: 8080 });
+
+wss.on('connection', function connection(ws) {
+ ws.on('error', console.error);
+
+ ws.on('message', function message(data, isBinary) {
+ wss.clients.forEach(function each(client) {
+ if (client.readyState === WebSocket.OPEN) {
+ client.send(data, { binary: isBinary });
+ }
+ });
+ });
+});
+```
+
+A client WebSocket broadcasting to every other connected WebSocket clients,
+excluding itself.
+
+```js
+import WebSocket, { WebSocketServer } from 'ws';
+
+const wss = new WebSocketServer({ port: 8080 });
+
+wss.on('connection', function connection(ws) {
+ ws.on('error', console.error);
+
+ ws.on('message', function message(data, isBinary) {
+ wss.clients.forEach(function each(client) {
+ if (client !== ws && client.readyState === WebSocket.OPEN) {
+ client.send(data, { binary: isBinary });
+ }
+ });
+ });
+});
+```
+
+### Round-trip time
+
+```js
+import WebSocket from 'ws';
+
+const ws = new WebSocket('wss://websocket-echo.com/');
+
+ws.on('error', console.error);
+
+ws.on('open', function open() {
+ console.log('connected');
+ ws.send(Date.now());
+});
+
+ws.on('close', function close() {
+ console.log('disconnected');
+});
+
+ws.on('message', function message(data) {
+ console.log(`Round-trip time: ${Date.now() - data} ms`);
+
+ setTimeout(function timeout() {
+ ws.send(Date.now());
+ }, 500);
+});
+```
+
+### Use the Node.js streams API
+
+```js
+import WebSocket, { createWebSocketStream } from 'ws';
+
+const ws = new WebSocket('wss://websocket-echo.com/');
+
+const duplex = createWebSocketStream(ws, { encoding: 'utf8' });
+
+duplex.on('error', console.error);
+
+duplex.pipe(process.stdout);
+process.stdin.pipe(duplex);
+```
+
+### Other examples
+
+For a full example with a browser client communicating with a ws server, see the
+examples folder.
+
+Otherwise, see the test cases.
+
+## FAQ
+
+### How to get the IP address of the client?
+
+The remote IP address can be obtained from the raw socket.
+
+```js
+import { WebSocketServer } from 'ws';
+
+const wss = new WebSocketServer({ port: 8080 });
+
+wss.on('connection', function connection(ws, req) {
+ const ip = req.socket.remoteAddress;
+
+ ws.on('error', console.error);
+});
+```
+
+When the server runs behind a proxy like NGINX, the de-facto standard is to use
+the `X-Forwarded-For` header.
+
+```js
+wss.on('connection', function connection(ws, req) {
+ const ip = req.headers['x-forwarded-for'].split(',')[0].trim();
+
+ ws.on('error', console.error);
+});
+```
+
+### How to detect and close broken connections?
+
+Sometimes the link between the server and the client can be interrupted in a way
+that keeps both the server and the client unaware of the broken state of the
+connection (e.g. when pulling the cord).
+
+In these cases ping messages can be used as a means to verify that the remote
+endpoint is still responsive.
+
+```js
+import { WebSocketServer } from 'ws';
+
+function heartbeat() {
+ this.isAlive = true;
+}
+
+const wss = new WebSocketServer({ port: 8080 });
+
+wss.on('connection', function connection(ws) {
+ ws.isAlive = true;
+ ws.on('error', console.error);
+ ws.on('pong', heartbeat);
+});
+
+const interval = setInterval(function ping() {
+ wss.clients.forEach(function each(ws) {
+ if (ws.isAlive === false) return ws.terminate();
+
+ ws.isAlive = false;
+ ws.ping();
+ });
+}, 30000);
+
+wss.on('close', function close() {
+ clearInterval(interval);
+});
+```
+
+Pong messages are automatically sent in response to ping messages as required by
+the spec.
+
+Just like the server example above your clients might as well lose connection
+without knowing it. You might want to add a ping listener on your clients to
+prevent that. A simple implementation would be:
+
+```js
+import WebSocket from 'ws';
+
+function heartbeat() {
+ clearTimeout(this.pingTimeout);
+
+ // Use `WebSocket#terminate()`, which immediately destroys the connection,
+ // instead of `WebSocket#close()`, which waits for the close timer.
+ // Delay should be equal to the interval at which your server
+ // sends out pings plus a conservative assumption of the latency.
+ this.pingTimeout = setTimeout(() => {
+ this.terminate();
+ }, 30000 + 1000);
+}
+
+const client = new WebSocket('wss://websocket-echo.com/');
+
+client.on('error', console.error);
+client.on('open', heartbeat);
+client.on('ping', heartbeat);
+client.on('close', function clear() {
+ clearTimeout(this.pingTimeout);
+});
+```
+
+### How to connect via a proxy?
+
+Use a custom `http.Agent` implementation like [https-proxy-agent][] or
+[socks-proxy-agent][].
+
+## Changelog
+
+We're using the GitHub [releases][changelog] for changelog entries.
+
+## License
+
+[MIT](LICENSE)
+
+[`buffer.isutf8()`]: https://nodejs.org/api/buffer.html#bufferisutf8input
+[changelog]: https://github.com/websockets/ws/releases
+[client-report]: http://websockets.github.io/ws/autobahn/clients/
+[https-proxy-agent]: https://github.com/TooTallNate/node-https-proxy-agent
+[node-zlib-bug]: https://github.com/nodejs/node/issues/8871
+[node-zlib-deflaterawdocs]:
+ https://nodejs.org/api/zlib.html#zlib_zlib_createdeflateraw_options
+[permessage-deflate]: https://tools.ietf.org/html/rfc7692
+[server-report]: http://websockets.github.io/ws/autobahn/servers/
+[session-parse-example]: ./examples/express-session-parse
+[socks-proxy-agent]: https://github.com/TooTallNate/node-socks-proxy-agent
+[ws-server-options]: ./doc/ws.md#new-websocketserveroptions-callback
diff --git a/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/browser.js b/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/browser.js
new file mode 100644
index 0000000..ca4f628
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/browser.js
@@ -0,0 +1,8 @@
+'use strict';
+
+module.exports = function () {
+ throw new Error(
+ 'ws does not work in the browser. Browser clients must use the native ' +
+ 'WebSocket object'
+ );
+};
diff --git a/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/index.js b/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/index.js
new file mode 100644
index 0000000..41edb3b
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/index.js
@@ -0,0 +1,13 @@
+'use strict';
+
+const WebSocket = require('./lib/websocket');
+
+WebSocket.createWebSocketStream = require('./lib/stream');
+WebSocket.Server = require('./lib/websocket-server');
+WebSocket.Receiver = require('./lib/receiver');
+WebSocket.Sender = require('./lib/sender');
+
+WebSocket.WebSocket = WebSocket;
+WebSocket.WebSocketServer = WebSocket.Server;
+
+module.exports = WebSocket;
diff --git a/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/buffer-util.js b/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/buffer-util.js
new file mode 100644
index 0000000..f7536e2
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/buffer-util.js
@@ -0,0 +1,131 @@
+'use strict';
+
+const { EMPTY_BUFFER } = require('./constants');
+
+const FastBuffer = Buffer[Symbol.species];
+
+/**
+ * Merges an array of buffers into a new buffer.
+ *
+ * @param {Buffer[]} list The array of buffers to concat
+ * @param {Number} totalLength The total length of buffers in the list
+ * @return {Buffer} The resulting buffer
+ * @public
+ */
+function concat(list, totalLength) {
+ if (list.length === 0) return EMPTY_BUFFER;
+ if (list.length === 1) return list[0];
+
+ const target = Buffer.allocUnsafe(totalLength);
+ let offset = 0;
+
+ for (let i = 0; i < list.length; i++) {
+ const buf = list[i];
+ target.set(buf, offset);
+ offset += buf.length;
+ }
+
+ if (offset < totalLength) {
+ return new FastBuffer(target.buffer, target.byteOffset, offset);
+ }
+
+ return target;
+}
+
+/**
+ * Masks a buffer using the given mask.
+ *
+ * @param {Buffer} source The buffer to mask
+ * @param {Buffer} mask The mask to use
+ * @param {Buffer} output The buffer where to store the result
+ * @param {Number} offset The offset at which to start writing
+ * @param {Number} length The number of bytes to mask.
+ * @public
+ */
+function _mask(source, mask, output, offset, length) {
+ for (let i = 0; i < length; i++) {
+ output[offset + i] = source[i] ^ mask[i & 3];
+ }
+}
+
+/**
+ * Unmasks a buffer using the given mask.
+ *
+ * @param {Buffer} buffer The buffer to unmask
+ * @param {Buffer} mask The mask to use
+ * @public
+ */
+function _unmask(buffer, mask) {
+ for (let i = 0; i < buffer.length; i++) {
+ buffer[i] ^= mask[i & 3];
+ }
+}
+
+/**
+ * Converts a buffer to an `ArrayBuffer`.
+ *
+ * @param {Buffer} buf The buffer to convert
+ * @return {ArrayBuffer} Converted buffer
+ * @public
+ */
+function toArrayBuffer(buf) {
+ if (buf.length === buf.buffer.byteLength) {
+ return buf.buffer;
+ }
+
+ return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.length);
+}
+
+/**
+ * Converts `data` to a `Buffer`.
+ *
+ * @param {*} data The data to convert
+ * @return {Buffer} The buffer
+ * @throws {TypeError}
+ * @public
+ */
+function toBuffer(data) {
+ toBuffer.readOnly = true;
+
+ if (Buffer.isBuffer(data)) return data;
+
+ let buf;
+
+ if (data instanceof ArrayBuffer) {
+ buf = new FastBuffer(data);
+ } else if (ArrayBuffer.isView(data)) {
+ buf = new FastBuffer(data.buffer, data.byteOffset, data.byteLength);
+ } else {
+ buf = Buffer.from(data);
+ toBuffer.readOnly = false;
+ }
+
+ return buf;
+}
+
+module.exports = {
+ concat,
+ mask: _mask,
+ toArrayBuffer,
+ toBuffer,
+ unmask: _unmask
+};
+
+/* istanbul ignore else */
+if (!process.env.WS_NO_BUFFER_UTIL) {
+ try {
+ const bufferUtil = require('bufferutil');
+
+ module.exports.mask = function (source, mask, output, offset, length) {
+ if (length < 48) _mask(source, mask, output, offset, length);
+ else bufferUtil.mask(source, mask, output, offset, length);
+ };
+
+ module.exports.unmask = function (buffer, mask) {
+ if (buffer.length < 32) _unmask(buffer, mask);
+ else bufferUtil.unmask(buffer, mask);
+ };
+ } catch (e) {
+ // Continue regardless of the error.
+ }
+}
diff --git a/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/constants.js b/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/constants.js
new file mode 100644
index 0000000..d691b30
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/constants.js
@@ -0,0 +1,12 @@
+'use strict';
+
+module.exports = {
+ BINARY_TYPES: ['nodebuffer', 'arraybuffer', 'fragments'],
+ EMPTY_BUFFER: Buffer.alloc(0),
+ GUID: '258EAFA5-E914-47DA-95CA-C5AB0DC85B11',
+ kForOnEventAttribute: Symbol('kIsForOnEventAttribute'),
+ kListener: Symbol('kListener'),
+ kStatusCode: Symbol('status-code'),
+ kWebSocket: Symbol('websocket'),
+ NOOP: () => {}
+};
diff --git a/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/event-target.js b/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/event-target.js
new file mode 100644
index 0000000..fea4cbc
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/event-target.js
@@ -0,0 +1,292 @@
+'use strict';
+
+const { kForOnEventAttribute, kListener } = require('./constants');
+
+const kCode = Symbol('kCode');
+const kData = Symbol('kData');
+const kError = Symbol('kError');
+const kMessage = Symbol('kMessage');
+const kReason = Symbol('kReason');
+const kTarget = Symbol('kTarget');
+const kType = Symbol('kType');
+const kWasClean = Symbol('kWasClean');
+
+/**
+ * Class representing an event.
+ */
+class Event {
+ /**
+ * Create a new `Event`.
+ *
+ * @param {String} type The name of the event
+ * @throws {TypeError} If the `type` argument is not specified
+ */
+ constructor(type) {
+ this[kTarget] = null;
+ this[kType] = type;
+ }
+
+ /**
+ * @type {*}
+ */
+ get target() {
+ return this[kTarget];
+ }
+
+ /**
+ * @type {String}
+ */
+ get type() {
+ return this[kType];
+ }
+}
+
+Object.defineProperty(Event.prototype, 'target', { enumerable: true });
+Object.defineProperty(Event.prototype, 'type', { enumerable: true });
+
+/**
+ * Class representing a close event.
+ *
+ * @extends Event
+ */
+class CloseEvent extends Event {
+ /**
+ * Create a new `CloseEvent`.
+ *
+ * @param {String} type The name of the event
+ * @param {Object} [options] A dictionary object that allows for setting
+ * attributes via object members of the same name
+ * @param {Number} [options.code=0] The status code explaining why the
+ * connection was closed
+ * @param {String} [options.reason=''] A human-readable string explaining why
+ * the connection was closed
+ * @param {Boolean} [options.wasClean=false] Indicates whether or not the
+ * connection was cleanly closed
+ */
+ constructor(type, options = {}) {
+ super(type);
+
+ this[kCode] = options.code === undefined ? 0 : options.code;
+ this[kReason] = options.reason === undefined ? '' : options.reason;
+ this[kWasClean] = options.wasClean === undefined ? false : options.wasClean;
+ }
+
+ /**
+ * @type {Number}
+ */
+ get code() {
+ return this[kCode];
+ }
+
+ /**
+ * @type {String}
+ */
+ get reason() {
+ return this[kReason];
+ }
+
+ /**
+ * @type {Boolean}
+ */
+ get wasClean() {
+ return this[kWasClean];
+ }
+}
+
+Object.defineProperty(CloseEvent.prototype, 'code', { enumerable: true });
+Object.defineProperty(CloseEvent.prototype, 'reason', { enumerable: true });
+Object.defineProperty(CloseEvent.prototype, 'wasClean', { enumerable: true });
+
+/**
+ * Class representing an error event.
+ *
+ * @extends Event
+ */
+class ErrorEvent extends Event {
+ /**
+ * Create a new `ErrorEvent`.
+ *
+ * @param {String} type The name of the event
+ * @param {Object} [options] A dictionary object that allows for setting
+ * attributes via object members of the same name
+ * @param {*} [options.error=null] The error that generated this event
+ * @param {String} [options.message=''] The error message
+ */
+ constructor(type, options = {}) {
+ super(type);
+
+ this[kError] = options.error === undefined ? null : options.error;
+ this[kMessage] = options.message === undefined ? '' : options.message;
+ }
+
+ /**
+ * @type {*}
+ */
+ get error() {
+ return this[kError];
+ }
+
+ /**
+ * @type {String}
+ */
+ get message() {
+ return this[kMessage];
+ }
+}
+
+Object.defineProperty(ErrorEvent.prototype, 'error', { enumerable: true });
+Object.defineProperty(ErrorEvent.prototype, 'message', { enumerable: true });
+
+/**
+ * Class representing a message event.
+ *
+ * @extends Event
+ */
+class MessageEvent extends Event {
+ /**
+ * Create a new `MessageEvent`.
+ *
+ * @param {String} type The name of the event
+ * @param {Object} [options] A dictionary object that allows for setting
+ * attributes via object members of the same name
+ * @param {*} [options.data=null] The message content
+ */
+ constructor(type, options = {}) {
+ super(type);
+
+ this[kData] = options.data === undefined ? null : options.data;
+ }
+
+ /**
+ * @type {*}
+ */
+ get data() {
+ return this[kData];
+ }
+}
+
+Object.defineProperty(MessageEvent.prototype, 'data', { enumerable: true });
+
+/**
+ * This provides methods for emulating the `EventTarget` interface. It's not
+ * meant to be used directly.
+ *
+ * @mixin
+ */
+const EventTarget = {
+ /**
+ * Register an event listener.
+ *
+ * @param {String} type A string representing the event type to listen for
+ * @param {(Function|Object)} handler The listener to add
+ * @param {Object} [options] An options object specifies characteristics about
+ * the event listener
+ * @param {Boolean} [options.once=false] A `Boolean` indicating that the
+ * listener should be invoked at most once after being added. If `true`,
+ * the listener would be automatically removed when invoked.
+ * @public
+ */
+ addEventListener(type, handler, options = {}) {
+ for (const listener of this.listeners(type)) {
+ if (
+ !options[kForOnEventAttribute] &&
+ listener[kListener] === handler &&
+ !listener[kForOnEventAttribute]
+ ) {
+ return;
+ }
+ }
+
+ let wrapper;
+
+ if (type === 'message') {
+ wrapper = function onMessage(data, isBinary) {
+ const event = new MessageEvent('message', {
+ data: isBinary ? data : data.toString()
+ });
+
+ event[kTarget] = this;
+ callListener(handler, this, event);
+ };
+ } else if (type === 'close') {
+ wrapper = function onClose(code, message) {
+ const event = new CloseEvent('close', {
+ code,
+ reason: message.toString(),
+ wasClean: this._closeFrameReceived && this._closeFrameSent
+ });
+
+ event[kTarget] = this;
+ callListener(handler, this, event);
+ };
+ } else if (type === 'error') {
+ wrapper = function onError(error) {
+ const event = new ErrorEvent('error', {
+ error,
+ message: error.message
+ });
+
+ event[kTarget] = this;
+ callListener(handler, this, event);
+ };
+ } else if (type === 'open') {
+ wrapper = function onOpen() {
+ const event = new Event('open');
+
+ event[kTarget] = this;
+ callListener(handler, this, event);
+ };
+ } else {
+ return;
+ }
+
+ wrapper[kForOnEventAttribute] = !!options[kForOnEventAttribute];
+ wrapper[kListener] = handler;
+
+ if (options.once) {
+ this.once(type, wrapper);
+ } else {
+ this.on(type, wrapper);
+ }
+ },
+
+ /**
+ * Remove an event listener.
+ *
+ * @param {String} type A string representing the event type to remove
+ * @param {(Function|Object)} handler The listener to remove
+ * @public
+ */
+ removeEventListener(type, handler) {
+ for (const listener of this.listeners(type)) {
+ if (listener[kListener] === handler && !listener[kForOnEventAttribute]) {
+ this.removeListener(type, listener);
+ break;
+ }
+ }
+ }
+};
+
+module.exports = {
+ CloseEvent,
+ ErrorEvent,
+ Event,
+ EventTarget,
+ MessageEvent
+};
+
+/**
+ * Call an event listener
+ *
+ * @param {(Function|Object)} listener The listener to call
+ * @param {*} thisArg The value to use as `this`` when calling the listener
+ * @param {Event} event The event to pass to the listener
+ * @private
+ */
+function callListener(listener, thisArg, event) {
+ if (typeof listener === 'object' && listener.handleEvent) {
+ listener.handleEvent.call(listener, event);
+ } else {
+ listener.call(thisArg, event);
+ }
+}
diff --git a/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/extension.js b/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/extension.js
new file mode 100644
index 0000000..3d7895c
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/extension.js
@@ -0,0 +1,203 @@
+'use strict';
+
+const { tokenChars } = require('./validation');
+
+/**
+ * Adds an offer to the map of extension offers or a parameter to the map of
+ * parameters.
+ *
+ * @param {Object} dest The map of extension offers or parameters
+ * @param {String} name The extension or parameter name
+ * @param {(Object|Boolean|String)} elem The extension parameters or the
+ * parameter value
+ * @private
+ */
+function push(dest, name, elem) {
+ if (dest[name] === undefined) dest[name] = [elem];
+ else dest[name].push(elem);
+}
+
+/**
+ * Parses the `Sec-WebSocket-Extensions` header into an object.
+ *
+ * @param {String} header The field value of the header
+ * @return {Object} The parsed object
+ * @public
+ */
+function parse(header) {
+ const offers = Object.create(null);
+ let params = Object.create(null);
+ let mustUnescape = false;
+ let isEscaping = false;
+ let inQuotes = false;
+ let extensionName;
+ let paramName;
+ let start = -1;
+ let code = -1;
+ let end = -1;
+ let i = 0;
+
+ for (; i < header.length; i++) {
+ code = header.charCodeAt(i);
+
+ if (extensionName === undefined) {
+ if (end === -1 && tokenChars[code] === 1) {
+ if (start === -1) start = i;
+ } else if (
+ i !== 0 &&
+ (code === 0x20 /* ' ' */ || code === 0x09) /* '\t' */
+ ) {
+ if (end === -1 && start !== -1) end = i;
+ } else if (code === 0x3b /* ';' */ || code === 0x2c /* ',' */) {
+ if (start === -1) {
+ throw new SyntaxError(`Unexpected character at index ${i}`);
+ }
+
+ if (end === -1) end = i;
+ const name = header.slice(start, end);
+ if (code === 0x2c) {
+ push(offers, name, params);
+ params = Object.create(null);
+ } else {
+ extensionName = name;
+ }
+
+ start = end = -1;
+ } else {
+ throw new SyntaxError(`Unexpected character at index ${i}`);
+ }
+ } else if (paramName === undefined) {
+ if (end === -1 && tokenChars[code] === 1) {
+ if (start === -1) start = i;
+ } else if (code === 0x20 || code === 0x09) {
+ if (end === -1 && start !== -1) end = i;
+ } else if (code === 0x3b || code === 0x2c) {
+ if (start === -1) {
+ throw new SyntaxError(`Unexpected character at index ${i}`);
+ }
+
+ if (end === -1) end = i;
+ push(params, header.slice(start, end), true);
+ if (code === 0x2c) {
+ push(offers, extensionName, params);
+ params = Object.create(null);
+ extensionName = undefined;
+ }
+
+ start = end = -1;
+ } else if (code === 0x3d /* '=' */ && start !== -1 && end === -1) {
+ paramName = header.slice(start, i);
+ start = end = -1;
+ } else {
+ throw new SyntaxError(`Unexpected character at index ${i}`);
+ }
+ } else {
+ //
+ // The value of a quoted-string after unescaping must conform to the
+ // token ABNF, so only token characters are valid.
+ // Ref: https://tools.ietf.org/html/rfc6455#section-9.1
+ //
+ if (isEscaping) {
+ if (tokenChars[code] !== 1) {
+ throw new SyntaxError(`Unexpected character at index ${i}`);
+ }
+ if (start === -1) start = i;
+ else if (!mustUnescape) mustUnescape = true;
+ isEscaping = false;
+ } else if (inQuotes) {
+ if (tokenChars[code] === 1) {
+ if (start === -1) start = i;
+ } else if (code === 0x22 /* '"' */ && start !== -1) {
+ inQuotes = false;
+ end = i;
+ } else if (code === 0x5c /* '\' */) {
+ isEscaping = true;
+ } else {
+ throw new SyntaxError(`Unexpected character at index ${i}`);
+ }
+ } else if (code === 0x22 && header.charCodeAt(i - 1) === 0x3d) {
+ inQuotes = true;
+ } else if (end === -1 && tokenChars[code] === 1) {
+ if (start === -1) start = i;
+ } else if (start !== -1 && (code === 0x20 || code === 0x09)) {
+ if (end === -1) end = i;
+ } else if (code === 0x3b || code === 0x2c) {
+ if (start === -1) {
+ throw new SyntaxError(`Unexpected character at index ${i}`);
+ }
+
+ if (end === -1) end = i;
+ let value = header.slice(start, end);
+ if (mustUnescape) {
+ value = value.replace(/\\/g, '');
+ mustUnescape = false;
+ }
+ push(params, paramName, value);
+ if (code === 0x2c) {
+ push(offers, extensionName, params);
+ params = Object.create(null);
+ extensionName = undefined;
+ }
+
+ paramName = undefined;
+ start = end = -1;
+ } else {
+ throw new SyntaxError(`Unexpected character at index ${i}`);
+ }
+ }
+ }
+
+ if (start === -1 || inQuotes || code === 0x20 || code === 0x09) {
+ throw new SyntaxError('Unexpected end of input');
+ }
+
+ if (end === -1) end = i;
+ const token = header.slice(start, end);
+ if (extensionName === undefined) {
+ push(offers, token, params);
+ } else {
+ if (paramName === undefined) {
+ push(params, token, true);
+ } else if (mustUnescape) {
+ push(params, paramName, token.replace(/\\/g, ''));
+ } else {
+ push(params, paramName, token);
+ }
+ push(offers, extensionName, params);
+ }
+
+ return offers;
+}
+
+/**
+ * Builds the `Sec-WebSocket-Extensions` header field value.
+ *
+ * @param {Object} extensions The map of extensions and parameters to format
+ * @return {String} A string representing the given object
+ * @public
+ */
+function format(extensions) {
+ return Object.keys(extensions)
+ .map((extension) => {
+ let configurations = extensions[extension];
+ if (!Array.isArray(configurations)) configurations = [configurations];
+ return configurations
+ .map((params) => {
+ return [extension]
+ .concat(
+ Object.keys(params).map((k) => {
+ let values = params[k];
+ if (!Array.isArray(values)) values = [values];
+ return values
+ .map((v) => (v === true ? k : `${k}=${v}`))
+ .join('; ');
+ })
+ )
+ .join('; ');
+ })
+ .join(', ');
+ })
+ .join(', ');
+}
+
+module.exports = { format, parse };
diff --git a/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/limiter.js b/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/limiter.js
new file mode 100644
index 0000000..3fd3578
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/limiter.js
@@ -0,0 +1,55 @@
+'use strict';
+
+const kDone = Symbol('kDone');
+const kRun = Symbol('kRun');
+
+/**
+ * A very simple job queue with adjustable concurrency. Adapted from
+ * https://github.com/STRML/async-limiter
+ */
+class Limiter {
+ /**
+ * Creates a new `Limiter`.
+ *
+ * @param {Number} [concurrency=Infinity] The maximum number of jobs allowed
+ * to run concurrently
+ */
+ constructor(concurrency) {
+ this[kDone] = () => {
+ this.pending--;
+ this[kRun]();
+ };
+ this.concurrency = concurrency || Infinity;
+ this.jobs = [];
+ this.pending = 0;
+ }
+
+ /**
+ * Adds a job to the queue.
+ *
+ * @param {Function} job The job to run
+ * @public
+ */
+ add(job) {
+ this.jobs.push(job);
+ this[kRun]();
+ }
+
+ /**
+ * Removes a job from the queue and runs it if possible.
+ *
+ * @private
+ */
+ [kRun]() {
+ if (this.pending === this.concurrency) return;
+
+ if (this.jobs.length) {
+ const job = this.jobs.shift();
+
+ this.pending++;
+ job(this[kDone]);
+ }
+ }
+}
+
+module.exports = Limiter;
diff --git a/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/permessage-deflate.js b/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/permessage-deflate.js
new file mode 100644
index 0000000..77d918b
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/permessage-deflate.js
@@ -0,0 +1,514 @@
+'use strict';
+
+const zlib = require('zlib');
+
+const bufferUtil = require('./buffer-util');
+const Limiter = require('./limiter');
+const { kStatusCode } = require('./constants');
+
+const FastBuffer = Buffer[Symbol.species];
+const TRAILER = Buffer.from([0x00, 0x00, 0xff, 0xff]);
+const kPerMessageDeflate = Symbol('permessage-deflate');
+const kTotalLength = Symbol('total-length');
+const kCallback = Symbol('callback');
+const kBuffers = Symbol('buffers');
+const kError = Symbol('error');
+
+//
+// We limit zlib concurrency, which prevents severe memory fragmentation
+// as documented in https://github.com/nodejs/node/issues/8871#issuecomment-250915913
+// and https://github.com/websockets/ws/issues/1202
+//
+// Intentionally global; it's the global thread pool that's an issue.
+//
+let zlibLimiter;
+
+/**
+ * permessage-deflate implementation.
+ */
+class PerMessageDeflate {
+ /**
+ * Creates a PerMessageDeflate instance.
+ *
+ * @param {Object} [options] Configuration options
+ * @param {(Boolean|Number)} [options.clientMaxWindowBits] Advertise support
+ * for, or request, a custom client window size
+ * @param {Boolean} [options.clientNoContextTakeover=false] Advertise/
+ * acknowledge disabling of client context takeover
+ * @param {Number} [options.concurrencyLimit=10] The number of concurrent
+ * calls to zlib
+ * @param {(Boolean|Number)} [options.serverMaxWindowBits] Request/confirm the
+ * use of a custom server window size
+ * @param {Boolean} [options.serverNoContextTakeover=false] Request/accept
+ * disabling of server context takeover
+ * @param {Number} [options.threshold=1024] Size (in bytes) below which
+ * messages should not be compressed if context takeover is disabled
+ * @param {Object} [options.zlibDeflateOptions] Options to pass to zlib on
+ * deflate
+ * @param {Object} [options.zlibInflateOptions] Options to pass to zlib on
+ * inflate
+ * @param {Boolean} [isServer=false] Create the instance in either server or
+ * client mode
+ * @param {Number} [maxPayload=0] The maximum allowed message length
+ */
+ constructor(options, isServer, maxPayload) {
+ this._maxPayload = maxPayload | 0;
+ this._options = options || {};
+ this._threshold =
+ this._options.threshold !== undefined ? this._options.threshold : 1024;
+ this._isServer = !!isServer;
+ this._deflate = null;
+ this._inflate = null;
+
+ this.params = null;
+
+ if (!zlibLimiter) {
+ const concurrency =
+ this._options.concurrencyLimit !== undefined
+ ? this._options.concurrencyLimit
+ : 10;
+ zlibLimiter = new Limiter(concurrency);
+ }
+ }
+
+ /**
+ * @type {String}
+ */
+ static get extensionName() {
+ return 'permessage-deflate';
+ }
+
+ /**
+ * Create an extension negotiation offer.
+ *
+ * @return {Object} Extension parameters
+ * @public
+ */
+ offer() {
+ const params = {};
+
+ if (this._options.serverNoContextTakeover) {
+ params.server_no_context_takeover = true;
+ }
+ if (this._options.clientNoContextTakeover) {
+ params.client_no_context_takeover = true;
+ }
+ if (this._options.serverMaxWindowBits) {
+ params.server_max_window_bits = this._options.serverMaxWindowBits;
+ }
+ if (this._options.clientMaxWindowBits) {
+ params.client_max_window_bits = this._options.clientMaxWindowBits;
+ } else if (this._options.clientMaxWindowBits == null) {
+ params.client_max_window_bits = true;
+ }
+
+ return params;
+ }
+
+ /**
+ * Accept an extension negotiation offer/response.
+ *
+ * @param {Array} configurations The extension negotiation offers/reponse
+ * @return {Object} Accepted configuration
+ * @public
+ */
+ accept(configurations) {
+ configurations = this.normalizeParams(configurations);
+
+ this.params = this._isServer
+ ? this.acceptAsServer(configurations)
+ : this.acceptAsClient(configurations);
+
+ return this.params;
+ }
+
+ /**
+ * Releases all resources used by the extension.
+ *
+ * @public
+ */
+ cleanup() {
+ if (this._inflate) {
+ this._inflate.close();
+ this._inflate = null;
+ }
+
+ if (this._deflate) {
+ const callback = this._deflate[kCallback];
+
+ this._deflate.close();
+ this._deflate = null;
+
+ if (callback) {
+ callback(
+ new Error(
+ 'The deflate stream was closed while data was being processed'
+ )
+ );
+ }
+ }
+ }
+
+ /**
+ * Accept an extension negotiation offer.
+ *
+ * @param {Array} offers The extension negotiation offers
+ * @return {Object} Accepted configuration
+ * @private
+ */
+ acceptAsServer(offers) {
+ const opts = this._options;
+ const accepted = offers.find((params) => {
+ if (
+ (opts.serverNoContextTakeover === false &&
+ params.server_no_context_takeover) ||
+ (params.server_max_window_bits &&
+ (opts.serverMaxWindowBits === false ||
+ (typeof opts.serverMaxWindowBits === 'number' &&
+ opts.serverMaxWindowBits > params.server_max_window_bits))) ||
+ (typeof opts.clientMaxWindowBits === 'number' &&
+ !params.client_max_window_bits)
+ ) {
+ return false;
+ }
+
+ return true;
+ });
+
+ if (!accepted) {
+ throw new Error('None of the extension offers can be accepted');
+ }
+
+ if (opts.serverNoContextTakeover) {
+ accepted.server_no_context_takeover = true;
+ }
+ if (opts.clientNoContextTakeover) {
+ accepted.client_no_context_takeover = true;
+ }
+ if (typeof opts.serverMaxWindowBits === 'number') {
+ accepted.server_max_window_bits = opts.serverMaxWindowBits;
+ }
+ if (typeof opts.clientMaxWindowBits === 'number') {
+ accepted.client_max_window_bits = opts.clientMaxWindowBits;
+ } else if (
+ accepted.client_max_window_bits === true ||
+ opts.clientMaxWindowBits === false
+ ) {
+ delete accepted.client_max_window_bits;
+ }
+
+ return accepted;
+ }
+
+ /**
+ * Accept the extension negotiation response.
+ *
+ * @param {Array} response The extension negotiation response
+ * @return {Object} Accepted configuration
+ * @private
+ */
+ acceptAsClient(response) {
+ const params = response[0];
+
+ if (
+ this._options.clientNoContextTakeover === false &&
+ params.client_no_context_takeover
+ ) {
+ throw new Error('Unexpected parameter "client_no_context_takeover"');
+ }
+
+ if (!params.client_max_window_bits) {
+ if (typeof this._options.clientMaxWindowBits === 'number') {
+ params.client_max_window_bits = this._options.clientMaxWindowBits;
+ }
+ } else if (
+ this._options.clientMaxWindowBits === false ||
+ (typeof this._options.clientMaxWindowBits === 'number' &&
+ params.client_max_window_bits > this._options.clientMaxWindowBits)
+ ) {
+ throw new Error(
+ 'Unexpected or invalid parameter "client_max_window_bits"'
+ );
+ }
+
+ return params;
+ }
+
+ /**
+ * Normalize parameters.
+ *
+ * @param {Array} configurations The extension negotiation offers/reponse
+ * @return {Array} The offers/response with normalized parameters
+ * @private
+ */
+ normalizeParams(configurations) {
+ configurations.forEach((params) => {
+ Object.keys(params).forEach((key) => {
+ let value = params[key];
+
+ if (value.length > 1) {
+ throw new Error(`Parameter "${key}" must have only a single value`);
+ }
+
+ value = value[0];
+
+ if (key === 'client_max_window_bits') {
+ if (value !== true) {
+ const num = +value;
+ if (!Number.isInteger(num) || num < 8 || num > 15) {
+ throw new TypeError(
+ `Invalid value for parameter "${key}": ${value}`
+ );
+ }
+ value = num;
+ } else if (!this._isServer) {
+ throw new TypeError(
+ `Invalid value for parameter "${key}": ${value}`
+ );
+ }
+ } else if (key === 'server_max_window_bits') {
+ const num = +value;
+ if (!Number.isInteger(num) || num < 8 || num > 15) {
+ throw new TypeError(
+ `Invalid value for parameter "${key}": ${value}`
+ );
+ }
+ value = num;
+ } else if (
+ key === 'client_no_context_takeover' ||
+ key === 'server_no_context_takeover'
+ ) {
+ if (value !== true) {
+ throw new TypeError(
+ `Invalid value for parameter "${key}": ${value}`
+ );
+ }
+ } else {
+ throw new Error(`Unknown parameter "${key}"`);
+ }
+
+ params[key] = value;
+ });
+ });
+
+ return configurations;
+ }
+
+ /**
+ * Decompress data. Concurrency limited.
+ *
+ * @param {Buffer} data Compressed data
+ * @param {Boolean} fin Specifies whether or not this is the last fragment
+ * @param {Function} callback Callback
+ * @public
+ */
+ decompress(data, fin, callback) {
+ zlibLimiter.add((done) => {
+ this._decompress(data, fin, (err, result) => {
+ done();
+ callback(err, result);
+ });
+ });
+ }
+
+ /**
+ * Compress data. Concurrency limited.
+ *
+ * @param {(Buffer|String)} data Data to compress
+ * @param {Boolean} fin Specifies whether or not this is the last fragment
+ * @param {Function} callback Callback
+ * @public
+ */
+ compress(data, fin, callback) {
+ zlibLimiter.add((done) => {
+ this._compress(data, fin, (err, result) => {
+ done();
+ callback(err, result);
+ });
+ });
+ }
+
+ /**
+ * Decompress data.
+ *
+ * @param {Buffer} data Compressed data
+ * @param {Boolean} fin Specifies whether or not this is the last fragment
+ * @param {Function} callback Callback
+ * @private
+ */
+ _decompress(data, fin, callback) {
+ const endpoint = this._isServer ? 'client' : 'server';
+
+ if (!this._inflate) {
+ const key = `${endpoint}_max_window_bits`;
+ const windowBits =
+ typeof this.params[key] !== 'number'
+ ? zlib.Z_DEFAULT_WINDOWBITS
+ : this.params[key];
+
+ this._inflate = zlib.createInflateRaw({
+ ...this._options.zlibInflateOptions,
+ windowBits
+ });
+ this._inflate[kPerMessageDeflate] = this;
+ this._inflate[kTotalLength] = 0;
+ this._inflate[kBuffers] = [];
+ this._inflate.on('error', inflateOnError);
+ this._inflate.on('data', inflateOnData);
+ }
+
+ this._inflate[kCallback] = callback;
+
+ this._inflate.write(data);
+ if (fin) this._inflate.write(TRAILER);
+
+ this._inflate.flush(() => {
+ const err = this._inflate[kError];
+
+ if (err) {
+ this._inflate.close();
+ this._inflate = null;
+ callback(err);
+ return;
+ }
+
+ const data = bufferUtil.concat(
+ this._inflate[kBuffers],
+ this._inflate[kTotalLength]
+ );
+
+ if (this._inflate._readableState.endEmitted) {
+ this._inflate.close();
+ this._inflate = null;
+ } else {
+ this._inflate[kTotalLength] = 0;
+ this._inflate[kBuffers] = [];
+
+ if (fin && this.params[`${endpoint}_no_context_takeover`]) {
+ this._inflate.reset();
+ }
+ }
+
+ callback(null, data);
+ });
+ }
+
+ /**
+ * Compress data.
+ *
+ * @param {(Buffer|String)} data Data to compress
+ * @param {Boolean} fin Specifies whether or not this is the last fragment
+ * @param {Function} callback Callback
+ * @private
+ */
+ _compress(data, fin, callback) {
+ const endpoint = this._isServer ? 'server' : 'client';
+
+ if (!this._deflate) {
+ const key = `${endpoint}_max_window_bits`;
+ const windowBits =
+ typeof this.params[key] !== 'number'
+ ? zlib.Z_DEFAULT_WINDOWBITS
+ : this.params[key];
+
+ this._deflate = zlib.createDeflateRaw({
+ ...this._options.zlibDeflateOptions,
+ windowBits
+ });
+
+ this._deflate[kTotalLength] = 0;
+ this._deflate[kBuffers] = [];
+
+ this._deflate.on('data', deflateOnData);
+ }
+
+ this._deflate[kCallback] = callback;
+
+ this._deflate.write(data);
+ this._deflate.flush(zlib.Z_SYNC_FLUSH, () => {
+ if (!this._deflate) {
+ //
+ // The deflate stream was closed while data was being processed.
+ //
+ return;
+ }
+
+ let data = bufferUtil.concat(
+ this._deflate[kBuffers],
+ this._deflate[kTotalLength]
+ );
+
+ if (fin) {
+ data = new FastBuffer(data.buffer, data.byteOffset, data.length - 4);
+ }
+
+ //
+ // Ensure that the callback will not be called again in
+ // `PerMessageDeflate#cleanup()`.
+ //
+ this._deflate[kCallback] = null;
+
+ this._deflate[kTotalLength] = 0;
+ this._deflate[kBuffers] = [];
+
+ if (fin && this.params[`${endpoint}_no_context_takeover`]) {
+ this._deflate.reset();
+ }
+
+ callback(null, data);
+ });
+ }
+}
+
+module.exports = PerMessageDeflate;
+
+/**
+ * The listener of the `zlib.DeflateRaw` stream `'data'` event.
+ *
+ * @param {Buffer} chunk A chunk of data
+ * @private
+ */
+function deflateOnData(chunk) {
+ this[kBuffers].push(chunk);
+ this[kTotalLength] += chunk.length;
+}
+
+/**
+ * The listener of the `zlib.InflateRaw` stream `'data'` event.
+ *
+ * @param {Buffer} chunk A chunk of data
+ * @private
+ */
+function inflateOnData(chunk) {
+ this[kTotalLength] += chunk.length;
+
+ if (
+ this[kPerMessageDeflate]._maxPayload < 1 ||
+ this[kTotalLength] <= this[kPerMessageDeflate]._maxPayload
+ ) {
+ this[kBuffers].push(chunk);
+ return;
+ }
+
+ this[kError] = new RangeError('Max payload size exceeded');
+ this[kError].code = 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH';
+ this[kError][kStatusCode] = 1009;
+ this.removeListener('data', inflateOnData);
+ this.reset();
+}
+
+/**
+ * The listener of the `zlib.InflateRaw` stream `'error'` event.
+ *
+ * @param {Error} err The emitted error
+ * @private
+ */
+function inflateOnError(err) {
+ //
+ // There is no need to call `Zlib#close()` as the handle is automatically
+ // closed when an error is emitted.
+ //
+ this[kPerMessageDeflate]._inflate = null;
+ err[kStatusCode] = 1007;
+ this[kCallback](err);
+}
diff --git a/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/receiver.js b/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/receiver.js
new file mode 100644
index 0000000..1d425ea
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/receiver.js
@@ -0,0 +1,679 @@
+'use strict';
+
+const { Writable } = require('stream');
+
+const PerMessageDeflate = require('./permessage-deflate');
+const {
+ BINARY_TYPES,
+ EMPTY_BUFFER,
+ kStatusCode,
+ kWebSocket
+} = require('./constants');
+const { concat, toArrayBuffer, unmask } = require('./buffer-util');
+const { isValidStatusCode, isValidUTF8 } = require('./validation');
+
+const FastBuffer = Buffer[Symbol.species];
+const promise = Promise.resolve();
+
+//
+// `queueMicrotask()` is not available in Node.js < 11.
+//
+const queueTask =
+ typeof queueMicrotask === 'function' ? queueMicrotask : queueMicrotaskShim;
+
+const GET_INFO = 0;
+const GET_PAYLOAD_LENGTH_16 = 1;
+const GET_PAYLOAD_LENGTH_64 = 2;
+const GET_MASK = 3;
+const GET_DATA = 4;
+const INFLATING = 5;
+const WAIT_MICROTASK = 6;
+
+/**
+ * HyBi Receiver implementation.
+ *
+ * @extends Writable
+ */
+class Receiver extends Writable {
+ /**
+ * Creates a Receiver instance.
+ *
+ * @param {Object} [options] Options object
+ * @param {String} [options.binaryType=nodebuffer] The type for binary data
+ * @param {Object} [options.extensions] An object containing the negotiated
+ * extensions
+ * @param {Boolean} [options.isServer=false] Specifies whether to operate in
+ * client or server mode
+ * @param {Number} [options.maxPayload=0] The maximum allowed message length
+ * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or
+ * not to skip UTF-8 validation for text and close messages
+ */
+ constructor(options = {}) {
+ super();
+
+ this._binaryType = options.binaryType || BINARY_TYPES[0];
+ this._extensions = options.extensions || {};
+ this._isServer = !!options.isServer;
+ this._maxPayload = options.maxPayload | 0;
+ this._skipUTF8Validation = !!options.skipUTF8Validation;
+ this[kWebSocket] = undefined;
+
+ this._bufferedBytes = 0;
+ this._buffers = [];
+
+ this._compressed = false;
+ this._payloadLength = 0;
+ this._mask = undefined;
+ this._fragmented = 0;
+ this._masked = false;
+ this._fin = false;
+ this._opcode = 0;
+
+ this._totalPayloadLength = 0;
+ this._messageLength = 0;
+ this._fragments = [];
+
+ this._state = GET_INFO;
+ this._loop = false;
+ }
+
+ /**
+ * Implements `Writable.prototype._write()`.
+ *
+ * @param {Buffer} chunk The chunk of data to write
+ * @param {String} encoding The character encoding of `chunk`
+ * @param {Function} cb Callback
+ * @private
+ */
+ _write(chunk, encoding, cb) {
+ if (this._opcode === 0x08 && this._state == GET_INFO) return cb();
+
+ this._bufferedBytes += chunk.length;
+ this._buffers.push(chunk);
+ this.startLoop(cb);
+ }
+
+ /**
+ * Consumes `n` bytes from the buffered data.
+ *
+ * @param {Number} n The number of bytes to consume
+ * @return {Buffer} The consumed bytes
+ * @private
+ */
+ consume(n) {
+ this._bufferedBytes -= n;
+
+ if (n === this._buffers[0].length) return this._buffers.shift();
+
+ if (n < this._buffers[0].length) {
+ const buf = this._buffers[0];
+ this._buffers[0] = new FastBuffer(
+ buf.buffer,
+ buf.byteOffset + n,
+ buf.length - n
+ );
+
+ return new FastBuffer(buf.buffer, buf.byteOffset, n);
+ }
+
+ const dst = Buffer.allocUnsafe(n);
+
+ do {
+ const buf = this._buffers[0];
+ const offset = dst.length - n;
+
+ if (n >= buf.length) {
+ dst.set(this._buffers.shift(), offset);
+ } else {
+ dst.set(new Uint8Array(buf.buffer, buf.byteOffset, n), offset);
+ this._buffers[0] = new FastBuffer(
+ buf.buffer,
+ buf.byteOffset + n,
+ buf.length - n
+ );
+ }
+
+ n -= buf.length;
+ } while (n > 0);
+
+ return dst;
+ }
+
+ /**
+ * Starts the parsing loop.
+ *
+ * @param {Function} cb Callback
+ * @private
+ */
+ startLoop(cb) {
+ let err;
+ this._loop = true;
+
+ do {
+ switch (this._state) {
+ case GET_INFO:
+ err = this.getInfo();
+ break;
+ case GET_PAYLOAD_LENGTH_16:
+ err = this.getPayloadLength16();
+ break;
+ case GET_PAYLOAD_LENGTH_64:
+ err = this.getPayloadLength64();
+ break;
+ case GET_MASK:
+ this.getMask();
+ break;
+ case GET_DATA:
+ err = this.getData(cb);
+ break;
+ case INFLATING:
+ this._loop = false;
+ return;
+ default:
+ //
+ // `WAIT_MICROTASK`.
+ //
+ this._loop = false;
+
+ queueTask(() => {
+ this._state = GET_INFO;
+ this.startLoop(cb);
+ });
+ return;
+ }
+ } while (this._loop);
+
+ cb(err);
+ }
+
+ /**
+ * Reads the first two bytes of a frame.
+ *
+ * @return {(RangeError|undefined)} A possible error
+ * @private
+ */
+ getInfo() {
+ if (this._bufferedBytes < 2) {
+ this._loop = false;
+ return;
+ }
+
+ const buf = this.consume(2);
+
+ if ((buf[0] & 0x30) !== 0x00) {
+ this._loop = false;
+ return error(
+ RangeError,
+ 'RSV2 and RSV3 must be clear',
+ true,
+ 1002,
+ 'WS_ERR_UNEXPECTED_RSV_2_3'
+ );
+ }
+
+ const compressed = (buf[0] & 0x40) === 0x40;
+
+ if (compressed && !this._extensions[PerMessageDeflate.extensionName]) {
+ this._loop = false;
+ return error(
+ RangeError,
+ 'RSV1 must be clear',
+ true,
+ 1002,
+ 'WS_ERR_UNEXPECTED_RSV_1'
+ );
+ }
+
+ this._fin = (buf[0] & 0x80) === 0x80;
+ this._opcode = buf[0] & 0x0f;
+ this._payloadLength = buf[1] & 0x7f;
+
+ if (this._opcode === 0x00) {
+ if (compressed) {
+ this._loop = false;
+ return error(
+ RangeError,
+ 'RSV1 must be clear',
+ true,
+ 1002,
+ 'WS_ERR_UNEXPECTED_RSV_1'
+ );
+ }
+
+ if (!this._fragmented) {
+ this._loop = false;
+ return error(
+ RangeError,
+ 'invalid opcode 0',
+ true,
+ 1002,
+ 'WS_ERR_INVALID_OPCODE'
+ );
+ }
+
+ this._opcode = this._fragmented;
+ } else if (this._opcode === 0x01 || this._opcode === 0x02) {
+ if (this._fragmented) {
+ this._loop = false;
+ return error(
+ RangeError,
+ `invalid opcode ${this._opcode}`,
+ true,
+ 1002,
+ 'WS_ERR_INVALID_OPCODE'
+ );
+ }
+
+ this._compressed = compressed;
+ } else if (this._opcode > 0x07 && this._opcode < 0x0b) {
+ if (!this._fin) {
+ this._loop = false;
+ return error(
+ RangeError,
+ 'FIN must be set',
+ true,
+ 1002,
+ 'WS_ERR_EXPECTED_FIN'
+ );
+ }
+
+ if (compressed) {
+ this._loop = false;
+ return error(
+ RangeError,
+ 'RSV1 must be clear',
+ true,
+ 1002,
+ 'WS_ERR_UNEXPECTED_RSV_1'
+ );
+ }
+
+ if (
+ this._payloadLength > 0x7d ||
+ (this._opcode === 0x08 && this._payloadLength === 1)
+ ) {
+ this._loop = false;
+ return error(
+ RangeError,
+ `invalid payload length ${this._payloadLength}`,
+ true,
+ 1002,
+ 'WS_ERR_INVALID_CONTROL_PAYLOAD_LENGTH'
+ );
+ }
+ } else {
+ this._loop = false;
+ return error(
+ RangeError,
+ `invalid opcode ${this._opcode}`,
+ true,
+ 1002,
+ 'WS_ERR_INVALID_OPCODE'
+ );
+ }
+
+ if (!this._fin && !this._fragmented) this._fragmented = this._opcode;
+ this._masked = (buf[1] & 0x80) === 0x80;
+
+ if (this._isServer) {
+ if (!this._masked) {
+ this._loop = false;
+ return error(
+ RangeError,
+ 'MASK must be set',
+ true,
+ 1002,
+ 'WS_ERR_EXPECTED_MASK'
+ );
+ }
+ } else if (this._masked) {
+ this._loop = false;
+ return error(
+ RangeError,
+ 'MASK must be clear',
+ true,
+ 1002,
+ 'WS_ERR_UNEXPECTED_MASK'
+ );
+ }
+
+ if (this._payloadLength === 126) this._state = GET_PAYLOAD_LENGTH_16;
+ else if (this._payloadLength === 127) this._state = GET_PAYLOAD_LENGTH_64;
+ else return this.haveLength();
+ }
+
+ /**
+ * Gets extended payload length (7+16).
+ *
+ * @return {(RangeError|undefined)} A possible error
+ * @private
+ */
+ getPayloadLength16() {
+ if (this._bufferedBytes < 2) {
+ this._loop = false;
+ return;
+ }
+
+ this._payloadLength = this.consume(2).readUInt16BE(0);
+ return this.haveLength();
+ }
+
+ /**
+ * Gets extended payload length (7+64).
+ *
+ * @return {(RangeError|undefined)} A possible error
+ * @private
+ */
+ getPayloadLength64() {
+ if (this._bufferedBytes < 8) {
+ this._loop = false;
+ return;
+ }
+
+ const buf = this.consume(8);
+ const num = buf.readUInt32BE(0);
+
+ //
+ // The maximum safe integer in JavaScript is 2^53 - 1. An error is returned
+ // if payload length is greater than this number.
+ //
+ if (num > Math.pow(2, 53 - 32) - 1) {
+ this._loop = false;
+ return error(
+ RangeError,
+ 'Unsupported WebSocket frame: payload length > 2^53 - 1',
+ false,
+ 1009,
+ 'WS_ERR_UNSUPPORTED_DATA_PAYLOAD_LENGTH'
+ );
+ }
+
+ this._payloadLength = num * Math.pow(2, 32) + buf.readUInt32BE(4);
+ return this.haveLength();
+ }
+
+ /**
+ * Payload length has been read.
+ *
+ * @return {(RangeError|undefined)} A possible error
+ * @private
+ */
+ haveLength() {
+ if (this._payloadLength && this._opcode < 0x08) {
+ this._totalPayloadLength += this._payloadLength;
+ if (this._totalPayloadLength > this._maxPayload && this._maxPayload > 0) {
+ this._loop = false;
+ return error(
+ RangeError,
+ 'Max payload size exceeded',
+ false,
+ 1009,
+ 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH'
+ );
+ }
+ }
+
+ if (this._masked) this._state = GET_MASK;
+ else this._state = GET_DATA;
+ }
+
+ /**
+ * Reads mask bytes.
+ *
+ * @private
+ */
+ getMask() {
+ if (this._bufferedBytes < 4) {
+ this._loop = false;
+ return;
+ }
+
+ this._mask = this.consume(4);
+ this._state = GET_DATA;
+ }
+
+ /**
+ * Reads data bytes.
+ *
+ * @param {Function} cb Callback
+ * @return {(Error|RangeError|undefined)} A possible error
+ * @private
+ */
+ getData(cb) {
+ let data = EMPTY_BUFFER;
+
+ if (this._payloadLength) {
+ if (this._bufferedBytes < this._payloadLength) {
+ this._loop = false;
+ return;
+ }
+
+ data = this.consume(this._payloadLength);
+
+ if (
+ this._masked &&
+ (this._mask[0] | this._mask[1] | this._mask[2] | this._mask[3]) !== 0
+ ) {
+ unmask(data, this._mask);
+ }
+ }
+
+ if (this._opcode > 0x07) return this.controlMessage(data);
+
+ if (this._compressed) {
+ this._state = INFLATING;
+ this.decompress(data, cb);
+ return;
+ }
+
+ if (data.length) {
+ //
+ // This message is not compressed so its length is the sum of the payload
+ // length of all fragments.
+ //
+ this._messageLength = this._totalPayloadLength;
+ this._fragments.push(data);
+ }
+
+ return this.dataMessage();
+ }
+
+ /**
+ * Decompresses data.
+ *
+ * @param {Buffer} data Compressed data
+ * @param {Function} cb Callback
+ * @private
+ */
+ decompress(data, cb) {
+ const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];
+
+ perMessageDeflate.decompress(data, this._fin, (err, buf) => {
+ if (err) return cb(err);
+
+ if (buf.length) {
+ this._messageLength += buf.length;
+ if (this._messageLength > this._maxPayload && this._maxPayload > 0) {
+ return cb(
+ error(
+ RangeError,
+ 'Max payload size exceeded',
+ false,
+ 1009,
+ 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH'
+ )
+ );
+ }
+
+ this._fragments.push(buf);
+ }
+
+ const er = this.dataMessage();
+ if (er) return cb(er);
+
+ this.startLoop(cb);
+ });
+ }
+
+ /**
+ * Handles a data message.
+ *
+ * @return {(Error|undefined)} A possible error
+ * @private
+ */
+ dataMessage() {
+ if (this._fin) {
+ const messageLength = this._messageLength;
+ const fragments = this._fragments;
+
+ this._totalPayloadLength = 0;
+ this._messageLength = 0;
+ this._fragmented = 0;
+ this._fragments = [];
+
+ if (this._opcode === 2) {
+ let data;
+
+ if (this._binaryType === 'nodebuffer') {
+ data = concat(fragments, messageLength);
+ } else if (this._binaryType === 'arraybuffer') {
+ data = toArrayBuffer(concat(fragments, messageLength));
+ } else {
+ data = fragments;
+ }
+
+ this.emit('message', data, true);
+ } else {
+ const buf = concat(fragments, messageLength);
+
+ if (!this._skipUTF8Validation && !isValidUTF8(buf)) {
+ this._loop = false;
+ return error(
+ Error,
+ 'invalid UTF-8 sequence',
+ true,
+ 1007,
+ 'WS_ERR_INVALID_UTF8'
+ );
+ }
+
+ this.emit('message', buf, false);
+ }
+ }
+
+ this._state = WAIT_MICROTASK;
+ }
+
+ /**
+ * Handles a control message.
+ *
+ * @param {Buffer} data Data to handle
+ * @return {(Error|RangeError|undefined)} A possible error
+ * @private
+ */
+ controlMessage(data) {
+ if (this._opcode === 0x08) {
+ this._loop = false;
+
+ if (data.length === 0) {
+ this.emit('conclude', 1005, EMPTY_BUFFER);
+ this.end();
+
+ this._state = GET_INFO;
+ } else {
+ const code = data.readUInt16BE(0);
+
+ if (!isValidStatusCode(code)) {
+ return error(
+ RangeError,
+ `invalid status code ${code}`,
+ true,
+ 1002,
+ 'WS_ERR_INVALID_CLOSE_CODE'
+ );
+ }
+
+ const buf = new FastBuffer(
+ data.buffer,
+ data.byteOffset + 2,
+ data.length - 2
+ );
+
+ if (!this._skipUTF8Validation && !isValidUTF8(buf)) {
+ return error(
+ Error,
+ 'invalid UTF-8 sequence',
+ true,
+ 1007,
+ 'WS_ERR_INVALID_UTF8'
+ );
+ }
+
+ this.emit('conclude', code, buf);
+ this.end();
+
+ this._state = GET_INFO;
+ }
+ } else if (this._opcode === 0x09) {
+ this.emit('ping', data);
+ this._state = WAIT_MICROTASK;
+ } else {
+ this.emit('pong', data);
+ this._state = WAIT_MICROTASK;
+ }
+ }
+}
+
+module.exports = Receiver;
+
+/**
+ * Builds an error object.
+ *
+ * @param {function(new:Error|RangeError)} ErrorCtor The error constructor
+ * @param {String} message The error message
+ * @param {Boolean} prefix Specifies whether or not to add a default prefix to
+ * `message`
+ * @param {Number} statusCode The status code
+ * @param {String} errorCode The exposed error code
+ * @return {(Error|RangeError)} The error
+ * @private
+ */
+function error(ErrorCtor, message, prefix, statusCode, errorCode) {
+ const err = new ErrorCtor(
+ prefix ? `Invalid WebSocket frame: ${message}` : message
+ );
+
+ Error.captureStackTrace(err, error);
+ err.code = errorCode;
+ err[kStatusCode] = statusCode;
+ return err;
+}
+
+/**
+ * A shim for `queueMicrotask()`.
+ *
+ * @param {Function} cb Callback
+ */
+function queueMicrotaskShim(cb) {
+ promise.then(cb).catch(throwErrorNextTick);
+}
+
+/**
+ * Throws an error.
+ *
+ * @param {Error} err The error to throw
+ * @private
+ */
+function throwError(err) {
+ throw err;
+}
+
+/**
+ * Throws an error in the next tick.
+ *
+ * @param {Error} err The error to throw
+ * @private
+ */
+function throwErrorNextTick(err) {
+ process.nextTick(throwError, err);
+}
diff --git a/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/sender.js b/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/sender.js
new file mode 100644
index 0000000..1ed04b0
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/sender.js
@@ -0,0 +1,477 @@
+/* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^Duplex" }] */
+
+'use strict';
+
+const { Duplex } = require('stream');
+const { randomFillSync } = require('crypto');
+
+const PerMessageDeflate = require('./permessage-deflate');
+const { EMPTY_BUFFER } = require('./constants');
+const { isValidStatusCode } = require('./validation');
+const { mask: applyMask, toBuffer } = require('./buffer-util');
+
+const kByteLength = Symbol('kByteLength');
+const maskBuffer = Buffer.alloc(4);
+
+/**
+ * HyBi Sender implementation.
+ */
+class Sender {
+ /**
+ * Creates a Sender instance.
+ *
+ * @param {Duplex} socket The connection socket
+ * @param {Object} [extensions] An object containing the negotiated extensions
+ * @param {Function} [generateMask] The function used to generate the masking
+ * key
+ */
+ constructor(socket, extensions, generateMask) {
+ this._extensions = extensions || {};
+
+ if (generateMask) {
+ this._generateMask = generateMask;
+ this._maskBuffer = Buffer.alloc(4);
+ }
+
+ this._socket = socket;
+
+ this._firstFragment = true;
+ this._compress = false;
+
+ this._bufferedBytes = 0;
+ this._deflating = false;
+ this._queue = [];
+ }
+
+ /**
+ * Frames a piece of data according to the HyBi WebSocket protocol.
+ *
+ * @param {(Buffer|String)} data The data to frame
+ * @param {Object} options Options object
+ * @param {Boolean} [options.fin=false] Specifies whether or not to set the
+ * FIN bit
+ * @param {Function} [options.generateMask] The function used to generate the
+ * masking key
+ * @param {Boolean} [options.mask=false] Specifies whether or not to mask
+ * `data`
+ * @param {Buffer} [options.maskBuffer] The buffer used to store the masking
+ * key
+ * @param {Number} options.opcode The opcode
+ * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be
+ * modified
+ * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the
+ * RSV1 bit
+ * @return {(Buffer|String)[]} The framed data
+ * @public
+ */
+ static frame(data, options) {
+ let mask;
+ let merge = false;
+ let offset = 2;
+ let skipMasking = false;
+
+ if (options.mask) {
+ mask = options.maskBuffer || maskBuffer;
+
+ if (options.generateMask) {
+ options.generateMask(mask);
+ } else {
+ randomFillSync(mask, 0, 4);
+ }
+
+ skipMasking = (mask[0] | mask[1] | mask[2] | mask[3]) === 0;
+ offset = 6;
+ }
+
+ let dataLength;
+
+ if (typeof data === 'string') {
+ if (
+ (!options.mask || skipMasking) &&
+ options[kByteLength] !== undefined
+ ) {
+ dataLength = options[kByteLength];
+ } else {
+ data = Buffer.from(data);
+ dataLength = data.length;
+ }
+ } else {
+ dataLength = data.length;
+ merge = options.mask && options.readOnly && !skipMasking;
+ }
+
+ let payloadLength = dataLength;
+
+ if (dataLength >= 65536) {
+ offset += 8;
+ payloadLength = 127;
+ } else if (dataLength > 125) {
+ offset += 2;
+ payloadLength = 126;
+ }
+
+ const target = Buffer.allocUnsafe(merge ? dataLength + offset : offset);
+
+ target[0] = options.fin ? options.opcode | 0x80 : options.opcode;
+ if (options.rsv1) target[0] |= 0x40;
+
+ target[1] = payloadLength;
+
+ if (payloadLength === 126) {
+ target.writeUInt16BE(dataLength, 2);
+ } else if (payloadLength === 127) {
+ target[2] = target[3] = 0;
+ target.writeUIntBE(dataLength, 4, 6);
+ }
+
+ if (!options.mask) return [target, data];
+
+ target[1] |= 0x80;
+ target[offset - 4] = mask[0];
+ target[offset - 3] = mask[1];
+ target[offset - 2] = mask[2];
+ target[offset - 1] = mask[3];
+
+ if (skipMasking) return [target, data];
+
+ if (merge) {
+ applyMask(data, mask, target, offset, dataLength);
+ return [target];
+ }
+
+ applyMask(data, mask, data, 0, dataLength);
+ return [target, data];
+ }
+
+ /**
+ * Sends a close message to the other peer.
+ *
+ * @param {Number} [code] The status code component of the body
+ * @param {(String|Buffer)} [data] The message component of the body
+ * @param {Boolean} [mask=false] Specifies whether or not to mask the message
+ * @param {Function} [cb] Callback
+ * @public
+ */
+ close(code, data, mask, cb) {
+ let buf;
+
+ if (code === undefined) {
+ buf = EMPTY_BUFFER;
+ } else if (typeof code !== 'number' || !isValidStatusCode(code)) {
+ throw new TypeError('First argument must be a valid error code number');
+ } else if (data === undefined || !data.length) {
+ buf = Buffer.allocUnsafe(2);
+ buf.writeUInt16BE(code, 0);
+ } else {
+ const length = Buffer.byteLength(data);
+
+ if (length > 123) {
+ throw new RangeError('The message must not be greater than 123 bytes');
+ }
+
+ buf = Buffer.allocUnsafe(2 + length);
+ buf.writeUInt16BE(code, 0);
+
+ if (typeof data === 'string') {
+ buf.write(data, 2);
+ } else {
+ buf.set(data, 2);
+ }
+ }
+
+ const options = {
+ [kByteLength]: buf.length,
+ fin: true,
+ generateMask: this._generateMask,
+ mask,
+ maskBuffer: this._maskBuffer,
+ opcode: 0x08,
+ readOnly: false,
+ rsv1: false
+ };
+
+ if (this._deflating) {
+ this.enqueue([this.dispatch, buf, false, options, cb]);
+ } else {
+ this.sendFrame(Sender.frame(buf, options), cb);
+ }
+ }
+
+ /**
+ * Sends a ping message to the other peer.
+ *
+ * @param {*} data The message to send
+ * @param {Boolean} [mask=false] Specifies whether or not to mask `data`
+ * @param {Function} [cb] Callback
+ * @public
+ */
+ ping(data, mask, cb) {
+ let byteLength;
+ let readOnly;
+
+ if (typeof data === 'string') {
+ byteLength = Buffer.byteLength(data);
+ readOnly = false;
+ } else {
+ data = toBuffer(data);
+ byteLength = data.length;
+ readOnly = toBuffer.readOnly;
+ }
+
+ if (byteLength > 125) {
+ throw new RangeError('The data size must not be greater than 125 bytes');
+ }
+
+ const options = {
+ [kByteLength]: byteLength,
+ fin: true,
+ generateMask: this._generateMask,
+ mask,
+ maskBuffer: this._maskBuffer,
+ opcode: 0x09,
+ readOnly,
+ rsv1: false
+ };
+
+ if (this._deflating) {
+ this.enqueue([this.dispatch, data, false, options, cb]);
+ } else {
+ this.sendFrame(Sender.frame(data, options), cb);
+ }
+ }
+
+ /**
+ * Sends a pong message to the other peer.
+ *
+ * @param {*} data The message to send
+ * @param {Boolean} [mask=false] Specifies whether or not to mask `data`
+ * @param {Function} [cb] Callback
+ * @public
+ */
+ pong(data, mask, cb) {
+ let byteLength;
+ let readOnly;
+
+ if (typeof data === 'string') {
+ byteLength = Buffer.byteLength(data);
+ readOnly = false;
+ } else {
+ data = toBuffer(data);
+ byteLength = data.length;
+ readOnly = toBuffer.readOnly;
+ }
+
+ if (byteLength > 125) {
+ throw new RangeError('The data size must not be greater than 125 bytes');
+ }
+
+ const options = {
+ [kByteLength]: byteLength,
+ fin: true,
+ generateMask: this._generateMask,
+ mask,
+ maskBuffer: this._maskBuffer,
+ opcode: 0x0a,
+ readOnly,
+ rsv1: false
+ };
+
+ if (this._deflating) {
+ this.enqueue([this.dispatch, data, false, options, cb]);
+ } else {
+ this.sendFrame(Sender.frame(data, options), cb);
+ }
+ }
+
+ /**
+ * Sends a data message to the other peer.
+ *
+ * @param {*} data The message to send
+ * @param {Object} options Options object
+ * @param {Boolean} [options.binary=false] Specifies whether `data` is binary
+ * or text
+ * @param {Boolean} [options.compress=false] Specifies whether or not to
+ * compress `data`
+ * @param {Boolean} [options.fin=false] Specifies whether the fragment is the
+ * last one
+ * @param {Boolean} [options.mask=false] Specifies whether or not to mask
+ * `data`
+ * @param {Function} [cb] Callback
+ * @public
+ */
+ send(data, options, cb) {
+ const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];
+ let opcode = options.binary ? 2 : 1;
+ let rsv1 = options.compress;
+
+ let byteLength;
+ let readOnly;
+
+ if (typeof data === 'string') {
+ byteLength = Buffer.byteLength(data);
+ readOnly = false;
+ } else {
+ data = toBuffer(data);
+ byteLength = data.length;
+ readOnly = toBuffer.readOnly;
+ }
+
+ if (this._firstFragment) {
+ this._firstFragment = false;
+ if (
+ rsv1 &&
+ perMessageDeflate &&
+ perMessageDeflate.params[
+ perMessageDeflate._isServer
+ ? 'server_no_context_takeover'
+ : 'client_no_context_takeover'
+ ]
+ ) {
+ rsv1 = byteLength >= perMessageDeflate._threshold;
+ }
+ this._compress = rsv1;
+ } else {
+ rsv1 = false;
+ opcode = 0;
+ }
+
+ if (options.fin) this._firstFragment = true;
+
+ if (perMessageDeflate) {
+ const opts = {
+ [kByteLength]: byteLength,
+ fin: options.fin,
+ generateMask: this._generateMask,
+ mask: options.mask,
+ maskBuffer: this._maskBuffer,
+ opcode,
+ readOnly,
+ rsv1
+ };
+
+ if (this._deflating) {
+ this.enqueue([this.dispatch, data, this._compress, opts, cb]);
+ } else {
+ this.dispatch(data, this._compress, opts, cb);
+ }
+ } else {
+ this.sendFrame(
+ Sender.frame(data, {
+ [kByteLength]: byteLength,
+ fin: options.fin,
+ generateMask: this._generateMask,
+ mask: options.mask,
+ maskBuffer: this._maskBuffer,
+ opcode,
+ readOnly,
+ rsv1: false
+ }),
+ cb
+ );
+ }
+ }
+
+ /**
+ * Dispatches a message.
+ *
+ * @param {(Buffer|String)} data The message to send
+ * @param {Boolean} [compress=false] Specifies whether or not to compress
+ * `data`
+ * @param {Object} options Options object
+ * @param {Boolean} [options.fin=false] Specifies whether or not to set the
+ * FIN bit
+ * @param {Function} [options.generateMask] The function used to generate the
+ * masking key
+ * @param {Boolean} [options.mask=false] Specifies whether or not to mask
+ * `data`
+ * @param {Buffer} [options.maskBuffer] The buffer used to store the masking
+ * key
+ * @param {Number} options.opcode The opcode
+ * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be
+ * modified
+ * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the
+ * RSV1 bit
+ * @param {Function} [cb] Callback
+ * @private
+ */
+ dispatch(data, compress, options, cb) {
+ if (!compress) {
+ this.sendFrame(Sender.frame(data, options), cb);
+ return;
+ }
+
+ const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];
+
+ this._bufferedBytes += options[kByteLength];
+ this._deflating = true;
+ perMessageDeflate.compress(data, options.fin, (_, buf) => {
+ if (this._socket.destroyed) {
+ const err = new Error(
+ 'The socket was closed while data was being compressed'
+ );
+
+ if (typeof cb === 'function') cb(err);
+
+ for (let i = 0; i < this._queue.length; i++) {
+ const params = this._queue[i];
+ const callback = params[params.length - 1];
+
+ if (typeof callback === 'function') callback(err);
+ }
+
+ return;
+ }
+
+ this._bufferedBytes -= options[kByteLength];
+ this._deflating = false;
+ options.readOnly = false;
+ this.sendFrame(Sender.frame(buf, options), cb);
+ this.dequeue();
+ });
+ }
+
+ /**
+ * Executes queued send operations.
+ *
+ * @private
+ */
+ dequeue() {
+ while (!this._deflating && this._queue.length) {
+ const params = this._queue.shift();
+
+ this._bufferedBytes -= params[3][kByteLength];
+ Reflect.apply(params[0], this, params.slice(1));
+ }
+ }
+
+ /**
+ * Enqueues a send operation.
+ *
+ * @param {Array} params Send operation parameters.
+ * @private
+ */
+ enqueue(params) {
+ this._bufferedBytes += params[3][kByteLength];
+ this._queue.push(params);
+ }
+
+ /**
+ * Sends a frame.
+ *
+ * @param {Buffer[]} list The frame to send
+ * @param {Function} [cb] Callback
+ * @private
+ */
+ sendFrame(list, cb) {
+ if (list.length === 2) {
+ this._socket.cork();
+ this._socket.write(list[0]);
+ this._socket.write(list[1], cb);
+ this._socket.uncork();
+ } else {
+ this._socket.write(list[0], cb);
+ }
+ }
+}
+
+module.exports = Sender;
diff --git a/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/stream.js b/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/stream.js
new file mode 100644
index 0000000..230734b
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/stream.js
@@ -0,0 +1,159 @@
+'use strict';
+
+const { Duplex } = require('stream');
+
+/**
+ * Emits the `'close'` event on a stream.
+ *
+ * @param {Duplex} stream The stream.
+ * @private
+ */
+function emitClose(stream) {
+ stream.emit('close');
+}
+
+/**
+ * The listener of the `'end'` event.
+ *
+ * @private
+ */
+function duplexOnEnd() {
+ if (!this.destroyed && this._writableState.finished) {
+ this.destroy();
+ }
+}
+
+/**
+ * The listener of the `'error'` event.
+ *
+ * @param {Error} err The error
+ * @private
+ */
+function duplexOnError(err) {
+ this.removeListener('error', duplexOnError);
+ this.destroy();
+ if (this.listenerCount('error') === 0) {
+ // Do not suppress the throwing behavior.
+ this.emit('error', err);
+ }
+}
+
+/**
+ * Wraps a `WebSocket` in a duplex stream.
+ *
+ * @param {WebSocket} ws The `WebSocket` to wrap
+ * @param {Object} [options] The options for the `Duplex` constructor
+ * @return {Duplex} The duplex stream
+ * @public
+ */
+function createWebSocketStream(ws, options) {
+ let terminateOnDestroy = true;
+
+ const duplex = new Duplex({
+ ...options,
+ autoDestroy: false,
+ emitClose: false,
+ objectMode: false,
+ writableObjectMode: false
+ });
+
+ ws.on('message', function message(msg, isBinary) {
+ const data =
+ !isBinary && duplex._readableState.objectMode ? msg.toString() : msg;
+
+ if (!duplex.push(data)) ws.pause();
+ });
+
+ ws.once('error', function error(err) {
+ if (duplex.destroyed) return;
+
+ // Prevent `ws.terminate()` from being called by `duplex._destroy()`.
+ //
+ // - If the `'error'` event is emitted before the `'open'` event, then
+ // `ws.terminate()` is a noop as no socket is assigned.
+ // - Otherwise, the error is re-emitted by the listener of the `'error'`
+ // event of the `Receiver` object. The listener already closes the
+ // connection by calling `ws.close()`. This allows a close frame to be
+ // sent to the other peer. If `ws.terminate()` is called right after this,
+ // then the close frame might not be sent.
+ terminateOnDestroy = false;
+ duplex.destroy(err);
+ });
+
+ ws.once('close', function close() {
+ if (duplex.destroyed) return;
+
+ duplex.push(null);
+ });
+
+ duplex._destroy = function (err, callback) {
+ if (ws.readyState === ws.CLOSED) {
+ callback(err);
+ process.nextTick(emitClose, duplex);
+ return;
+ }
+
+ let called = false;
+
+ ws.once('error', function error(err) {
+ called = true;
+ callback(err);
+ });
+
+ ws.once('close', function close() {
+ if (!called) callback(err);
+ process.nextTick(emitClose, duplex);
+ });
+
+ if (terminateOnDestroy) ws.terminate();
+ };
+
+ duplex._final = function (callback) {
+ if (ws.readyState === ws.CONNECTING) {
+ ws.once('open', function open() {
+ duplex._final(callback);
+ });
+ return;
+ }
+
+ // If the value of the `_socket` property is `null` it means that `ws` is a
+ // client websocket and the handshake failed. In fact, when this happens, a
+ // socket is never assigned to the websocket. Wait for the `'error'` event
+ // that will be emitted by the websocket.
+ if (ws._socket === null) return;
+
+ if (ws._socket._writableState.finished) {
+ callback();
+ if (duplex._readableState.endEmitted) duplex.destroy();
+ } else {
+ ws._socket.once('finish', function finish() {
+ // `duplex` is not destroyed here because the `'end'` event will be
+ // emitted on `duplex` after this `'finish'` event. The EOF signaling
+ // `null` chunk is, in fact, pushed when the websocket emits `'close'`.
+ callback();
+ });
+ ws.close();
+ }
+ };
+
+ duplex._read = function () {
+ if (ws.isPaused) ws.resume();
+ };
+
+ duplex._write = function (chunk, encoding, callback) {
+ if (ws.readyState === ws.CONNECTING) {
+ ws.once('open', function open() {
+ duplex._write(chunk, encoding, callback);
+ });
+ return;
+ }
+
+ ws.send(chunk, callback);
+ };
+
+ duplex.on('end', duplexOnEnd);
+ duplex.on('error', duplexOnError);
+ return duplex;
+}
+
+module.exports = createWebSocketStream;
diff --git a/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/subprotocol.js b/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/subprotocol.js
new file mode 100644
index 0000000..d4381e8
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/subprotocol.js
@@ -0,0 +1,62 @@
+'use strict';
+
+const { tokenChars } = require('./validation');
+
+/**
+ * Parses the `Sec-WebSocket-Protocol` header into a set of subprotocol names.
+ *
+ * @param {String} header The field value of the header
+ * @return {Set} The subprotocol names
+ * @public
+ */
+function parse(header) {
+ const protocols = new Set();
+ let start = -1;
+ let end = -1;
+ let i = 0;
+
+ for (i; i < header.length; i++) {
+ const code = header.charCodeAt(i);
+
+ if (end === -1 && tokenChars[code] === 1) {
+ if (start === -1) start = i;
+ } else if (
+ i !== 0 &&
+ (code === 0x20 /* ' ' */ || code === 0x09) /* '\t' */
+ ) {
+ if (end === -1 && start !== -1) end = i;
+ } else if (code === 0x2c /* ',' */) {
+ if (start === -1) {
+ throw new SyntaxError(`Unexpected character at index ${i}`);
+ }
+
+ if (end === -1) end = i;
+
+ const protocol = header.slice(start, end);
+
+ if (protocols.has(protocol)) {
+ throw new SyntaxError(`The "${protocol}" subprotocol is duplicated`);
+ }
+
+ protocols.add(protocol);
+ start = end = -1;
+ } else {
+ throw new SyntaxError(`Unexpected character at index ${i}`);
+ }
+ }
+
+ if (start === -1 || end !== -1) {
+ throw new SyntaxError('Unexpected end of input');
+ }
+
+ const protocol = header.slice(start, i);
+
+ if (protocols.has(protocol)) {
+ throw new SyntaxError(`The "${protocol}" subprotocol is duplicated`);
+ }
+
+ protocols.add(protocol);
+ return protocols;
+}
+
+module.exports = { parse };
diff --git a/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/validation.js b/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/validation.js
new file mode 100644
index 0000000..c352e6e
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/validation.js
@@ -0,0 +1,130 @@
+'use strict';
+
+const { isUtf8 } = require('buffer');
+
+//
+// Allowed token characters:
+//
+// '!', '#', '$', '%', '&', ''', '*', '+', '-',
+// '.', 0-9, A-Z, '^', '_', '`', a-z, '|', '~'
+//
+// tokenChars[32] === 0 // ' '
+// tokenChars[33] === 1 // '!'
+// tokenChars[34] === 0 // '"'
+// ...
+//
+// prettier-ignore
+const tokenChars = [
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 15
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16 - 31
+ 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, // 32 - 47
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 48 - 63
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64 - 79
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, // 80 - 95
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96 - 111
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0 // 112 - 127
+];
+
+/**
+ * Checks if a status code is allowed in a close frame.
+ *
+ * @param {Number} code The status code
+ * @return {Boolean} `true` if the status code is valid, else `false`
+ * @public
+ */
+function isValidStatusCode(code) {
+ return (
+ (code >= 1000 &&
+ code <= 1014 &&
+ code !== 1004 &&
+ code !== 1005 &&
+ code !== 1006) ||
+ (code >= 3000 && code <= 4999)
+ );
+}
+
+/**
+ * Checks if a given buffer contains only correct UTF-8.
+ * Ported from https://www.cl.cam.ac.uk/%7Emgk25/ucs/utf8_check.c by
+ * Markus Kuhn.
+ *
+ * @param {Buffer} buf The buffer to check
+ * @return {Boolean} `true` if `buf` contains only correct UTF-8, else `false`
+ * @public
+ */
+function _isValidUTF8(buf) {
+ const len = buf.length;
+ let i = 0;
+
+ while (i < len) {
+ if ((buf[i] & 0x80) === 0) {
+ // 0xxxxxxx
+ i++;
+ } else if ((buf[i] & 0xe0) === 0xc0) {
+ // 110xxxxx 10xxxxxx
+ if (
+ i + 1 === len ||
+ (buf[i + 1] & 0xc0) !== 0x80 ||
+ (buf[i] & 0xfe) === 0xc0 // Overlong
+ ) {
+ return false;
+ }
+
+ i += 2;
+ } else if ((buf[i] & 0xf0) === 0xe0) {
+ // 1110xxxx 10xxxxxx 10xxxxxx
+ if (
+ i + 2 >= len ||
+ (buf[i + 1] & 0xc0) !== 0x80 ||
+ (buf[i + 2] & 0xc0) !== 0x80 ||
+ (buf[i] === 0xe0 && (buf[i + 1] & 0xe0) === 0x80) || // Overlong
+ (buf[i] === 0xed && (buf[i + 1] & 0xe0) === 0xa0) // Surrogate (U+D800 - U+DFFF)
+ ) {
+ return false;
+ }
+
+ i += 3;
+ } else if ((buf[i] & 0xf8) === 0xf0) {
+ // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+ if (
+ i + 3 >= len ||
+ (buf[i + 1] & 0xc0) !== 0x80 ||
+ (buf[i + 2] & 0xc0) !== 0x80 ||
+ (buf[i + 3] & 0xc0) !== 0x80 ||
+ (buf[i] === 0xf0 && (buf[i + 1] & 0xf0) === 0x80) || // Overlong
+ (buf[i] === 0xf4 && buf[i + 1] > 0x8f) ||
+ buf[i] > 0xf4 // > U+10FFFF
+ ) {
+ return false;
+ }
+
+ i += 4;
+ } else {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+module.exports = {
+ isValidStatusCode,
+ isValidUTF8: _isValidUTF8,
+ tokenChars
+};
+
+if (isUtf8) {
+ module.exports.isValidUTF8 = function (buf) {
+ return buf.length < 24 ? _isValidUTF8(buf) : isUtf8(buf);
+ };
+} /* istanbul ignore else */ else if (!process.env.WS_NO_UTF_8_VALIDATE) {
+ try {
+ const isValidUTF8 = require('utf-8-validate');
+
+ module.exports.isValidUTF8 = function (buf) {
+ return buf.length < 32 ? _isValidUTF8(buf) : isValidUTF8(buf);
+ };
+ } catch (e) {
+ // Continue regardless of the error.
+ }
+}
diff --git a/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/websocket-server.js b/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/websocket-server.js
new file mode 100644
index 0000000..b0ed7bd
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/websocket-server.js
@@ -0,0 +1,531 @@
+/* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^Duplex$" }] */
+
+'use strict';
+
+const EventEmitter = require('events');
+const http = require('http');
+const { Duplex } = require('stream');
+const { createHash } = require('crypto');
+
+const extension = require('./extension');
+const PerMessageDeflate = require('./permessage-deflate');
+const subprotocol = require('./subprotocol');
+const WebSocket = require('./websocket');
+const { GUID, kWebSocket } = require('./constants');
+
+const keyRegex = /^[+/0-9A-Za-z]{22}==$/;
+
+const RUNNING = 0;
+const CLOSING = 1;
+const CLOSED = 2;
+
+/**
+ * Class representing a WebSocket server.
+ *
+ * @extends EventEmitter
+ */
+class WebSocketServer extends EventEmitter {
+ /**
+ * Create a `WebSocketServer` instance.
+ *
+ * @param {Object} options Configuration options
+ * @param {Number} [options.backlog=511] The maximum length of the queue of
+ * pending connections
+ * @param {Boolean} [options.clientTracking=true] Specifies whether or not to
+ * track clients
+ * @param {Function} [options.handleProtocols] A hook to handle protocols
+ * @param {String} [options.host] The hostname where to bind the server
+ * @param {Number} [options.maxPayload=104857600] The maximum allowed message
+ * size
+ * @param {Boolean} [options.noServer=false] Enable no server mode
+ * @param {String} [options.path] Accept only connections matching this path
+ * @param {(Boolean|Object)} [options.perMessageDeflate=false] Enable/disable
+ * permessage-deflate
+ * @param {Number} [options.port] The port where to bind the server
+ * @param {(http.Server|https.Server)} [options.server] A pre-created HTTP/S
+ * server to use
+ * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or
+ * not to skip UTF-8 validation for text and close messages
+ * @param {Function} [options.verifyClient] A hook to reject connections
+ * @param {Function} [options.WebSocket=WebSocket] Specifies the `WebSocket`
+ * class to use. It must be the `WebSocket` class or class that extends it
+ * @param {Function} [callback] A listener for the `listening` event
+ */
+ constructor(options, callback) {
+ super();
+
+ options = {
+ maxPayload: 100 * 1024 * 1024,
+ skipUTF8Validation: false,
+ perMessageDeflate: false,
+ handleProtocols: null,
+ clientTracking: true,
+ verifyClient: null,
+ noServer: false,
+ backlog: null, // use default (511 as implemented in net.js)
+ server: null,
+ host: null,
+ path: null,
+ port: null,
+ WebSocket,
+ ...options
+ };
+
+ if (
+ (options.port == null && !options.server && !options.noServer) ||
+ (options.port != null && (options.server || options.noServer)) ||
+ (options.server && options.noServer)
+ ) {
+ throw new TypeError(
+ 'One and only one of the "port", "server", or "noServer" options ' +
+ 'must be specified'
+ );
+ }
+
+ if (options.port != null) {
+ this._server = http.createServer((req, res) => {
+ const body = http.STATUS_CODES[426];
+
+ res.writeHead(426, {
+ 'Content-Length': body.length,
+ 'Content-Type': 'text/plain'
+ });
+ res.end(body);
+ });
+ this._server.listen(
+ options.port,
+ options.host,
+ options.backlog,
+ callback
+ );
+ } else if (options.server) {
+ this._server = options.server;
+ }
+
+ if (this._server) {
+ const emitConnection = this.emit.bind(this, 'connection');
+
+ this._removeListeners = addListeners(this._server, {
+ listening: this.emit.bind(this, 'listening'),
+ error: this.emit.bind(this, 'error'),
+ upgrade: (req, socket, head) => {
+ this.handleUpgrade(req, socket, head, emitConnection);
+ }
+ });
+ }
+
+ if (options.perMessageDeflate === true) options.perMessageDeflate = {};
+ if (options.clientTracking) {
+ this.clients = new Set();
+ this._shouldEmitClose = false;
+ }
+
+ this.options = options;
+ this._state = RUNNING;
+ }
+
+ /**
+ * Returns the bound address, the address family name, and port of the server
+ * as reported by the operating system if listening on an IP socket.
+ * If the server is listening on a pipe or UNIX domain socket, the name is
+ * returned as a string.
+ *
+ * @return {(Object|String|null)} The address of the server
+ * @public
+ */
+ address() {
+ if (this.options.noServer) {
+ throw new Error('The server is operating in "noServer" mode');
+ }
+
+ if (!this._server) return null;
+ return this._server.address();
+ }
+
+ /**
+ * Stop the server from accepting new connections and emit the `'close'` event
+ * when all existing connections are closed.
+ *
+ * @param {Function} [cb] A one-time listener for the `'close'` event
+ * @public
+ */
+ close(cb) {
+ if (this._state === CLOSED) {
+ if (cb) {
+ this.once('close', () => {
+ cb(new Error('The server is not running'));
+ });
+ }
+
+ process.nextTick(emitClose, this);
+ return;
+ }
+
+ if (cb) this.once('close', cb);
+
+ if (this._state === CLOSING) return;
+ this._state = CLOSING;
+
+ if (this.options.noServer || this.options.server) {
+ if (this._server) {
+ this._removeListeners();
+ this._removeListeners = this._server = null;
+ }
+
+ if (this.clients) {
+ if (!this.clients.size) {
+ process.nextTick(emitClose, this);
+ } else {
+ this._shouldEmitClose = true;
+ }
+ } else {
+ process.nextTick(emitClose, this);
+ }
+ } else {
+ const server = this._server;
+
+ this._removeListeners();
+ this._removeListeners = this._server = null;
+
+ //
+ // The HTTP/S server was created internally. Close it, and rely on its
+ // `'close'` event.
+ //
+ server.close(() => {
+ emitClose(this);
+ });
+ }
+ }
+
+ /**
+ * See if a given request should be handled by this server instance.
+ *
+ * @param {http.IncomingMessage} req Request object to inspect
+ * @return {Boolean} `true` if the request is valid, else `false`
+ * @public
+ */
+ shouldHandle(req) {
+ if (this.options.path) {
+ const index = req.url.indexOf('?');
+ const pathname = index !== -1 ? req.url.slice(0, index) : req.url;
+
+ if (pathname !== this.options.path) return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Handle a HTTP Upgrade request.
+ *
+ * @param {http.IncomingMessage} req The request object
+ * @param {Duplex} socket The network socket between the server and client
+ * @param {Buffer} head The first packet of the upgraded stream
+ * @param {Function} cb Callback
+ * @public
+ */
+ handleUpgrade(req, socket, head, cb) {
+ socket.on('error', socketOnError);
+
+ const key = req.headers['sec-websocket-key'];
+ const version = +req.headers['sec-websocket-version'];
+
+ if (req.method !== 'GET') {
+ const message = 'Invalid HTTP method';
+ abortHandshakeOrEmitwsClientError(this, req, socket, 405, message);
+ return;
+ }
+
+ if (req.headers.upgrade.toLowerCase() !== 'websocket') {
+ const message = 'Invalid Upgrade header';
+ abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);
+ return;
+ }
+
+ if (!key || !keyRegex.test(key)) {
+ const message = 'Missing or invalid Sec-WebSocket-Key header';
+ abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);
+ return;
+ }
+
+ if (version !== 8 && version !== 13) {
+ const message = 'Missing or invalid Sec-WebSocket-Version header';
+ abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);
+ return;
+ }
+
+ if (!this.shouldHandle(req)) {
+ abortHandshake(socket, 400);
+ return;
+ }
+
+ const secWebSocketProtocol = req.headers['sec-websocket-protocol'];
+ let protocols = new Set();
+
+ if (secWebSocketProtocol !== undefined) {
+ try {
+ protocols = subprotocol.parse(secWebSocketProtocol);
+ } catch (err) {
+ const message = 'Invalid Sec-WebSocket-Protocol header';
+ abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);
+ return;
+ }
+ }
+
+ const secWebSocketExtensions = req.headers['sec-websocket-extensions'];
+ const extensions = {};
+
+ if (
+ this.options.perMessageDeflate &&
+ secWebSocketExtensions !== undefined
+ ) {
+ const perMessageDeflate = new PerMessageDeflate(
+ this.options.perMessageDeflate,
+ true,
+ this.options.maxPayload
+ );
+
+ try {
+ const offers = extension.parse(secWebSocketExtensions);
+
+ if (offers[PerMessageDeflate.extensionName]) {
+ perMessageDeflate.accept(offers[PerMessageDeflate.extensionName]);
+ extensions[PerMessageDeflate.extensionName] = perMessageDeflate;
+ }
+ } catch (err) {
+ const message =
+ 'Invalid or unacceptable Sec-WebSocket-Extensions header';
+ abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);
+ return;
+ }
+ }
+
+ //
+ // Optionally call external client verification handler.
+ //
+ if (this.options.verifyClient) {
+ const info = {
+ origin:
+ req.headers[`${version === 8 ? 'sec-websocket-origin' : 'origin'}`],
+ secure: !!(req.socket.authorized || req.socket.encrypted),
+ req
+ };
+
+ if (this.options.verifyClient.length === 2) {
+ this.options.verifyClient(info, (verified, code, message, headers) => {
+ if (!verified) {
+ return abortHandshake(socket, code || 401, message, headers);
+ }
+
+ this.completeUpgrade(
+ extensions,
+ key,
+ protocols,
+ req,
+ socket,
+ head,
+ cb
+ );
+ });
+ return;
+ }
+
+ if (!this.options.verifyClient(info)) return abortHandshake(socket, 401);
+ }
+
+ this.completeUpgrade(extensions, key, protocols, req, socket, head, cb);
+ }
+
+ /**
+ * Upgrade the connection to WebSocket.
+ *
+ * @param {Object} extensions The accepted extensions
+ * @param {String} key The value of the `Sec-WebSocket-Key` header
+ * @param {Set} protocols The subprotocols
+ * @param {http.IncomingMessage} req The request object
+ * @param {Duplex} socket The network socket between the server and client
+ * @param {Buffer} head The first packet of the upgraded stream
+ * @param {Function} cb Callback
+ * @throws {Error} If called more than once with the same socket
+ * @private
+ */
+ completeUpgrade(extensions, key, protocols, req, socket, head, cb) {
+ //
+ // Destroy the socket if the client has already sent a FIN packet.
+ //
+ if (!socket.readable || !socket.writable) return socket.destroy();
+
+ if (socket[kWebSocket]) {
+ throw new Error(
+ 'server.handleUpgrade() was called more than once with the same ' +
+ 'socket, possibly due to a misconfiguration'
+ );
+ }
+
+ if (this._state > RUNNING) return abortHandshake(socket, 503);
+
+ const digest = createHash('sha1')
+ .update(key + GUID)
+ .digest('base64');
+
+ const headers = [
+ 'HTTP/1.1 101 Switching Protocols',
+ 'Upgrade: websocket',
+ 'Connection: Upgrade',
+ `Sec-WebSocket-Accept: ${digest}`
+ ];
+
+ const ws = new this.options.WebSocket(null);
+
+ if (protocols.size) {
+ //
+ // Optionally call external protocol selection handler.
+ //
+ const protocol = this.options.handleProtocols
+ ? this.options.handleProtocols(protocols, req)
+ : protocols.values().next().value;
+
+ if (protocol) {
+ headers.push(`Sec-WebSocket-Protocol: ${protocol}`);
+ ws._protocol = protocol;
+ }
+ }
+
+ if (extensions[PerMessageDeflate.extensionName]) {
+ const params = extensions[PerMessageDeflate.extensionName].params;
+ const value = extension.format({
+ [PerMessageDeflate.extensionName]: [params]
+ });
+ headers.push(`Sec-WebSocket-Extensions: ${value}`);
+ ws._extensions = extensions;
+ }
+
+ //
+ // Allow external modification/inspection of handshake headers.
+ //
+ this.emit('headers', headers, req);
+
+ socket.write(headers.concat('\r\n').join('\r\n'));
+ socket.removeListener('error', socketOnError);
+
+ ws.setSocket(socket, head, {
+ maxPayload: this.options.maxPayload,
+ skipUTF8Validation: this.options.skipUTF8Validation
+ });
+
+ if (this.clients) {
+ this.clients.add(ws);
+ ws.on('close', () => {
+ this.clients.delete(ws);
+
+ if (this._shouldEmitClose && !this.clients.size) {
+ process.nextTick(emitClose, this);
+ }
+ });
+ }
+
+ cb(ws, req);
+ }
+}
+
+module.exports = WebSocketServer;
+
+/**
+ * Add event listeners on an `EventEmitter` using a map of <event, listener>
+ * pairs.
+ *
+ * @param {EventEmitter} server The event emitter
+ * @param {Object.<String, Function>} map The listeners to add
+ * @return {Function} A function that will remove the added listeners when
+ * called
+ * @private
+ */
+function addListeners(server, map) {
+ for (const event of Object.keys(map)) server.on(event, map[event]);
+
+ return function removeListeners() {
+ for (const event of Object.keys(map)) {
+ server.removeListener(event, map[event]);
+ }
+ };
+}
+
+/**
+ * Emit a `'close'` event on an `EventEmitter`.
+ *
+ * @param {EventEmitter} server The event emitter
+ * @private
+ */
+function emitClose(server) {
+ server._state = CLOSED;
+ server.emit('close');
+}
+
+/**
+ * Handle socket errors.
+ *
+ * @private
+ */
+function socketOnError() {
+ this.destroy();
+}
+
+/**
+ * Close the connection when preconditions are not fulfilled.
+ *
+ * @param {Duplex} socket The socket of the upgrade request
+ * @param {Number} code The HTTP response status code
+ * @param {String} [message] The HTTP response body
+ * @param {Object} [headers] Additional HTTP response headers
+ * @private
+ */
+function abortHandshake(socket, code, message, headers) {
+ //
+ // The socket is writable unless the user destroyed or ended it before calling
+ // `server.handleUpgrade()` or in the `verifyClient` function, which is a user
+ // error. Handling this does not make much sense as the worst that can happen
+ // is that some of the data written by the user might be discarded due to the
+ // call to `socket.end()` below, which triggers an `'error'` event that in
+ // turn causes the socket to be destroyed.
+ //
+ message = message || http.STATUS_CODES[code];
+ headers = {
+ Connection: 'close',
+ 'Content-Type': 'text/html',
+ 'Content-Length': Buffer.byteLength(message),
+ ...headers
+ };
+
+ socket.once('finish', socket.destroy);
+
+ socket.end(
+ `HTTP/1.1 ${code} ${http.STATUS_CODES[code]}\r\n` +
+ Object.keys(headers)
+ .map((h) => `${h}: ${headers[h]}`)
+ .join('\r\n') +
+ '\r\n\r\n' +
+ message
+ );
+}
+
+/**
+ * Emit a `'wsClientError'` event on a `WebSocketServer` if there is at least
+ * one listener for it, otherwise call `abortHandshake()`.
+ *
+ * @param {WebSocketServer} server The WebSocket server
+ * @param {http.IncomingMessage} req The request object
+ * @param {Duplex} socket The socket of the upgrade request
+ * @param {Number} code The HTTP response status code
+ * @param {String} message The HTTP response body
+ * @private
+ */
+function abortHandshakeOrEmitwsClientError(server, req, socket, code, message) {
+ if (server.listenerCount('wsClientError')) {
+ const err = new Error(message);
+ Error.captureStackTrace(err, abortHandshakeOrEmitwsClientError);
+
+ server.emit('wsClientError', err, socket, req);
+ } else {
+ abortHandshake(socket, code, message);
+ }
+}
diff --git a/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/websocket.js b/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/websocket.js
new file mode 100644
index 0000000..8685ff7
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/lib/websocket.js
@@ -0,0 +1,1319 @@
+/* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^Duplex|Readable$" }] */
+
+'use strict';
+
+const EventEmitter = require('events');
+const https = require('https');
+const http = require('http');
+const net = require('net');
+const tls = require('tls');
+const { randomBytes, createHash } = require('crypto');
+const { Duplex, Readable } = require('stream');
+const { URL } = require('url');
+
+const PerMessageDeflate = require('./permessage-deflate');
+const Receiver = require('./receiver');
+const Sender = require('./sender');
+const {
+ BINARY_TYPES,
+ EMPTY_BUFFER,
+ GUID,
+ kForOnEventAttribute,
+ kListener,
+ kStatusCode,
+ kWebSocket,
+ NOOP
+} = require('./constants');
+const {
+ EventTarget: { addEventListener, removeEventListener }
+} = require('./event-target');
+const { format, parse } = require('./extension');
+const { toBuffer } = require('./buffer-util');
+
+const closeTimeout = 30 * 1000;
+const kAborted = Symbol('kAborted');
+const protocolVersions = [8, 13];
+const readyStates = ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED'];
+const subprotocolRegex = /^[!#$%&'*+\-.0-9A-Z^_`|a-z~]+$/;
+
+/**
+ * Class representing a WebSocket.
+ *
+ * @extends EventEmitter
+ */
+class WebSocket extends EventEmitter {
+ /**
+ * Create a new `WebSocket`.
+ *
+ * @param {(String|URL)} address The URL to which to connect
+ * @param {(String|String[])} [protocols] The subprotocols
+ * @param {Object} [options] Connection options
+ */
+ constructor(address, protocols, options) {
+ super();
+
+ this._binaryType = BINARY_TYPES[0];
+ this._closeCode = 1006;
+ this._closeFrameReceived = false;
+ this._closeFrameSent = false;
+ this._closeMessage = EMPTY_BUFFER;
+ this._closeTimer = null;
+ this._extensions = {};
+ this._paused = false;
+ this._protocol = '';
+ this._readyState = WebSocket.CONNECTING;
+ this._receiver = null;
+ this._sender = null;
+ this._socket = null;
+
+ if (address !== null) {
+ this._bufferedAmount = 0;
+ this._isServer = false;
+ this._redirects = 0;
+
+ if (protocols === undefined) {
+ protocols = [];
+ } else if (!Array.isArray(protocols)) {
+ if (typeof protocols === 'object' && protocols !== null) {
+ options = protocols;
+ protocols = [];
+ } else {
+ protocols = [protocols];
+ }
+ }
+
+ initAsClient(this, address, protocols, options);
+ } else {
+ this._isServer = true;
+ }
+ }
+
+ /**
+ * This deviates from the WHATWG interface since ws doesn't support the
+ * required default "blob" type (instead we define a custom "nodebuffer"
+ * type).
+ *
+ * @type {String}
+ */
+ get binaryType() {
+ return this._binaryType;
+ }
+
+ set binaryType(type) {
+ if (!BINARY_TYPES.includes(type)) return;
+
+ this._binaryType = type;
+
+ //
+ // Allow to change `binaryType` on the fly.
+ //
+ if (this._receiver) this._receiver._binaryType = type;
+ }
+
+ /**
+ * @type {Number}
+ */
+ get bufferedAmount() {
+ if (!this._socket) return this._bufferedAmount;
+
+ return this._socket._writableState.length + this._sender._bufferedBytes;
+ }
+
+ /**
+ * @type {String}
+ */
+ get extensions() {
+ return Object.keys(this._extensions).join();
+ }
+
+ /**
+ * @type {Boolean}
+ */
+ get isPaused() {
+ return this._paused;
+ }
+
+ /**
+ * @type {Function}
+ */
+ /* istanbul ignore next */
+ get onclose() {
+ return null;
+ }
+
+ /**
+ * @type {Function}
+ */
+ /* istanbul ignore next */
+ get onerror() {
+ return null;
+ }
+
+ /**
+ * @type {Function}
+ */
+ /* istanbul ignore next */
+ get onopen() {
+ return null;
+ }
+
+ /**
+ * @type {Function}
+ */
+ /* istanbul ignore next */
+ get onmessage() {
+ return null;
+ }
+
+ /**
+ * @type {String}
+ */
+ get protocol() {
+ return this._protocol;
+ }
+
+ /**
+ * @type {Number}
+ */
+ get readyState() {
+ return this._readyState;
+ }
+
+ /**
+ * @type {String}
+ */
+ get url() {
+ return this._url;
+ }
+
+ /**
+ * Set up the socket and the internal resources.
+ *
+ * @param {Duplex} socket The network socket between the server and client
+ * @param {Buffer} head The first packet of the upgraded stream
+ * @param {Object} options Options object
+ * @param {Function} [options.generateMask] The function used to generate the
+ * masking key
+ * @param {Number} [options.maxPayload=0] The maximum allowed message size
+ * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or
+ * not to skip UTF-8 validation for text and close messages
+ * @private
+ */
+ setSocket(socket, head, options) {
+ const receiver = new Receiver({
+ binaryType: this.binaryType,
+ extensions: this._extensions,
+ isServer: this._isServer,
+ maxPayload: options.maxPayload,
+ skipUTF8Validation: options.skipUTF8Validation
+ });
+
+ this._sender = new Sender(socket, this._extensions, options.generateMask);
+ this._receiver = receiver;
+ this._socket = socket;
+
+ receiver[kWebSocket] = this;
+ socket[kWebSocket] = this;
+
+ receiver.on('conclude', receiverOnConclude);
+ receiver.on('drain', receiverOnDrain);
+ receiver.on('error', receiverOnError);
+ receiver.on('message', receiverOnMessage);
+ receiver.on('ping', receiverOnPing);
+ receiver.on('pong', receiverOnPong);
+
+ //
+ // These methods may not be available if `socket` is just a `Duplex`.
+ //
+ if (socket.setTimeout) socket.setTimeout(0);
+ if (socket.setNoDelay) socket.setNoDelay();
+
+ if (head.length > 0) socket.unshift(head);
+
+ socket.on('close', socketOnClose);
+ socket.on('data', socketOnData);
+ socket.on('end', socketOnEnd);
+ socket.on('error', socketOnError);
+
+ this._readyState = WebSocket.OPEN;
+ this.emit('open');
+ }
+
+ /**
+ * Emit the `'close'` event.
+ *
+ * @private
+ */
+ emitClose() {
+ if (!this._socket) {
+ this._readyState = WebSocket.CLOSED;
+ this.emit('close', this._closeCode, this._closeMessage);
+ return;
+ }
+
+ if (this._extensions[PerMessageDeflate.extensionName]) {
+ this._extensions[PerMessageDeflate.extensionName].cleanup();
+ }
+
+ this._receiver.removeAllListeners();
+ this._readyState = WebSocket.CLOSED;
+ this.emit('close', this._closeCode, this._closeMessage);
+ }
+
+ /**
+ * Start a closing handshake.
+ *
+ * +----------+ +-----------+ +----------+
+ * - - -|ws.close()|-->|close frame|-->|ws.close()|- - -
+ * | +----------+ +-----------+ +----------+ |
+ * +----------+ +-----------+ |
+ * CLOSING |ws.close()|<--|close frame|<--+-----+ CLOSING
+ * +----------+ +-----------+ |
+ * | | | +---+ |
+ * +------------------------+-->|fin| - - - -
+ * | +---+ | +---+
+ * - - - - -|fin|<---------------------+
+ * +---+
+ *
+ * @param {Number} [code] Status code explaining why the connection is closing
+ * @param {(String|Buffer)} [data] The reason why the connection is
+ * closing
+ * @public
+ */
+ close(code, data) {
+ if (this.readyState === WebSocket.CLOSED) return;
+ if (this.readyState === WebSocket.CONNECTING) {
+ const msg = 'WebSocket was closed before the connection was established';
+ abortHandshake(this, this._req, msg);
+ return;
+ }
+
+ if (this.readyState === WebSocket.CLOSING) {
+ if (
+ this._closeFrameSent &&
+ (this._closeFrameReceived || this._receiver._writableState.errorEmitted)
+ ) {
+ this._socket.end();
+ }
+
+ return;
+ }
+
+ this._readyState = WebSocket.CLOSING;
+ this._sender.close(code, data, !this._isServer, (err) => {
+ //
+ // This error is handled by the `'error'` listener on the socket. We only
+ // want to know if the close frame has been sent here.
+ //
+ if (err) return;
+
+ this._closeFrameSent = true;
+
+ if (
+ this._closeFrameReceived ||
+ this._receiver._writableState.errorEmitted
+ ) {
+ this._socket.end();
+ }
+ });
+
+ //
+ // Specify a timeout for the closing handshake to complete.
+ //
+ this._closeTimer = setTimeout(
+ this._socket.destroy.bind(this._socket),
+ closeTimeout
+ );
+ }
+
+ /**
+ * Pause the socket.
+ *
+ * @public
+ */
+ pause() {
+ if (
+ this.readyState === WebSocket.CONNECTING ||
+ this.readyState === WebSocket.CLOSED
+ ) {
+ return;
+ }
+
+ this._paused = true;
+ this._socket.pause();
+ }
+
+ /**
+ * Send a ping.
+ *
+ * @param {*} [data] The data to send
+ * @param {Boolean} [mask] Indicates whether or not to mask `data`
+ * @param {Function} [cb] Callback which is executed when the ping is sent
+ * @public
+ */
+ ping(data, mask, cb) {
+ if (this.readyState === WebSocket.CONNECTING) {
+ throw new Error('WebSocket is not open: readyState 0 (CONNECTING)');
+ }
+
+ if (typeof data === 'function') {
+ cb = data;
+ data = mask = undefined;
+ } else if (typeof mask === 'function') {
+ cb = mask;
+ mask = undefined;
+ }
+
+ if (typeof data === 'number') data = data.toString();
+
+ if (this.readyState !== WebSocket.OPEN) {
+ sendAfterClose(this, data, cb);
+ return;
+ }
+
+ if (mask === undefined) mask = !this._isServer;
+ this._sender.ping(data || EMPTY_BUFFER, mask, cb);
+ }
+
+ /**
+ * Send a pong.
+ *
+ * @param {*} [data] The data to send
+ * @param {Boolean} [mask] Indicates whether or not to mask `data`
+ * @param {Function} [cb] Callback which is executed when the pong is sent
+ * @public
+ */
+ pong(data, mask, cb) {
+ if (this.readyState === WebSocket.CONNECTING) {
+ throw new Error('WebSocket is not open: readyState 0 (CONNECTING)');
+ }
+
+ if (typeof data === 'function') {
+ cb = data;
+ data = mask = undefined;
+ } else if (typeof mask === 'function') {
+ cb = mask;
+ mask = undefined;
+ }
+
+ if (typeof data === 'number') data = data.toString();
+
+ if (this.readyState !== WebSocket.OPEN) {
+ sendAfterClose(this, data, cb);
+ return;
+ }
+
+ if (mask === undefined) mask = !this._isServer;
+ this._sender.pong(data || EMPTY_BUFFER, mask, cb);
+ }
+
+ /**
+ * Resume the socket.
+ *
+ * @public
+ */
+ resume() {
+ if (
+ this.readyState === WebSocket.CONNECTING ||
+ this.readyState === WebSocket.CLOSED
+ ) {
+ return;
+ }
+
+ this._paused = false;
+ if (!this._receiver._writableState.needDrain) this._socket.resume();
+ }
+
+ /**
+ * Send a data message.
+ *
+ * @param {*} data The message to send
+ * @param {Object} [options] Options object
+ * @param {Boolean} [options.binary] Specifies whether `data` is binary or
+ * text
+ * @param {Boolean} [options.compress] Specifies whether or not to compress
+ * `data`
+ * @param {Boolean} [options.fin=true] Specifies whether the fragment is the
+ * last one
+ * @param {Boolean} [options.mask] Specifies whether or not to mask `data`
+ * @param {Function} [cb] Callback which is executed when data is written out
+ * @public
+ */
+ send(data, options, cb) {
+ if (this.readyState === WebSocket.CONNECTING) {
+ throw new Error('WebSocket is not open: readyState 0 (CONNECTING)');
+ }
+
+ if (typeof options === 'function') {
+ cb = options;
+ options = {};
+ }
+
+ if (typeof data === 'number') data = data.toString();
+
+ if (this.readyState !== WebSocket.OPEN) {
+ sendAfterClose(this, data, cb);
+ return;
+ }
+
+ const opts = {
+ binary: typeof data !== 'string',
+ mask: !this._isServer,
+ compress: true,
+ fin: true,
+ ...options
+ };
+
+ if (!this._extensions[PerMessageDeflate.extensionName]) {
+ opts.compress = false;
+ }
+
+ this._sender.send(data || EMPTY_BUFFER, opts, cb);
+ }
+
+ /**
+ * Forcibly close the connection.
+ *
+ * @public
+ */
+ terminate() {
+ if (this.readyState === WebSocket.CLOSED) return;
+ if (this.readyState === WebSocket.CONNECTING) {
+ const msg = 'WebSocket was closed before the connection was established';
+ abortHandshake(this, this._req, msg);
+ return;
+ }
+
+ if (this._socket) {
+ this._readyState = WebSocket.CLOSING;
+ this._socket.destroy();
+ }
+ }
+}
+
+/**
+ * @constant {Number} CONNECTING
+ * @memberof WebSocket
+ */
+Object.defineProperty(WebSocket, 'CONNECTING', {
+ enumerable: true,
+ value: readyStates.indexOf('CONNECTING')
+});
+
+/**
+ * @constant {Number} CONNECTING
+ * @memberof WebSocket.prototype
+ */
+Object.defineProperty(WebSocket.prototype, 'CONNECTING', {
+ enumerable: true,
+ value: readyStates.indexOf('CONNECTING')
+});
+
+/**
+ * @constant {Number} OPEN
+ * @memberof WebSocket
+ */
+Object.defineProperty(WebSocket, 'OPEN', {
+ enumerable: true,
+ value: readyStates.indexOf('OPEN')
+});
+
+/**
+ * @constant {Number} OPEN
+ * @memberof WebSocket.prototype
+ */
+Object.defineProperty(WebSocket.prototype, 'OPEN', {
+ enumerable: true,
+ value: readyStates.indexOf('OPEN')
+});
+
+/**
+ * @constant {Number} CLOSING
+ * @memberof WebSocket
+ */
+Object.defineProperty(WebSocket, 'CLOSING', {
+ enumerable: true,
+ value: readyStates.indexOf('CLOSING')
+});
+
+/**
+ * @constant {Number} CLOSING
+ * @memberof WebSocket.prototype
+ */
+Object.defineProperty(WebSocket.prototype, 'CLOSING', {
+ enumerable: true,
+ value: readyStates.indexOf('CLOSING')
+});
+
+/**
+ * @constant {Number} CLOSED
+ * @memberof WebSocket
+ */
+Object.defineProperty(WebSocket, 'CLOSED', {
+ enumerable: true,
+ value: readyStates.indexOf('CLOSED')
+});
+
+/**
+ * @constant {Number} CLOSED
+ * @memberof WebSocket.prototype
+ */
+Object.defineProperty(WebSocket.prototype, 'CLOSED', {
+ enumerable: true,
+ value: readyStates.indexOf('CLOSED')
+});
+
+[
+ 'binaryType',
+ 'bufferedAmount',
+ 'extensions',
+ 'isPaused',
+ 'protocol',
+ 'readyState',
+ 'url'
+].forEach((property) => {
+ Object.defineProperty(WebSocket.prototype, property, { enumerable: true });
+});
+
+//
+// Add the `onopen`, `onerror`, `onclose`, and `onmessage` attributes.
+// See https://html.spec.whatwg.org/multipage/comms.html#the-websocket-interface
+//
+['open', 'error', 'close', 'message'].forEach((method) => {
+ Object.defineProperty(WebSocket.prototype, `on${method}`, {
+ enumerable: true,
+ get() {
+ for (const listener of this.listeners(method)) {
+ if (listener[kForOnEventAttribute]) return listener[kListener];
+ }
+
+ return null;
+ },
+ set(handler) {
+ for (const listener of this.listeners(method)) {
+ if (listener[kForOnEventAttribute]) {
+ this.removeListener(method, listener);
+ break;
+ }
+ }
+
+ if (typeof handler !== 'function') return;
+
+ this.addEventListener(method, handler, {
+ [kForOnEventAttribute]: true
+ });
+ }
+ });
+});
+
+WebSocket.prototype.addEventListener = addEventListener;
+WebSocket.prototype.removeEventListener = removeEventListener;
+
+module.exports = WebSocket;
+
+/**
+ * Initialize a WebSocket client.
+ *
+ * @param {WebSocket} websocket The client to initialize
+ * @param {(String|URL)} address The URL to which to connect
+ * @param {Array} protocols The subprotocols
+ * @param {Object} [options] Connection options
+ * @param {Boolean} [options.followRedirects=false] Whether or not to follow
+ * redirects
+ * @param {Function} [options.generateMask] The function used to generate the
+ * masking key
+ * @param {Number} [options.handshakeTimeout] Timeout in milliseconds for the
+ * handshake request
+ * @param {Number} [options.maxPayload=104857600] The maximum allowed message
+ * size
+ * @param {Number} [options.maxRedirects=10] The maximum number of redirects
+ * allowed
+ * @param {String} [options.origin] Value of the `Origin` or
+ * `Sec-WebSocket-Origin` header
+ * @param {(Boolean|Object)} [options.perMessageDeflate=true] Enable/disable
+ * permessage-deflate
+ * @param {Number} [options.protocolVersion=13] Value of the
+ * `Sec-WebSocket-Version` header
+ * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or
+ * not to skip UTF-8 validation for text and close messages
+ * @private
+ */
+function initAsClient(websocket, address, protocols, options) {
+ const opts = {
+ protocolVersion: protocolVersions[1],
+ maxPayload: 100 * 1024 * 1024,
+ skipUTF8Validation: false,
+ perMessageDeflate: true,
+ followRedirects: false,
+ maxRedirects: 10,
+ ...options,
+ createConnection: undefined,
+ socketPath: undefined,
+ hostname: undefined,
+ protocol: undefined,
+ timeout: undefined,
+ method: 'GET',
+ host: undefined,
+ path: undefined,
+ port: undefined
+ };
+
+ if (!protocolVersions.includes(opts.protocolVersion)) {
+ throw new RangeError(
+ `Unsupported protocol version: ${opts.protocolVersion} ` +
+ `(supported versions: ${protocolVersions.join(', ')})`
+ );
+ }
+
+ let parsedUrl;
+
+ if (address instanceof URL) {
+ parsedUrl = address;
+ } else {
+ try {
+ parsedUrl = new URL(address);
+ } catch (e) {
+ throw new SyntaxError(`Invalid URL: ${address}`);
+ }
+ }
+
+ if (parsedUrl.protocol === 'http:') {
+ parsedUrl.protocol = 'ws:';
+ } else if (parsedUrl.protocol === 'https:') {
+ parsedUrl.protocol = 'wss:';
+ }
+
+ websocket._url = parsedUrl.href;
+
+ const isSecure = parsedUrl.protocol === 'wss:';
+ const isIpcUrl = parsedUrl.protocol === 'ws+unix:';
+ let invalidUrlMessage;
+
+ if (parsedUrl.protocol !== 'ws:' && !isSecure && !isIpcUrl) {
+ invalidUrlMessage =
+ 'The URL\'s protocol must be one of "ws:", "wss:", ' +
+ '"http:", "https", or "ws+unix:"';
+ } else if (isIpcUrl && !parsedUrl.pathname) {
+ invalidUrlMessage = "The URL's pathname is empty";
+ } else if (parsedUrl.hash) {
+ invalidUrlMessage = 'The URL contains a fragment identifier';
+ }
+
+ if (invalidUrlMessage) {
+ const err = new SyntaxError(invalidUrlMessage);
+
+ if (websocket._redirects === 0) {
+ throw err;
+ } else {
+ emitErrorAndClose(websocket, err);
+ return;
+ }
+ }
+
+ const defaultPort = isSecure ? 443 : 80;
+ const key = randomBytes(16).toString('base64');
+ const request = isSecure ? https.request : http.request;
+ const protocolSet = new Set();
+ let perMessageDeflate;
+
+ opts.createConnection = isSecure ? tlsConnect : netConnect;
+ opts.defaultPort = opts.defaultPort || defaultPort;
+ opts.port = parsedUrl.port || defaultPort;
+ opts.host = parsedUrl.hostname.startsWith('[')
+ ? parsedUrl.hostname.slice(1, -1)
+ : parsedUrl.hostname;
+ opts.headers = {
+ ...opts.headers,
+ 'Sec-WebSocket-Version': opts.protocolVersion,
+ 'Sec-WebSocket-Key': key,
+ Connection: 'Upgrade',
+ Upgrade: 'websocket'
+ };
+ opts.path = parsedUrl.pathname + parsedUrl.search;
+ opts.timeout = opts.handshakeTimeout;
+
+ if (opts.perMessageDeflate) {
+ perMessageDeflate = new PerMessageDeflate(
+ opts.perMessageDeflate !== true ? opts.perMessageDeflate : {},
+ false,
+ opts.maxPayload
+ );
+ opts.headers['Sec-WebSocket-Extensions'] = format({
+ [PerMessageDeflate.extensionName]: perMessageDeflate.offer()
+ });
+ }
+ if (protocols.length) {
+ for (const protocol of protocols) {
+ if (
+ typeof protocol !== 'string' ||
+ !subprotocolRegex.test(protocol) ||
+ protocolSet.has(protocol)
+ ) {
+ throw new SyntaxError(
+ 'An invalid or duplicated subprotocol was specified'
+ );
+ }
+
+ protocolSet.add(protocol);
+ }
+
+ opts.headers['Sec-WebSocket-Protocol'] = protocols.join(',');
+ }
+ if (opts.origin) {
+ if (opts.protocolVersion < 13) {
+ opts.headers['Sec-WebSocket-Origin'] = opts.origin;
+ } else {
+ opts.headers.Origin = opts.origin;
+ }
+ }
+ if (parsedUrl.username || parsedUrl.password) {
+ opts.auth = `${parsedUrl.username}:${parsedUrl.password}`;
+ }
+
+ if (isIpcUrl) {
+ const parts = opts.path.split(':');
+
+ opts.socketPath = parts[0];
+ opts.path = parts[1];
+ }
+
+ let req;
+
+ if (opts.followRedirects) {
+ if (websocket._redirects === 0) {
+ websocket._originalIpc = isIpcUrl;
+ websocket._originalSecure = isSecure;
+ websocket._originalHostOrSocketPath = isIpcUrl
+ ? opts.socketPath
+ : parsedUrl.host;
+
+ const headers = options && options.headers;
+
+ //
+ // Shallow copy the user provided options so that headers can be changed
+ // without mutating the original object.
+ //
+ options = { ...options, headers: {} };
+
+ if (headers) {
+ for (const [key, value] of Object.entries(headers)) {
+ options.headers[key.toLowerCase()] = value;
+ }
+ }
+ } else if (websocket.listenerCount('redirect') === 0) {
+ const isSameHost = isIpcUrl
+ ? websocket._originalIpc
+ ? opts.socketPath === websocket._originalHostOrSocketPath
+ : false
+ : websocket._originalIpc
+ ? false
+ : parsedUrl.host === websocket._originalHostOrSocketPath;
+
+ if (!isSameHost || (websocket._originalSecure && !isSecure)) {
+ //
+ // Match curl 7.77.0 behavior and drop the following headers. These
+ // headers are also dropped when following a redirect to a subdomain.
+ //
+ delete opts.headers.authorization;
+ delete opts.headers.cookie;
+
+ if (!isSameHost) delete opts.headers.host;
+
+ opts.auth = undefined;
+ }
+ }
+
+ //
+ // Match curl 7.77.0 behavior and make the first `Authorization` header win.
+ // If the `Authorization` header is set, then there is nothing to do as it
+ // will take precedence.
+ //
+ if (opts.auth && !options.headers.authorization) {
+ options.headers.authorization =
+ 'Basic ' + Buffer.from(opts.auth).toString('base64');
+ }
+
+ req = websocket._req = request(opts);
+
+ if (websocket._redirects) {
+ //
+ // Unlike what is done for the `'upgrade'` event, no early exit is
+ // triggered here if the user calls `websocket.close()` or
+ // `websocket.terminate()` from a listener of the `'redirect'` event. This
+ // is because the user can also call `request.destroy()` with an error
+ // before calling `websocket.close()` or `websocket.terminate()` and this
+ // would result in an error being emitted on the `request` object with no
+ // `'error'` event listeners attached.
+ //
+ websocket.emit('redirect', websocket.url, req);
+ }
+ } else {
+ req = websocket._req = request(opts);
+ }
+
+ if (opts.timeout) {
+ req.on('timeout', () => {
+ abortHandshake(websocket, req, 'Opening handshake has timed out');
+ });
+ }
+
+ req.on('error', (err) => {
+ if (req === null || req[kAborted]) return;
+
+ req = websocket._req = null;
+ emitErrorAndClose(websocket, err);
+ });
+
+ req.on('response', (res) => {
+ const location = res.headers.location;
+ const statusCode = res.statusCode;
+
+ if (
+ location &&
+ opts.followRedirects &&
+ statusCode >= 300 &&
+ statusCode < 400
+ ) {
+ if (++websocket._redirects > opts.maxRedirects) {
+ abortHandshake(websocket, req, 'Maximum redirects exceeded');
+ return;
+ }
+
+ req.abort();
+
+ let addr;
+
+ try {
+ addr = new URL(location, address);
+ } catch (e) {
+ const err = new SyntaxError(`Invalid URL: ${location}`);
+ emitErrorAndClose(websocket, err);
+ return;
+ }
+
+ initAsClient(websocket, addr, protocols, options);
+ } else if (!websocket.emit('unexpected-response', req, res)) {
+ abortHandshake(
+ websocket,
+ req,
+ `Unexpected server response: ${res.statusCode}`
+ );
+ }
+ });
+
+ req.on('upgrade', (res, socket, head) => {
+ websocket.emit('upgrade', res);
+
+ //
+ // The user may have closed the connection from a listener of the
+ // `'upgrade'` event.
+ //
+ if (websocket.readyState !== WebSocket.CONNECTING) return;
+
+ req = websocket._req = null;
+
+ if (res.headers.upgrade.toLowerCase() !== 'websocket') {
+ abortHandshake(websocket, socket, 'Invalid Upgrade header');
+ return;
+ }
+
+ const digest = createHash('sha1')
+ .update(key + GUID)
+ .digest('base64');
+
+ if (res.headers['sec-websocket-accept'] !== digest) {
+ abortHandshake(websocket, socket, 'Invalid Sec-WebSocket-Accept header');
+ return;
+ }
+
+ const serverProt = res.headers['sec-websocket-protocol'];
+ let protError;
+
+ if (serverProt !== undefined) {
+ if (!protocolSet.size) {
+ protError = 'Server sent a subprotocol but none was requested';
+ } else if (!protocolSet.has(serverProt)) {
+ protError = 'Server sent an invalid subprotocol';
+ }
+ } else if (protocolSet.size) {
+ protError = 'Server sent no subprotocol';
+ }
+
+ if (protError) {
+ abortHandshake(websocket, socket, protError);
+ return;
+ }
+
+ if (serverProt) websocket._protocol = serverProt;
+
+ const secWebSocketExtensions = res.headers['sec-websocket-extensions'];
+
+ if (secWebSocketExtensions !== undefined) {
+ if (!perMessageDeflate) {
+ const message =
+ 'Server sent a Sec-WebSocket-Extensions header but no extension ' +
+ 'was requested';
+ abortHandshake(websocket, socket, message);
+ return;
+ }
+
+ let extensions;
+
+ try {
+ extensions = parse(secWebSocketExtensions);
+ } catch (err) {
+ const message = 'Invalid Sec-WebSocket-Extensions header';
+ abortHandshake(websocket, socket, message);
+ return;
+ }
+
+ const extensionNames = Object.keys(extensions);
+
+ if (
+ extensionNames.length !== 1 ||
+ extensionNames[0] !== PerMessageDeflate.extensionName
+ ) {
+ const message = 'Server indicated an extension that was not requested';
+ abortHandshake(websocket, socket, message);
+ return;
+ }
+
+ try {
+ perMessageDeflate.accept(extensions[PerMessageDeflate.extensionName]);
+ } catch (err) {
+ const message = 'Invalid Sec-WebSocket-Extensions header';
+ abortHandshake(websocket, socket, message);
+ return;
+ }
+
+ websocket._extensions[PerMessageDeflate.extensionName] =
+ perMessageDeflate;
+ }
+
+ websocket.setSocket(socket, head, {
+ generateMask: opts.generateMask,
+ maxPayload: opts.maxPayload,
+ skipUTF8Validation: opts.skipUTF8Validation
+ });
+ });
+
+ if (opts.finishRequest) {
+ opts.finishRequest(req, websocket);
+ } else {
+ req.end();
+ }
+}
+
+/**
+ * Emit the `'error'` and `'close'` events.
+ *
+ * @param {WebSocket} websocket The WebSocket instance
+ * @param {Error} The error to emit
+ * @private
+ */
+function emitErrorAndClose(websocket, err) {
+ websocket._readyState = WebSocket.CLOSING;
+ websocket.emit('error', err);
+ websocket.emitClose();
+}
+
+/**
+ * Create a `net.Socket` and initiate a connection.
+ *
+ * @param {Object} options Connection options
+ * @return {net.Socket} The newly created socket used to start the connection
+ * @private
+ */
+function netConnect(options) {
+ options.path = options.socketPath;
+ return net.connect(options);
+}
+
+/**
+ * Create a `tls.TLSSocket` and initiate a connection.
+ *
+ * @param {Object} options Connection options
+ * @return {tls.TLSSocket} The newly created socket used to start the connection
+ * @private
+ */
+function tlsConnect(options) {
+ options.path = undefined;
+
+ if (!options.servername && options.servername !== '') {
+ options.servername = net.isIP(options.host) ? '' : options.host;
+ }
+
+ return tls.connect(options);
+}
+
+/**
+ * Abort the handshake and emit an error.
+ *
+ * @param {WebSocket} websocket The WebSocket instance
+ * @param {(http.ClientRequest|net.Socket|tls.Socket)} stream The request to
+ * abort or the socket to destroy
+ * @param {String} message The error message
+ * @private
+ */
+function abortHandshake(websocket, stream, message) {
+ websocket._readyState = WebSocket.CLOSING;
+
+ const err = new Error(message);
+ Error.captureStackTrace(err, abortHandshake);
+
+ if (stream.setHeader) {
+ stream[kAborted] = true;
+ stream.abort();
+
+ if (stream.socket && !stream.socket.destroyed) {
+ //
+ // On Node.js >= 14.3.0 `request.abort()` does not destroy the socket if
+ // called after the request completed. See
+ // https://github.com/websockets/ws/issues/1869.
+ //
+ stream.socket.destroy();
+ }
+
+ process.nextTick(emitErrorAndClose, websocket, err);
+ } else {
+ stream.destroy(err);
+ stream.once('error', websocket.emit.bind(websocket, 'error'));
+ stream.once('close', websocket.emitClose.bind(websocket));
+ }
+}
+
+/**
+ * Handle cases where the `ping()`, `pong()`, or `send()` methods are called
+ * when the `readyState` attribute is `CLOSING` or `CLOSED`.
+ *
+ * @param {WebSocket} websocket The WebSocket instance
+ * @param {*} [data] The data to send
+ * @param {Function} [cb] Callback
+ * @private
+ */
+function sendAfterClose(websocket, data, cb) {
+ if (data) {
+ const length = toBuffer(data).length;
+
+ //
+ // The `_bufferedAmount` property is used only when the peer is a client and
+ // the opening handshake fails. Under these circumstances, in fact, the
+ // `setSocket()` method is not called, so the `_socket` and `_sender`
+ // properties are set to `null`.
+ //
+ if (websocket._socket) websocket._sender._bufferedBytes += length;
+ else websocket._bufferedAmount += length;
+ }
+
+ if (cb) {
+ const err = new Error(
+ `WebSocket is not open: readyState ${websocket.readyState} ` +
+ `(${readyStates[websocket.readyState]})`
+ );
+ process.nextTick(cb, err);
+ }
+}
+
+/**
+ * The listener of the `Receiver` `'conclude'` event.
+ *
+ * @param {Number} code The status code
+ * @param {Buffer} reason The reason for closing
+ * @private
+ */
+function receiverOnConclude(code, reason) {
+ const websocket = this[kWebSocket];
+
+ websocket._closeFrameReceived = true;
+ websocket._closeMessage = reason;
+ websocket._closeCode = code;
+
+ if (websocket._socket[kWebSocket] === undefined) return;
+
+ websocket._socket.removeListener('data', socketOnData);
+ process.nextTick(resume, websocket._socket);
+
+ if (code === 1005) websocket.close();
+ else websocket.close(code, reason);
+}
+
+/**
+ * The listener of the `Receiver` `'drain'` event.
+ *
+ * @private
+ */
+function receiverOnDrain() {
+ const websocket = this[kWebSocket];
+
+ if (!websocket.isPaused) websocket._socket.resume();
+}
+
+/**
+ * The listener of the `Receiver` `'error'` event.
+ *
+ * @param {(RangeError|Error)} err The emitted error
+ * @private
+ */
+function receiverOnError(err) {
+ const websocket = this[kWebSocket];
+
+ if (websocket._socket[kWebSocket] !== undefined) {
+ websocket._socket.removeListener('data', socketOnData);
+
+ //
+ // On Node.js < 14.0.0 the `'error'` event is emitted synchronously. See
+ // https://github.com/websockets/ws/issues/1940.
+ //
+ process.nextTick(resume, websocket._socket);
+
+ websocket.close(err[kStatusCode]);
+ }
+
+ websocket.emit('error', err);
+}
+
+/**
+ * The listener of the `Receiver` `'finish'` event.
+ *
+ * @private
+ */
+function receiverOnFinish() {
+ this[kWebSocket].emitClose();
+}
+
+/**
+ * The listener of the `Receiver` `'message'` event.
+ *
+ * @param {Buffer|ArrayBuffer|Buffer[])} data The message
+ * @param {Boolean} isBinary Specifies whether the message is binary or not
+ * @private
+ */
+function receiverOnMessage(data, isBinary) {
+ this[kWebSocket].emit('message', data, isBinary);
+}
+
+/**
+ * The listener of the `Receiver` `'ping'` event.
+ *
+ * @param {Buffer} data The data included in the ping frame
+ * @private
+ */
+function receiverOnPing(data) {
+ const websocket = this[kWebSocket];
+
+ websocket.pong(data, !websocket._isServer, NOOP);
+ websocket.emit('ping', data);
+}
+
+/**
+ * The listener of the `Receiver` `'pong'` event.
+ *
+ * @param {Buffer} data The data included in the pong frame
+ * @private
+ */
+function receiverOnPong(data) {
+ this[kWebSocket].emit('pong', data);
+}
+
+/**
+ * Resume a readable stream
+ *
+ * @param {Readable} stream The readable stream
+ * @private
+ */
+function resume(stream) {
+ stream.resume();
+}
+
+/**
+ * The listener of the socket `'close'` event.
+ *
+ * @private
+ */
+function socketOnClose() {
+ const websocket = this[kWebSocket];
+
+ this.removeListener('close', socketOnClose);
+ this.removeListener('data', socketOnData);
+ this.removeListener('end', socketOnEnd);
+
+ websocket._readyState = WebSocket.CLOSING;
+
+ let chunk;
+
+ //
+ // The close frame might not have been received or the `'end'` event emitted,
+ // for example, if the socket was destroyed due to an error. Ensure that the
+ // `receiver` stream is closed after writing any remaining buffered data to
+ // it. If the readable side of the socket is in flowing mode then there is no
+ // buffered data as everything has been already written and `readable.read()`
+ // will return `null`. If instead, the socket is paused, any possible buffered
+ // data will be read as a single chunk.
+ //
+ if (
+ !this._readableState.endEmitted &&
+ !websocket._closeFrameReceived &&
+ !websocket._receiver._writableState.errorEmitted &&
+ (chunk = websocket._socket.read()) !== null
+ ) {
+ websocket._receiver.write(chunk);
+ }
+
+ websocket._receiver.end();
+
+ this[kWebSocket] = undefined;
+
+ clearTimeout(websocket._closeTimer);
+
+ if (
+ websocket._receiver._writableState.finished ||
+ websocket._receiver._writableState.errorEmitted
+ ) {
+ websocket.emitClose();
+ } else {
+ websocket._receiver.on('error', receiverOnFinish);
+ websocket._receiver.on('finish', receiverOnFinish);
+ }
+}
+
+/**
+ * The listener of the socket `'data'` event.
+ *
+ * @param {Buffer} chunk A chunk of data
+ * @private
+ */
+function socketOnData(chunk) {
+ if (!this[kWebSocket]._receiver.write(chunk)) {
+ this.pause();
+ }
+}
+
+/**
+ * The listener of the socket `'end'` event.
+ *
+ * @private
+ */
+function socketOnEnd() {
+ const websocket = this[kWebSocket];
+
+ websocket._readyState = WebSocket.CLOSING;
+ websocket._receiver.end();
+ this.end();
+}
+
+/**
+ * The listener of the socket `'error'` event.
+ *
+ * @private
+ */
+function socketOnError() {
+ const websocket = this[kWebSocket];
+
+ this.removeListener('error', socketOnError);
+ this.on('error', NOOP);
+
+ if (websocket) {
+ websocket._readyState = WebSocket.CLOSING;
+ this.destroy();
+ }
+}
diff --git a/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/package.json b/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/package.json
new file mode 100644
index 0000000..107c188
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/package.json
@@ -0,0 +1,68 @@
+{
+ "name": "ws",
+ "version": "8.14.2",
+ "description": "Simple to use, blazing fast and thoroughly tested websocket client and server for Node.js",
+ "keywords": [
+ "HyBi",
+ "Push",
+ "RFC-6455",
+ "WebSocket",
+ "WebSockets",
+ "real-time"
+ ],
+ "homepage": "https://github.com/websockets/ws",
+ "bugs": "https://github.com/websockets/ws/issues",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/websockets/ws.git"
+ },
+ "author": "Einar Otto Stangvik <einaros@gmail.com> (http://2x.io)",
+ "license": "MIT",
+ "main": "index.js",
+ "exports": {
+ ".": {
+ "browser": "./browser.js",
+ "import": "./wrapper.mjs",
+ "require": "./index.js"
+ },
+ "./package.json": "./package.json"
+ },
+ "browser": "browser.js",
+ "engines": {
+ "node": ">=10.0.0"
+ },
+ "files": [
+ "browser.js",
+ "index.js",
+ "lib/*.js",
+ "wrapper.mjs"
+ ],
+ "scripts": {
+ "test": "nyc --reporter=lcov --reporter=text mocha --throw-deprecation test/*.test.js",
+ "integration": "mocha --throw-deprecation test/*.integration.js",
+ "lint": "eslint --ignore-path .gitignore . && prettier --check --ignore-path .gitignore \"**/*.{json,md,yaml,yml}\""
+ },
+ "peerDependencies": {
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": ">=5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
+ },
+ "devDependencies": {
+ "benchmark": "^2.1.4",
+ "bufferutil": "^4.0.1",
+ "eslint": "^8.0.0",
+ "eslint-config-prettier": "^9.0.0",
+ "eslint-plugin-prettier": "^5.0.0",
+ "mocha": "^8.4.0",
+ "nyc": "^15.0.0",
+ "prettier": "^3.0.0",
+ "utf-8-validate": "^6.0.0"
+ }
+}
diff --git a/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/wrapper.mjs b/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/wrapper.mjs
new file mode 100644
index 0000000..7245ad1
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/node_modules/ws/wrapper.mjs
@@ -0,0 +1,8 @@
+import createWebSocketStream from './lib/stream.js';
+import Receiver from './lib/receiver.js';
+import Sender from './lib/sender.js';
+import WebSocket from './lib/websocket.js';
+import WebSocketServer from './lib/websocket-server.js';
+
+export { createWebSocketStream, Receiver, Sender, WebSocket, WebSocketServer };
+export default WebSocket;
diff --git a/desktop/node_modules/@xhayper/discord-rpc/package.json b/desktop/node_modules/@xhayper/discord-rpc/package.json
new file mode 100644
index 0000000..d39f7a9
--- /dev/null
+++ b/desktop/node_modules/@xhayper/discord-rpc/package.json
@@ -0,0 +1,40 @@
+{
+ "name": "@xhayper/discord-rpc",
+ "version": "1.0.24",
+ "description": "a fork of discordjs/RPC",
+ "main": "dist/index.js",
+ "author": "xhayper",
+ "license": "ISC",
+ "types": "dist/index.d.ts",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/xhayper/discord-rpc.git"
+ },
+ "keywords": [
+ "typescript",
+ "discord",
+ "ipc",
+ "rpc",
+ "rich-presence",
+ "discord-rpc",
+ "discord-ipc"
+ ],
+ "scripts": {
+ "build": "del-cli -f dist && tsc",
+ "prepack": "pnpm run build"
+ },
+ "dependencies": {
+ "axios": "^1.5.1",
+ "ws": "^8.14.2"
+ },
+ "devDependencies": {
+ "@types/node": "^14.*",
+ "@types/ws": "^8.5.6",
+ "discord-api-types": "^0.37.60",
+ "del-cli": "^5.1.0"
+ },
+ "engines": {
+ "node": ">=14.18.0"
+ },
+ "packageManager": "pnpm@8.9.0"
+}