From c9f0f740609b93ff225331d0a6d20f0ac8937f22 Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 12 Nov 2021 17:51:02 +0000 Subject: [PATCH] chore(housekeeping): format code using prettier --- .prettierrc.js | 2 - README.md | 20 +- package.json | 5 +- src/Client.ts | 287 ++++--- src/api/permissions.ts | 24 +- src/api/routes.ts | 1384 ++++++++++++++++---------------- src/config.ts | 6 +- src/index.ts | 10 +- src/maps/Bots.ts | 54 +- src/maps/Channels.ts | 283 +++++-- src/maps/Collection.ts | 5 +- src/maps/Members.ts | 44 +- src/maps/Messages.ts | 111 ++- src/maps/Servers.ts | 158 +++- src/maps/Users.ts | 123 ++- src/tester.ts | 85 +- src/websocket/client.ts | 293 ++++--- src/websocket/notifications.ts | 141 ++-- yarn.lock | 385 +-------- 19 files changed, 1785 insertions(+), 1635 deletions(-) diff --git a/.prettierrc.js b/.prettierrc.js index 6e632161..b2268242 100644 --- a/.prettierrc.js +++ b/.prettierrc.js @@ -2,6 +2,4 @@ module.exports = { tabWidth: 4, trailingComma: "all", jsxBracketSameLine: true, - importOrder: ["/(api)", "/(maps)", "/(util)", "/(websocket)", "^[./]"], - importOrderSeparation: true, }; diff --git a/README.md b/README.md index 3e85e9a1..967136b4 100644 --- a/README.md +++ b/README.md @@ -9,25 +9,17 @@ ```typescript let client = new Client(); -client.on('ready', async () => - console.info(`Logged in as ${client.user!.username}!`) +client.on("ready", async () => + console.info(`Logged in as ${client.user!.username}!`), ); -client.on('message', async message => { - if (message.content === 'sus') { - message.channel!.sendMessage('sus!'); +client.on("message", async (message) => { + if (message.content === "sus") { + message.channel!.sendMessage("sus!"); } }); -// To login as a bot: -client.loginBot('..'); - -// To login as a user, -// either create a new session: -client.login({ email: '..', password: '..' }); - -// Or use an existing session: -client.useExistingSession({ token: '..' }); +client.loginBot(".."); ``` ## MobX diff --git a/package.json b/package.json index 738b355e..170eae82 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "revolt.js", - "version": "5.1.0-alpha.8", + "version": "5.1.0-alpha.9", "main": "dist/index.js", "repository": "https://github.com/revoltchat/revolt.js", "author": "Paul Makles ", @@ -18,7 +18,6 @@ "ws": "^8.2.2" }, "devDependencies": { - "@trivago/prettier-plugin-sort-imports": "^3.1.1", "@types/events": "^3.0.0", "@types/lodash": "^4.14.168", "@types/lodash.defaultsdeep": "^4.6.6", @@ -38,7 +37,7 @@ "rimraf": "^3.0.2", "tsc-watch": "^4.1.0", "typedoc": "^0.21.4", - "typescript": "^4.2.3" + "typescript": "^4.4.4" }, "eslintConfig": { "parser": "@typescript-eslint/parser", diff --git a/src/Client.ts b/src/Client.ts index 496b4c45..99dbe7ae 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -1,66 +1,75 @@ -import Axios, { AxiosInstance, AxiosRequestConfig } from 'axios'; -import defaultsDeep from 'lodash.defaultsdeep'; -import { EventEmitter } from 'eventemitter3'; +import Axios, { AxiosInstance, AxiosRequestConfig } from "axios"; +import { EventEmitter } from "eventemitter3"; +import defaultsDeep from "lodash.defaultsdeep"; +import { makeObservable, observable } from "mobx"; +import type { Session } from "revolt-api/types/Auth"; +import type { SizeOptions } from "revolt-api/types/Autumn"; +import type { RevoltConfiguration } from "revolt-api/types/Core"; +import { MemberCompositeKey, Role } from "revolt-api/types/Servers"; -import { WebSocketClient } from './websocket/client'; -import { Route, RoutePath, RouteMethod } from './api/routes'; -import { ClientboundNotification } from './websocket/notifications'; +import { Route, RoutePath, RouteMethod } from "./api/routes"; -import type { RevoltConfiguration } from 'revolt-api/types/Core'; -import type { SizeOptions } from 'revolt-api/types/Autumn'; -import type { Session } from 'revolt-api/types/Auth'; +import Bots from "./maps/Bots"; +import Channels, { Channel } from "./maps/Channels"; +import Members, { Member } from "./maps/Members"; +import Messages, { Message } from "./maps/Messages"; +import Servers, { Server } from "./maps/Servers"; +import Users, { User } from "./maps/Users"; -import Users, { User } from './maps/Users'; -import Channels, { Channel } from './maps/Channels'; -import Servers, { Server } from './maps/Servers'; -import Members, { Member } from './maps/Members'; -import Messages, { Message } from './maps/Messages'; -import Bots from './maps/Bots'; +import { WebSocketClient } from "./websocket/client"; +import { ClientboundNotification } from "./websocket/notifications"; -import { makeObservable, observable } from 'mobx'; -import { defaultConfig } from './config'; -import { MemberCompositeKey, Role } from 'revolt-api/types/Servers'; +import { defaultConfig } from "./config"; /** * Client options object */ export interface ClientOptions { - apiURL: string - debug: boolean - cache: boolean + apiURL: string; + debug: boolean; + cache: boolean; - heartbeat: number - autoReconnect: boolean + heartbeat: number; + autoReconnect: boolean; - ackRateLimiter: boolean + ackRateLimiter: boolean; } export declare interface Client { - on(event: 'connected', listener: () => void): this; - on(event: 'connecting', listener: () => void): this; - on(event: 'dropped', listener: () => void): this; - on(event: 'ready', listener: () => void): this; - on(event: 'packet', listener: (packet: ClientboundNotification) => void): this; + on(event: "connected", listener: () => void): this; + on(event: "connecting", listener: () => void): this; + on(event: "dropped", listener: () => void): this; + on(event: "ready", listener: () => void): this; + on( + event: "packet", + listener: (packet: ClientboundNotification) => void, + ): this; - on(event: 'message', listener: (message: Message) => void): this; - on(event: 'message/update', listener: (message: Message) => void): this; - on(event: 'message/delete', listener: (id: string) => void): this; + on(event: "message", listener: (message: Message) => void): this; + on(event: "message/update", listener: (message: Message) => void): this; + on(event: "message/delete", listener: (id: string) => void): this; - on(event: 'channel/create', listener: (channel: Channel) => void): this; - on(event: 'channel/update', listener: (channel: Channel) => void): this; - on(event: 'channel/delete', listener: (id: string) => void): this; + on(event: "channel/create", listener: (channel: Channel) => void): this; + on(event: "channel/update", listener: (channel: Channel) => void): this; + on(event: "channel/delete", listener: (id: string) => void): this; - on(event: 'server/update', listener: (server: Server) => void): this; - on(event: 'server/delete', listener: (id: string) => void): this; + on(event: "server/update", listener: (server: Server) => void): this; + on(event: "server/delete", listener: (id: string) => void): this; - on(event: 'role/update', listener: (roleId: string, role: Role, serverId: string) => void): this; - on(event: 'role/delete', listener: (id: string, serverId: string) => void): this; + on( + event: "role/update", + listener: (roleId: string, role: Role, serverId: string) => void, + ): this; + on( + event: "role/delete", + listener: (id: string, serverId: string) => void, + ): this; - on(event: 'member/join', listener: (member: Member) => void): this; - on(event: 'member/update', listener: (member: Member) => void): this; - on(event: 'member/leave', listener: (id: MemberCompositeKey) => void): this; + on(event: "member/join", listener: (member: Member) => void): this; + on(event: "member/update", listener: (member: Member) => void): this; + on(event: "member/leave", listener: (id: MemberCompositeKey) => void): this; - on(event: 'user/relationship', listener: (user: User) => void): this; + on(event: "user/relationship", listener: (user: User) => void): this; } /** @@ -73,7 +82,11 @@ export const RE_MENTIONS = /<@([A-z0-9]{26})>/g; */ export const RE_SPOILER = /!!.+!!/g; -export type FileArgs = [ options?: SizeOptions, allowAnimation?: boolean, fallback?: string ]; +export type FileArgs = [ + options?: SizeOptions, + allowAnimation?: boolean, + fallback?: string, +]; export class Client extends EventEmitter { heartbeat: number; @@ -103,15 +116,19 @@ export class Client extends EventEmitter { this.messages = new Messages(this); this.bots = new Bots(this); - makeObservable(this, { - users: observable, - channels: observable, - servers: observable, - members: observable, - messages: observable - }, { - proxy: false - }); + makeObservable( + this, + { + users: observable, + channels: observable, + servers: observable, + members: observable, + messages: observable, + }, + { + proxy: false, + }, + ); this.options = defaultsDeep(options, defaultConfig); if (this.options.cache) throw "Cache is not supported yet."; @@ -121,21 +138,29 @@ export class Client extends EventEmitter { this.heartbeat = this.options.heartbeat; if (options.debug) { - this.Axios.interceptors.request.use(request => { - console.debug('[<]', request.method?.toUpperCase(), request.url); - return request - }) - - this.Axios.interceptors.response.use(response => { - console.debug('[>] (' + response.status + ':', response.statusText + ')', JSON.stringify(response.data)); - return response - }) + this.Axios.interceptors.request.use((request) => { + console.debug( + "[<]", + request.method?.toUpperCase(), + request.url, + ); + return request; + }); + + this.Axios.interceptors.response.use((response) => { + console.debug( + "[>] (" + response.status + ":", + response.statusText + ")", + JSON.stringify(response.data), + ); + return response; + }); } - this.on('message', async message => { + this.on("message", async (message) => { let channel = message.channel; if (!channel) return; - if (channel.channel_type === 'DirectMessage') { + if (channel.channel_type === "DirectMessage") { channel.active = true; } @@ -162,9 +187,16 @@ export class Client extends EventEmitter { /** * ? Axios request wrapper. */ - - req(method: M, url: T): Promise["response"]>; - req(method: M, url: T, data: Route["data"]): Promise["response"]>; + + req( + method: M, + url: T, + ): Promise["response"]>; + req( + method: M, + url: T, + data: Route["data"], + ): Promise["response"]>; /** * Perform an HTTP request using Axios, specifying a route data object. @@ -173,11 +205,15 @@ export class Client extends EventEmitter { * @param data Route data object * @returns The response body */ - async req(method: M, url: T, data?: Route["data"]): Promise["response"]> { + async req( + method: M, + url: T, + data?: Route["data"], + ): Promise["response"]> { let res = await this.Axios.request({ method, data, - url + url, }); return res.data; @@ -190,7 +226,11 @@ export class Client extends EventEmitter { * @param data Axios request config object * @returns The response body */ - async request(method: M, url: T, data: AxiosRequestConfig): Promise["response"]> { + async request( + method: M, + url: T, + data: AxiosRequestConfig, + ): Promise["response"]> { let res = await this.Axios.request({ ...data, method, @@ -203,35 +243,36 @@ export class Client extends EventEmitter { /** * ? Authentication and connection. */ - + /** * Fetches the configuration of the server. - * + * * @remarks * Unlike `fetchConfiguration`, this function also fetches the * configuration if it has already been fetched before. */ async connect() { - this.configuration = await this.req('GET', '/'); + this.configuration = await this.req("GET", "/"); } /** * Fetches the configuration of the server if it has not been already fetched. */ async fetchConfiguration() { - if (!this.configuration) - await this.connect(); + if (!this.configuration) await this.connect(); } - private $generateHeaders(session: Session | string | undefined = this.session) { - if (typeof session === 'string') { + private $generateHeaders( + session: Session | string | undefined = this.session, + ) { + if (typeof session === "string") { return { - 'x-bot-token': session - } + "x-bot-token": session, + }; } else { return { - 'x-session-token': session?.token - } + "x-session-token": session?.token, + }; } } @@ -240,10 +281,10 @@ export class Client extends EventEmitter { * @param details Login data object * @returns An onboarding function if onboarding is required, undefined otherwise */ - async login(details: Route<'POST', '/auth/session/login'>["data"]) { + async login(details: Route<"POST", "/auth/session/login">["data"]) { await this.fetchConfiguration(); - this.session = await this.req('POST', '/auth/session/login', details); - + this.session = await this.req("POST", "/auth/session/login", details); + return await this.$connect(); } @@ -272,7 +313,7 @@ export class Client extends EventEmitter { // Check onboarding status and connect to notifications service. private async $connect() { this.Axios.defaults.headers = this.$generateHeaders(); - let { onboarding } = await this.req('GET', '/onboard/hello'); + let { onboarding } = await this.req("GET", "/onboard/hello"); if (onboarding) { return (username: string, loginAfterSuccess?: boolean) => this.completeOnboarding({ username }, loginAfterSuccess); @@ -286,8 +327,11 @@ export class Client extends EventEmitter { * @param data Onboarding data object * @param loginAfterSuccess Defines whether to automatically log in and connect after onboarding finishes */ - async completeOnboarding(data: Route<'POST', '/onboard/complete'>["data"], loginAfterSuccess?: boolean) { - await this.req('POST', '/onboard/complete', data); + async completeOnboarding( + data: Route<"POST", "/onboard/complete">["data"], + loginAfterSuccess?: boolean, + ) { + await this.req("POST", "/onboard/complete", data); if (loginAfterSuccess) { await this.$connect(); } @@ -303,7 +347,7 @@ export class Client extends EventEmitter { * @returns Invite information. */ async fetchInvite(code: string) { - return await this.req('GET', `/invites/${code}` as '/invites/id'); + return await this.req("GET", `/invites/${code}` as "/invites/id"); } /** @@ -312,7 +356,7 @@ export class Client extends EventEmitter { * @returns Data provided by invite. */ async joinInvite(code: string) { - return await this.req('POST', `/invites/${code}` as '/invites/id'); + return await this.req("POST", `/invites/${code}` as "/invites/id"); } /** @@ -320,7 +364,7 @@ export class Client extends EventEmitter { * @param code The invite code. */ async deleteInvite(code: string) { - await this.req('DELETE', `/invites/${code}` as '/invites/id'); + await this.req("DELETE", `/invites/${code}` as "/invites/id"); } /** @@ -329,7 +373,7 @@ export class Client extends EventEmitter { * @returns Key-value object of settings. */ async syncFetchSettings(keys: string[]) { - return await this.req('POST', '/sync/settings/fetch', { keys }); + return await this.req("POST", "/sync/settings/fetch", { keys }); } /** @@ -337,15 +381,23 @@ export class Client extends EventEmitter { * @param data Data to set as an object. Any non-string values will be automatically serialised. * @param timestamp Timestamp to use for the current revision. */ - async syncSetSettings(data: { [key: string]: object | string }, timestamp?: number) { + async syncSetSettings( + data: { [key: string]: object | string }, + timestamp?: number, + ) { let requestData: { [key: string]: string } = {}; for (let key of Object.keys(data)) { let value = data[key]; - requestData[key] = typeof value === 'string' ? value : JSON.stringify(value); + requestData[key] = + typeof value === "string" ? value : JSON.stringify(value); } - let query = timestamp ? `?timestamp=${timestamp}` : ''; - await this.req('POST', `/sync/settings/set${query}` as '/sync/settings/set', requestData); + let query = timestamp ? `?timestamp=${timestamp}` : ""; + await this.req( + "POST", + `/sync/settings/set${query}` as "/sync/settings/set", + requestData, + ); } /** @@ -353,7 +405,7 @@ export class Client extends EventEmitter { * @returns Array of channel unreads. */ async syncFetchUnreads() { - return await this.req('GET', '/sync/unreads'); + return await this.req("GET", "/sync/unreads"); } /** @@ -365,7 +417,7 @@ export class Client extends EventEmitter { */ async logout() { this.websocket.disconnect(); - await this.req('POST', '/auth/session/logout'); + await this.req("POST", "/auth/session/logout"); this.reset(); } @@ -390,8 +442,8 @@ export class Client extends EventEmitter { * @param data Registration data object * @returns A promise containing a registration response object */ - register(data: Route<'POST', '/auth/account/create'>["data"]) { - return this.request('POST', '/auth/account/create', { data }); + register(data: Route<"POST", "/auth/account/create">["data"]) { + return this.request("POST", "/auth/account/create", { data }); } /** @@ -401,23 +453,17 @@ export class Client extends EventEmitter { */ markdownToText(source: string) { return source - .replace( - RE_MENTIONS, - (sub: string, ...args: any[]) => { + .replace(RE_MENTIONS, (sub: string, ...args: any[]) => { const id = args[0], user = this.users.get(id); - + if (user) { return `@${user.username}`; } return sub; - } - ) - .replace( - RE_SPOILER, - '' - ); + }) + .replace(RE_SPOILER, ""); } /** @@ -427,7 +473,9 @@ export class Client extends EventEmitter { */ proxyFile(url: string): string | undefined { if (this.configuration?.features.january.enabled) { - return `${this.configuration.features.january.url}/proxy?url=${encodeURIComponent(url)}`; + return `${ + this.configuration.features.january.url + }/proxy?url=${encodeURIComponent(url)}`; } } @@ -439,8 +487,11 @@ export class Client extends EventEmitter { * @param fallback Fallback URL * @returns Generated URL or nothing */ - generateFileURL(attachment?: { tag: string, _id: string, content_type?: string }, ...args: FileArgs) { - const [ options, allowAnimation, fallback ] = args; + generateFileURL( + attachment?: { tag: string; _id: string; content_type?: string }, + ...args: FileArgs + ) { + const [options, allowAnimation, fallback] = args; let autumn = this.configuration?.features.autumn; if (!autumn?.enabled) return fallback; @@ -448,13 +499,17 @@ export class Client extends EventEmitter { let { tag, _id, content_type } = attachment; - let query = ''; + let query = ""; if (options) { - if (!allowAnimation || content_type !== 'image/gif') { - query = '?' + Object.keys(options).map(k => `${k}=${(options as any)[k]}`).join('&'); + if (!allowAnimation || content_type !== "image/gif") { + query = + "?" + + Object.keys(options) + .map((k) => `${k}=${(options as any)[k]}`) + .join("&"); } } return `${autumn.url}/${tag}/${_id}${query}`; } -} \ No newline at end of file +} diff --git a/src/api/permissions.ts b/src/api/permissions.ts index 624260b5..49768d9c 100644 --- a/src/api/permissions.ts +++ b/src/api/permissions.ts @@ -3,7 +3,7 @@ export const UserPermission = { ViewProfile: 1 << 1, SendMessage: 1 << 2, Invite: 1 << 3, -} +}; export const ChannelPermission = { View: 1 << 0, @@ -15,7 +15,7 @@ export const ChannelPermission = { EmbedLinks: 1 << 6, UploadFiles: 1 << 7, Masquerade: 1 << 8, -} +}; export const ServerPermission = { View: 1 << 0, @@ -28,16 +28,16 @@ export const ServerPermission = { ManageNicknames: 1 << 13, ChangeAvatar: 1 << 14, RemoveAvatars: 1 << 15, -} +}; -export const U32_MAX = 2**32 - 1; // 4294967295 +export const U32_MAX = 2 ** 32 - 1; // 4294967295 export const DEFAULT_PERMISSION_DM = - ChannelPermission.View - + ChannelPermission.SendMessage - + ChannelPermission.ManageChannel - + ChannelPermission.VoiceCall - + ChannelPermission.InviteOthers - + ChannelPermission.EmbedLinks - + ChannelPermission.UploadFiles - + ChannelPermission.Masquerade; + ChannelPermission.View + + ChannelPermission.SendMessage + + ChannelPermission.ManageChannel + + ChannelPermission.VoiceCall + + ChannelPermission.InviteOthers + + ChannelPermission.EmbedLinks + + ChannelPermission.UploadFiles + + ChannelPermission.Masquerade; diff --git a/src/api/routes.ts b/src/api/routes.ts index 6e731007..4aa62365 100644 --- a/src/api/routes.ts +++ b/src/api/routes.ts @@ -1,814 +1,844 @@ -import type { Bot, PublicBot } from 'revolt-api/types/Bots'; -import type { RevoltConfiguration } from 'revolt-api/types/Core'; -import type { UserSettings, ChannelUnread } from 'revolt-api/types/Sync'; -import type { RetrievedInvite, ServerInvite } from 'revolt-api/types/Invites' -import type { Profile, Relationship, RelationshipOnly, Status, User } from 'revolt-api/types/Users'; -import type { Ban, Category, Member, PermissionTuple, Server, SystemMessageChannels } from 'revolt-api/types/Servers'; -import type { Channel, DirectMessageChannel, GroupChannel, Message, TextChannel, VoiceChannel } from 'revolt-api/types/Channels'; -import { Account, SessionInfo } from 'revolt-api/types/Auth'; +import { Account, SessionInfo } from "revolt-api/types/Auth"; +import type { Bot, PublicBot } from "revolt-api/types/Bots"; +import type { + Channel, + DirectMessageChannel, + GroupChannel, + Message, + TextChannel, + VoiceChannel, +} from "revolt-api/types/Channels"; +import type { RevoltConfiguration } from "revolt-api/types/Core"; +import type { RetrievedInvite, ServerInvite } from "revolt-api/types/Invites"; +import type { + Ban, + Category, + Member, + PermissionTuple, + Server, + SystemMessageChannels, +} from "revolt-api/types/Servers"; +import type { UserSettings, ChannelUnread } from "revolt-api/types/Sync"; +import type { + Profile, + Relationship, + RelationshipOnly, + Status, + User, +} from "revolt-api/types/Users"; -export type RemoveUserField = 'ProfileContent' | 'ProfileBackground' | 'StatusText' | 'Avatar'; -export type RemoveChannelField = 'Icon' | 'Description'; -export type RemoveServerField = 'Icon' | 'Banner' | 'Description'; -export type RemoveMemberField = 'Nickname' | 'Avatar'; -export type RemoveRoleField = 'Colour'; +export type RemoveUserField = + | "ProfileContent" + | "ProfileBackground" + | "StatusText" + | "Avatar"; +export type RemoveChannelField = "Icon" | "Description"; +export type RemoveServerField = "Icon" | "Banner" | "Description"; +export type RemoveMemberField = "Nickname" | "Avatar"; +export type RemoveRoleField = "Colour"; -type Id = 'id'; +type Id = "id"; type Routes = /** * Core */ | { - // Query Revolt node. - method: 'GET', - route: `/`, - data: undefined, - response: RevoltConfiguration - } + // Query Revolt node. + method: "GET"; + route: `/`; + data: undefined; + response: RevoltConfiguration; + } /** * Auth */ | { - method: 'GET', - route: `/auth/account`, - data: undefined, - response: Account, - } + method: "GET"; + route: `/auth/account`; + data: undefined; + response: Account; + } | { - method: 'POST', - route: `/auth/account/create`, - data: { - email: string, - password: string, - invite?: string, - captcha?: string - }, - response: undefined - } + method: "POST"; + route: `/auth/account/create`; + data: { + email: string; + password: string; + invite?: string; + captcha?: string; + }; + response: undefined; + } | { - method: 'POST', - route: `/auth/account/reverify`, - data: { - email: string, - captcha?: string - }, - response: undefined - } + method: "POST"; + route: `/auth/account/reverify`; + data: { + email: string; + captcha?: string; + }; + response: undefined; + } | { - method: 'POST', - route: `/auth/account/verify/:code`, - data: undefined, - response: undefined - } + method: "POST"; + route: `/auth/account/verify/:code`; + data: undefined; + response: undefined; + } | { - method: 'POST', - route: `/auth/account/reset_password`, - data: { - email: string, - captcha?: string - }, - response: undefined - } + method: "POST"; + route: `/auth/account/reset_password`; + data: { + email: string; + captcha?: string; + }; + response: undefined; + } | { - method: 'PATCH', - route: `/auth/account/reset_password`, - data: { - password: string, - token: string - }, - response: undefined - } + method: "PATCH"; + route: `/auth/account/reset_password`; + data: { + password: string; + token: string; + }; + response: undefined; + } | { - method: 'PATCH', - route: `/auth/account/change/password`, - data: { - password: string, - current_password: string - }, - response: undefined - } + method: "PATCH"; + route: `/auth/account/change/password`; + data: { + password: string; + current_password: string; + }; + response: undefined; + } | { - method: 'PATCH', - route: `/auth/account/change/email`, - data: { - email: string, - current_password: string - }, - response: undefined - } + method: "PATCH"; + route: `/auth/account/change/email`; + data: { + email: string; + current_password: string; + }; + response: undefined; + } | { - method: 'POST', - route: `/auth/session/login`, - data: { - email: string, - password?: string, - challenge?: string, - friendly_name?: string, - captcha?: string - }, - response: undefined - } + method: "POST"; + route: `/auth/session/login`; + data: { + email: string; + password?: string; + challenge?: string; + friendly_name?: string; + captcha?: string; + }; + response: undefined; + } | { - method: 'POST', - route: `/auth/session/logout`, - data: undefined, - response: undefined - } + method: "POST"; + route: `/auth/session/logout`; + data: undefined; + response: undefined; + } | { - method: 'PATCH', - route: `/auth/session/${Id}`, - data: { - friendly_name: string - }, - response: undefined - } + method: "PATCH"; + route: `/auth/session/${Id}`; + data: { + friendly_name: string; + }; + response: undefined; + } | { - method: 'DELETE', - route: `/auth/session/${Id}`, - data: undefined, - response: undefined - } + method: "DELETE"; + route: `/auth/session/${Id}`; + data: undefined; + response: undefined; + } | { - method: 'GET', - route: `/auth/session/all`, - data: undefined, - response: SessionInfo[] - } + method: "GET"; + route: `/auth/session/all`; + data: undefined; + response: SessionInfo[]; + } | { - method: 'DELETE', - route: `/auth/session/all`, - data: undefined, - response: undefined - } + method: "DELETE"; + route: `/auth/session/all`; + data: undefined; + response: undefined; + } /** * Onboarding */ | { - // Ask server for user status. - method: 'GET', - route: `/onboard/hello`, - data: undefined, - response: { - onboarding: boolean, - id?: string - } - } + // Ask server for user status. + method: "GET"; + route: `/onboard/hello`; + data: undefined; + response: { + onboarding: boolean; + id?: string; + }; + } | { - // Complete onboarding. - method: 'POST', - route: `/onboard/complete`, - data: { - username: string - }, - response: { - onboarding: boolean - } - } + // Complete onboarding. + method: "POST"; + route: `/onboard/complete`; + data: { + username: string; + }; + response: { + onboarding: boolean; + }; + } /** * Users */ | { - // Retrieve a user's information. - method: 'GET', - route: `/users/${Id}`, - data: undefined, - response: User - } + // Retrieve a user's information. + method: "GET"; + route: `/users/${Id}`; + data: undefined; + response: User; + } | { - // Edit user. - method: 'PATCH', - route: `/users/${Id}`, - data: { - status?: Status, - profile?: { - content?: string, - background?: string - }, - avatar?: string, - remove?: RemoveUserField - }, - response: undefined - } + // Edit user. + method: "PATCH"; + route: `/users/${Id}`; + data: { + status?: Status; + profile?: { + content?: string; + background?: string; + }; + avatar?: string; + remove?: RemoveUserField; + }; + response: undefined; + } | { - // Change username. - method: 'PATCH', - route: `/users/${Id}/username`, - data: { - username: string, - password: string - }, - response: undefined - } + // Change username. + method: "PATCH"; + route: `/users/${Id}/username`; + data: { + username: string; + password: string; + }; + response: undefined; + } | { - // Retrieve a user's profile. - method: 'GET', - route: `/users/${Id}/profile`, - data: undefined, - response: Profile - } + // Retrieve a user's profile. + method: "GET"; + route: `/users/${Id}/profile`; + data: undefined; + response: Profile; + } | { - // Fetch all your DM conversations. - method: 'GET', - route: `/users/dms`, - data: undefined, - response: (DirectMessageChannel | GroupChannel)[] - } + // Fetch all your DM conversations. + method: "GET"; + route: `/users/dms`; + data: undefined; + response: (DirectMessageChannel | GroupChannel)[]; + } | { - // Open a DM with another user. - method: 'GET', - route: `/users/${Id}/dm`, - data: undefined, - response: DirectMessageChannel - } + // Open a DM with another user. + method: "GET"; + route: `/users/${Id}/dm`; + data: undefined; + response: DirectMessageChannel; + } | { - // Fetch all of your relationships with other users. - method: 'GET', - route: `/users/relationships`, - data: undefined, - response: Relationship[] - } + // Fetch all of your relationships with other users. + method: "GET"; + route: `/users/relationships`; + data: undefined; + response: Relationship[]; + } | { - // Fetch your relationship with another other user. - method: 'GET', - route: `/users/${Id}/relationship`, - data: undefined, - response: RelationshipOnly - } + // Fetch your relationship with another other user. + method: "GET"; + route: `/users/${Id}/relationship`; + data: undefined; + response: RelationshipOnly; + } | { - // Fetch your mutual relationships with another user. - method: 'GET', - route: `/users/${Id}/mutual`, - data: undefined, - response: { - users: string[], - servers: string[] - } - } + // Fetch your mutual relationships with another user. + method: "GET"; + route: `/users/${Id}/mutual`; + data: undefined; + response: { + users: string[]; + servers: string[]; + }; + } | { - // Send a friend request / accept a friend request. - method: 'PUT', - route: `/users/${Id}/friend`, - data: undefined, - response: RelationshipOnly - } + // Send a friend request / accept a friend request. + method: "PUT"; + route: `/users/${Id}/friend`; + data: undefined; + response: RelationshipOnly; + } | { - // Delete a friend request / remove a friend. - method: 'DELETE', - route: `/users/${Id}/friend`, - data: undefined, - response: RelationshipOnly - } + // Delete a friend request / remove a friend. + method: "DELETE"; + route: `/users/${Id}/friend`; + data: undefined; + response: RelationshipOnly; + } | { - // Block a user. - method: 'PUT', - route: `/users/${Id}/block`, - data: undefined, - response: RelationshipOnly - } + // Block a user. + method: "PUT"; + route: `/users/${Id}/block`; + data: undefined; + response: RelationshipOnly; + } | { - // Unblock a user. - method: 'DELETE', - route: `/users/${Id}/block`, - data: undefined, - response: RelationshipOnly - } + // Unblock a user. + method: "DELETE"; + route: `/users/${Id}/block`; + data: undefined; + response: RelationshipOnly; + } | { - // Fetch a user's avatar. - method: 'GET', - route: `/users/${Id}/avatar`, - data: undefined, - response: any - } + // Fetch a user's avatar. + method: "GET"; + route: `/users/${Id}/avatar`; + data: undefined; + response: any; + } | { - // Fetch default avatar for user. - method: 'GET', - route: `/users/${Id}/default_avatar`, - data: undefined, - response: any - } + // Fetch default avatar for user. + method: "GET"; + route: `/users/${Id}/default_avatar`; + data: undefined; + response: any; + } /** * Channels */ | { - // Fetch a channel by ID. - method: 'GET', - route: `/channels/${Id}`, - data: undefined, - response: Channel - } + // Fetch a channel by ID. + method: "GET"; + route: `/channels/${Id}`; + data: undefined; + response: Channel; + } | { - // Fetch a channel's members by ID. - method: 'GET', - route: `/channels/${Id}/members`, - data: undefined, - response: User[] - } + // Fetch a channel's members by ID. + method: "GET"; + route: `/channels/${Id}/members`; + data: undefined; + response: User[]; + } | { - // Edit a channel. - method: 'PATCH', - route: `/channels/${Id}`, - data: { - name?: string, - description?: string, - icon?: string, - nsfw?: boolean, - remove?: RemoveChannelField - }, - response: undefined - } + // Edit a channel. + method: "PATCH"; + route: `/channels/${Id}`; + data: { + name?: string; + description?: string; + icon?: string; + nsfw?: boolean; + remove?: RemoveChannelField; + }; + response: undefined; + } | { - // Close DM channel or leave group channel. - method: 'DELETE', - route: `/channels/${Id}`, - data: undefined, - response: undefined - } + // Close DM channel or leave group channel. + method: "DELETE"; + route: `/channels/${Id}`; + data: undefined; + response: undefined; + } | { - // Create a group DM. - method: 'POST', - route: `/channels/create`, - data: { - name: string, - description?: string, - nonce: string, - users: string[] - }, - response: GroupChannel - } + // Create a group DM. + method: "POST"; + route: `/channels/create`; + data: { + name: string; + description?: string; + nonce: string; + users: string[]; + }; + response: GroupChannel; + } | { - // Create an invite to a channel. - method: 'POST', - route: `/channels/${Id}/invites`, - data: undefined, - response: { code: string } - } + // Create an invite to a channel. + method: "POST"; + route: `/channels/${Id}/invites`; + data: undefined; + response: { code: string }; + } | { - // Add member to group. - method: 'PUT', - route: `/channels/${Id}/recipients/${Id}`, - data: undefined, - response: undefined - } + // Add member to group. + method: "PUT"; + route: `/channels/${Id}/recipients/${Id}`; + data: undefined; + response: undefined; + } | { - // Remove member from group. - method: 'DELETE', - route: `/channels/${Id}/recipients/${Id}`, - data: undefined, - response: undefined - } + // Remove member from group. + method: "DELETE"; + route: `/channels/${Id}/recipients/${Id}`; + data: undefined; + response: undefined; + } | { - // Mark a channel as read at message. - method: 'PUT', - route: `/channels/${Id}/ack/${Id}`, - data: undefined, - response: undefined - } + // Mark a channel as read at message. + method: "PUT"; + route: `/channels/${Id}/ack/${Id}`; + data: undefined; + response: undefined; + } | { - // Set role permission for channel. - method: 'PUT', - route: `/channels/${Id}/permissions/${Id}`, - data: { - permissions?: number - }, - response: undefined - } + // Set role permission for channel. + method: "PUT"; + route: `/channels/${Id}/permissions/${Id}`; + data: { + permissions?: number; + }; + response: undefined; + } /** * Messaging */ | { - // Send message to channel. - method: 'POST', - route: `/channels/${Id}/messages`, - data: { - content: string, - nonce: string, - attachments?: string[], - replies?: { id: string, mention: boolean }[] - }, - response: Message - } + // Send message to channel. + method: "POST"; + route: `/channels/${Id}/messages`; + data: { + content: string; + nonce: string; + attachments?: string[]; + replies?: { id: string; mention: boolean }[]; + }; + response: Message; + } | { - // Fetch message from channel. - method: 'GET', - route: `/channels/${Id}/messages/${Id}`, - data: undefined, - response: Message - } + // Fetch message from channel. + method: "GET"; + route: `/channels/${Id}/messages/${Id}`; + data: undefined; + response: Message; + } | { - // Query messages from channel (optionally include users as well). - method: 'GET', - route: `/channels/${Id}/messages`, - data: { - limit?: number, - before?: string, - after?: string, - sort?: 'Latest' | 'Oldest', - nearby?: string, - include_users?: boolean - }, - response: Message[] | { - messages: Message[], - users: User[], - members?: Member[] - } - } + // Query messages from channel (optionally include users as well). + method: "GET"; + route: `/channels/${Id}/messages`; + data: { + limit?: number; + before?: string; + after?: string; + sort?: "Latest" | "Oldest"; + nearby?: string; + include_users?: boolean; + }; + response: + | Message[] + | { + messages: Message[]; + users: User[]; + members?: Member[]; + }; + } | { - // Search messages in a channel (optionally include users as well). - method: 'POST', - route: `/channels/${Id}/search`, - data: { - query: string, + // Search messages in a channel (optionally include users as well). + method: "POST"; + route: `/channels/${Id}/search`; + data: { + query: string; - limit?: number, - before?: string, - after?: string, - sort?: 'Relevance' | 'Latest' | 'Oldest', - include_users?: boolean - }, - response: Message[] | { - messages: Message[], - users: User[], - members?: Member[] - } - } + limit?: number; + before?: string; + after?: string; + sort?: "Relevance" | "Latest" | "Oldest"; + include_users?: boolean; + }; + response: + | Message[] + | { + messages: Message[]; + users: User[]; + members?: Member[]; + }; + } | { - // Query updated messages from channel. - method: 'POST', - route: `/channels/${Id}/messages/stale`, - data: { - ids: string[] - }, - response: { - updated: Message[], - deleted: string[] - } - } + // Query updated messages from channel. + method: "POST"; + route: `/channels/${Id}/messages/stale`; + data: { + ids: string[]; + }; + response: { + updated: Message[]; + deleted: string[]; + }; + } | { - // Edit message. - method: 'PATCH', - route: `/channels/${Id}/messages/${Id}`, - data: { - content: string - }, - response: undefined - } + // Edit message. + method: "PATCH"; + route: `/channels/${Id}/messages/${Id}`; + data: { + content: string; + }; + response: undefined; + } | { - // Delete message. - method: 'DELETE', - route: `/channels/${Id}/messages/${Id}`, - data: undefined, - response: undefined - } + // Delete message. + method: "DELETE"; + route: `/channels/${Id}/messages/${Id}`; + data: undefined; + response: undefined; + } /** * Servers */ | { - // Create a server. - method: 'POST', - route: `/servers/create`, - data: { - name: string, - nonce: string - }, - response: Server - } + // Create a server. + method: "POST"; + route: `/servers/create`; + data: { + name: string; + nonce: string; + }; + response: Server; + } | { - // Fetch a server by ID. - method: 'GET', - route: `/servers/${Id}`, - data: undefined, - response: Server - } + // Fetch a server by ID. + method: "GET"; + route: `/servers/${Id}`; + data: undefined; + response: Server; + } | { - // Delete or leave a server. - method: 'DELETE', - route: `/servers/${Id}`, - data: undefined, - response: undefined - } + // Delete or leave a server. + method: "DELETE"; + route: `/servers/${Id}`; + data: undefined; + response: undefined; + } | { - // Edit a server. - method: 'PATCH', - route: `/servers/${Id}`, - data: { - name?: string, - description?: string, - icon?: string, - banner?: string, - categories?: Category[], - system_messages?: SystemMessageChannels, - nsfw?: boolean, - remove?: RemoveServerField - }, - response: undefined - } + // Edit a server. + method: "PATCH"; + route: `/servers/${Id}`; + data: { + name?: string; + description?: string; + icon?: string; + banner?: string; + categories?: Category[]; + system_messages?: SystemMessageChannels; + nsfw?: boolean; + remove?: RemoveServerField; + }; + response: undefined; + } | { - // Mark an entire server as read. - method: 'PUT', - route: `/servers/${Id}/ack`, - data: undefined, - response: undefined - } + // Mark an entire server as read. + method: "PUT"; + route: `/servers/${Id}/ack`; + data: undefined; + response: undefined; + } | { - // Fetch a server's members - method: 'GET', - route: `/servers/${Id}/members`, - data: undefined, - response: { - members: Member[], - users: User[] - } - } + // Fetch a server's members + method: "GET"; + route: `/servers/${Id}/members`; + data: undefined; + response: { + members: Member[]; + users: User[]; + }; + } | { - // Fetch a server member by their ID - method: 'GET', - route: `/servers/${Id}/members/${Id}`, - data: undefined, - response: Member - } + // Fetch a server member by their ID + method: "GET"; + route: `/servers/${Id}/members/${Id}`; + data: undefined; + response: Member; + } | { - // Edit a server member - method: 'PATCH', - route: `/servers/${Id}/members/${Id}`, - data: { - nickname?: string, - avatar?: string, - roles?: string[], - remove?: RemoveMemberField - }, - response: undefined - } + // Edit a server member + method: "PATCH"; + route: `/servers/${Id}/members/${Id}`; + data: { + nickname?: string; + avatar?: string; + roles?: string[]; + remove?: RemoveMemberField; + }; + response: undefined; + } | { - // Kick a server member - method: 'DELETE', - route: `/servers/${Id}/members/${Id}`, - data: undefined, - response: undefined - } + // Kick a server member + method: "DELETE"; + route: `/servers/${Id}/members/${Id}`; + data: undefined; + response: undefined; + } | { - // Ban a user from the server - method: 'PUT', - route: `/servers/${Id}/bans/${Id}`, - data: { - reason?: string - }, - response: undefined - } + // Ban a user from the server + method: "PUT"; + route: `/servers/${Id}/bans/${Id}`; + data: { + reason?: string; + }; + response: undefined; + } | { - // Unban a user from the server - method: 'DELETE', - route: `/servers/${Id}/bans/${Id}`, - data: undefined, - response: undefined - } + // Unban a user from the server + method: "DELETE"; + route: `/servers/${Id}/bans/${Id}`; + data: undefined; + response: undefined; + } | { - // Fetch a server's bans - method: 'GET', - route: `/servers/${Id}/bans`, - data: undefined, - response: { - users: Pick[], - bans: Ban[] - } - } + // Fetch a server's bans + method: "GET"; + route: `/servers/${Id}/bans`; + data: undefined; + response: { + users: Pick[]; + bans: Ban[]; + }; + } | { - // Create a new server channel - method: 'POST', - route: `/servers/${Id}/channels`, - data: { - type?: 'Text' | 'Voice', - name: string, - description?: string, - nonce: string - }, - response: TextChannel | VoiceChannel - } + // Create a new server channel + method: "POST"; + route: `/servers/${Id}/channels`; + data: { + type?: "Text" | "Voice"; + name: string; + description?: string; + nonce: string; + }; + response: TextChannel | VoiceChannel; + } | { - // Fetch a server's invites - method: 'GET', - route: `/servers/${Id}/invites`, - data: undefined, - response: ServerInvite[] - } + // Fetch a server's invites + method: "GET"; + route: `/servers/${Id}/invites`; + data: undefined; + response: ServerInvite[]; + } | { - // Create role - method: 'POST', - route: `/servers/${Id}/roles`, - data: { - name: string - }, - response: { - id: string, - permissions: PermissionTuple - } - } + // Create role + method: "POST"; + route: `/servers/${Id}/roles`; + data: { + name: string; + }; + response: { + id: string; + permissions: PermissionTuple; + }; + } | { - // Edit a role. - method: 'PATCH', - route: `/servers/${Id}/roles/${Id}`, - data: { - name?: string, - colour?: string, - hoist?: boolean, - rank?: number, - remove?: RemoveRoleField - }, - response: undefined - } + // Edit a role. + method: "PATCH"; + route: `/servers/${Id}/roles/${Id}`; + data: { + name?: string; + colour?: string; + hoist?: boolean; + rank?: number; + remove?: RemoveRoleField; + }; + response: undefined; + } | { - // Delete role - method: 'DELETE', - route: `/servers/${Id}/roles/${Id}`, - data: undefined, - response: undefined - } + // Delete role + method: "DELETE"; + route: `/servers/${Id}/roles/${Id}`; + data: undefined; + response: undefined; + } | { - // Set role permission for server. - method: 'PUT', - route: `/servers/${Id}/permissions/${Id}`, - data: { - permissions?: { - server: number, - channel: number - } - }, - response: undefined - } + // Set role permission for server. + method: "PUT"; + route: `/servers/${Id}/permissions/${Id}`; + data: { + permissions?: { + server: number; + channel: number; + }; + }; + response: undefined; + } /** * Bots */ | { - // Create Bot - method: 'POST', - route: `/bots/create`, - data: { - name: string - }, - response: Bot - } + // Create Bot + method: "POST"; + route: `/bots/create`; + data: { + name: string; + }; + response: Bot; + } | { - // Fetch Owned Bots - method: 'GET', - route: `/bots/@me`, - data: undefined, - response: { - bots: Bot[], - users: User[] - } - } + // Fetch Owned Bots + method: "GET"; + route: `/bots/@me`; + data: undefined; + response: { + bots: Bot[]; + users: User[]; + }; + } | { - // Fetch Bot - method: 'GET', - route: `/bots/${Id}`, - data: undefined, - response: { - bot: Bot, - user: User - } - } + // Fetch Bot + method: "GET"; + route: `/bots/${Id}`; + data: undefined; + response: { + bot: Bot; + user: User; + }; + } | { - // Edit Bot - method: 'PATCH', - route: `/bots/${Id}`, - data: { - name?: string, - public?: boolean, - interactionsURL?: string, - remove?: 'InteractionsURL' - }, - response: undefined - } + // Edit Bot + method: "PATCH"; + route: `/bots/${Id}`; + data: { + name?: string; + public?: boolean; + interactionsURL?: string; + remove?: "InteractionsURL"; + }; + response: undefined; + } | { - // Delete Bot - method: 'DELETE', - route: `/bots/${Id}`, - data: undefined, - response: undefined - } + // Delete Bot + method: "DELETE"; + route: `/bots/${Id}`; + data: undefined; + response: undefined; + } | { - // Fetch Public Bot - method: 'GET', - route: `/bots/${Id}/invite`, - data: undefined, - response: PublicBot - } + // Fetch Public Bot + method: "GET"; + route: `/bots/${Id}/invite`; + data: undefined; + response: PublicBot; + } | { - // Invite Public Bot - method: 'POST', - route: `/bots/${Id}/invite`, - data: ( - { server: string } | - { group: string } - ), - response: undefined - } + // Invite Public Bot + method: "POST"; + route: `/bots/${Id}/invite`; + data: { server: string } | { group: string }; + response: undefined; + } /** * Invites */ | { - // Fetch information about an invite. - method: 'GET', - route: `/invites/${Id}`, - data: undefined, - response: RetrievedInvite - } + // Fetch information about an invite. + method: "GET"; + route: `/invites/${Id}`; + data: undefined; + response: RetrievedInvite; + } | { - // Use an invite. - method: 'POST', - route: `/invites/${Id}`, - data: undefined, - response: ( - { - type: 'Server', - channel: TextChannel, - server: Server - } - ) - } + // Use an invite. + method: "POST"; + route: `/invites/${Id}`; + data: undefined; + response: { + type: "Server"; + channel: TextChannel; + server: Server; + }; + } | { - // Delete an invite. - method: 'DELETE', - route: `/invites/${Id}`, - data: undefined, - response: undefined - } + // Delete an invite. + method: "DELETE"; + route: `/invites/${Id}`; + data: undefined; + response: undefined; + } /** * Sync */ | { - // Fetch user settings. - method: 'POST', - route: `/sync/settings/fetch`, - data: { - keys: string[] - }, - response: UserSettings - } + // Fetch user settings. + method: "POST"; + route: `/sync/settings/fetch`; + data: { + keys: string[]; + }; + response: UserSettings; + } | { - // Set user settings. - method: 'POST', - route: `/sync/settings/set`, - data: { - [key: string]: string - }, - response: undefined - } + // Set user settings. + method: "POST"; + route: `/sync/settings/set`; + data: { + [key: string]: string; + }; + response: undefined; + } | { - // Fetch unreads. - method: 'GET', - route: `/sync/unreads`, - data: undefined, - response: ChannelUnread[] - } + // Fetch unreads. + method: "GET"; + route: `/sync/unreads`; + data: undefined; + response: ChannelUnread[]; + } /** * Push API */ | { - method: 'POST', - route: `/push/subscribe`, - data: { - endpoint: string, - p256dh: string, - auth: string - }, - response: undefined - } + method: "POST"; + route: `/push/subscribe`; + data: { + endpoint: string; + p256dh: string; + auth: string; + }; + response: undefined; + } | { - method: 'POST', - route: `/push/unsubscribe`, - data: undefined, - response: undefined - } + method: "POST"; + route: `/push/unsubscribe`; + data: undefined; + response: undefined; + } /** * Voice API */ | { - // Join voice call for channel. - method: 'POST', - route: `/channels/${Id}/join_call`, - data: undefined, - response: { - token: string - } - } + // Join voice call for channel. + method: "POST"; + route: `/channels/${Id}/join_call`; + data: undefined; + response: { + token: string; + }; + }; // ? Below are Typescript typings for extracting route data from the object above. // ? https://artsy.github.io/blog/2018/11/21/conditional-types-in-typescript/ -export type RoutePath = Routes["route"] -export type RouteMethod = Routes["method"] +export type RoutePath = Routes["route"]; +export type RouteMethod = Routes["method"]; type ExcludeRouteKey = K extends "route" ? never : K; type ExcludeRouteField = { [K in ExcludeRouteKey]: A[K] }; -type ExtractRouteParameters = A extends { route: T } ? ExcludeRouteField : never; +type ExtractRouteParameters = A extends { route: T } + ? ExcludeRouteField + : never; type ExcludeMethodKey = K extends "method" ? never : K; type ExcludeMethodField = { [K in ExcludeMethodKey]: A[K] }; -type ExtractMethodParameters = A extends { method: T } ? ExcludeMethodField : never; +type ExtractMethodParameters = A extends { method: T } + ? ExcludeMethodField + : never; -export type Route = ExtractMethodParameters, M>; +export type Route< + M extends RouteMethod, + T extends RoutePath, +> = ExtractMethodParameters, M>; declare function dispatch( type: T, - args: ExtractRouteParameters -): void + args: ExtractRouteParameters, +): void; diff --git a/src/config.ts b/src/config.ts index 67c36298..7f31578e 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,11 +1,11 @@ -export const LIBRARY_VERSION = '5.1.0-alpha.7'; +export const LIBRARY_VERSION = "5.1.0-alpha.7"; export const defaultConfig = { - apiURL: 'https://api.revolt.chat', + apiURL: "https://api.revolt.chat", autoReconnect: true, heartbeat: 30, debug: false, cache: false, - + ackRateLimiter: true, }; diff --git a/src/index.ts b/src/index.ts index 1b26adfa..b0b1fa46 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,7 @@ -export * from './Client'; -export * from './config'; -export { UserPermission, ChannelPermission, ServerPermission } from './api/permissions'; +export * from "./Client"; +export * from "./config"; +export { + UserPermission, + ChannelPermission, + ServerPermission, +} from "./api/permissions"; diff --git a/src/maps/Bots.ts b/src/maps/Bots.ts index ec9c3e32..4e54cd00 100644 --- a/src/maps/Bots.ts +++ b/src/maps/Bots.ts @@ -1,6 +1,8 @@ -import { runInAction } from 'mobx'; -import { Route } from '../api/routes'; -import { Client } from '../Client'; +import { runInAction } from "mobx"; + +import { Route } from "../api/routes"; + +import { Client } from "../Client"; export default class Bots { client: Client; @@ -15,10 +17,13 @@ export default class Bots { * @returns Bot and User object */ async fetch(id: string) { - let { bot, user } = await this.client.req('GET', `/bots/${id}` as '/bots/id'); + let { bot, user } = await this.client.req( + "GET", + `/bots/${id}` as "/bots/id", + ); return { bot, - user: await this.client.users.fetch(user._id, user) + user: await this.client.users.fetch(user._id, user), }; } @@ -27,7 +32,7 @@ export default class Bots { * @param id Bot ID */ async delete(id: string) { - await this.client.req('DELETE', `/bots/${id}` as '/bots/id'); + await this.client.req("DELETE", `/bots/${id}` as "/bots/id"); } /** @@ -36,7 +41,10 @@ export default class Bots { * @returns Public Bot object */ async fetchPublic(id: string) { - return await this.client.req('GET', `/bots/${id}/invite` as '/bots/id/invite'); + return await this.client.req( + "GET", + `/bots/${id}/invite` as "/bots/id/invite", + ); } /** @@ -44,8 +52,15 @@ export default class Bots { * @param id Bot ID * @param destination The group or server to add to */ - async invite(id: string, destination: Route<'POST', '/bots/id/invite'>["data"]) { - return await this.client.req('POST', `/bots/${id}/invite` as '/bots/id/invite', destination); + async invite( + id: string, + destination: Route<"POST", "/bots/id/invite">["data"], + ) { + return await this.client.req( + "POST", + `/bots/${id}/invite` as "/bots/id/invite", + destination, + ); } /** @@ -54,13 +69,16 @@ export default class Bots { * @returns Bot and User objects */ async fetchOwned() { - const { bots, users: userObjects } = await this.client.req('GET', `/bots/@me`); + const { bots, users: userObjects } = await this.client.req( + "GET", + `/bots/@me`, + ); let users = []; for (const obj of userObjects) { users.push(await this.client.users.fetch(obj._id, obj)); } - + return { bots, users }; } @@ -69,8 +87,8 @@ export default class Bots { * @param id Bot ID * @param data Bot edit data object */ - async edit(id: string, data: Route<'PATCH', '/bots/id'>["data"]) { - await this.client.req('PATCH', `/bots/${id}` as '/bots/id', data); + async edit(id: string, data: Route<"PATCH", "/bots/id">["data"]) { + await this.client.req("PATCH", `/bots/${id}` as "/bots/id", data); if (data.name) { let user = this.client.users.get(id); @@ -86,19 +104,19 @@ export default class Bots { * Create a bot * @param data Bot creation data */ - async create(data: Route<'POST', '/bots/create'>["data"]) { - let bot = await this.client.req('POST', '/bots/create', data); + async create(data: Route<"POST", "/bots/create">["data"]) { + let bot = await this.client.req("POST", "/bots/create", data); let user = await this.client.users.fetch(bot._id, { _id: bot._id, username: data.name, bot: { - owner: this.client.user!._id - } + owner: this.client.user!._id, + }, }); return { bot, - user + user, }; } } diff --git a/src/maps/Channels.ts b/src/maps/Channels.ts index fe42325e..dbc7e568 100644 --- a/src/maps/Channels.ts +++ b/src/maps/Channels.ts @@ -1,18 +1,25 @@ -import type { Channel as ChannelI, Message as MessageI, SystemMessage } from 'revolt-api/types/Channels'; -import type { RemoveChannelField, Route } from '../api/routes'; -import type { Attachment } from 'revolt-api/types/Autumn'; -import type { Member } from 'revolt-api/types/Servers'; -import type { User } from 'revolt-api/types/Users'; +import type { + Channel as ChannelI, + Message as MessageI, +} from "revolt-api/types/Channels"; +import type { RemoveChannelField, Route } from "../api/routes"; +import type { Attachment } from "revolt-api/types/Autumn"; +import type { Member } from "revolt-api/types/Servers"; +import type { User } from "revolt-api/types/Users"; -import { action, computed, makeAutoObservable, runInAction } from 'mobx'; -import isEqual from 'lodash.isequal'; -import { decodeTime, ulid } from 'ulid'; +import { action, computed, makeAutoObservable, runInAction } from "mobx"; +import isEqual from "lodash.isequal"; +import { decodeTime, ulid } from "ulid"; -import { Nullable, toNullable } from '../util/null'; -import Collection from './Collection'; -import { Message } from './Messages'; -import { Client, FileArgs } from '..'; -import { DEFAULT_PERMISSION_DM, U32_MAX, UserPermission } from '../api/permissions'; +import { Nullable, toNullable } from "../util/null"; +import Collection from "./Collection"; +import { Message } from "./Messages"; +import { Client, FileArgs } from ".."; +import { + DEFAULT_PERMISSION_DM, + U32_MAX, + UserPermission, +} from "../api/permissions"; export class Channel { client: Client; @@ -90,7 +97,7 @@ export class Channel { * Users typing in channel. */ typing_ids: Set = new Set(); - + /** * Channel is not safe for work. * @requires `Group`, `TextChannel`, `VoiceChannel` @@ -120,7 +127,9 @@ export class Channel { * @requires `DM` */ get recipient() { - const user_id = this.recipient_ids?.find(x => this.client.user!._id !== x); + const user_id = this.recipient_ids?.find( + (x) => this.client.user!._id !== x, + ); if (!user_id) return; return this.client.users.get(user_id); @@ -133,7 +142,7 @@ export class Channel { get last_message() { const id = this.last_message_id; if (!id) return; - + return this.client.messages.get(id); } @@ -142,14 +151,16 @@ export class Channel { * @requires `Group` */ get recipients() { - return this.recipient_ids?.map(id => this.client.users.get(id)); + return this.recipient_ids?.map((id) => this.client.users.get(id)); } /** * Users typing. */ get typing() { - return Array.from(this.typing_ids).map(id => this.client.users.get(id)); + return Array.from(this.typing_ids).map((id) => + this.client.users.get(id), + ); } /** @@ -207,14 +218,15 @@ export class Channel { }); } - @action update( - data: Partial, - clear?: RemoveChannelField, - ) { + @action update(data: Partial, clear?: RemoveChannelField) { const apply = (key: string, target?: string) => { // This code has been tested. - // @ts-expect-error - if (typeof data[key] !== 'undefined' && !isEqual(this[target ?? key], data[key])) { + if ( + // @ts-expect-error + typeof data[key] !== "undefined" && + // @ts-expect-error + !isEqual(this[target ?? key], data[key]) + ) { // @ts-expect-error this[target ?? key] = data[key]; } @@ -266,7 +278,10 @@ export class Channel { * @returns An array of the channel's members. */ async fetchMembers() { - let members = await this.client.req('GET', `/channels/${this._id}/members` as '/channels/id/members'); + let members = await this.client.req( + "GET", + `/channels/${this._id}/members` as "/channels/id/members", + ); return members.map(this.client.users.createObj); } @@ -274,8 +289,12 @@ export class Channel { * Edit a channel * @param data Channel editing route data */ - async edit(data: Route<'PATCH', '/channels/id'>["data"]) { - return await this.client.req('PATCH', `/channels/${this._id}` as '/channels/id', data); + async edit(data: Route<"PATCH", "/channels/id">["data"]) { + return await this.client.req( + "PATCH", + `/channels/${this._id}` as "/channels/id", + data, + ); // ! FIXME: return $set in req } @@ -285,18 +304,26 @@ export class Channel { */ async delete(avoidReq?: boolean) { if (!avoidReq) - await this.client.req('DELETE', `/channels/${this._id}` as '/channels/id'); + await this.client.req( + "DELETE", + `/channels/${this._id}` as "/channels/id", + ); runInAction(() => { - if (this.channel_type === 'DirectMessage') { + if (this.channel_type === "DirectMessage") { this.active = true; return; } - if (this.channel_type === 'TextChannel' || this.channel_type === 'VoiceChannel') { + if ( + this.channel_type === "TextChannel" || + this.channel_type === "VoiceChannel" + ) { let server = this.server; if (server) { - server.channel_ids = server.channel_ids.filter(x => x !== this._id); + server.channel_ids = server.channel_ids.filter( + (x) => x !== this._id, + ); } } @@ -309,7 +336,10 @@ export class Channel { * @param user_id ID of the target user */ async addMember(user_id: string) { - return await this.client.req('PUT', `/channels/${this._id}/recipients/${user_id}` as '/channels/id/recipients/id'); + return await this.client.req( + "PUT", + `/channels/${this._id}/recipients/${user_id}` as "/channels/id/recipients/id", + ); } /** @@ -317,7 +347,10 @@ export class Channel { * @param user_id ID of the target user */ async removeMember(user_id: string) { - return await this.client.req('DELETE', `/channels/${this._id}/recipients/${user_id}` as '/channels/id/recipients/id'); + return await this.client.req( + "DELETE", + `/channels/${this._id}/recipients/${user_id}` as "/channels/id/recipients/id", + ); } /** @@ -325,13 +358,23 @@ export class Channel { * @param data Either the message as a string or message sending route data * @returns The message */ - async sendMessage(data: string | (Omit["data"], 'nonce'> & { nonce?: string })) { - let msg: Route<'POST', '/channels/id/messages'>["data"] = { + async sendMessage( + data: + | string + | (Omit["data"], "nonce"> & { + nonce?: string; + }), + ) { + let msg: Route<"POST", "/channels/id/messages">["data"] = { nonce: ulid(), - ...(typeof data === 'string' ? { content: data } : data) + ...(typeof data === "string" ? { content: data } : data), }; - let message = await this.client.req('POST', `/channels/${this._id}/messages` as '/channels/id/messages', msg); + let message = await this.client.req( + "POST", + `/channels/${this._id}/messages` as "/channels/id/messages", + msg, + ); return this.client.messages.createObj(message, true); } @@ -341,7 +384,10 @@ export class Channel { * @returns The message */ async fetchMessage(message_id: string) { - let message = await this.client.req('GET', `/channels/${this._id}/messages/${message_id}` as '/channels/id/messages/id'); + let message = await this.client.req( + "GET", + `/channels/${this._id}/messages/${message_id}` as "/channels/id/messages/id", + ); return this.client.messages.createObj(message); } @@ -350,8 +396,17 @@ export class Channel { * @param params Message fetching route data * @returns The messages */ - async fetchMessages(params?: Omit["data"], 'include_users'>) { - let messages = await this.client.request('GET', `/channels/${this._id}/messages` as '/channels/id/messages', { params }) as MessageI[]; + async fetchMessages( + params?: Omit< + Route<"GET", "/channels/id/messages">["data"], + "include_users" + >, + ) { + let messages = (await this.client.request( + "GET", + `/channels/${this._id}/messages` as "/channels/id/messages", + { params }, + )) as MessageI[]; return runInAction(() => messages.map(this.client.messages.createObj)); } @@ -360,15 +415,24 @@ export class Channel { * @param params Message fetching route data * @returns Object including messages and users */ - async fetchMessagesWithUsers(params?: Omit["data"], 'include_users'>) { - let data = await this.client.request('GET', `/channels/${this._id}/messages` as '/channels/id/messages', { params: { ...params, include_users: true } }) as { messages: MessageI[], users: User[], members?: Member[] }; + async fetchMessagesWithUsers( + params?: Omit< + Route<"GET", "/channels/id/messages">["data"], + "include_users" + >, + ) { + let data = (await this.client.request( + "GET", + `/channels/${this._id}/messages` as "/channels/id/messages", + { params: { ...params, include_users: true } }, + )) as { messages: MessageI[]; users: User[]; members?: Member[] }; return runInAction(() => { return { messages: data.messages.map(this.client.messages.createObj), users: data.users.map(this.client.users.createObj), - members: data.members?.map(this.client.members.createObj) - } - }) + members: data.members?.map(this.client.members.createObj), + }; + }); } /** @@ -376,8 +440,17 @@ export class Channel { * @param params Message searching route data * @returns The messages */ - async search(params: Omit["data"], 'include_users'>) { - let messages = await this.client.req('POST', `/channels/${this._id}/search` as '/channels/id/search', params) as MessageI[]; + async search( + params: Omit< + Route<"POST", "/channels/id/search">["data"], + "include_users" + >, + ) { + let messages = (await this.client.req( + "POST", + `/channels/${this._id}/search` as "/channels/id/search", + params, + )) as MessageI[]; return runInAction(() => messages.map(this.client.messages.createObj)); } @@ -386,15 +459,24 @@ export class Channel { * @param params Message searching route data * @returns The messages */ - async searchWithUsers(params: Omit["data"], 'include_users'>) { - let data = await this.client.req('POST', `/channels/${this._id}/search` as '/channels/id/search', { ...params, include_users: true }) as { messages: MessageI[], users: User[], members?: Member[] }; + async searchWithUsers( + params: Omit< + Route<"POST", "/channels/id/search">["data"], + "include_users" + >, + ) { + let data = (await this.client.req( + "POST", + `/channels/${this._id}/search` as "/channels/id/search", + { ...params, include_users: true }, + )) as { messages: MessageI[]; users: User[]; members?: Member[] }; return runInAction(() => { return { messages: data.messages.map(this.client.messages.createObj), users: data.users.map(this.client.users.createObj), - members: data.members?.map(this.client.members.createObj) - } - }) + members: data.members?.map(this.client.members.createObj), + }; + }); } /** @@ -403,13 +485,19 @@ export class Channel { * @returns The stale messages */ async fetchStale(ids: string[]) { - let data = await this.client.req('POST', `/channels/${this._id}/messages/stale` as '/channels/id/messages/stale', { ids }); + let data = await this.client.req( + "POST", + `/channels/${this._id}/messages/stale` as "/channels/id/messages/stale", + { ids }, + ); runInAction(() => { - data.deleted.forEach(id => this.client.messages.delete(id)); - data.updated.forEach(data => this.client.messages.get(data._id)?.update(data)); + data.deleted.forEach((id) => this.client.messages.delete(id)); + data.updated.forEach((data) => + this.client.messages.get(data._id)?.update(data), + ); }); - + return data; } @@ -418,7 +506,10 @@ export class Channel { * @returns Newly created invite code */ async createInvite() { - let res = await this.client.req('POST', `/channels/${this._id}/invites` as '/channels/id/invites'); + let res = await this.client.req( + "POST", + `/channels/${this._id}/invites` as "/channels/id/invites", + ); return res.code; } @@ -427,7 +518,10 @@ export class Channel { * @returns Join call response data */ async joinCall() { - return await this.client.req('POST', `/channels/${this._id}/join_call` as '/channels/id/join_call'); + return await this.client.req( + "POST", + `/channels/${this._id}/join_call` as "/channels/id/join_call", + ); } private ackTimeout?: number; @@ -439,24 +533,31 @@ export class Channel { * @param skipRateLimiter Whether to skip the internal rate limiter */ async ack(message?: Message | string, skipRateLimiter?: boolean) { - const id = (typeof message === 'string' ? message : message?._id) ?? this.last_message_id ?? ulid(); + const id = + (typeof message === "string" ? message : message?._id) ?? + this.last_message_id ?? + ulid(); const performAck = () => { delete this.ackLimit; - this.client.req('PUT', `/channels/${this._id}/ack/${id}` as '/channels/id/ack/id'); - } + this.client.req( + "PUT", + `/channels/${this._id}/ack/${id}` as "/channels/id/ack/id", + ); + }; + + if (!this.client.options.ackRateLimiter || skipRateLimiter) + return performAck(); - if (!this.client.options.ackRateLimiter || skipRateLimiter) return performAck(); - clearTimeout(this.ackTimeout); - if (this.ackLimit && + new Date() > this.ackLimit) { + if (this.ackLimit && +new Date() > this.ackLimit) { performAck(); } - + // We need to use setTimeout here for both Node.js and browser. this.ackTimeout = setTimeout(performAck, 5000) as unknown as number; - + if (!this.ackLimit) { - this.ackLimit = + new Date() + 15e3; + this.ackLimit = +new Date() + 15e3; } } @@ -465,22 +566,26 @@ export class Channel { * @param role_id Role Id, set to 'default' to affect all users * @param permissions Permission number, removes permission if unset */ - async setPermissions(role_id: string = 'default', permissions?: number) { - return await this.client.req('PUT', `/channels/${this._id}/permissions/${role_id}` as '/channels/id/permissions/id', { permissions }); + async setPermissions(role_id: string = "default", permissions?: number) { + return await this.client.req( + "PUT", + `/channels/${this._id}/permissions/${role_id}` as "/channels/id/permissions/id", + { permissions }, + ); } /** * Start typing in this channel */ startTyping() { - this.client.websocket.send({ type: 'BeginTyping', channel: this._id }); + this.client.websocket.send({ type: "BeginTyping", channel: this._id }); } /** * Stop typing in this channel */ stopTyping() { - this.client.websocket.send({ type: 'EndTyping', channel: this._id }); + this.client.websocket.send({ type: "EndTyping", channel: this._id }); } generateIconURL(...args: FileArgs) { @@ -489,8 +594,9 @@ export class Channel { @computed get permission() { switch (this.channel_type) { - case 'SavedMessages': return U32_MAX; - case 'DirectMessage': { + case "SavedMessages": + return U32_MAX; + case "DirectMessage": { let user_permissions = this.recipient?.permission || 0; if (user_permissions & UserPermission.SendMessage) { @@ -499,37 +605,38 @@ export class Channel { return 0; } } - case 'Group': { + case "Group": { if (this.owner_id === this.client.user!._id) { return DEFAULT_PERMISSION_DM; } else { return this.permissions ?? DEFAULT_PERMISSION_DM; } } - case 'TextChannel': - case 'VoiceChannel': { + case "TextChannel": + case "VoiceChannel": { let server = this.server; - if (typeof server === 'undefined') return 0; + if (typeof server === "undefined") return 0; if (server.owner === this.client.user?._id) { return U32_MAX; } else { let member = this.client.members.getKey({ user: this.client.user!._id, - server: server._id + server: server._id, }) ?? { roles: null }; if (!member) return 0; - let perm = ( - this.default_permissions ?? - server.default_permissions[1] - ) >>> 0; + let perm = + (this.default_permissions ?? + server.default_permissions[1]) >>> 0; if (member.roles) { for (let role of member.roles) { perm |= (this.role_permissions?.[role] ?? 0) >>> 0; - perm |= (server.roles?.[role].permissions[1] ?? 0) >>> 0; + perm |= + (server.roles?.[role].permissions[1] ?? 0) >>> + 0; } } @@ -559,7 +666,9 @@ export default class Channels extends Collection { */ async fetch(id: string, data?: ChannelI) { if (this.has(id)) return this.$get(id); - let res = data ?? await this.client.req('GET', `/channels/${id}` as '/channels/id'); + let res = + data ?? + (await this.client.req("GET", `/channels/${id}` as "/channels/id")); return this.createObj(res); } @@ -578,7 +687,7 @@ export default class Channels extends Collection { this.set(data._id, channel); }); - if (emit === true) this.client.emit('channel/create', channel); + if (emit === true) this.client.emit("channel/create", channel); return channel; } @@ -587,8 +696,8 @@ export default class Channels extends Collection { * @param data Group create route data * @returns The newly-created group */ - async createGroup(data: Route<'POST', '/channels/create'>["data"]) { - let group = await this.client.req('POST', `/channels/create`, data); + async createGroup(data: Route<"POST", "/channels/create">["data"]) { + let group = await this.client.req("POST", `/channels/create`, data); return (await this.fetch(group._id, group))!; } } diff --git a/src/maps/Collection.ts b/src/maps/Collection.ts index 7817e8ea..168f269c 100644 --- a/src/maps/Collection.ts +++ b/src/maps/Collection.ts @@ -1,5 +1,6 @@ -import { Client } from '../Client'; -import { ObservableMap } from 'mobx'; +import { ObservableMap } from "mobx"; + +import { Client } from "../Client"; export default class Collection extends ObservableMap { client: Client; diff --git a/src/maps/Members.ts b/src/maps/Members.ts index 886732f0..853e5573 100644 --- a/src/maps/Members.ts +++ b/src/maps/Members.ts @@ -1,13 +1,16 @@ -import type { Member as MemberI, MemberCompositeKey } from 'revolt-api/types/Servers'; -import type { RemoveMemberField, Route } from '../api/routes'; -import type { Attachment } from 'revolt-api/types/Autumn'; +import type { + Member as MemberI, + MemberCompositeKey, +} from "revolt-api/types/Servers"; +import type { RemoveMemberField, Route } from "../api/routes"; +import type { Attachment } from "revolt-api/types/Autumn"; -import { makeAutoObservable, runInAction, action, computed } from 'mobx'; -import isEqual from 'lodash.isequal'; +import { makeAutoObservable, runInAction, action, computed } from "mobx"; +import isEqual from "lodash.isequal"; -import { Nullable, toNullable } from '../util/null'; -import Collection from './Collection'; -import { Client, FileArgs } from '..'; +import { Nullable, toNullable } from "../util/null"; +import Collection from "./Collection"; +import { Client, FileArgs } from ".."; export class Member { client: Client; @@ -49,8 +52,12 @@ export class Member { @action update(data: Partial, clear?: RemoveMemberField) { const apply = (key: string) => { // This code has been tested. - // @ts-expect-error - if (typeof data[key] !== 'undefined' && !isEqual(this[key], data[key])) { + if ( + // @ts-expect-error + typeof data[key] !== "undefined" && + // @ts-expect-error + !isEqual(this[key], data[key]) + ) { // @ts-expect-error this[key] = data[key]; } @@ -75,8 +82,12 @@ export class Member { * @param data Member editing route data * @returns Server member object */ - async edit(data: Route<'PATCH', '/servers/id/members/id'>["data"]) { - return await this.client.req('PATCH', `/servers/${this._id.server}/members/${this._id.user}` as '/servers/id/members/id', data); + async edit(data: Route<"PATCH", "/servers/id/members/id">["data"]) { + return await this.client.req( + "PATCH", + `/servers/${this._id.server}/members/${this._id.user}` as "/servers/id/members/id", + data, + ); } /** @@ -84,7 +95,10 @@ export class Member { * @param user_id User ID */ async kick() { - return await this.client.req('DELETE', `/servers/${this._id.server}/members/${this._id.user}` as '/servers/id/members/id'); + return await this.client.req( + "DELETE", + `/servers/${this._id.server}/members/${this._id.user}` as "/servers/id/members/id", + ); } @computed generateAvatarURL(...args: FileArgs) { @@ -99,7 +113,7 @@ export default class Members extends Collection { } static toKey(id: MemberCompositeKey) { - return JSON.stringify(id, Object.keys(id).sort()) + return JSON.stringify(id, Object.keys(id).sort()); } hasKey(id: MemberCompositeKey) { @@ -140,7 +154,7 @@ export default class Members extends Collection { this.setKey(data._id, member); }); - if (emit === true) this.client.emit('member/join', member); + if (emit === true) this.client.emit("member/join", member); return member; } } diff --git a/src/maps/Messages.ts b/src/maps/Messages.ts index 236f4274..8c02e60f 100644 --- a/src/maps/Messages.ts +++ b/src/maps/Messages.ts @@ -1,15 +1,19 @@ -import type { Masquerade, Message as MessageI, SystemMessage } from 'revolt-api/types/Channels'; -import type { Attachment } from 'revolt-api/types/Autumn'; -import type { Embed } from 'revolt-api/types/January'; -import type { Route } from '../api/routes'; +import type { + Masquerade, + Message as MessageI, + SystemMessage, +} from "revolt-api/types/Channels"; +import type { Attachment } from "revolt-api/types/Autumn"; +import type { Embed } from "revolt-api/types/January"; +import type { Route } from "../api/routes"; -import { makeAutoObservable, runInAction, action, computed } from 'mobx'; -import isEqual from 'lodash.isequal'; +import { makeAutoObservable, runInAction, action, computed } from "mobx"; +import isEqual from "lodash.isequal"; -import { Nullable, toNullable, toNullableDate } from '../util/null'; -import Collection from './Collection'; +import { Nullable, toNullable, toNullableDate } from "../util/null"; +import Collection from "./Collection"; import { Client } from ".."; -import { decodeTime } from 'ulid'; +import { decodeTime } from "ulid"; export class Message { client: Client; @@ -37,16 +41,16 @@ export class Message { get member() { const channel = this.channel; - if (channel?.channel_type === 'TextChannel') { + if (channel?.channel_type === "TextChannel") { return this.client.members.getKey({ server: channel.server_id!, - user: this.author_id + user: this.author_id, }); } } get mentions() { - return this.mention_ids?.map(id => this.client.users.get(id)); + return this.mention_ids?.map((id) => this.client.users.get(id)); } /** @@ -64,21 +68,31 @@ export class Message { @computed get asSystemMessage() { const content = this.content; - if (typeof content === 'string') return { type: 'text', content }; + if (typeof content === "string") return { type: "text", content }; const { type } = content; const get = (id: string) => this.client.users.get(id); switch (content.type) { - case 'text': return content; - case 'user_added': return { type, user: get(content.id), by: get(content.by) }; - case 'user_remove': return { type, user: get(content.id), by: get(content.by) }; - case 'user_joined': return { type, user: get(content.id) }; - case 'user_left': return { type, user: get(content.id) }; - case 'user_kicked': return { type, user: get(content.id) }; - case 'user_banned': return { type, user: get(content.id) }; - case 'channel_renamed': return { type, name: content.name, by: get(content.by) }; - case 'channel_description_changed': return { type, by: get(content.by) }; - case 'channel_icon_changed': return { type, by: get(content.by) }; + case "text": + return content; + case "user_added": + return { type, user: get(content.id), by: get(content.by) }; + case "user_remove": + return { type, user: get(content.id), by: get(content.by) }; + case "user_joined": + return { type, user: get(content.id) }; + case "user_left": + return { type, user: get(content.id) }; + case "user_kicked": + return { type, user: get(content.id) }; + case "user_banned": + return { type, user: get(content.id) }; + case "channel_renamed": + return { type, name: content.name, by: get(content.by) }; + case "channel_description_changed": + return { type, by: get(content.by) }; + case "channel_icon_changed": + return { type, by: get(content.by) }; } } @@ -104,12 +118,24 @@ export class Message { } @action update(data: Partial) { - const apply = (key: string, target?: string, transform?: (obj: unknown) => unknown) => { + const apply = ( + key: string, + target?: string, + transform?: (obj: unknown) => unknown, + ) => { // This code has been tested. - // @ts-expect-error - if (typeof data[key] !== 'undefined' && !isEqual(this[target ?? key], data[key])) { + if ( // @ts-expect-error - this[target ?? key] = transform ? transform(data[key]) : data[key]; + typeof data[key] !== "undefined" && + // @ts-expect-error + !isEqual(this[target ?? key], data[key]) + ) { + // @ts-expect-error + this[target ?? key] = transform + ? // @ts-expect-error + transform(data[key]) + : // @ts-expect-error + data[key]; } }; @@ -124,15 +150,22 @@ export class Message { * Edit a message * @param data Message edit route data */ - async edit(data: Route<'PATCH', '/channels/id/messages/id'>["data"]) { - return await this.client.req('PATCH', `/channels/${this.channel_id}/messages/${this._id}` as '/channels/id/messages/id', data); + async edit(data: Route<"PATCH", "/channels/id/messages/id">["data"]) { + return await this.client.req( + "PATCH", + `/channels/${this.channel_id}/messages/${this._id}` as "/channels/id/messages/id", + data, + ); } /** * Delete a message */ async delete() { - return await this.client.req('DELETE', `/channels/${this.channel_id}/messages/${this._id}` as '/channels/id/messages/id'); + return await this.client.req( + "DELETE", + `/channels/${this.channel_id}/messages/${this._id}` as "/channels/id/messages/id", + ); } /** @@ -145,9 +178,19 @@ export class Message { /** * Reply to Message */ - reply(data: string | (Omit["data"], 'nonce'> & { nonce?: string }), mention = true) { - let obj = typeof data === 'string' ? { content: data } : data; - return this.channel?.sendMessage({ ...obj, replies: [{ id: this._id, mention }] }) + reply( + data: + | string + | (Omit["data"], "nonce"> & { + nonce?: string; + }), + mention = true, + ) { + let obj = typeof data === "string" ? { content: data } : data; + return this.channel?.sendMessage({ + ...obj, + replies: [{ id: this._id, mention }], + }); } } @@ -178,7 +221,7 @@ export default class Messages extends Collection { this.set(data._id, message); }); - if (emit === true) this.client.emit('message', message); + if (emit === true) this.client.emit("message", message); return message; } } diff --git a/src/maps/Servers.ts b/src/maps/Servers.ts index 0138f971..ad393102 100644 --- a/src/maps/Servers.ts +++ b/src/maps/Servers.ts @@ -1,16 +1,22 @@ -import type { Category, PermissionTuple, Role, Server as ServerI, SystemMessageChannels } from 'revolt-api/types/Servers'; -import type { RemoveServerField, Route } from '../api/routes'; -import type { Attachment } from 'revolt-api/types/Autumn'; +import type { + Category, + PermissionTuple, + Role, + Server as ServerI, + SystemMessageChannels, +} from "revolt-api/types/Servers"; +import type { RemoveServerField, Route } from "../api/routes"; +import type { Attachment } from "revolt-api/types/Autumn"; -import { makeAutoObservable, action, runInAction, computed } from 'mobx'; -import isEqual from 'lodash.isequal'; +import { makeAutoObservable, action, runInAction, computed } from "mobx"; +import isEqual from "lodash.isequal"; -import { Nullable, toNullable } from '../util/null'; -import { U32_MAX } from '../api/permissions'; -import Collection from './Collection'; -import { User } from './Users'; -import { Client, FileArgs } from '..'; -import { decodeTime } from 'ulid'; +import { Nullable, toNullable } from "../util/null"; +import { U32_MAX } from "../api/permissions"; +import Collection from "./Collection"; +import { User } from "./Users"; +import { Client, FileArgs } from ".."; +import { decodeTime } from "ulid"; export class Server { client: Client; @@ -34,7 +40,7 @@ export class Server { flags: Nullable = null; get channels() { - return this.channel_ids.map(x => this.client.channels.get(x)); + return this.channel_ids.map((x) => this.client.channels.get(x)); } /** @@ -46,7 +52,7 @@ export class Server { constructor(client: Client, data: ServerI) { this.client = client; - + this._id = data._id; this.owner = data.owner; this.name = data.name; @@ -74,8 +80,12 @@ export class Server { @action update(data: Partial, clear?: RemoveServerField) { const apply = (key: string, target?: string) => { // This code has been tested. - // @ts-expect-error - if (typeof data[key] !== 'undefined' && !isEqual(this[target ?? key], data[key])) { + if ( + // @ts-expect-error + typeof data[key] !== "undefined" && + // @ts-expect-error + !isEqual(this[target ?? key], data[key]) + ) { // @ts-expect-error this[target ?? key] = data[key]; } @@ -112,16 +122,24 @@ export class Server { * @param data Channel create route data * @returns The newly-created channel */ - async createChannel(data: Route<'POST', '/servers/id/channels'>["data"]) { - return await this.client.req('POST', `/servers/${this._id}/channels` as '/servers/id/channels', data); + async createChannel(data: Route<"POST", "/servers/id/channels">["data"]) { + return await this.client.req( + "POST", + `/servers/${this._id}/channels` as "/servers/id/channels", + data, + ); } /** * Edit a server * @param data Server editing route data */ - async edit(data: Route<'PATCH', '/servers/id'>["data"]) { - return await this.client.req('PATCH', `/servers/${this._id}` as '/servers/id', data); + async edit(data: Route<"PATCH", "/servers/id">["data"]) { + return await this.client.req( + "PATCH", + `/servers/${this._id}` as "/servers/id", + data, + ); } /** @@ -129,7 +147,10 @@ export class Server { */ async delete(avoidReq?: boolean) { if (!avoidReq) - await this.client.req('DELETE', `/servers/${this._id}` as '/servers/id'); + await this.client.req( + "DELETE", + `/servers/${this._id}` as "/servers/id", + ); runInAction(() => { this.client.servers.delete(this._id); @@ -140,15 +161,25 @@ export class Server { * Mark a server as read */ async ack() { - return await this.client.req('PUT', `/servers/${this._id}/ack` as '/servers/id/ack'); + return await this.client.req( + "PUT", + `/servers/${this._id}/ack` as "/servers/id/ack", + ); } /** * Ban user * @param user_id User ID */ - async banUser(user_id: string, data: Route<'PUT', '/servers/id/bans/id'>["data"]) { - return await this.client.req('PUT', `/servers/${this._id}/bans/${user_id}` as '/servers/id/bans/id', data); + async banUser( + user_id: string, + data: Route<"PUT", "/servers/id/bans/id">["data"], + ) { + return await this.client.req( + "PUT", + `/servers/${this._id}/bans/${user_id}` as "/servers/id/bans/id", + data, + ); } /** @@ -156,7 +187,10 @@ export class Server { * @param user_id User ID */ async unbanUser(user_id: string) { - return await this.client.req('DELETE', `/servers/${this._id}/bans/${user_id}` as '/servers/id/bans/id'); + return await this.client.req( + "DELETE", + `/servers/${this._id}/bans/${user_id}` as "/servers/id/bans/id", + ); } /** @@ -164,7 +198,10 @@ export class Server { * @returns An array of the server's invites */ async fetchInvites() { - return await this.client.req('GET', `/servers/${this._id}/invites` as '/servers/id/invites'); + return await this.client.req( + "GET", + `/servers/${this._id}/invites` as "/servers/id/invites", + ); } /** @@ -172,7 +209,10 @@ export class Server { * @returns An array of the server's bans. */ async fetchBans() { - return await this.client.req('GET', `/servers/${this._id}/bans` as '/servers/id/bans'); + return await this.client.req( + "GET", + `/servers/${this._id}/bans` as "/servers/id/bans", + ); } /** @@ -180,8 +220,15 @@ export class Server { * @param role_id Role Id, set to 'default' to affect all users * @param permissions Permission number, removes permission if unset */ - async setPermissions(role_id: string = 'default', permissions?: { server: number, channel: number }) { - return await this.client.req('PUT', `/servers/${this._id}/permissions/${role_id}` as '/servers/id/permissions/id', { permissions }); + async setPermissions( + role_id: string = "default", + permissions?: { server: number; channel: number }, + ) { + return await this.client.req( + "PUT", + `/servers/${this._id}/permissions/${role_id}` as "/servers/id/permissions/id", + { permissions }, + ); } /** @@ -189,7 +236,11 @@ export class Server { * @param name Role name */ async createRole(name: string) { - return await this.client.req('POST', `/servers/${this._id}/roles` as '/servers/id/roles', { name }); + return await this.client.req( + "POST", + `/servers/${this._id}/roles` as "/servers/id/roles", + { name }, + ); } /** @@ -197,8 +248,15 @@ export class Server { * @param role_id Role ID * @param data Role editing route data */ - async editRole(role_id: string, data: Route<'PATCH', '/servers/id/roles/id'>["data"]) { - return await this.client.req('PATCH', `/servers/${this._id}/roles/${role_id}` as '/servers/id/roles/id', data); + async editRole( + role_id: string, + data: Route<"PATCH", "/servers/id/roles/id">["data"], + ) { + return await this.client.req( + "PATCH", + `/servers/${this._id}/roles/${role_id}` as "/servers/id/roles/id", + data, + ); } /** @@ -206,7 +264,10 @@ export class Server { * @param role_id Role ID */ async deleteRole(role_id: string) { - return await this.client.req('DELETE', `/servers/${this._id}/roles/${role_id}` as '/servers/id/roles/id'); + return await this.client.req( + "DELETE", + `/servers/${this._id}/roles/${role_id}` as "/servers/id/roles/id", + ); } /** @@ -215,11 +276,17 @@ export class Server { * @returns Server member object */ async fetchMember(user: User | string) { - const user_id = typeof user === 'string' ? user : user._id; - const existing = this.client.members.getKey({ server: this._id, user: user_id }); + const user_id = typeof user === "string" ? user : user._id; + const existing = this.client.members.getKey({ + server: this._id, + user: user_id, + }); if (existing) return existing; - const member = await this.client.req('GET', `/servers/${this._id}/members/${user_id}` as '/servers/id/members/id'); + const member = await this.client.req( + "GET", + `/servers/${this._id}/members/${user_id}` as "/servers/id/members/id", + ); return this.client.members.createObj(member); } @@ -228,12 +295,15 @@ export class Server { * @returns An array of the server's members and their user objects. */ async fetchMembers() { - let data = await this.client.req('GET', `/servers/${this._id}/members` as '/servers/id/members'); + let data = await this.client.req( + "GET", + `/servers/${this._id}/members` as "/servers/id/members", + ); return runInAction(() => { return { members: data.members.map(this.client.members.createObj), - users: data.users.map(this.client.users.createObj) - } + users: data.users.map(this.client.users.createObj), + }; }); } @@ -251,7 +321,7 @@ export class Server { } else { let member = this.client.members.getKey({ user: this.client.user!._id, - server: this._id + server: this._id, }) ?? { roles: null }; if (!member) return 0; @@ -287,7 +357,9 @@ export default class Servers extends Collection { */ async fetch(id: string, data?: ServerI) { if (this.has(id)) return this.$get(id, data); - let res = data ?? await this.client.req('GET', `/servers/${id}` as '/servers/id'); + let res = + data ?? + (await this.client.req("GET", `/servers/${id}` as "/servers/id")); return runInAction(async () => { for (let channel of res.channels) { @@ -295,7 +367,7 @@ export default class Servers extends Collection { // ! FIXME: OR the WHOLE server try { await this.client.channels.fetch(channel); - // future proofing for when not + // future proofing for when not } catch (err) {} } @@ -325,8 +397,8 @@ export default class Servers extends Collection { * @param data Server create route data * @returns The newly-created server */ - async createServer(data: Route<'POST', '/servers/create'>["data"]) { - let server = await this.client.req('POST', `/servers/create`, data); + async createServer(data: Route<"POST", "/servers/create">["data"]) { + let server = await this.client.req("POST", `/servers/create`, data); return this.fetch(server._id, server); } } diff --git a/src/maps/Users.ts b/src/maps/Users.ts index a8faa4a5..ff0bc5a6 100644 --- a/src/maps/Users.ts +++ b/src/maps/Users.ts @@ -1,16 +1,20 @@ -import type { BotInformation, Status, User as UserI } from 'revolt-api/types/Users'; -import type { RemoveUserField, Route } from '../api/routes'; -import type { Attachment } from 'revolt-api/types/Autumn'; +import type { + BotInformation, + Status, + User as UserI, +} from "revolt-api/types/Users"; +import type { RemoveUserField, Route } from "../api/routes"; +import type { Attachment } from "revolt-api/types/Autumn"; -import { makeAutoObservable, action, runInAction, computed } from 'mobx'; -import isEqual from 'lodash.isequal'; +import { makeAutoObservable, action, runInAction, computed } from "mobx"; +import isEqual from "lodash.isequal"; -import { U32_MAX, UserPermission } from '../api/permissions'; -import { toNullable, Nullable } from '../util/null'; -import Collection from './Collection'; -import { Client, FileArgs } from '..'; -import _ from 'lodash'; -import { decodeTime } from 'ulid'; +import { U32_MAX, UserPermission } from "../api/permissions"; +import { toNullable, Nullable } from "../util/null"; +import Collection from "./Collection"; +import { Client, FileArgs } from ".."; +import _ from "lodash"; +import { decodeTime } from "ulid"; enum RelationshipStatus { None = "None", @@ -19,7 +23,7 @@ enum RelationshipStatus { Outgoing = "Outgoing", Incoming = "Incoming", Blocked = "Blocked", - BlockedOther = "BlockedOther" + BlockedOther = "BlockedOther", } export class User { @@ -66,13 +70,17 @@ export class User { @action update(data: Partial, clear?: RemoveUserField) { const apply = (key: string) => { // This code has been tested. - // @ts-expect-error - if (typeof data[key] !== 'undefined' && !isEqual(this[key], data[key])) { + if ( + // @ts-expect-error + typeof data[key] !== "undefined" && + // @ts-expect-error + !isEqual(this[key], data[key]) + ) { // @ts-expect-error this[key] = data[key]; - if (key === 'relationship') { - this.client.emit('user/relationship', this); + if (key === "relationship") { + this.client.emit("user/relationship", this); } } }; @@ -103,7 +111,10 @@ export class User { * @returns DM Channel */ async openDM() { - const dm = await this.client.req('GET', `/users/${this._id}/dm` as '/users/id/dm'); + const dm = await this.client.req( + "GET", + `/users/${this._id}/dm` as "/users/id/dm", + ); return (await this.client.channels.fetch(dm._id, dm))!; } @@ -111,28 +122,40 @@ export class User { * Send a friend request to a user */ async addFriend() { - await this.client.req('PUT', `/users/${this.username}/friend` as '/users/id/friend'); + await this.client.req( + "PUT", + `/users/${this.username}/friend` as "/users/id/friend", + ); } /** * Remove a user from the friend list */ async removeFriend() { - await this.client.req('DELETE', `/users/${this._id}/friend` as '/users/id/friend'); + await this.client.req( + "DELETE", + `/users/${this._id}/friend` as "/users/id/friend", + ); } /** * Block a user */ async blockUser() { - await this.client.req('PUT', `/users/${this._id}/block` as '/users/id/block'); + await this.client.req( + "PUT", + `/users/${this._id}/block` as "/users/id/block", + ); } /** * Unblock a user */ async unblockUser() { - await this.client.req('DELETE', `/users/${this._id}/block` as '/users/id/block'); + await this.client.req( + "DELETE", + `/users/${this._id}/block` as "/users/id/block", + ); } /** @@ -140,7 +163,10 @@ export class User { * @returns The profile of the user */ async fetchProfile() { - return await this.client.req('GET', `/users/${this._id}/profile` as '/users/id/profile'); + return await this.client.req( + "GET", + `/users/${this._id}/profile` as "/users/id/profile", + ); } /** @@ -148,7 +174,10 @@ export class User { * @returns The mutual connections of the current user and a target user */ async fetchMutual() { - return await this.client.req('GET', `/users/${this._id}/mutual` as '/users/id/mutual'); + return await this.client.req( + "GET", + `/users/${this._id}/mutual` as "/users/id/mutual", + ); } /** @@ -159,7 +188,10 @@ export class User { } @computed generateAvatarURL(...args: FileArgs) { - return this.client.generateFileURL(this.avatar ?? undefined, ...args) ?? this.defaultAvatarURL; + return ( + this.client.generateFileURL(this.avatar ?? undefined, ...args) ?? + this.defaultAvatarURL + ); } @computed get permission() { @@ -176,12 +208,17 @@ export class User { permissions = UserPermission.Access; } - if ([...this.client.channels.values()].find(channel => - (channel.channel_type === 'Group' || channel.channel_type === 'DirectMessage') - && channel.recipient_ids?.includes(this.client.user!._id) - ) || [...this.client.members.values()].find(member => - member._id.user === this.client.user!._id - )) { + if ( + [...this.client.channels.values()].find( + (channel) => + (channel.channel_type === "Group" || + channel.channel_type === "DirectMessage") && + channel.recipient_ids?.includes(this.client.user!._id), + ) || + [...this.client.members.values()].find( + (member) => member._id.user === this.client.user!._id, + ) + ) { permissions |= UserPermission.Access | UserPermission.ViewProfile; } @@ -193,10 +230,13 @@ export default class Users extends Collection { constructor(client: Client) { super(client); this.createObj = this.createObj.bind(this); - this.set('00000000000000000000000000', new User(client, { - _id: '00000000000000000000000000', - username: 'Revolt' - })); + this.set( + "00000000000000000000000000", + new User(client, { + _id: "00000000000000000000000000", + username: "Revolt", + }), + ); } @action $get(id: string, data?: UserI) { @@ -212,7 +252,9 @@ export default class Users extends Collection { */ async fetch(id: string, data?: UserI) { if (this.has(id)) return this.$get(id, data); - let res = data ?? await this.client.req('GET', `/users/${id}` as '/users/id'); + let res = + data ?? + (await this.client.req("GET", `/users/${id}` as "/users/id")); return this.createObj(res); } @@ -230,7 +272,7 @@ export default class Users extends Collection { this.set(data._id, user); }); - this.client.emit('user/relationship', user); + this.client.emit("user/relationship", user); return user; } @@ -238,8 +280,8 @@ export default class Users extends Collection { * Edit the current user * @param data User edit data object */ - async edit(data: Route<'PATCH', '/users/id'>["data"]) { - await this.client.req('PATCH', '/users/id', data); + async edit(data: Route<"PATCH", "/users/id">["data"]) { + await this.client.req("PATCH", "/users/id", data); } /** @@ -248,6 +290,9 @@ export default class Users extends Collection { * @param password Current password */ async changeUsername(username: string, password: string) { - return await this.client.req('PATCH', '/users/id/username', { username, password }); + return await this.client.req("PATCH", "/users/id/username", { + username, + password, + }); } } diff --git a/src/tester.ts b/src/tester.ts index 03304514..e80be94e 100644 --- a/src/tester.ts +++ b/src/tester.ts @@ -1,5 +1,7 @@ -import { config } from 'dotenv'; -import { Client } from '.'; +import { config } from "dotenv"; + +import { Client } from "."; + config(); // To run this example, you need to have a local Revolt server running and an existing account. @@ -8,53 +10,72 @@ config(); function user() { let client = new Client({ apiURL: process.env.API_URL, - debug: true + debug: true, }); - client.on('ready', async () => { + client.on("ready", async () => { console.info(`Logged in as ${client.user!.username}!`); }); - client.on('message', async message => { - if (message.content === 'sus') { - message.channel!.sendMessage('sus!'); - } else if (message.content === 'bot') { - let bot = await client.req('POST', '/bots/create', { name: 'basedbot12' }); + client.on("message", async (message) => { + if (message.content === "sus") { + message.channel!.sendMessage("sus!"); + } else if (message.content === "bot") { + let bot = await client.req("POST", "/bots/create", { + name: "basedbot12", + }); message.channel!.sendMessage(JSON.stringify(bot)); - } else if (message.content === 'my bots') { - message.channel!.sendMessage(JSON.stringify( - await client.req('GET', '/bots/@me') - )); - } else if (message.content === 'join bot') { - await client.req('POST', `/bots/01FCV7DCMRD9MT3JBYT5VEKVRD/invite` as '/bots/id/invite', - { group: message.channel_id }); - // { server: '01FATEGMHEE2M1QGPA65NS6V8K' }); - } else if (message.content === 'edit bot name') { - await client.req('PATCH', `/bots/01FCV7DCMRD9MT3JBYT5VEKVRD` as '/bots/id', - { name: 'testingbkaka' }); - } else if (message.content === 'make bot public') { - await client.req('PATCH', `/bots/01FCV7DCMRD9MT3JBYT5VEKVRD` as '/bots/id', - { public: true }); - } else if (message.content === 'delete bot') { - await client.req('DELETE', `/bots/01FCV7DCMRD9MT3JBYT5VEKVRD` as '/bots/id'); + } else if (message.content === "my bots") { + message.channel!.sendMessage( + JSON.stringify(await client.req("GET", "/bots/@me")), + ); + } else if (message.content === "join bot") { + await client.req( + "POST", + `/bots/01FCV7DCMRD9MT3JBYT5VEKVRD/invite` as "/bots/id/invite", + { group: message.channel_id }, + ); + // { server: '01FATEGMHEE2M1QGPA65NS6V8K' }); + } else if (message.content === "edit bot name") { + await client.req( + "PATCH", + `/bots/01FCV7DCMRD9MT3JBYT5VEKVRD` as "/bots/id", + { name: "testingbkaka" }, + ); + } else if (message.content === "make bot public") { + await client.req( + "PATCH", + `/bots/01FCV7DCMRD9MT3JBYT5VEKVRD` as "/bots/id", + { public: true }, + ); + } else if (message.content === "delete bot") { + await client.req( + "DELETE", + `/bots/01FCV7DCMRD9MT3JBYT5VEKVRD` as "/bots/id", + ); } }); - client.login({ email: process.env.EMAIL as string, password: process.env.PASSWORD as string }) + client.login({ + email: process.env.EMAIL as string, + password: process.env.PASSWORD as string, + }); } function bot() { let client = new Client({ - apiURL: process.env.API_URL + apiURL: process.env.API_URL, }); - client.on('ready', async () => { - console.info(`Logged in as ${client.user!.username}! [${client.user!._id}]`); + client.on("ready", async () => { + console.info( + `Logged in as ${client.user!.username}! [${client.user!._id}]`, + ); }); - client.on('message', async message => { - if (message.content === 'sus') { - message.channel!.sendMessage('sus!'); + client.on("message", async (message) => { + if (message.content === "sus") { + message.channel!.sendMessage("sus!"); } }); diff --git a/src/websocket/client.ts b/src/websocket/client.ts index 6df1e321..a0d4b2d9 100644 --- a/src/websocket/client.ts +++ b/src/websocket/client.ts @@ -1,12 +1,13 @@ -import WebSocket from 'isomorphic-ws'; -import { backOff } from 'exponential-backoff'; +import { backOff } from "exponential-backoff"; +import WebSocket from "isomorphic-ws"; +import { runInAction } from "mobx"; +import { Role } from "revolt-api/types/Servers"; -import { Client } from '..'; -import { ServerboundNotification, ClientboundNotification } from './notifications'; - -import { runInAction } from 'mobx'; - -import { Role } from 'revolt-api/types/Servers'; +import { Client } from ".."; +import { + ServerboundNotification, + ClientboundNotification, +} from "./notifications"; export class WebSocketClient { client: Client; @@ -33,7 +34,10 @@ export class WebSocketClient { this.connected = false; this.ready = false; - if (typeof this.ws !== 'undefined' && this.ws.readyState === WebSocket.OPEN) { + if ( + typeof this.ws !== "undefined" && + this.ws.readyState === WebSocket.OPEN + ) { this.ws.close(); } } @@ -43,10 +47,14 @@ export class WebSocketClient { * @param notification Serverbound notification */ send(notification: ServerboundNotification) { - if (typeof this.ws === 'undefined' || this.ws.readyState !== WebSocket.OPEN) return; + if ( + typeof this.ws === "undefined" || + this.ws.readyState !== WebSocket.OPEN + ) + return; let data = JSON.stringify(notification); - if (this.client.debug) console.debug('[<] PACKET', data); + if (this.client.debug) console.debug("[<] PACKET", data); this.ws.send(data); } @@ -55,7 +63,7 @@ export class WebSocketClient { * @param disallowReconnect Whether to disallow reconnection */ connect(disallowReconnect?: boolean): Promise { - this.client.emit('connecting'); + this.client.emit("connecting"); return new Promise((resolve, $reject) => { let thrown = false; @@ -68,49 +76,59 @@ export class WebSocketClient { this.disconnect(); - if (typeof this.client.configuration === 'undefined') { - throw new Error("Attempted to open WebSocket without syncing configuration from server."); + if (typeof this.client.configuration === "undefined") { + throw new Error( + "Attempted to open WebSocket without syncing configuration from server.", + ); } - if (typeof this.client.session === 'undefined') { - throw new Error("Attempted to open WebSocket without valid session."); + if (typeof this.client.session === "undefined") { + throw new Error( + "Attempted to open WebSocket without valid session.", + ); } let ws = new WebSocket(this.client.configuration.ws); this.ws = ws; ws.onopen = () => { - if (typeof this.client.session === 'string') { - this.send({ type: 'Authenticate', token: this.client.session! }); + if (typeof this.client.session === "string") { + this.send({ + type: "Authenticate", + token: this.client.session!, + }); } else { - this.send({ type: 'Authenticate', ...this.client.session! }); + this.send({ + type: "Authenticate", + ...this.client.session!, + }); } }; let timeouts: Record = {}; let handle = async (msg: WebSocket.MessageEvent) => { let data = msg.data; - if (typeof data !== 'string') return; + if (typeof data !== "string") return; - if (this.client.debug) console.debug('[>] PACKET', data); + if (this.client.debug) console.debug("[>] PACKET", data); let packet = JSON.parse(data) as ClientboundNotification; - this.client.emit('packet', packet); + this.client.emit("packet", packet); switch (packet.type) { - case 'Error': { + case "Error": { reject(packet.error); break; } - case 'Authenticated': { + case "Authenticated": { disallowReconnect = false; - this.client.emit('connected'); + this.client.emit("connected"); this.connected = true; break; } - case 'Ready': { + case "Ready": { runInAction(() => { - if (packet.type !== 'Ready') throw 0; + if (packet.type !== "Ready") throw 0; for (let user of packet.users) { this.client.users.createObj(user); @@ -130,45 +148,60 @@ export class WebSocketClient { }); this.client.user = this.client.users.get( - packet.users.find(x => x.relationship === 'User')!._id + packet.users.find((x) => x.relationship === "User")! + ._id, )!; - this.client.emit('ready'); + this.client.emit("ready"); this.ready = true; resolve(); if (this.client.heartbeat > 0) { - this.send({ type: 'Ping', data: + new Date() }); + this.send({ type: "Ping", data: +new Date() }); this.heartbeat = setInterval( - () => this.send({ type: 'Ping', data: + new Date() }), - this.client.heartbeat * 1e3 + () => + this.send({ + type: "Ping", + data: +new Date(), + }), + this.client.heartbeat * 1e3, ) as any; } - + break; } case "Message": { if (!this.client.messages.has(packet._id)) { - if (packet.author === '00000000000000000000000000') { - if (typeof packet.content === 'object') { + if ( + packet.author === "00000000000000000000000000" + ) { + if (typeof packet.content === "object") { switch (packet.content.type) { - case 'user_added': - case 'user_remove': - await this.client.users.fetch(packet.content.by); - case 'user_left': - await this.client.users.fetch(packet.content.id); + case "user_added": + case "user_remove": + await this.client.users.fetch( + packet.content.by, + ); + case "user_left": + await this.client.users.fetch( + packet.content.id, + ); break; - case 'user_joined': - case 'user_left': - case 'user_banned': - case 'user_kicked': - await this.client.users.fetch(packet.content.id); + case "user_joined": + case "user_left": + case "user_banned": + case "user_kicked": + await this.client.users.fetch( + packet.content.id, + ); break; - case 'channel_description_changed': - case 'channel_icon_changed': - case 'channel_renamed': - await this.client.users.fetch(packet.content.by); + case "channel_description_changed": + case "channel_icon_changed": + case "channel_renamed": + await this.client.users.fetch( + packet.content.by, + ); break; } } @@ -176,10 +209,18 @@ export class WebSocketClient { await this.client.users.fetch(packet.author); } - let channel = await this.client.channels.fetch(packet.channel); - if (channel.channel_type === 'TextChannel') { - let server = await this.client.servers.fetch(channel.server_id!); - if (packet.author !== '00000000000000000000000000') await server.fetchMember(packet.author); + let channel = await this.client.channels.fetch( + packet.channel, + ); + if (channel.channel_type === "TextChannel") { + let server = await this.client.servers.fetch( + channel.server_id!, + ); + if ( + packet.author !== + "00000000000000000000000000" + ) + await server.fetchMember(packet.author); } this.client.messages.createObj(packet, true); @@ -191,23 +232,28 @@ export class WebSocketClient { let message = this.client.messages.get(packet.id); if (message) { message.update(packet.data); - this.client.emit('message/update', message); + this.client.emit("message/update", message); } break; } case "MessageDelete": { this.client.messages.delete(packet.id); - this.client.emit('message/delete', packet.id); + this.client.emit("message/delete", packet.id); break; } case "ChannelCreate": { runInAction(async () => { - if (packet.type !== 'ChannelCreate') throw 0; + if (packet.type !== "ChannelCreate") throw 0; - if (packet.channel_type === 'TextChannel' || packet.channel_type === 'VoiceChannel') { - let server = await this.client.servers.fetch(packet.server); + if ( + packet.channel_type === "TextChannel" || + packet.channel_type === "VoiceChannel" + ) { + let server = await this.client.servers.fetch( + packet.server, + ); server.channel_ids.push(packet._id); } @@ -220,24 +266,28 @@ export class WebSocketClient { let channel = this.client.channels.get(packet.id); if (channel) { channel.update(packet.data, packet.clear); - this.client.emit('channel/update', channel); + this.client.emit("channel/update", channel); } break; } case "ChannelDelete": { this.client.channels.get(packet.id)?.delete(true); - this.client.emit('channel/delete', packet.id); + this.client.emit("channel/delete", packet.id); break; } case "ChannelGroupJoin": { - this.client.channels.get(packet.id)?.updateGroupJoin(packet.user); + this.client.channels + .get(packet.id) + ?.updateGroupJoin(packet.user); break; } case "ChannelGroupLeave": { - this.client.channels.get(packet.id)?.updateGroupLeave(packet.user); + this.client.channels + .get(packet.id) + ?.updateGroupLeave(packet.user); break; } @@ -245,14 +295,14 @@ export class WebSocketClient { let server = this.client.servers.get(packet.id); if (server) { server.update(packet.data, packet.clear); - this.client.emit('server/update', server); + this.client.emit("server/update", server); } break; } case "ServerDelete": { this.client.servers.get(packet.id)?.delete(true); - this.client.emit('server/delete', packet.id); + this.client.emit("server/delete", packet.id); break; } @@ -260,24 +310,27 @@ export class WebSocketClient { let member = this.client.members.getKey(packet.id); if (member) { member.update(packet.data, packet.clear); - this.client.emit('member/update', member); + this.client.emit("member/update", member); } break; } case "ServerMemberJoin": { runInAction(async () => { - if (packet.type !== 'ServerMemberJoin') return 0; + if (packet.type !== "ServerMemberJoin") return 0; await this.client.servers.fetch(packet.id); await this.client.users.fetch(packet.user); - this.client.members.createObj({ - _id: { - server: packet.id, - user: packet.user - } - }, true); + this.client.members.createObj( + { + _id: { + server: packet.id, + user: packet.user, + }, + }, + true, + ); }); break; @@ -285,24 +338,29 @@ export class WebSocketClient { case "ServerMemberLeave": { if (packet.user === this.client.user!._id) { - const server_id = packet.id + const server_id = packet.id; runInAction(() => { - this.client.servers.get(server_id)?.delete(true); - [...this.client.members.keys()] - .forEach(key => { - if (JSON.parse(key).server === server_id) { + this.client.servers + .get(server_id) + ?.delete(true); + [...this.client.members.keys()].forEach( + (key) => { + if ( + JSON.parse(key).server === server_id + ) { this.client.members.delete(key); } - }); + }, + ); }); } else { this.client.members.deleteKey({ server: packet.id, - user: packet.user + user: packet.user, }); - this.client.emit('member/leave', { + this.client.emit("member/leave", { server: packet.id, - user: packet.user + user: packet.user, }); } @@ -314,13 +372,18 @@ export class WebSocketClient { if (server) { let role = { ...server.roles?.[packet.role_id], - ...packet.data - } as Role + ...packet.data, + } as Role; server.roles = { ...server.roles, - [packet.role_id]: role - } - this.client.emit('role/update', packet.role_id, role, packet.id); + [packet.role_id]: role, + }; + this.client.emit( + "role/update", + packet.role_id, + role, + packet.id, + ); } break; } @@ -328,20 +391,27 @@ export class WebSocketClient { case "ServerRoleDelete": { let server = this.client.servers.get(packet.id); if (server) { - let { [packet.role_id]: _, ...roles } = server.roles ?? {}; + let { [packet.role_id]: _, ...roles } = + server.roles ?? {}; server.roles = roles; - this.client.emit('role/delete', packet.role_id, packet.id); + this.client.emit( + "role/delete", + packet.role_id, + packet.id, + ); } break; } case "UserUpdate": { - this.client.users.get(packet.id)?.update(packet.data, packet.clear); + this.client.users + .get(packet.id) + ?.update(packet.data, packet.clear); break; } case "UserRelationship": { - let user = this.client.users.get(packet.user._id) + let user = this.client.users.get(packet.user._id); if (user) { user.update({ relationship: packet.status }); } else { @@ -358,8 +428,8 @@ export class WebSocketClient { if (channel) { channel.updateStartTyping(user); - clearInterval(timeouts[packet.id+user]); - timeouts[packet.id+user] = setTimeout(() => { + clearInterval(timeouts[packet.id + user]); + timeouts[packet.id + user] = setTimeout(() => { channel!.updateStopTyping(user); }, 3000); } @@ -368,22 +438,29 @@ export class WebSocketClient { } case "ChannelStopTyping": { - this.client.channels.get(packet.id)?.updateStopTyping(packet.user); - clearInterval(timeouts[packet.id+packet.user]); + this.client.channels + .get(packet.id) + ?.updateStopTyping(packet.user); + clearInterval(timeouts[packet.id + packet.user]); break; } - case "ChannelAck": break; + case "ChannelAck": + break; case "Pong": { - this.ping = + new Date() - packet.data; + this.ping = +new Date() - packet.data; break; } - default: this.client.debug && console.warn(`Warning: Unhandled packet! ${packet.type}`); + default: + this.client.debug && + console.warn( + `Warning: Unhandled packet! ${packet.type}`, + ); } - } - + }; + let processing = false; let queue: WebSocket.MessageEvent[] = []; ws.onmessage = async (data) => { @@ -396,22 +473,28 @@ export class WebSocketClient { } processing = false; } - } + }; ws.onerror = (err) => { reject(err); - } + }; ws.onclose = () => { - this.client.emit('dropped'); + this.client.emit("dropped"); this.connected = false; this.ready = false; - Object.keys(timeouts).map(k => timeouts[k]).forEach(clearTimeout); + Object.keys(timeouts) + .map((k) => timeouts[k]) + .forEach(clearTimeout); runInAction(() => { - [...this.client.users.values()].forEach(user => user.online = false); - [...this.client.channels.values()].forEach(channel => channel.typing_ids.clear()); + [...this.client.users.values()].forEach( + (user) => (user.online = false), + ); + [...this.client.channels.values()].forEach((channel) => + channel.typing_ids.clear(), + ); }); if (!disallowReconnect && this.client.autoReconnect) { diff --git a/src/websocket/notifications.ts b/src/websocket/notifications.ts index c801bbb4..8849aa99 100644 --- a/src/websocket/notifications.ts +++ b/src/websocket/notifications.ts @@ -1,62 +1,95 @@ +import type { Session } from "revolt-api/types/Auth"; +import type { Channel, Message } from "revolt-api/types/Channels"; +import type { + Member, + MemberCompositeKey, + Role, + Server, +} from "revolt-api/types/Servers"; +import type { UserSettings } from "revolt-api/types/Sync"; +import type { RelationshipStatus, User } from "revolt-api/types/Users"; -import type { Session } from 'revolt-api/types/Auth'; -import type { UserSettings } from 'revolt-api/types/Sync'; -import type { Channel, Message } from 'revolt-api/types/Channels'; -import type { RelationshipStatus, User } from 'revolt-api/types/Users'; -import type { Member, MemberCompositeKey, Role, Server } from 'revolt-api/types/Servers'; -import type { RemoveChannelField, RemoveServerField, RemoveUserField, RemoveMemberField } from '../api/routes'; +import type { + RemoveChannelField, + RemoveServerField, + RemoveUserField, + RemoveMemberField, +} from "../api/routes"; type WebSocketError = { - error: 'InternalError' | 'InvalidSession' | 'OnboardingNotFinished' | 'AlreadyAuthenticated' + error: + | "InternalError" + | "InvalidSession" + | "OnboardingNotFinished" + | "AlreadyAuthenticated"; }; -export type ServerboundNotification = ( - { type: 'Ping', data: number } | - { type: 'Pong', data: number } | - ({ type: 'Authenticate' } & Session) | - ({ type: 'Authenticate', token: string }) | - ({ type: 'BeginTyping', channel: string }) | - ({ type: 'EndTyping', channel: string }) -); +export type ServerboundNotification = + | { type: "Ping"; data: number } + | { type: "Pong"; data: number } + | ({ type: "Authenticate" } & Session) + | { type: "Authenticate"; token: string } + | { type: "BeginTyping"; channel: string } + | { type: "EndTyping"; channel: string }; export type ReadyPacket = { - type: 'Ready', - users: User[], - servers: Server[], - channels: Channel[], - members: Member[] -} + type: "Ready"; + users: User[]; + servers: Server[]; + channels: Channel[]; + members: Member[]; +}; -export type ClientboundNotification = ( - { type: 'Ping', data: number } | - { type: 'Pong', data: number } | - ({ type: 'Error' } & WebSocketError) | - { type: 'Authenticated' } | - ReadyPacket | - - ({ type: 'Message' } & Message) | - ({ type: 'MessageUpdate', id: string, data: Partial }) | - ({ type: 'MessageDelete', id: string }) | - - ({ type: 'ChannelCreate' } & Channel) | - { type: 'ChannelUpdate', id: string, data: Partial, clear?: RemoveChannelField } | - { type: 'ChannelDelete', id: string } | - { type: 'ChannelGroupJoin', id: string, user: string } | - { type: 'ChannelGroupLeave', id: string, user: string } | - { type: 'ChannelStartTyping', id: string, user: string } | - { type: 'ChannelStopTyping', id: string, user: string } | - { type: 'ChannelAck', id: string, user: string, message_id: string } | - - ({ type: 'ServerUpdate', id: string, data: Partial, clear?: RemoveServerField }) | - ({ type: 'ServerDelete', id: string }) | - ({ type: 'ServerMemberUpdate', id: MemberCompositeKey, data: Partial, clear?: RemoveMemberField }) | - ({ type: 'ServerMemberJoin', id: string, user: string }) | - ({ type: 'ServerMemberLeave', id: string, user: string }) | - ({ type: 'ServerRoleUpdate', id: string, role_id: string, data: Partial }) | - ({ type: 'ServerRoleDelete', id: string, role_id: string }) | - - { type: 'UserUpdate', id: string, data: Partial, clear?: RemoveUserField } | - { type: 'UserRelationship', user: User, status: RelationshipStatus } | - { type: 'UserPresence', id: string, online: boolean } | - { type: 'UserSettingsUpdate', id: string, update: UserSettings } -) +export type ClientboundNotification = + | { type: "Ping"; data: number } + | { type: "Pong"; data: number } + | ({ type: "Error" } & WebSocketError) + | { type: "Authenticated" } + | ReadyPacket + | ({ type: "Message" } & Message) + | { type: "MessageUpdate"; id: string; data: Partial } + | { type: "MessageDelete"; id: string } + | ({ type: "ChannelCreate" } & Channel) + | { + type: "ChannelUpdate"; + id: string; + data: Partial; + clear?: RemoveChannelField; + } + | { type: "ChannelDelete"; id: string } + | { type: "ChannelGroupJoin"; id: string; user: string } + | { type: "ChannelGroupLeave"; id: string; user: string } + | { type: "ChannelStartTyping"; id: string; user: string } + | { type: "ChannelStopTyping"; id: string; user: string } + | { type: "ChannelAck"; id: string; user: string; message_id: string } + | { + type: "ServerUpdate"; + id: string; + data: Partial; + clear?: RemoveServerField; + } + | { type: "ServerDelete"; id: string } + | { + type: "ServerMemberUpdate"; + id: MemberCompositeKey; + data: Partial; + clear?: RemoveMemberField; + } + | { type: "ServerMemberJoin"; id: string; user: string } + | { type: "ServerMemberLeave"; id: string; user: string } + | { + type: "ServerRoleUpdate"; + id: string; + role_id: string; + data: Partial; + } + | { type: "ServerRoleDelete"; id: string; role_id: string } + | { + type: "UserUpdate"; + id: string; + data: Partial; + clear?: RemoveUserField; + } + | { type: "UserRelationship"; user: User; status: RelationshipStatus } + | { type: "UserPresence"; id: string; online: boolean } + | { type: "UserSettingsUpdate"; id: string; update: UserSettings }; diff --git a/yarn.lock b/yarn.lock index 3d2106d8..8f374f3c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,244 +2,6 @@ # yarn lockfile v1 -"@babel/code-frame@^7.12.13", "@babel/code-frame@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.0.tgz#0dfc80309beec8411e65e706461c408b0bb9b431" - integrity sha512-IF4EOMEV+bfYwOmNxGzSnjR2EmQod7f1UXOpZM3l4i4o4QNwzjtJAu/HxdjHq0aYBvdqMuQEY1eg0nqW9ZPORA== - dependencies: - "@babel/highlight" "^7.16.0" - -"@babel/compat-data@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.16.0.tgz#ea269d7f78deb3a7826c39a4048eecda541ebdaa" - integrity sha512-DGjt2QZse5SGd9nfOSqO4WLJ8NN/oHkijbXbPrxuoJO3oIPJL3TciZs9FX+cOHNiY9E9l0opL8g7BmLe3T+9ew== - -"@babel/core@7.13.10": - version "7.13.10" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.13.10.tgz#07de050bbd8193fcd8a3c27918c0890613a94559" - integrity sha512-bfIYcT0BdKeAZrovpMqX2Mx5NrgAckGbwT982AkdS5GNfn3KMGiprlBAtmBcFZRUmpaufS6WZFP8trvx8ptFDw== - dependencies: - "@babel/code-frame" "^7.12.13" - "@babel/generator" "^7.13.9" - "@babel/helper-compilation-targets" "^7.13.10" - "@babel/helper-module-transforms" "^7.13.0" - "@babel/helpers" "^7.13.10" - "@babel/parser" "^7.13.10" - "@babel/template" "^7.12.13" - "@babel/traverse" "^7.13.0" - "@babel/types" "^7.13.0" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.2" - json5 "^2.1.2" - lodash "^4.17.19" - semver "^6.3.0" - source-map "^0.5.0" - -"@babel/generator@7.13.9": - version "7.13.9" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.13.9.tgz#3a7aa96f9efb8e2be42d38d80e2ceb4c64d8de39" - integrity sha512-mHOOmY0Axl/JCTkxTU6Lf5sWOg/v8nUa+Xkt4zMTftX0wqmb6Sh7J8gvcehBw7q0AhrhAR+FDacKjCZ2X8K+Sw== - dependencies: - "@babel/types" "^7.13.0" - jsesc "^2.5.1" - source-map "^0.5.0" - -"@babel/generator@^7.13.0", "@babel/generator@^7.13.9", "@babel/generator@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.16.0.tgz#d40f3d1d5075e62d3500bccb67f3daa8a95265b2" - integrity sha512-RR8hUCfRQn9j9RPKEVXo9LiwoxLPYn6hNZlvUOR8tSnaxlD0p0+la00ZP9/SnRt6HchKr+X0fO2r8vrETiJGew== - dependencies: - "@babel/types" "^7.16.0" - jsesc "^2.5.1" - source-map "^0.5.0" - -"@babel/helper-compilation-targets@^7.13.10": - version "7.16.3" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.3.tgz#5b480cd13f68363df6ec4dc8ac8e2da11363cbf0" - integrity sha512-vKsoSQAyBmxS35JUOOt+07cLc6Nk/2ljLIHwmq2/NM6hdioUaqEXq/S+nXvbvXbZkNDlWOymPanJGOc4CBjSJA== - dependencies: - "@babel/compat-data" "^7.16.0" - "@babel/helper-validator-option" "^7.14.5" - browserslist "^4.17.5" - semver "^6.3.0" - -"@babel/helper-function-name@^7.12.13", "@babel/helper-function-name@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.16.0.tgz#b7dd0797d00bbfee4f07e9c4ea5b0e30c8bb1481" - integrity sha512-BZh4mEk1xi2h4HFjWUXRQX5AEx4rvaZxHgax9gcjdLWdkjsY7MKt5p0otjsg5noXw+pB+clMCjw+aEVYADMjog== - dependencies: - "@babel/helper-get-function-arity" "^7.16.0" - "@babel/template" "^7.16.0" - "@babel/types" "^7.16.0" - -"@babel/helper-get-function-arity@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.0.tgz#0088c7486b29a9cb5d948b1a1de46db66e089cfa" - integrity sha512-ASCquNcywC1NkYh/z7Cgp3w31YW8aojjYIlNg4VeJiHkqyP4AzIvr4qx7pYDb4/s8YcsZWqqOSxgkvjUz1kpDQ== - dependencies: - "@babel/types" "^7.16.0" - -"@babel/helper-hoist-variables@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.0.tgz#4c9023c2f1def7e28ff46fc1dbcd36a39beaa81a" - integrity sha512-1AZlpazjUR0EQZQv3sgRNfM9mEVWPK3M6vlalczA+EECcPz3XPh6VplbErL5UoMpChhSck5wAJHthlj1bYpcmg== - dependencies: - "@babel/types" "^7.16.0" - -"@babel/helper-member-expression-to-functions@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.0.tgz#29287040efd197c77636ef75188e81da8bccd5a4" - integrity sha512-bsjlBFPuWT6IWhl28EdrQ+gTvSvj5tqVP5Xeftp07SEuz5pLnsXZuDkDD3Rfcxy0IsHmbZ+7B2/9SHzxO0T+sQ== - dependencies: - "@babel/types" "^7.16.0" - -"@babel/helper-module-imports@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.16.0.tgz#90538e60b672ecf1b448f5f4f5433d37e79a3ec3" - integrity sha512-kkH7sWzKPq0xt3H1n+ghb4xEMP8k0U7XV3kkB+ZGy69kDk2ySFW1qPi06sjKzFY3t1j6XbJSqr4mF9L7CYVyhg== - dependencies: - "@babel/types" "^7.16.0" - -"@babel/helper-module-transforms@^7.13.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.16.0.tgz#1c82a8dd4cb34577502ebd2909699b194c3e9bb5" - integrity sha512-My4cr9ATcaBbmaEa8M0dZNA74cfI6gitvUAskgDtAFmAqyFKDSHQo5YstxPbN+lzHl2D9l/YOEFqb2mtUh4gfA== - dependencies: - "@babel/helper-module-imports" "^7.16.0" - "@babel/helper-replace-supers" "^7.16.0" - "@babel/helper-simple-access" "^7.16.0" - "@babel/helper-split-export-declaration" "^7.16.0" - "@babel/helper-validator-identifier" "^7.15.7" - "@babel/template" "^7.16.0" - "@babel/traverse" "^7.16.0" - "@babel/types" "^7.16.0" - -"@babel/helper-optimise-call-expression@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.0.tgz#cecdb145d70c54096b1564f8e9f10cd7d193b338" - integrity sha512-SuI467Gi2V8fkofm2JPnZzB/SUuXoJA5zXe/xzyPP2M04686RzFKFHPK6HDVN6JvWBIEW8tt9hPR7fXdn2Lgpw== - dependencies: - "@babel/types" "^7.16.0" - -"@babel/helper-replace-supers@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.16.0.tgz#73055e8d3cf9bcba8ddb55cad93fedc860f68f17" - integrity sha512-TQxuQfSCdoha7cpRNJvfaYxxxzmbxXw/+6cS7V02eeDYyhxderSoMVALvwupA54/pZcOTtVeJ0xccp1nGWladA== - dependencies: - "@babel/helper-member-expression-to-functions" "^7.16.0" - "@babel/helper-optimise-call-expression" "^7.16.0" - "@babel/traverse" "^7.16.0" - "@babel/types" "^7.16.0" - -"@babel/helper-simple-access@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.16.0.tgz#21d6a27620e383e37534cf6c10bba019a6f90517" - integrity sha512-o1rjBT/gppAqKsYfUdfHq5Rk03lMQrkPHG1OWzHWpLgVXRH4HnMM9Et9CVdIqwkCQlobnGHEJMsgWP/jE1zUiw== - dependencies: - "@babel/types" "^7.16.0" - -"@babel/helper-split-export-declaration@^7.12.13", "@babel/helper-split-export-declaration@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.0.tgz#29672f43663e936df370aaeb22beddb3baec7438" - integrity sha512-0YMMRpuDFNGTHNRiiqJX19GjNXA4H0E8jZ2ibccfSxaCogbm3am5WN/2nQNj0YnQwGWM1J06GOcQ2qnh3+0paw== - dependencies: - "@babel/types" "^7.16.0" - -"@babel/helper-validator-identifier@^7.12.11", "@babel/helper-validator-identifier@^7.15.7": - version "7.15.7" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz#220df993bfe904a4a6b02ab4f3385a5ebf6e2389" - integrity sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w== - -"@babel/helper-validator-option@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz#6e72a1fff18d5dfcb878e1e62f1a021c4b72d5a3" - integrity sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow== - -"@babel/helpers@^7.13.10": - version "7.16.3" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.16.3.tgz#27fc64f40b996e7074dc73128c3e5c3e7f55c43c" - integrity sha512-Xn8IhDlBPhvYTvgewPKawhADichOsbkZuzN7qz2BusOM0brChsyXMDJvldWaYMMUNiCQdQzNEioXTp3sC8Nt8w== - dependencies: - "@babel/template" "^7.16.0" - "@babel/traverse" "^7.16.3" - "@babel/types" "^7.16.0" - -"@babel/highlight@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.0.tgz#6ceb32b2ca4b8f5f361fb7fd821e3fddf4a1725a" - integrity sha512-t8MH41kUQylBtu2+4IQA3atqevA2lRgqA2wyVB/YiWmsDSuylZZuXOUy9ric30hfzauEFfdsuk/eXTRrGrfd0g== - dependencies: - "@babel/helper-validator-identifier" "^7.15.7" - chalk "^2.0.0" - js-tokens "^4.0.0" - -"@babel/parser@7.14.6": - version "7.14.6" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.14.6.tgz#d85cc68ca3cac84eae384c06f032921f5227f4b2" - integrity sha512-oG0ej7efjEXxb4UgE+klVx+3j4MVo+A2vCzm7OUN4CLo6WhQ+vSOD2yJ8m7B+DghObxtLxt3EfgMWpq+AsWehQ== - -"@babel/parser@^7.13.0", "@babel/parser@^7.13.10", "@babel/parser@^7.16.0", "@babel/parser@^7.16.3": - version "7.16.3" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.16.3.tgz#271bafcb811080905a119222edbc17909c82261d" - integrity sha512-dcNwU1O4sx57ClvLBVFbEgx0UZWfd0JQX5X6fxFRCLHelFBGXFfSz6Y0FAq2PEwUqlqLkdVjVr4VASEOuUnLJw== - -"@babel/template@^7.12.13", "@babel/template@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.0.tgz#d16a35ebf4cd74e202083356fab21dd89363ddd6" - integrity sha512-MnZdpFD/ZdYhXwiunMqqgyZyucaYsbL0IrjoGjaVhGilz+x8YB++kRfygSOIj1yOtWKPlx7NBp+9I1RQSgsd5A== - dependencies: - "@babel/code-frame" "^7.16.0" - "@babel/parser" "^7.16.0" - "@babel/types" "^7.16.0" - -"@babel/traverse@7.13.0": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.13.0.tgz#6d95752475f86ee7ded06536de309a65fc8966cc" - integrity sha512-xys5xi5JEhzC3RzEmSGrs/b3pJW/o87SypZ+G/PhaE7uqVQNv/jlmVIBXuoh5atqQ434LfXV+sf23Oxj0bchJQ== - dependencies: - "@babel/code-frame" "^7.12.13" - "@babel/generator" "^7.13.0" - "@babel/helper-function-name" "^7.12.13" - "@babel/helper-split-export-declaration" "^7.12.13" - "@babel/parser" "^7.13.0" - "@babel/types" "^7.13.0" - debug "^4.1.0" - globals "^11.1.0" - lodash "^4.17.19" - -"@babel/traverse@^7.13.0", "@babel/traverse@^7.16.0", "@babel/traverse@^7.16.3": - version "7.16.3" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.16.3.tgz#f63e8a938cc1b780f66d9ed3c54f532ca2d14787" - integrity sha512-eolumr1vVMjqevCpwVO99yN/LoGL0EyHiLO5I043aYQvwOJ9eR5UsZSClHVCzfhBduMAsSzgA/6AyqPjNayJag== - dependencies: - "@babel/code-frame" "^7.16.0" - "@babel/generator" "^7.16.0" - "@babel/helper-function-name" "^7.16.0" - "@babel/helper-hoist-variables" "^7.16.0" - "@babel/helper-split-export-declaration" "^7.16.0" - "@babel/parser" "^7.16.3" - "@babel/types" "^7.16.0" - debug "^4.1.0" - globals "^11.1.0" - -"@babel/types@7.13.0": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.13.0.tgz#74424d2816f0171b4100f0ab34e9a374efdf7f80" - integrity sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA== - dependencies: - "@babel/helper-validator-identifier" "^7.12.11" - lodash "^4.17.19" - to-fast-properties "^2.0.0" - -"@babel/types@^7.13.0", "@babel/types@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.16.0.tgz#db3b313804f96aadd0b776c4823e127ad67289ba" - integrity sha512-PJgg/k3SdLsGb3hhisFvtLOw5ts113klrpLuIPtCJIU+BB24fqq6lf8RWqKJEjzqXR9AEH1rIb5XTqwBHB+kQg== - dependencies: - "@babel/helper-validator-identifier" "^7.15.7" - to-fast-properties "^2.0.0" - "@eslint/eslintrc@^1.0.4": version "1.0.4" resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.0.4.tgz#dfe0ff7ba270848d10c5add0715e04964c034b31" @@ -290,19 +52,6 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@trivago/prettier-plugin-sort-imports@^3.1.1": - version "3.1.1" - resolved "https://registry.yarnpkg.com/@trivago/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-3.1.1.tgz#101e34eadb252572ec32aea6d5487d93b90a0037" - integrity sha512-T9EJNEOugWts4WxdmpWeY+sp+2fUHhvGh9QSBCowEGJfcbnu355HQRqok5bKwejdieMaI1+uGZhuTNMZwjqOCQ== - dependencies: - "@babel/core" "7.13.10" - "@babel/generator" "7.13.9" - "@babel/parser" "7.14.6" - "@babel/traverse" "7.13.0" - "@babel/types" "7.13.0" - javascript-natural-sort "0.7.1" - lodash "4.17.21" - "@types/events@^3.0.0": version "3.0.0" resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7" @@ -468,13 +217,6 @@ ansi-regex@^5.0.1: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== -ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - ansi-styles@^4.1.0: version "4.3.0" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" @@ -700,17 +442,6 @@ braces@^3.0.1: dependencies: fill-range "^7.0.1" -browserslist@^4.17.5: - version "4.17.6" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.17.6.tgz#c76be33e7786b497f66cad25a73756c8b938985d" - integrity sha512-uPgz3vyRTlEiCv4ee9KlsKgo2V6qPk7Jsn0KAn2OBqbqKo3iNcPEC1Ti6J4dwnz+aIRfEEEuOzC9IBk8tXUomw== - dependencies: - caniuse-lite "^1.0.30001274" - electron-to-chromium "^1.3.886" - escalade "^3.1.1" - node-releases "^2.0.1" - picocolors "^1.0.0" - buffer-equal@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/buffer-equal/-/buffer-equal-1.0.0.tgz#59616b498304d556abd466966b22eeda3eca5fbe" @@ -754,20 +485,6 @@ camelcase@^3.0.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" integrity sha1-MvxLn82vhF/N9+c7uXysImHwqwo= -caniuse-lite@^1.0.30001274: - version "1.0.30001280" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001280.tgz#066a506046ba4be34cde5f74a08db7a396718fb7" - integrity sha512-kFXwYvHe5rix25uwueBxC569o53J6TpnGu0BEEn+6Lhl2vsnAumRFWEBhDft1fwyo6m1r4i+RqA4+163FpeFcA== - -chalk@^2.0.0: - version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - chalk@^4.0.0: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" @@ -860,13 +577,6 @@ collection-visit@^1.0.0: map-visit "^1.0.0" object-visit "^1.0.0" -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - color-convert@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" @@ -874,11 +584,6 @@ color-convert@^2.0.1: dependencies: color-name "~1.1.4" -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= - color-name@~1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" @@ -909,7 +614,7 @@ concat-stream@^1.6.0: readable-stream "^2.2.2" typedarray "^0.0.6" -convert-source-map@^1.5.0, convert-source-map@^1.7.0: +convert-source-map@^1.5.0: version "1.8.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== @@ -958,7 +663,7 @@ debug@^2.2.0, debug@^2.3.3: dependencies: ms "2.0.0" -debug@^4.1.0, debug@^4.1.1, debug@^4.3.2: +debug@^4.1.1, debug@^4.3.2: version "4.3.2" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== @@ -1068,11 +773,6 @@ each-props@^1.3.2: is-plain-object "^2.0.1" object.defaults "^1.1.0" -electron-to-chromium@^1.3.886: - version "1.3.895" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.895.tgz#9b0f8f2e32d8283bbb200156fd5d8dfd775f31ed" - integrity sha512-9Ww3fB8CWctjqHwkOt7DQbMZMpal2x2reod+/lU4b9axO1XJEDUpPMBxs7YnjLhhqpKXIIB5SRYN/B4K0QpvyQ== - end-of-stream@^1.0.0, end-of-stream@^1.1.0: version "1.4.4" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" @@ -1130,16 +830,6 @@ es6-weak-map@^2.0.1: es6-iterator "^2.0.3" es6-symbol "^3.1.1" -escalade@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" - integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== - -escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= - escape-string-regexp@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" @@ -1559,11 +1249,6 @@ functional-red-black-tree@^1.0.1: resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= -gensync@^1.0.0-beta.2: - version "1.0.0-beta.2" - resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" - integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== - get-caller-file@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" @@ -1678,11 +1363,6 @@ global-prefix@^1.0.1: is-windows "^1.0.1" which "^1.2.14" -globals@^11.1.0: - version "11.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" - integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== - globals@^13.6.0, globals@^13.9.0: version "13.12.0" resolved "https://registry.yarnpkg.com/globals/-/globals-13.12.0.tgz#4d733760304230a0082ed96e21e5c565f898089e" @@ -1778,11 +1458,6 @@ handlebars@^4.7.7: optionalDependencies: uglify-js "^3.1.4" -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= - has-flag@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" @@ -2112,16 +1787,6 @@ isomorphic-ws@^4.0.1: resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz#55fd4cd6c5e6491e76dc125938dd863f5cd4f2dc" integrity sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w== -javascript-natural-sort@0.7.1: - version "0.7.1" - resolved "https://registry.yarnpkg.com/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz#f9e2303d4507f6d74355a73664d1440fb5a0ef59" - integrity sha1-+eIwPUUH9tdDVac2ZNFED7Wg71k= - -js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - js-yaml@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" @@ -2142,11 +1807,6 @@ jsdoc-regex@^1.0.1: resolved "https://registry.yarnpkg.com/jsdoc-regex/-/jsdoc-regex-1.0.1.tgz#8424428d5b563ad8c5c7fbec079b9a8b09c8dcfa" integrity sha1-hCRCjVtWOtjFx/vsB5uaiwnI3Po= -jsesc@^2.5.1: - version "2.5.2" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" - integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== - json-schema-traverse@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" @@ -2157,7 +1817,7 @@ json-stable-stringify-without-jsonify@^1.0.1: resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= -json5@^2.1.2, json5@^2.2.0: +json5@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3" integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA== @@ -2270,7 +1930,7 @@ lodash.merge@^4.6.2: resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== -lodash@4.17.21, lodash@^4.17.10, lodash@^4.17.19: +lodash@^4.17.10: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -2457,11 +2117,6 @@ node-fetch@^2.6.1: resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== -node-releases@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.1.tgz#3d1d395f204f1f2f29a54358b9fb678765ad2fc5" - integrity sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA== - normalize-package-data@^2.3.2: version "2.5.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" @@ -2698,11 +2353,6 @@ pause-stream@0.0.11, pause-stream@^0.0.11: dependencies: through "~2.3" -picocolors@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" - integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== - picomatch@^2.2.3: version "2.3.0" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972" @@ -3005,11 +2655,6 @@ semver-greatest-satisfied-range@^1.1.0: resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== -semver@^6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== - semver@^7.2.1, semver@^7.3.5: version "7.3.5" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" @@ -3104,7 +2749,7 @@ source-map-url@^0.4.0: resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56" integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw== -source-map@^0.5.0, source-map@^0.5.6: +source-map@^0.5.6: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= @@ -3258,13 +2903,6 @@ strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== -supports-color@^5.3.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - supports-color@^7.1.0: version "7.2.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" @@ -3319,11 +2957,6 @@ to-absolute-glob@^2.0.0: is-absolute "^1.0.0" is-negated-glob "^1.0.0" -to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" - integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= - to-object-path@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" @@ -3432,10 +3065,10 @@ typedoc@^0.21.4: shiki "^0.9.3" typedoc-default-themes "^0.12.10" -typescript@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.3.tgz#39062d8019912d43726298f09493d598048c1ce3" - integrity sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw== +typescript@^4.4.4: + version "4.4.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.4.4.tgz#2cd01a1a1f160704d3101fd5a58ff0f9fcb8030c" + integrity sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA== uglify-js@^3.1.4: version "3.13.10"