diff --git a/.copilotignore b/.copilotignore new file mode 100644 index 000000000..412c25747 --- /dev/null +++ b/.copilotignore @@ -0,0 +1 @@ +docker-compose.yml \ No newline at end of file diff --git a/.dockerignore b/.dockerignore index 25c138f27..d85ff3ea5 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,6 +1,11 @@ node_modules data +muse dist dts .env Dockerfile +.git +.gitignore +*.md +/*.sh diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..484a77bce --- /dev/null +++ b/.gitattributes @@ -0,0 +1,14 @@ +# Set default behavior for all files +* text=auto + +# Force LF line endings for shell scripts +*.sh text eol=lf + +# Force LF for other Unix-specific files +Dockerfile text eol=lf +*.yml text eol=lf +*.yaml text eol=lf + +# Force CRLF for Windows-specific files +*.bat text eol=crlf +*.cmd text eol=crlf diff --git a/.gitignore b/.gitignore index 6cbf08c2c..e406e7d57 100644 --- a/.gitignore +++ b/.gitignore @@ -107,3 +107,8 @@ dist # TernJS port file .tern-port + +docker-compose.yml +/muse + +.vscode \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 65e8156d8..049c78089 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,15 +1,18 @@ +# syntax=docker/dockerfile:1 FROM node:22-bookworm-slim AS base # openssl will be a required package if base is updated to 18.16+ due to node:*-slim base distro change # https://github.com/prisma/prisma/issues/19729#issuecomment-1591270599 -# Install ffmpeg +# Install ffmpeg and yt-dlp (will be updated on container start) RUN apt-get update \ && apt-get install --no-install-recommends -y \ ffmpeg \ tini \ openssl \ ca-certificates \ - && apt-get autoclean \ + python3 \ + python3-pip \ + && pip3 install --no-cache-dir --break-system-packages yt-dlp \ && apt-get autoremove \ && rm -rf /var/lib/apt/lists/* @@ -21,28 +24,27 @@ WORKDIR /usr/app # Add Python and build tools to compile native modules RUN apt-get update \ && apt-get install --no-install-recommends -y \ - python3 \ python-is-python3 \ build-essential \ - && apt-get autoclean \ && apt-get autoremove \ && rm -rf /var/lib/apt/lists/* COPY package.json . COPY yarn.lock . -RUN yarn install --prod +RUN --mount=type=cache,target=/root/.yarn \ + YARN_CACHE_FOLDER=/root/.yarn yarn install --prod --frozen-lockfile RUN cp -R node_modules /usr/app/prod_node_modules -RUN yarn install +RUN --mount=type=cache,target=/root/.yarn \ + YARN_CACHE_FOLDER=/root/.yarn yarn install --frozen-lockfile FROM dependencies AS builder COPY . . # Run tsc build -RUN yarn prisma generate -RUN yarn build +RUN yarn prisma generate && yarn build # Only keep what's necessary to run FROM base AS runner @@ -52,8 +54,14 @@ WORKDIR /usr/app COPY --from=builder /usr/app/dist ./dist COPY --from=dependencies /usr/app/prod_node_modules node_modules COPY --from=builder /usr/app/node_modules/.prisma/client ./node_modules/.prisma/client +COPY --from=builder /usr/app/scripts ./scripts -COPY . . +COPY schema.prisma . +COPY migrations ./migrations +COPY package.json . + +# Make the startup script executable +RUN chmod +x scripts/start-with-ytdlp-update.sh ARG COMMIT_HASH=unknown ARG BUILD_DATE=unknown @@ -64,4 +72,4 @@ ENV COMMIT_HASH=$COMMIT_HASH ENV BUILD_DATE=$BUILD_DATE ENV ENV_FILE=/config -CMD ["tini", "--", "node", "--enable-source-maps", "dist/scripts/migrate-and-start.js"] \ No newline at end of file +CMD ["tini", "--", "./scripts/start-with-ytdlp-update.sh"] \ No newline at end of file diff --git a/README.md b/README.md index d22400ec4..a47715f25 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ Muse is a **highly-opinionated midwestern self-hosted** Discord music bot **that Muse is written in TypeScript. You can either run Muse with Docker (recommended) or directly with Node.js. Both methods require API keys passed in as environment variables: - `DISCORD_TOKEN` can be acquired [here](https://discordapp.com/developers/applications) by creating a 'New Application', then going to 'Bot'. -- `SPOTIFY_CLIENT_ID` and `SPOTIFY_CLIENT_SECRET` can be acquired [here](https://developer.spotify.com/dashboard/applications) with 'Create a Client ID' (Optional). +- `SPOTIFY_CLIENT_ID` and `SPOTIFY_CLIENT_SECRET` can be acquired [here](https://developer.spotify.com/dashboard/applications) with 'Create a Client ID' (Optional). **Requires Spotify Premium** — omit these variables if you don't have a Premium account. - `YOUTUBE_API_KEY` can be acquired by [creating a new project](https://console.developers.google.com) in Google's Developer Console, enabling the YouTube API, and creating an API key under credentials. Muse will log a URL when run. Open this URL in a browser to invite Muse to your server. Muse will DM the server owner after it's added with setup instructions. @@ -147,3 +147,16 @@ You can configure the bot to automatically turn down the volume when people are - `/config set-reduce-vol-when-voice false` - Disable automatic volume reduction - `/config set-reduce-vol-when-voice-target ` - Set the target volume percentage when people speak (0-100, default is 70) +### Building from Source + +To build and run Muse locally using Docker Compose: + +1. Copy the example configuration: `cp docker-compose.example.yml docker-compose.yml` +2. Edit `docker-compose.yml` and populate the environment variables with your API keys and tokens +3. Build and start the container: + +```bash +docker-compose up --build +``` + +This will build the latest version from source and start Muse with your local changes. \ No newline at end of file diff --git a/docker-compose.example.yml b/docker-compose.example.yml new file mode 100644 index 000000000..5de58d75f --- /dev/null +++ b/docker-compose.example.yml @@ -0,0 +1,11 @@ +services: + muse: + image: muse-local:latest + restart: always + volumes: + - ./muse:/data + environment: + - DISCORD_TOKEN= + - YOUTUBE_API_KEY= + - SPOTIFY_CLIENT_ID= + - SPOTIFY_CLIENT_SECRET= \ No newline at end of file diff --git a/package.json b/package.json index deaa63718..b6cee59c9 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "@types/node-emoji": "^1.8.1", "@types/spotify-web-api-node": "^5.0.2", "@types/validator": "^13.12.2", - "@types/ws": "8.5.4", + "@types/ws": "^8.18.1", "@typescript-eslint/eslint-plugin": "^4.31.1", "@typescript-eslint/parser": "^4.31.1", "eslint": "^7.32.0", @@ -88,15 +88,14 @@ "@discordjs/builders": "1.1.0", "@discordjs/opus": "^0.10.0", "@discordjs/rest": "1.0.1", - "@discordjs/voice": "0.18.0", - "@distube/ytdl-core": "^4.16.10", + "@discordjs/voice": "0.19.1", "@distube/ytsr": "^2.0.4", "@prisma/client": "4.16.0", "@types/libsodium-wrappers": "^0.7.9", "array-shuffle": "^3.0.0", "debug": "^4.3.3", "delay": "^5.0.0", - "discord-api-types": "0.32.1", + "discord-api-types": "0.38.41", "discord.js": "14.11.0", "dotenv": "^16.4.5", "execa": "^6.1.0", @@ -131,7 +130,7 @@ "ytsr": "^3.8.4" }, "resolutions": { - "@types/ws": "8.5.4" + "@types/ws": "8.18.1" }, "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e" } diff --git a/scripts/start-with-ytdlp-update.sh b/scripts/start-with-ytdlp-update.sh new file mode 100644 index 000000000..d34df8ea9 --- /dev/null +++ b/scripts/start-with-ytdlp-update.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +# Update yt-dlp to latest version on startup +echo "🔄 Updating yt-dlp to latest version..." +pip3 install --no-cache-dir --break-system-packages --upgrade yt-dlp + +# Check yt-dlp version +echo "📦 yt-dlp version: $(yt-dlp --version)" + +# Start the bot +echo "🚀 Starting Muse bot..." +exec node --enable-source-maps dist/scripts/migrate-and-start.js \ No newline at end of file diff --git a/src/services/add-query-to-queue.ts b/src/services/add-query-to-queue.ts index 95e16ffff..7e5009975 100644 --- a/src/services/add-query-to-queue.ts +++ b/src/services/add-query-to-queue.ts @@ -1,4 +1,3 @@ -/* eslint-disable complexity */ import {ChatInputCommandInteraction, GuildMember} from 'discord.js'; import {inject, injectable} from 'inversify'; import shuffle from 'array-shuffle'; diff --git a/src/services/player.ts b/src/services/player.ts index 8a3dd4e0d..8896b8938 100644 --- a/src/services/player.ts +++ b/src/services/player.ts @@ -1,10 +1,10 @@ import {VoiceChannel, Snowflake} from 'discord.js'; import {Readable} from 'stream'; import hasha from 'hasha'; -import ytdl, {videoFormat} from '@distube/ytdl-core'; import {WriteStream} from 'fs-capacitor'; import ffmpeg from 'fluent-ffmpeg'; import shuffle from 'array-shuffle'; +import {spawn} from 'child_process'; import { AudioPlayer, AudioPlayerState, @@ -58,7 +58,36 @@ export interface PlayerEvents { statusChange: (oldStatus: STATUS, newStatus: STATUS) => void; } -type YTDLVideoFormat = videoFormat & {loudnessDb?: number}; +interface VideoFormat { + url: string; + itag: string | number; + codecs?: string; + container?: string; + audioSampleRate?: string; + averageBitrate?: number; + bitrate?: string | number; + isLive?: boolean; + loudnessDb?: number; +} + +interface YtDlpFormat { + url?: string; + format_id?: string; + acodec?: string; + vcodec?: string; + ext?: string; + asr?: number; + abr?: number; + tbr?: number; +} + +interface YtDlpResponse { + formats?: YtDlpFormat[]; + is_live?: boolean; + duration?: number; +} + +type YTDLVideoFormat = VideoFormat; export const DEFAULT_VOLUME = 100; @@ -99,27 +128,13 @@ export default class { this.voiceConnection = joinVoiceChannel({ channelId: channel.id, guildId: channel.guild.id, - selfDeaf: false, + selfDeaf: true, adapterCreator: channel.guild.voiceAdapterCreator as DiscordGatewayAdapterCreator, }); const guildSettings = await getGuildSettings(this.guildId); - // Workaround to disable keepAlive - this.voiceConnection.on('stateChange', (oldState, newState) => { - /* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call */ - const oldNetworking = Reflect.get(oldState, 'networking'); - const newNetworking = Reflect.get(newState, 'networking'); - - const networkStateChangeHandler = (_: any, newNetworkState: any) => { - const newUdp = Reflect.get(newNetworkState, 'udp'); - clearInterval(newUdp?.keepAliveInterval); - }; - - oldNetworking?.off('stateChange', networkStateChangeHandler); - newNetworking?.on('stateChange', networkStateChangeHandler); - /* eslint-enable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call */ - + this.voiceConnection.on('stateChange', (_oldState, newState) => { this.currentChannel = channel; if (newState.status === VoiceConnectionStatus.Ready) { this.registerVoiceActivityListener(guildSettings); @@ -213,6 +228,9 @@ export default class { this.audioPlayer.unpause(); this.status = STATUS.PLAYING; this.startTrackingPosition(); + + // Log when a song resumes from pause + console.log(`▶️ Resumed: "${currentSong.title}" by ${currentSong.artist} in guild ${this.guildId}`); return; } @@ -245,6 +263,9 @@ export default class { this.status = STATUS.PLAYING; this.nowPlaying = currentSong; + // Log when a song starts playing + console.log(`🎵 Now playing: "${currentSong.title}" by ${currentSong.artist} [${currentSong.source === MediaSource.Youtube ? 'YouTube' : 'HLS'}] - Requested by ${currentSong.requestedBy} in guild ${this.guildId}`); + if (currentSong.url === this.lastSongURL) { this.startTrackingPosition(); } else { @@ -490,6 +511,79 @@ export default class { return this.volume ?? this.defaultVolume; } + private async getVideoInfoWithYtDlp(url: string): Promise { + return new Promise((resolve, reject) => { + const ytDlp = spawn('yt-dlp', ['--dump-json', '--no-warnings', url]); + + let stdout = ''; + let stderr = ''; + + ytDlp.stdout.on('data', (data: Buffer) => { + stdout += data.toString(); + }); + + ytDlp.stderr.on('data', (data: Buffer) => { + stderr += data.toString(); + }); + + ytDlp.on('close', (code: number) => { + if (code === 0) { + try { + const info = JSON.parse(stdout) as YtDlpResponse; + resolve(info); + } catch (parseError: unknown) { + reject(new Error(`Failed to parse yt-dlp JSON output: ${String(parseError)}`)); + } + } else { + reject(new Error(`yt-dlp failed with code ${code}: ${stderr}`)); + } + }); + + ytDlp.on('error', (error: Error) => { + reject(new Error(`Failed to spawn yt-dlp: ${error.message}`)); + }); + }); + } + + private extractVideoId(url: string): string { + const regex = /(?:youtube\.com\/watch\?v=|youtu\.be\/|youtube\.com\/embed\/)([^&\n?#]+)/; + const match = regex.exec(url); + return match?.[1] ?? url; + } + + private async getYouTubeInfo(url: string): Promise<{ + formats: VideoFormat[]; + isLive: boolean; + lengthSeconds: string; + }> { + const videoId = this.extractVideoId(url); + + // Construct full YouTube URL if we only have a video ID + const fullUrl = url.includes('youtube.com') || url.includes('youtu.be') ? url : `https://www.youtube.com/watch?v=${videoId}`; + + const info = await this.getVideoInfoWithYtDlp(fullUrl); + + const formats: VideoFormat[] = (info.formats ?? []).map((format: YtDlpFormat) => ({ + url: format.url ?? '', + itag: format.format_id ?? '', + codecs: + format.acodec && format.acodec !== 'none' + ? format.acodec + : format.vcodec ?? '', + container: format.ext ?? '', + audioSampleRate: format.asr?.toString(), + averageBitrate: format.abr, + bitrate: format.tbr, + isLive: info.is_live ?? false, + })); + + return { + formats, + isLive: info.is_live ?? false, + lengthSeconds: info.duration?.toString() ?? '0', + }; + } + private getHashForCache(url: string): string { return hasha(url); } @@ -515,23 +609,24 @@ export default class { if (!ffmpegInput) { // Not yet cached, must download - const info = await ytdl.getInfo(song.url); + const info = await this.getYouTubeInfo(song.url); - const formats = info.formats as YTDLVideoFormat[]; + const {formats} = info; - const filter = (format: ytdl.videoFormat): boolean => format.codecs === 'opus' && format.container === 'webm' && format.audioSampleRate !== undefined && parseInt(format.audioSampleRate, 10) === 48000; + // Look for the ideal format (opus codec, webm container, 48kHz) + const filter = (format: VideoFormat): boolean => format.codecs === 'opus' && format.container === 'webm' && format.audioSampleRate !== undefined && parseInt(format.audioSampleRate, 10) === 48000 && Boolean(format.url); format = formats.find(filter); - const nextBestFormat = (formats: ytdl.videoFormat[]): ytdl.videoFormat | undefined => { + const nextBestFormat = (formats: VideoFormat[]): VideoFormat | undefined => { if (formats.length < 1) { return undefined; } if (formats[0].isLive) { - formats = formats.sort((a, b) => (b as unknown as {audioBitrate: number}).audioBitrate - (a as unknown as {audioBitrate: number}).audioBitrate); // Bad typings + formats = formats.sort((a, b) => (b as unknown as {audioBitrate: number}).audioBitrate - (a as unknown as {audioBitrate: number}).audioBitrate); - return formats.find(format => [128, 127, 120, 96, 95, 94, 93].includes(parseInt(format.itag as unknown as string, 10))); // Bad typings + return formats.find(format => [128, 127, 120, 96, 95, 94, 93].includes(parseInt(format.itag as unknown as string, 10))); } formats = formats @@ -561,7 +656,7 @@ export default class { // Don't cache livestreams or long videos const MAX_CACHE_LENGTH_SECONDS = 30 * 60; // 30 minutes - shouldCacheVideo = !info.player_response.videoDetails.isLiveContent && parseInt(info.videoDetails.lengthSeconds, 10) < MAX_CACHE_LENGTH_SECONDS && !options.seek; + shouldCacheVideo = !info.isLive && parseInt(info.lengthSeconds, 10) < MAX_CACHE_LENGTH_SECONDS && !options.seek; debug(shouldCacheVideo ? 'Caching video' : 'Not caching video'); @@ -690,6 +785,9 @@ export default class { }) .on('start', command => { debug(`Spawned ffmpeg with ${command}`); + }) + .on('stderr', line => { + debug(`ffmpeg: ${line}`); }); stream.pipe(capacitor); diff --git a/yarn.lock b/yarn.lock index b113aa279..2477195cd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -136,16 +136,17 @@ resolved "https://registry.npmjs.org/@discordjs/util/-/util-1.1.1.tgz#bafcde0faa116c834da1258d78ec237080bbab29" integrity sha512-eddz6UnOBEB1oITPinyrB2Pttej49M9FZQY8NxgEvc3tq6ZICZ19m70RsmzRdDHk80O9NoYN/25AqJl8vPVf/g== -"@discordjs/voice@0.18.0": - version "0.18.0" - resolved "https://registry.npmjs.org/@discordjs/voice/-/voice-0.18.0.tgz#8fb1f1c46fb19a26bdff7d7c4e609b25cb46b1ba" - integrity sha512-BvX6+VJE5/vhD9azV9vrZEt9hL1G+GlOdsQaVl5iv9n87fkXjf3cSwllhR3GdaUC8m6dqT8umXIWtn3yCu4afg== - dependencies: - "@types/ws" "^8.5.12" - discord-api-types "^0.37.103" +"@discordjs/voice@0.19.1": + version "0.19.1" + resolved "https://registry.yarnpkg.com/@discordjs/voice/-/voice-0.19.1.tgz#555b8478823a270100b43cb6ebf8a64fed21b3e9" + integrity sha512-XYbFVyUBB7zhRvrjREfiWDwio24nEp/vFaVe6u9aBIC5UYuT7HvoMt8LgNfZ5hOyaCW0flFr72pkhUGz+gWw4Q== + dependencies: + "@snazzah/davey" "^0.1.9" + "@types/ws" "^8.18.1" + discord-api-types "^0.38.41" prism-media "^1.3.5" - tslib "^2.6.3" - ws "^8.18.0" + tslib "^2.8.1" + ws "^8.19.0" "@discordjs/ws@^0.8.3": version "0.8.3" @@ -162,19 +163,6 @@ tslib "^2.5.0" ws "^8.13.0" -"@distube/ytdl-core@^4.16.6": - version "4.16.6" - resolved "https://registry.yarnpkg.com/@distube/ytdl-core/-/ytdl-core-4.16.6.tgz#d433b0c8a8863c199f0f8be68b236e29479be6fe" - integrity sha512-+K88E2FRk/QPSC3l/U/qNq2LO0hPmFnDmK8CHK1Pzwh530aSacTLBhuZPgtoJAwNNncaTkmskP6lXoaw2eZjQw== - dependencies: - http-cookie-agent "^6.0.8" - https-proxy-agent "^7.0.6" - m3u8stream "^0.8.6" - miniget "^4.2.3" - sax "^1.4.1" - tough-cookie "^5.1.0" - undici "^7.3.0" - "@distube/ytsr@^2.0.4": version "2.0.4" resolved "https://registry.npmjs.org/@distube/ytsr/-/ytsr-2.0.4.tgz#873b7ca767b5ff362bc0e136ae0d9ca5cbde8f7b" @@ -182,6 +170,28 @@ dependencies: undici "^6.18.2" +"@emnapi/core@^1.7.1": + version "1.8.1" + resolved "https://registry.yarnpkg.com/@emnapi/core/-/core-1.8.1.tgz#fd9efe721a616288345ffee17a1f26ac5dd01349" + integrity sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg== + dependencies: + "@emnapi/wasi-threads" "1.1.0" + tslib "^2.4.0" + +"@emnapi/runtime@^1.7.1": + version "1.8.1" + resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.8.1.tgz#550fa7e3c0d49c5fb175a116e8cd70614f9a22a5" + integrity sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg== + dependencies: + tslib "^2.4.0" + +"@emnapi/wasi-threads@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz#60b2102fddc9ccb78607e4a3cf8403ea69be41bf" + integrity sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ== + dependencies: + tslib "^2.4.0" + "@esbuild-kit/cjs-loader@^2.3.3": version "2.4.4" resolved "https://registry.npmjs.org/@esbuild-kit/cjs-loader/-/cjs-loader-2.4.4.tgz#8638177732e2de258a3243597bfdba082993c442" @@ -391,6 +401,15 @@ resolved "https://registry.npmjs.org/@inversifyjs/reflect-metadata-utils/-/reflect-metadata-utils-0.2.4.tgz#c65172283db9516c4a27e8d673ca7a31a07d528b" integrity sha512-u95rV3lKfG+NT2Uy/5vNzoDujos8vN8O18SSA5UyhxsGYd4GLQn/eUsGXfOsfa7m34eKrDelTKRUX1m/BcNX5w== +"@napi-rs/wasm-runtime@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.1.tgz#c3705ab549d176b8dc5172723d6156c3dc426af2" + integrity sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A== + dependencies: + "@emnapi/core" "^1.7.1" + "@emnapi/runtime" "^1.7.1" + "@tybys/wasm-util" "^0.10.1" + "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" @@ -605,6 +624,98 @@ resolved "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz#41dd6093d34652cddb5d5bdeee04eafc33826668" integrity sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g== +"@snazzah/davey-android-arm-eabi@0.1.10": + version "0.1.10" + resolved "https://registry.yarnpkg.com/@snazzah/davey-android-arm-eabi/-/davey-android-arm-eabi-0.1.10.tgz#33e85e45cd413c601123b30c422c8eda5f6840b6" + integrity sha512-7bwHxSNEI2wVXOT6xnmpnO9SHb2xwAnf9oEdL45dlfVHTgU1Okg5rwGwRvZ2aLVFFbTyecfC8EVZyhpyTkjLSw== + +"@snazzah/davey-android-arm64@0.1.10": + version "0.1.10" + resolved "https://registry.yarnpkg.com/@snazzah/davey-android-arm64/-/davey-android-arm64-0.1.10.tgz#0bb4d4f012e7e4ec5afca4b6eaf464ac4beea533" + integrity sha512-68WUf2LQwQTP9MgPcCqTWwJztJSIk0keGfF2Y/b+MihSDh29fYJl7C0rbz69aUrVCvCC2lYkB/46P8X1kBz7yg== + +"@snazzah/davey-darwin-arm64@0.1.10": + version "0.1.10" + resolved "https://registry.yarnpkg.com/@snazzah/davey-darwin-arm64/-/davey-darwin-arm64-0.1.10.tgz#fd62fed89592b5f9386f4885e87b7b8cae49edce" + integrity sha512-nYC+DWCGUC1jUGEenCNQE/jJpL/02m0ebY/NvTCQbul5ktI/ShVzgA3kzssEhZvhf6jbH048Rs39wDhp/b24Jg== + +"@snazzah/davey-darwin-x64@0.1.10": + version "0.1.10" + resolved "https://registry.yarnpkg.com/@snazzah/davey-darwin-x64/-/davey-darwin-x64-0.1.10.tgz#91db94ced55b4fcfdc54a501c84d81a4f9d036e8" + integrity sha512-0q5Rrcs+O9sSSnPX+A3R3djEQs2nTAtMe5N3lApO6lZas/QNMl6wkEWCvTbDc2cfAYBMSk2jgc1awlRXi4LX3Q== + +"@snazzah/davey-freebsd-x64@0.1.10": + version "0.1.10" + resolved "https://registry.yarnpkg.com/@snazzah/davey-freebsd-x64/-/davey-freebsd-x64-0.1.10.tgz#5159d6661deb35a09c7c3612a6891624b51809f4" + integrity sha512-/Gq5YDD6Oz8iBqVJLswUnetCv9JCRo1quYX5ujzpAG8zPCNItZo4g4h5p9C+h4Yoay2quWBYhoaVqQKT96bm8g== + +"@snazzah/davey-linux-arm-gnueabihf@0.1.10": + version "0.1.10" + resolved "https://registry.yarnpkg.com/@snazzah/davey-linux-arm-gnueabihf/-/davey-linux-arm-gnueabihf-0.1.10.tgz#2d795d83bb68b61d29d6d625feee0f983123d1cc" + integrity sha512-0Z7Vrt0WIbgxws9CeHB9qlueYJlvltI44rUuZmysdi70UcHGxlr7nE3MnzYCr9nRWRegohn8EQPWHMKMDJH2GA== + +"@snazzah/davey-linux-arm64-gnu@0.1.10": + version "0.1.10" + resolved "https://registry.yarnpkg.com/@snazzah/davey-linux-arm64-gnu/-/davey-linux-arm64-gnu-0.1.10.tgz#653759058857afa98ce9fb7a366c19914d5d4b35" + integrity sha512-xhZQycn4QB+qXhqm/QmZ+kb9MHMXcbjjoPfvcIL4WMQXFG/zUWHW8EiBk7ZTEGMOpeab3F9D1+MlgumglYByUQ== + +"@snazzah/davey-linux-arm64-musl@0.1.10": + version "0.1.10" + resolved "https://registry.yarnpkg.com/@snazzah/davey-linux-arm64-musl/-/davey-linux-arm64-musl-0.1.10.tgz#e3c68071659bdde529716d4d589d8e4dcbead4d1" + integrity sha512-pudzQCP9rZItwW4qHHvciMwtNd9kWH4l73g6Id1LRpe6sc8jiFBV7W+YXITj2PZbI0by6XPfkRP6Dk5IkGOuAw== + +"@snazzah/davey-linux-x64-gnu@0.1.10": + version "0.1.10" + resolved "https://registry.yarnpkg.com/@snazzah/davey-linux-x64-gnu/-/davey-linux-x64-gnu-0.1.10.tgz#646a623e9943699cbfa64f4cd37d58c5ab980ef7" + integrity sha512-DC8qRmk+xJEFNqjxKB46cETKeDQqgUqE5p39KXS2k6Vl/XTi8pw8pXOxrPfYte5neoqlWAVQzbxuLnwpyRJVEQ== + +"@snazzah/davey-linux-x64-musl@0.1.10": + version "0.1.10" + resolved "https://registry.yarnpkg.com/@snazzah/davey-linux-x64-musl/-/davey-linux-x64-musl-0.1.10.tgz#5cc349d37fde7d30df83a964142d1e74a5435cf2" + integrity sha512-wPR5/2QmsF7sR0WUaCwbk4XI3TLcxK9PVK8mhgcAYyuRpbhcVgNGWXs8ulcyMSXve5pFRJAFAuMTGCEb014peg== + +"@snazzah/davey-wasm32-wasi@0.1.10": + version "0.1.10" + resolved "https://registry.yarnpkg.com/@snazzah/davey-wasm32-wasi/-/davey-wasm32-wasi-0.1.10.tgz#f04df49177557c40d68246ee885584ca276f31bd" + integrity sha512-SfQavU+eKTDbRmPeLRodrVSfsWq25PYTmH1nIZW3B27L6IkijzjXZZuxiU1ZG1gdI5fB7mwXrOTtx34t+vAG7Q== + dependencies: + "@napi-rs/wasm-runtime" "^1.1.1" + +"@snazzah/davey-win32-arm64-msvc@0.1.10": + version "0.1.10" + resolved "https://registry.yarnpkg.com/@snazzah/davey-win32-arm64-msvc/-/davey-win32-arm64-msvc-0.1.10.tgz#dfa392760a4a0999d8b46d553b2929d249ed0a96" + integrity sha512-Raafk53smYs67wZCY9bQXHXzbaiRMS5QCdjTdin3D9fF5A06T/0Zv1z7/YnaN+O3GSL/Ou3RvynF7SziToYiFQ== + +"@snazzah/davey-win32-ia32-msvc@0.1.10": + version "0.1.10" + resolved "https://registry.yarnpkg.com/@snazzah/davey-win32-ia32-msvc/-/davey-win32-ia32-msvc-0.1.10.tgz#e1f739cfa0917759dd8de67f6598a4d700ee4f0c" + integrity sha512-pAs43l/DiZ+icqBwxIwNePzuYxFM1ZblVuf7t6vwwSLxvova7vnREnU7qDVjbc5/YTUHOsqYy3S6TpZMzDo2lw== + +"@snazzah/davey-win32-x64-msvc@0.1.10": + version "0.1.10" + resolved "https://registry.yarnpkg.com/@snazzah/davey-win32-x64-msvc/-/davey-win32-x64-msvc-0.1.10.tgz#2c35dfc29cf13f6237d04ab8cf55903af20c9b15" + integrity sha512-kr6148VVBoUT4CtD+5hYshTFRny7R/xQZxXFhFc0fYjtmdMVM8Px9M91olg1JFNxuNzdfMfTufR58Q3wfBocug== + +"@snazzah/davey@^0.1.9": + version "0.1.10" + resolved "https://registry.yarnpkg.com/@snazzah/davey/-/davey-0.1.10.tgz#a3c6916860c58a43a0f5ff20ea138b368d2b5a73" + integrity sha512-J5f7vV5/tnj0xGnqufFRd6qiWn3FcR3iXjpjpEmO2Ok+Io0AASkMaZ3I39TsL45as0Qo5bq9wWuamFQ77PjJ+g== + optionalDependencies: + "@snazzah/davey-android-arm-eabi" "0.1.10" + "@snazzah/davey-android-arm64" "0.1.10" + "@snazzah/davey-darwin-arm64" "0.1.10" + "@snazzah/davey-darwin-x64" "0.1.10" + "@snazzah/davey-freebsd-x64" "0.1.10" + "@snazzah/davey-linux-arm-gnueabihf" "0.1.10" + "@snazzah/davey-linux-arm64-gnu" "0.1.10" + "@snazzah/davey-linux-arm64-musl" "0.1.10" + "@snazzah/davey-linux-x64-gnu" "0.1.10" + "@snazzah/davey-linux-x64-musl" "0.1.10" + "@snazzah/davey-wasm32-wasi" "0.1.10" + "@snazzah/davey-win32-arm64-msvc" "0.1.10" + "@snazzah/davey-win32-ia32-msvc" "0.1.10" + "@snazzah/davey-win32-x64-msvc" "0.1.10" + "@szmarczak/http-timer@^1.1.2": version "1.1.2" resolved "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" @@ -629,6 +740,13 @@ resolved "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== +"@tybys/wasm-util@^0.10.1": + version "0.10.1" + resolved "https://registry.yarnpkg.com/@tybys/wasm-util/-/wasm-util-0.10.1.tgz#ecddd3205cf1e2d5274649ff0eedd2991ed7f414" + integrity sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg== + dependencies: + tslib "^2.4.0" + "@types/bluebird@^3.5.35": version "3.5.42" resolved "https://registry.npmjs.org/@types/bluebird/-/bluebird-3.5.42.tgz#7ec05f1ce9986d920313c1377a5662b1b563d366" @@ -734,10 +852,10 @@ resolved "https://registry.npmjs.org/@types/validator/-/validator-13.12.3.tgz#af160ddaf1e43ab66fe69473a90b14bb9f435d29" integrity sha512-2ipwZ2NydGQJImne+FhNdhgRM37e9lCev99KnqkbFHd94Xn/mErARWI1RSLem1QA19ch5kOhzIZd7e8CA2FI8g== -"@types/ws@8.5.4", "@types/ws@^8.5.12", "@types/ws@^8.5.4": - version "8.5.4" - resolved "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz#bb10e36116d6e570dd943735f86c933c1587b8a5" - integrity sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg== +"@types/ws@8.18.1", "@types/ws@^8.18.1", "@types/ws@^8.5.4": + version "8.18.1" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.18.1.tgz#48464e4bf2ddfd17db13d845467f6070ffea4aa9" + integrity sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg== dependencies: "@types/node" "*" @@ -862,11 +980,6 @@ agent-base@6, agent-base@^6.0.0, agent-base@^6.0.2: dependencies: debug "4" -agent-base@^7.1.2, agent-base@^7.1.3: - version "7.1.3" - resolved "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz#29435eb821bc4194633a5b89e5bc4703bafc25a1" - integrity sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw== - ajv@^6.10.0, ajv@^6.12.4: version "6.12.6" resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" @@ -1611,26 +1724,31 @@ dir-glob@^3.0.1: dependencies: path-type "^4.0.0" -discord-api-types@0.32.1: - version "0.32.1" - resolved "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.32.1.tgz#c468ec31a1ac2565673619ba1e0d35f01d339a65" - integrity sha512-/ewl0CPYT5xjOC+SJ7wADJKjtpZfiiUaYXOP/Ns54lnBcv4Xqa4iKSqRF/w1fjiUvWTYN9W8UuOiyCHtmu5fJw== - discord-api-types@0.37.61: version "0.37.61" resolved "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.61.tgz#9dd8e58c624237e6f1b23be2d29579af268b8c5b" integrity sha512-o/dXNFfhBpYHpQFdT6FWzeO7pKc838QeeZ9d91CfVAtpr5XLK4B/zYxQbYgPdoMiTDvJfzcsLW5naXgmHGDNXw== +discord-api-types@0.38.41: + version "0.38.41" + resolved "https://registry.yarnpkg.com/discord-api-types/-/discord-api-types-0.38.41.tgz#4dcf88da7d80d4afb6f3b811f3ecf804deed6b14" + integrity sha512-yMECyR8j9c2fVTvCQ+Qc24pweYFIZk/XoxDOmt1UvPeSw5tK6gXBd/2hhP+FEAe9Y6ny8pRMaf618XDK4U53OQ== + discord-api-types@^0.36.3: version "0.36.3" resolved "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.36.3.tgz#a931b7e57473a5c971d6937fa5f392eb30047579" integrity sha512-bz/NDyG0KBo/tY14vSkrwQ/n3HKPf87a0WFW/1M9+tXYK+vp5Z5EksawfCWo2zkAc6o7CClc0eff1Pjrqznlwg== -discord-api-types@^0.37.103, discord-api-types@^0.37.114, discord-api-types@^0.37.119, discord-api-types@^0.37.41: +discord-api-types@^0.37.114, discord-api-types@^0.37.119, discord-api-types@^0.37.41: version "0.37.119" resolved "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.119.tgz#29e32f635351da32dd4c92defcafdeb65156ad33" integrity sha512-WasbGFXEB+VQWXlo6IpW3oUv73Yuau1Ig4AZF/m13tXcTKnMpc/mHjpztIlz4+BM9FG9BHQkEXiPto3bKduQUg== +discord-api-types@^0.38.41: + version "0.38.42" + resolved "https://registry.yarnpkg.com/discord-api-types/-/discord-api-types-0.38.42.tgz#e5732b1ccf36fe7483b0bbec4ecf53260485ac9e" + integrity sha512-qs1kya7S84r5RR8m9kgttywGrmmoHaRifU1askAoi+wkoSefLpZP6aGXusjNw5b0jD3zOg3LTwUa3Tf2iHIceQ== + discord.js@14.11.0: version "14.11.0" resolved "https://registry.npmjs.org/discord.js/-/discord.js-14.11.0.tgz#6529d49f30d10fc5a9ff8e6796661aa998769afe" @@ -2835,13 +2953,6 @@ http-cache-semantics@^4.0.0, http-cache-semantics@^4.1.1: resolved "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== -http-cookie-agent@^6.0.8: - version "6.0.8" - resolved "https://registry.npmjs.org/http-cookie-agent/-/http-cookie-agent-6.0.8.tgz#f2635638f4172c7de0c482396ea7313e9731a62b" - integrity sha512-qnYh3yLSr2jBsTYkw11elq+T361uKAJaZ2dR4cfYZChw1dt9uL5t3zSUwehoqqVb4oldk1BpkXKm2oat8zV+oA== - dependencies: - agent-base "^7.1.3" - http-errors@2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" @@ -2878,14 +2989,6 @@ https-proxy-agent@5, https-proxy-agent@^5.0.0: agent-base "6" debug "4" -https-proxy-agent@^7.0.6: - version "7.0.6" - resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz#da8dfeac7da130b05c2ba4b59c9b6cd66611a6b9" - integrity sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw== - dependencies: - agent-base "^7.1.2" - debug "4" - human-signals@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" @@ -3608,14 +3711,6 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" -m3u8stream@^0.8.6: - version "0.8.6" - resolved "https://registry.npmjs.org/m3u8stream/-/m3u8stream-0.8.6.tgz#0d6de4ce8ee69731734e6b616e7b05dd9d9a55b1" - integrity sha512-LZj8kIVf9KCphiHmH7sbFQTVe4tOemb202fWwvJwR9W5ENW/1hxJN6ksAWGhQgSBSa3jyWhnjKU1Fw1GaOdbyA== - dependencies: - miniget "^4.2.2" - sax "^1.2.4" - macos-release@^2.5.0: version "2.5.1" resolved "https://registry.npmjs.org/macos-release/-/macos-release-2.5.1.tgz#bccac4a8f7b93163a8d163b8ebf385b3c5f55bf9" @@ -3703,7 +3798,7 @@ mimic-response@^4.0.0: resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz#35468b19e7c75d10f5165ea25e75a5ceea7cf70f" integrity sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg== -miniget@^4.2.2, miniget@^4.2.3: +miniget@^4.2.2: version "4.2.3" resolved "https://registry.npmjs.org/miniget/-/miniget-4.2.3.tgz#3707a24c7c11c25d359473291638ab28aab349bd" integrity sha512-SjbDPDICJ1zT+ZvQwK0hUcRY4wxlhhNpHL9nJOB2MEAXRGagTljsO8MEDzQMTFf0Q8g4QNi8P9lEm/g7e+qgzA== @@ -4701,11 +4796,6 @@ safe-regex-test@^1.1.0: resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -sax@^1.2.4, sax@^1.4.1: - version "1.4.1" - resolved "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz#44cc8988377f126304d3b3fc1010c733b929ef0f" - integrity sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg== - semver-compare@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" @@ -5180,18 +5270,6 @@ through@^2.3.6: resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== -tldts-core@^6.1.85: - version "6.1.85" - resolved "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.85.tgz#6f6b795468c0b5f7660a11c7306ff2766ceaea7e" - integrity sha512-DTjUVvxckL1fIoPSb3KE7ISNtkWSawZdpfxGxwiIrZoO6EbHVDXXUIlIuWympPaeS+BLGyggozX/HTMsRAdsoA== - -tldts@^6.1.32: - version "6.1.85" - resolved "https://registry.npmjs.org/tldts/-/tldts-6.1.85.tgz#c7636ad5ec2f02591264360da51c6b584ef6f7bb" - integrity sha512-gBdZ1RjCSevRPFix/hpaUWeak2/RNUZB4/8frF1r5uYMHjFptkiT0JXIebWvgI/0ZHXvxaUDDJshiA0j6GdL3w== - dependencies: - tldts-core "^6.1.85" - tmp@^0.0.33: version "0.0.33" resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" @@ -5224,13 +5302,6 @@ token-types@^5.0.0-alpha.2, token-types@^5.0.1: "@tokenizer/token" "^0.3.0" ieee754 "^1.2.1" -tough-cookie@^5.1.0: - version "5.1.2" - resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.2.tgz#66d774b4a1d9e12dc75089725af3ac75ec31bed7" - integrity sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A== - dependencies: - tldts "^6.1.32" - tr46@~0.0.3: version "0.0.3" resolved "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" @@ -5256,7 +5327,7 @@ tslib@^1.8.1: resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.0.1, tslib@^2.1.0, tslib@^2.4.0, tslib@^2.5.0, tslib@^2.6.3: +tslib@^2.0.1, tslib@^2.1.0, tslib@^2.4.0, tslib@^2.5.0, tslib@^2.6.3, tslib@^2.8.1: version "2.8.1" resolved "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== @@ -5407,11 +5478,6 @@ undici@^6.18.2: resolved "https://registry.npmjs.org/undici/-/undici-6.21.2.tgz#49c5884e8f9039c65a89ee9018ef3c8e2f1f4928" integrity sha512-uROZWze0R0itiAKVPsYhFov9LxrPMHLMEQFszeI2gCN6bnIIZ8twzBCJcN2LJrBBLfrP0t1FW0g+JmKVl8Vk1g== -undici@^7.3.0: - version "7.6.0" - resolved "https://registry.npmjs.org/undici/-/undici-7.6.0.tgz#a57f69b6710027b7ef7fed3654a6d05e788115e0" - integrity sha512-gaFsbThjrDGvAaD670r81RZro/s6H2PVZF640Qn0p5kZK+/rim7/mmyfp2W7VB5vOMaFM8vuFBJUaMlaZTYHlA== - unique-string@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz#39c6451f81afb2749de2b233e3f7c5e8843bd89d" @@ -5656,11 +5722,16 @@ write-file-atomic@^3.0.0: signal-exit "^3.0.2" typedarray-to-buffer "^3.1.5" -ws@^8.13.0, ws@^8.18.0: +ws@^8.13.0: version "8.18.1" resolved "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz#ea131d3784e1dfdff91adb0a4a116b127515e3cb" integrity sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w== +ws@^8.19.0: + version "8.19.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.19.0.tgz#ddc2bdfa5b9ad860204f5a72a4863a8895fd8c8b" + integrity sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg== + xbytes@^1.7.0: version "1.9.1" resolved "https://registry.npmjs.org/xbytes/-/xbytes-1.9.1.tgz#0a6a883205257a3fb747ef7cf45f52f8fc770523"