Remove more Discord. Start migration to bun

This commit is contained in:
Declan Chidlow 2024-07-12 18:20:10 +08:00
parent a74def6812
commit 01c4531129
14 changed files with 118 additions and 373 deletions

View file

@ -17,7 +17,7 @@ RUN pnpm install
RUN pnpm run build
WORKDIR /build/app
RUN yarn install --immutable
RUN yarn install
COPY ./bot .
RUN yarn build

View file

@ -28,6 +28,7 @@
"xlsx": "^0.17.3"
},
"devDependencies": {
"@types/ws": "^8.5.10",
"typescript": "^4.4.3"
},
"packageManager": "yarn@3.2.1",

View file

@ -6,7 +6,6 @@ import child_process from 'child_process';
import fs from 'fs';
import path from 'path';
import { User } from "revolt.js";
import { adminBotLog } from "../../logging";
import CommandCategory from "../../../struct/commands/CommandCategory";
import { getMutualServers, parseUserOrId } from "../../util";
@ -95,8 +94,6 @@ export default {
const sentMsg = await message.reply(msg.replace('%emoji%', ':lock:'), false);
setTimeout(() => sentMsg?.edit({ content: msg.replace('%emoji%', ':unlock:') }).catch(()=>{}), 200);
await adminBotLog({ type: 'WARN', message: `@${message.author!.username} has enabled sudo mode.` });
break;
}

View file

@ -11,7 +11,7 @@ export default {
name: 'login',
aliases: null,
description: 'Log into the web dashboard',
category: CommandCategory.Misc,
category: CommandCategory.Miscellaneous,
run: async (message: MessageCommandContext, args: string[]) => {
try {
const code = args.shift();

View file

@ -8,7 +8,7 @@ export default {
name: 'logout',
aliases: null,
description: 'Log out of sessions created with /login',
category: CommandCategory.Misc,
category: CommandCategory.Miscellaneous,
run: async (message: MessageCommandContext, args: string[]) => {
try {
const code = args.shift();

View file

@ -6,7 +6,7 @@ export default {
name: 'healthcheck',
aliases: null,
description: 'Health check',
category: CommandCategory.Misc,
category: CommandCategory.Miscellaneous,
run: async (message: MessageCommandContext, args: string[]) => {
const msg = await message.reply('Health check success: ' + args.join(' '));
}

View file

@ -7,7 +7,7 @@ export default {
name: 'ping',
aliases: null,
description: 'ping pong',
category: CommandCategory.Misc,
category: CommandCategory.Miscellaneous,
run: async (message: MessageCommandContext, args: string[]) => {
let now = Date.now();
message.reply(`Measuring...`)

View file

@ -6,7 +6,7 @@ export default {
name: 'test',
aliases: [ 'testalias' ],
description: 'Test command',
category: CommandCategory.Misc,
category: CommandCategory.Miscellaneous,
run: (message: MessageCommandContext, args: string[]) => {
message.reply({
content: 'Beep boop.',

View file

@ -1,42 +0,0 @@
import { ColorResolvable, MessageEmbed, WebhookClient } from "discord.js";
import logger from "./logger";
import { client as bot } from '../index'
let client: WebhookClient|undefined;
if (process.env.LOG_WEBHOOK) {
try {
client = new WebhookClient({ url: process.env.LOG_WEBHOOK });
} catch(e) {
console.error(e);
}
}
async function adminBotLog(data: { message: string, type: 'INFO'|'WARN'|'ERROR' }) {
logger.info(`[${data.type}] Admin log: ${data.message}`);
try {
let color: ColorResolvable = '#ffffff';
switch(data.type) {
case 'INFO': color = '#00ff73'; break;
case 'WARN': color = '#ffc823'; break;
case 'ERROR': color = '#ff4208'; break;
}
let embed = new MessageEmbed()
.setDescription(data.message)
.setColor(color);
await client?.send({
embeds: [ embed ],
username: bot.user?.username,
avatarURL: bot.user?.avatarURL,
});
} catch(e) {
logger.error(`Failed to log: ${e}`);
}
}
export {
client,
adminBotLog,
}

View file

@ -4,8 +4,8 @@
import ws from "ws";
import logger from "../logger";
import crypto from 'crypto';
import { client as bot, dbs } from '../..';
import crypto from "crypto";
import { client as bot, dbs } from "../..";
import { EventEmitter } from "events";
import { parseUser } from "../util";
import PendingLogin from "automod/dist/types/PendingLogin";
@ -14,135 +14,134 @@ import { ulid } from "ulid";
const wsEvents = new EventEmitter();
const { API_WS_URL, API_WS_TOKEN } = process.env;
const wsQueue: { [key: string]: string }[] = [];
let client: ws|undefined = undefined;
let client: ws | undefined = undefined;
type WSResponse = { success: false, error: string, statusCode?: number } | { success: true, [key: string]: any }
type WSResponse = { success: false; error: string; statusCode?: number } | { success: true; [key: string]: any };
if (!API_WS_URL || !API_WS_TOKEN)
logger.info("$API_WS_URL or $API_WS_TOKEN not found.");
if (!API_WS_URL || !API_WS_TOKEN) logger.info("$API_WS_URL or $API_WS_TOKEN not found.");
else {
logger.info(`$API_WS_URL and $API_WS_TOKEN set; Connecting to ${API_WS_URL}`);
connect();
logger.info(`$API_WS_URL and $API_WS_TOKEN set; Connecting to ${API_WS_URL}`);
connect();
}
function connect() {
if (client && client.readyState == ws.OPEN) client.close();
client = new ws(API_WS_URL!, { headers: { authorization: API_WS_TOKEN! } });
if (client && client.readyState == ws.OPEN) client.close();
client = new ws(API_WS_URL!, { headers: { authorization: API_WS_TOKEN! } });
client.once("open", () => {
logger.debug("WS connected");
if (wsQueue.length > 0) {
logger.debug(`Attempting to send ${wsQueue.length} queued WS messages`);
client.once("open", () => {
logger.debug("WS connected");
if (wsQueue.length > 0) {
logger.debug(`Attempting to send ${wsQueue.length} queued WS messages`);
while (wsQueue.length > 0) {
if (client?.readyState != ws.OPEN) break;
const data = JSON.stringify(wsQueue.shift());
logger.debug(`[WS] [FROM QUEUE] [>] ${data}`);
client.send(data);
}
}
});
while (wsQueue.length > 0) {
if (client?.readyState != ws.OPEN) break;
const data = JSON.stringify(wsQueue.shift());
logger.debug(`[WS] [FROM QUEUE] [>] ${data}`);
client.send(data);
}
}
});
client.once("close", () => {
client = undefined;
logger.warn(`WS closed, reconnecting in 3 seconds`);
setTimeout(connect, 3000);
});
client.once("close", () => {
client = undefined;
logger.warn(`WS closed, reconnecting in 3 seconds`);
setTimeout(connect, 3000);
});
client.once('error', (err) => {
client = undefined;
logger.warn(`WS: ${err}`);
});
client.once("error", (err: Error) => {
client = undefined;
logger.warn(`WS: ${err}`);
});
client.on('message', (msg) => {
logger.debug(`[WS] [<] ${msg.toString('utf8')}`);
try {
const jsonMsg = JSON.parse(msg.toString('utf8'));
wsEvents.emit('message', jsonMsg);
if (jsonMsg['nonce'] && jsonMsg['type']) {
const hasListeners = wsEvents.emit(`req:${jsonMsg.type}`, jsonMsg.data, (res: { [key: string]: any }) => {
wsSend({ nonce: jsonMsg.nonce, type: `response:${jsonMsg.nonce}`, data: res });
});
if (!hasListeners) {
wsSend({
nonce: jsonMsg.nonce,
type: `response:${jsonMsg.nonce}`,
data: {
success: false,
error: 'No event listeners available for event'
}
});
}
}
} catch(e) { console.error(e) }
});
client.on("message", (msg: ws.Data) => {
logger.debug(`[WS] [<] ${msg.toString("utf8")}`);
try {
const jsonMsg = JSON.parse(msg.toString("utf8"));
wsEvents.emit("message", jsonMsg);
if (jsonMsg["nonce"] && jsonMsg["type"]) {
const hasListeners = wsEvents.emit(`req:${jsonMsg.type}`, jsonMsg.data, (res: { [key: string]: any }) => {
wsSend({ nonce: jsonMsg.nonce, type: `response:${jsonMsg.nonce}`, data: res });
});
if (!hasListeners) {
wsSend({
nonce: jsonMsg.nonce,
type: `response:${jsonMsg.nonce}`,
data: {
success: false,
error: "No event listeners available for event",
},
});
}
}
} catch (e) {
console.error(e);
}
});
}
function wsSend(data: { [key: string]: any }) {
if (client && client.readyState == client.OPEN) {
logger.debug(`[WS] [>] ${JSON.stringify(data)}`);
client.send(JSON.stringify(data));
} else {
logger.debug(`[WS] [QUEUED] [>] ${JSON.stringify(data)}`);
wsQueue.push(data);
}
if (client && client.readyState == client.OPEN) {
logger.debug(`[WS] [>] ${JSON.stringify(data)}`);
client.send(JSON.stringify(data));
} else {
logger.debug(`[WS] [QUEUED] [>] ${JSON.stringify(data)}`);
wsQueue.push(data);
}
}
wsEvents.on('req:test', (data: any, res: (data: any) => void) => {
res({ received: data });
wsEvents.on("req:test", (data: any, res: (data: any) => void) => {
res({ received: data });
});
wsEvents.on('req:requestLogin', async (data: any, cb: (data: WSResponse) => void) => {
try {
const user = await parseUser(data.user);
if (!user)
return cb({ success: false, statusCode: 404, error: `The specified user could not be found` });
wsEvents.on("req:requestLogin", async (data: any, cb: (data: WSResponse) => void) => {
try {
const user = await parseUser(data.user);
if (!user) return cb({ success: false, statusCode: 404, error: `The specified user could not be found` });
let code: string|null = null;
while (!code) {
const c = crypto.randomBytes(8).toString('hex');
const found = await dbs.PENDING_LOGINS.find({ code: c, user: user.id, confirmed: false });
if (found.length > 0) continue;
code = c.substring(0, 8).toUpperCase();
}
let code: string | null = null;
while (!code) {
const c = crypto.randomBytes(8).toString("hex");
const found = await dbs.PENDING_LOGINS.find({ code: c, user: user.id, confirmed: false });
if (found.length > 0) continue;
code = c.substring(0, 8).toUpperCase();
}
logger.info(`Attempted login for user ${user.id} with code ${code}`);
logger.info(`Attempted login for user ${user.id} with code ${code}`);
const nonce = ulid();
const nonce = ulid();
const [previousLogins, currentValidLogins] = await Promise.all([
dbs.PENDING_LOGINS.find({ user: user.id, confirmed: true }),
dbs.PENDING_LOGINS.find({ user: user.id, confirmed: false, expires: { $gt: Date.now() } }),
]);
const [previousLogins, currentValidLogins] = await Promise.all([
dbs.PENDING_LOGINS.find({ user: user.id, confirmed: true }),
dbs.PENDING_LOGINS.find({ user: user.id, confirmed: false, expires: { $gt: Date.now() } }),
]);
if (currentValidLogins.length >= 5) return cb({ success: false, statusCode: 403, error: 'Too many pending logins. Try again later.' });
if (currentValidLogins.length >= 5) return cb({ success: false, statusCode: 403, error: "Too many pending logins. Try again later." });
await dbs.PENDING_LOGINS.insert({
code,
expires: Date.now() + (1000 * 60 * 15), // Expires in 15 minutes
user: user.id,
nonce: nonce,
confirmed: false,
requirePhishingConfirmation: previousLogins.length == 0,
exchanged: false,
invalid: false,
} as PendingLogin);
await dbs.PENDING_LOGINS.insert({
code,
expires: Date.now() + 1000 * 60 * 15, // Expires in 15 minutes
user: user.id,
nonce: nonce,
confirmed: false,
requirePhishingConfirmation: previousLogins.length == 0,
exchanged: false,
invalid: false,
} as PendingLogin);
cb({ success: true, uid: user.id, nonce, code });
} catch(e) {
console.error(e);
cb({ success: false, error: `${e}` });
}
cb({ success: true, uid: user.id, nonce, code });
} catch (e) {
console.error(e);
cb({ success: false, error: `${e}` });
}
});
wsEvents.on('req:stats', async (_data: any, cb: (data: { servers: number }) => void) => {
const servers = bot.servers.size();
cb({ servers });
wsEvents.on("req:stats", async (_data: any, cb: (data: { servers: number }) => void) => {
const servers = bot.servers.size();
cb({ servers });
});
export { wsEvents, wsSend, WSResponse }
export { wsEvents, wsSend, WSResponse };
import('./api/servers');
import('./api/server_details');
import('./api/users');
import("./api/servers");
import("./api/server_details");
import("./api/users");

View file

@ -7,7 +7,6 @@ import axios from 'axios';
import { Server } from "revolt.js";
import LogConfig from "automod/dist/types/LogConfig";
import LogMessage from "automod/dist/types/LogMessage";
import { ColorResolvable, MessageEmbed } from "discord.js";
import logger from "./logger";
import { ulid } from "ulid";
import { Channel } from "revolt.js";
@ -182,58 +181,6 @@ async function uploadFile(file: any, filename: string): Promise<string> {
}
async function sendLogMessage(config: LogConfig, content: LogMessage) {
if (config.discord?.webhookUrl) {
let c = { ...content, ...content.overrides?.discord };
const embed = new MessageEmbed();
if (c.title) embed.setTitle(content.title);
if (c.description) embed.setDescription(c.description);
if (c.color?.match(/^#[0-9a-fA-F]+$/))
embed.setColor(c.color as ColorResolvable);
if (c.fields?.length) {
for (const field of c.fields) {
embed.addField(
field.title,
field.content.trim() || "\u200b",
field.inline
);
}
}
if (content.image) {
if (content.image.type == "THUMBNAIL")
embed.setThumbnail(content.image.url);
else if (content.image.type == "BIG")
embed.setImage(content.image.url);
}
if (content.attachments?.length) {
embed.setFooter(
`Attachments: ${content.attachments
.map((a) => a.name)
.join(", ")}`
);
}
let data = new FormData();
content.attachments?.forEach((a) => {
data.append(`files[${ulid()}]`, a.content, { filename: a.name });
});
data.append(
"payload_json",
JSON.stringify({ embeds: [embed.toJSON()] }),
{ contentType: "application/json" }
);
axios
.post(config.discord.webhookUrl, data, {
headers: data.getHeaders(),
})
.catch((e) =>
logger.error(`Failed to send log message (discord): ${e}`)
);
}
if (config.revolt?.channel) {
let c = { ...content, ...content.overrides?.revolt };
try {

View file

@ -1,7 +1,6 @@
import * as Revolt from "revolt.js";
import { IMonkManager } from 'monk';
import logger from '../bot/logger';
import { adminBotLog } from "../bot/logging";
import { ClientOptions } from "revolt.js/src/Client";
class AutomodClient extends Revolt.Client {
@ -27,7 +26,6 @@ let login = (client: Revolt.Client): Promise<void> => new Promise((resolve, reje
client.once('ready', () => {
logger.done(`Bot logged in as ${client.user?.username}!`);
adminBotLog({ message: 'Bot logged in', type: 'INFO' });
resolve();
});
});

View file

@ -2,7 +2,7 @@ enum CommandCategory {
Moderation = 'Moderation',
Config = 'Config',
Owner = 'Owner',
Misc = 'Misc',
Miscellaneous = 'Miscellaneous',
None = 'None',
}

View file

@ -5,26 +5,6 @@ __metadata:
version: 6
cacheKey: 8
"@discordjs/builders@npm:^0.16.0":
version: 0.16.0
resolution: "@discordjs/builders@npm:0.16.0"
dependencies:
"@sapphire/shapeshift": ^3.5.1
discord-api-types: ^0.36.2
fast-deep-equal: ^3.1.3
ts-mixer: ^6.0.1
tslib: ^2.4.0
checksum: bf7ab00924bf84678c139b32c3b6bda16d62f190a1674ebaa4ec8767c7105890b1375716296037306661e138fe1c09c535b3141a047b7fceafaa92937a76cb8b
languageName: node
linkType: hard
"@discordjs/collection@npm:^0.7.0":
version: 0.7.0
resolution: "@discordjs/collection@npm:0.7.0"
checksum: 141aa35a5433bacba3617b533557b4948388c7b59cdaecee51ccd721c1b9242e50d95bdef53ee2491535a017095f5072ace3c3e9e594193f67a1c5a8a4b7db93
languageName: node
linkType: hard
"@insertish/oapi@npm:0.1.18":
version: 0.1.18
resolution: "@insertish/oapi@npm:0.1.18"
@ -52,23 +32,6 @@ __metadata:
languageName: node
linkType: hard
"@sapphire/async-queue@npm:^1.5.0":
version: 1.5.0
resolution: "@sapphire/async-queue@npm:1.5.0"
checksum: 983dbd1fd1b1798496e5edb6a0db7e4d90015160e1028f20475eab0a92625513f1e8d938bc0305811a9cec461c94e01b1e4191615ff03ba49356f568f3255250
languageName: node
linkType: hard
"@sapphire/shapeshift@npm:^3.5.1":
version: 3.8.1
resolution: "@sapphire/shapeshift@npm:3.8.1"
dependencies:
fast-deep-equal: ^3.1.3
lodash: ^4.17.21
checksum: 2a5954c76ee9a91506ae269141ffd2d71e05891c7f1618d0acbf3670312f0b473e356f9c3dafe484d8dc89282d7554f1fd7d720a2a3b0e921fb4e969d09513ee
languageName: node
linkType: hard
"@solid-primitives/map@npm:^0.4.3":
version: 0.4.3
resolution: "@solid-primitives/map@npm:0.4.3"
@ -139,16 +102,6 @@ __metadata:
languageName: node
linkType: hard
"@types/node-fetch@npm:^2.6.2":
version: 2.6.2
resolution: "@types/node-fetch@npm:2.6.2"
dependencies:
"@types/node": "*"
form-data: ^3.0.0
checksum: 6f73b1470000d303d25a6fb92875ea837a216656cb7474f66cdd67bb014aa81a5a11e7ac9c21fe19bee9ecb2ef87c1962bceeaec31386119d1ac86e4c30ad7a6
languageName: node
linkType: hard
"@types/node@npm:*":
version: 18.15.3
resolution: "@types/node@npm:18.15.3"
@ -156,12 +109,12 @@ __metadata:
languageName: node
linkType: hard
"@types/ws@npm:^8.5.3":
version: 8.5.4
resolution: "@types/ws@npm:8.5.4"
"@types/ws@npm:^8.5.10":
version: 8.5.10
resolution: "@types/ws@npm:8.5.10"
dependencies:
"@types/node": "*"
checksum: fefbad20d211929bb996285c4e6f699b12192548afedbe4930ab4384f8a94577c9cd421acaad163cacd36b88649509970a05a0b8f20615b30c501ed5269038d1
checksum: 3ec416ea2be24042ebd677932a462cf16d2080393d8d7d0b1b3f5d6eaa4a7387aaf0eefb99193c0bfd29444857cf2e0c3ac89899e130550dc6c14ada8a46d25e
languageName: node
linkType: hard
@ -367,37 +320,6 @@ __metadata:
languageName: node
linkType: hard
"discord-api-types@npm:^0.33.5":
version: 0.33.5
resolution: "discord-api-types@npm:0.33.5"
checksum: 6dcaad640c5693a69c9a4f5e444e739dde11ba835164ae6fd3dd5a1ab7b4d7f96cd022ed653eeaff2c8051ead0d998a5d502a2915cfacdde596364b82d9e3b3f
languageName: node
linkType: hard
"discord-api-types@npm:^0.36.2":
version: 0.36.3
resolution: "discord-api-types@npm:0.36.3"
checksum: 3089c0fb37425dc5df03c76d82988d43fcc272699b06a02fc830d0a3bef550009aaebdf6d646529e8a7ccea76ae3f43b099d736ea5ef37a0be143142ab49871d
languageName: node
linkType: hard
"discord.js@npm:^13.3.1":
version: 13.14.0
resolution: "discord.js@npm:13.14.0"
dependencies:
"@discordjs/builders": ^0.16.0
"@discordjs/collection": ^0.7.0
"@sapphire/async-queue": ^1.5.0
"@types/node-fetch": ^2.6.2
"@types/ws": ^8.5.3
discord-api-types: ^0.33.5
form-data: ^4.0.0
node-fetch: ^2.6.7
ws: ^8.9.0
checksum: 1eb64e121b2c473f13e9a92639341594f69b4c91f3b616e0942e4123bb8f5696587f6c9d31fe2257273c7923488ff3c530795a144abf91df16e79e2ce84c9597
languageName: node
linkType: hard
"dotenv@npm:^10.0.0":
version: 10.0.0
resolution: "dotenv@npm:10.0.0"
@ -419,13 +341,6 @@ __metadata:
languageName: node
linkType: hard
"fast-deep-equal@npm:^3.1.3":
version: 3.1.3
resolution: "fast-deep-equal@npm:3.1.3"
checksum: e21a9d8d84f53493b6aa15efc9cfd53dd5b714a1f23f67fb5dc8f574af80df889b3bce25dc081887c6d25457cce704e636395333abad896ccdec03abaf1f3f9d
languageName: node
linkType: hard
"follow-redirects@npm:^1.14.4, follow-redirects@npm:^1.14.8":
version: 1.15.2
resolution: "follow-redirects@npm:1.15.2"
@ -436,17 +351,6 @@ __metadata:
languageName: node
linkType: hard
"form-data@npm:^3.0.0":
version: 3.0.1
resolution: "form-data@npm:3.0.1"
dependencies:
asynckit: ^0.4.0
combined-stream: ^1.0.8
mime-types: ^2.1.12
checksum: b019e8d35c8afc14a2bd8a7a92fa4f525a4726b6d5a9740e8d2623c30e308fbb58dc8469f90415a856698933c8479b01646a9dff33c87cc4e76d72aedbbf860d
languageName: node
linkType: hard
"form-data@npm:^4.0.0":
version: 4.0.0
resolution: "form-data@npm:4.0.0"
@ -527,13 +431,6 @@ __metadata:
languageName: node
linkType: hard
"lodash@npm:^4.17.21":
version: 4.17.21
resolution: "lodash@npm:4.17.21"
checksum: eb835a2e51d381e561e508ce932ea50a8e5a68f4ebdd771ea240d3048244a8d13658acbd502cd4829768c56f2e16bdd4340b9ea141297d472517b83868e677f7
languageName: node
linkType: hard
"log75@npm:^2.2.0":
version: 2.2.0
resolution: "log75@npm:2.2.0"
@ -704,20 +601,6 @@ __metadata:
languageName: node
linkType: hard
"node-fetch@npm:^2.6.7":
version: 2.6.9
resolution: "node-fetch@npm:2.6.9"
dependencies:
whatwg-url: ^5.0.0
peerDependencies:
encoding: ^0.1.0
peerDependenciesMeta:
encoding:
optional: true
checksum: acb04f9ce7224965b2b59e71b33c639794d8991efd73855b0b250921382b38331ffc9d61bce502571f6cc6e11a8905ca9b1b6d4aeb586ab093e2756a1fd190d0
languageName: node
linkType: hard
"object-assign@npm:^4.1.1":
version: 4.1.1
resolution: "object-assign@npm:4.1.1"
@ -822,10 +705,10 @@ __metadata:
resolution: "revolt-automod@workspace:."
dependencies:
"@types/monk": ^6.0.0
"@types/ws": ^8.5.10
automod: ^0.1.0
axios: ^0.22.0
dayjs: ^1.10.7
discord.js: ^13.3.1
dotenv: ^10.0.0
form-data: ^4.0.0
log75: ^2.2.0
@ -962,27 +845,6 @@ __metadata:
languageName: node
linkType: hard
"tr46@npm:~0.0.3":
version: 0.0.3
resolution: "tr46@npm:0.0.3"
checksum: 726321c5eaf41b5002e17ffbd1fb7245999a073e8979085dacd47c4b4e8068ff5777142fc6726d6ca1fd2ff16921b48788b87225cbc57c72636f6efa8efbffe3
languageName: node
linkType: hard
"ts-mixer@npm:^6.0.1":
version: 6.0.3
resolution: "ts-mixer@npm:6.0.3"
checksum: 7fbaba0a413bf817835a6a23d46bccf4192dd4d7345b6bae9d594c88acffac35bf4995ef3cce753090c8abcdf2afd16dba8899365584a1f960ccc2a15bf2e2d6
languageName: node
linkType: hard
"tslib@npm:^2.4.0":
version: 2.5.0
resolution: "tslib@npm:2.5.0"
checksum: ae3ed5f9ce29932d049908ebfdf21b3a003a85653a9a140d614da6b767a93ef94f460e52c3d787f0e4f383546981713f165037dc2274df212ea9f8a4541004e1
languageName: node
linkType: hard
"typedoc@npm:^0.24.1":
version: 0.24.6
resolution: "typedoc@npm:0.24.6"
@ -1058,23 +920,6 @@ __metadata:
languageName: node
linkType: hard
"webidl-conversions@npm:^3.0.0":
version: 3.0.1
resolution: "webidl-conversions@npm:3.0.1"
checksum: c92a0a6ab95314bde9c32e1d0a6dfac83b578f8fa5f21e675bc2706ed6981bc26b7eb7e6a1fab158e5ce4adf9caa4a0aee49a52505d4d13c7be545f15021b17c
languageName: node
linkType: hard
"whatwg-url@npm:^5.0.0":
version: 5.0.0
resolution: "whatwg-url@npm:5.0.0"
dependencies:
tr46: ~0.0.3
webidl-conversions: ^3.0.0
checksum: b8daed4ad3356cc4899048a15b2c143a9aed0dfae1f611ebd55073310c7b910f522ad75d727346ad64203d7e6c79ef25eafd465f4d12775ca44b90fa82ed9e2c
languageName: node
linkType: hard
"wmf@npm:~1.0.1":
version: 1.0.2
resolution: "wmf@npm:1.0.2"
@ -1089,7 +934,7 @@ __metadata:
languageName: node
linkType: hard
"ws@npm:^8.13.0, ws@npm:^8.9.0":
"ws@npm:^8.13.0":
version: 8.13.0
resolution: "ws@npm:8.13.0"
peerDependencies: