diff --git a/.dev.env b/.dev.env index 26a975e..b9986bb 100644 --- a/.dev.env +++ b/.dev.env @@ -28,5 +28,7 @@ DB_CARD_FILE=:memory: EXPRESS_PORT=3303 +FEATURE_METADATA=true + GDRIVESYNC_WHITELIST=147392775707426816,887272961504071690 GDRIVESYNC_AUTO=true diff --git a/.prod.env b/.prod.env index f2356de..8f02e3c 100644 --- a/.prod.env +++ b/.prod.env @@ -28,5 +28,7 @@ DB_CARD_FILE=:memory: EXPRESS_PORT=3323 +FEATURE_METADATA=false + GDRIVESYNC_WHITELIST=147392775707426816,887272961504071690 GDRIVESYNC_AUTO=false diff --git a/.stage.env b/.stage.env index ab0babf..d3239c1 100644 --- a/.stage.env +++ b/.stage.env @@ -28,5 +28,7 @@ DB_CARD_FILE=:memory: EXPRESS_PORT=3313 +FEATURE_METADATA=true + GDRIVESYNC_WHITELIST=147392775707426816,887272961504071690 GDRIVESYNC_AUTO=false diff --git a/package.json b/package.json index ad7a30f..69ed68b 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "discord.js": "^14.3.0", "dotenv": "^16.0.0", "express": "^4.18.2", + "glob": "^10.3.10", "jest": "^29.0.0", "jest-mock-extended": "^3.0.0", "minimatch": "9.0.3", diff --git a/src/Functions/CardMetadataFunction.ts b/src/Functions/CardMetadataFunction.ts new file mode 100644 index 0000000..b0f0755 --- /dev/null +++ b/src/Functions/CardMetadataFunction.ts @@ -0,0 +1,38 @@ +import { readFileSync } from "fs"; +import path from "path"; +import Config from "../database/entities/app/Config"; +import { glob } from "glob"; +import SeriesMetadata from "../contracts/SeriesMetadata"; +import { CoreClient } from "../client/client"; + +export default class CardMetadataFunction { + public static async Execute(): Promise { + if (await Config.GetValue('safemode') == "true") return false; + + try { + CoreClient.Cards = await this.FindMetadataJSONs(); + + console.log(`Loaded ${CoreClient.Cards.flatMap(x => x.cards).length} cards to database`); + } catch { + await Config.SetValue('safemode', 'true'); + return false; + } + + return true; + } + + private static async FindMetadataJSONs(): Promise { + const res: SeriesMetadata[] = []; + + const seriesJSONs = await glob(path.join(process.cwd(), 'cards', '/**/*.json')); + + for (let jsonPath of seriesJSONs) { + const jsonFile = readFileSync(jsonPath); + const parsedJson: SeriesMetadata[] = JSON.parse(jsonFile.toString()); + + res.push(...parsedJson); + } + + return res; + } +} \ No newline at end of file diff --git a/src/buttonEvents/Reroll.ts b/src/buttonEvents/Reroll.ts index 38cae08..7945b56 100644 --- a/src/buttonEvents/Reroll.ts +++ b/src/buttonEvents/Reroll.ts @@ -6,9 +6,68 @@ import { v4 } from "uuid"; import { CoreClient } from "../client/client"; import Inventory from "../database/entities/app/Inventory"; import Config from "../database/entities/app/Config"; +import CardDropHelperMetadata from "../helpers/CardDropHelperMetadata"; +import path from "path"; export default class Reroll extends ButtonEvent { public override async execute(interaction: ButtonInteraction) { + if (!(process.env.FEATURE_METADATA && process.env.FEATURE_METADATA == 'true')) { + await this.executeLegacy(interaction); + return; + } + + if (!CoreClient.AllowDrops) { + await interaction.reply('Bot is currently syncing, please wait until its done.'); + return; + } + + if (await Config.GetValue('safemode') == "true") { + await interaction.reply('Safe Mode has been activated, please resync to continue.'); + return; + } + + const randomCard = CardDropHelperMetadata.GetRandomCard(); + + if (!randomCard) { + await interaction.reply('Unable to fetch card, please try again.'); + return; + } + + const image = readFileSync(path.join(process.cwd(), 'cards', randomCard.card.path)); + + await interaction.deferReply(); + + const attachment = new AttachmentBuilder(image, { name: randomCard.card.id }); + + const inventory = await Inventory.FetchOneByCardNumberAndUserId(interaction.user.id, randomCard.card.id); + const quantityClaimed = inventory ? inventory.Quantity : 0; + + const embed = CardDropHelperMetadata.GenerateDropEmbed(randomCard, quantityClaimed); + + const claimId = v4(); + + const row = CardDropHelperMetadata.GenerateDropButtons(randomCard, claimId, interaction.user.id); + + try { + await interaction.editReply({ + embeds: [ embed ], + files: [ attachment ], + components: [ row ], + }); + } catch (e) { + console.error(e); + + if (e instanceof DiscordAPIError) { + await interaction.editReply(`Unable to send next drop. Please try again, and report this if it keeps happening. Code: ${e.code}`); + } else { + await interaction.editReply(`Unable to send next drop. Please try again, and report this if it keeps happening. Code: UNKNOWN`); + } + } + + CoreClient.ClaimId = claimId; + } + + public async executeLegacy(interaction: ButtonInteraction) { if (!CoreClient.AllowDrops) { await interaction.reply('Bot is currently syncing, please wait until its done.'); return; diff --git a/src/client/client.ts b/src/client/client.ts index f909d19..1e1d887 100644 --- a/src/client/client.ts +++ b/src/client/client.ts @@ -14,6 +14,8 @@ import { ButtonEvent } from "../type/buttonEvent"; import AppDataSource from "../database/dataSources/appDataSource"; import { Environment } from "../constants/Environment"; import Webhooks from "../webhooks"; +import CardMetadataFunction from "../Functions/CardMetadataFunction"; +import SeriesMetadata from "../contracts/SeriesMetadata"; export class CoreClient extends Client { private static _commandItems: ICommandItem[]; @@ -27,6 +29,7 @@ export class CoreClient extends Client { public static ClaimId: string; public static Environment: Environment; public static AllowDrops: boolean; + public static Cards: SeriesMetadata[]; public static get commandItems(): ICommandItem[] { return this._commandItems; @@ -75,7 +78,11 @@ export class CoreClient extends Client { super.on("interactionCreate", this._events.onInteractionCreate); super.on("ready", this._events.onReady); - await CardSetupFunction.Execute(); + if (process.env.FEATURE_METADATA && process.env.FEATURE_METADATA == 'true') { + await CardMetadataFunction.Execute(); + } else { + await CardSetupFunction.Execute(); + } this._util.loadEvents(this, CoreClient._eventItems); this._util.loadSlashCommands(this); diff --git a/src/commands/drop.ts b/src/commands/drop.ts index bebe581..41045c5 100644 --- a/src/commands/drop.ts +++ b/src/commands/drop.ts @@ -6,6 +6,8 @@ import { CoreClient } from "../client/client"; import { v4 } from "uuid"; import Inventory from "../database/entities/app/Inventory"; import Config from "../database/entities/app/Config"; +import CardDropHelperMetadata from "../helpers/CardDropHelperMetadata"; +import path from "path"; export default class Drop extends Command { constructor() { @@ -17,6 +19,63 @@ export default class Drop extends Command { } public override async execute(interaction: CommandInteraction) { + if (!(process.env.FEATURE_METADATA && process.env.FEATURE_METADATA == 'true')) { + await this.executeLegacy(interaction); + return; + } + + if (!CoreClient.AllowDrops) { + await interaction.reply('Bot is currently syncing, please wait until its done.'); + return; + } + + if (await Config.GetValue('safemode') == "true") { + await interaction.reply('Safe Mode has been activated, please resync to continue.'); + return; + } + + const randomCard = CardDropHelperMetadata.GetRandomCard(); + + if (!randomCard) { + await interaction.reply('Unable to fetch card, please try again.'); + return; + } + + const image = readFileSync(path.join(process.cwd(), 'cards', randomCard.card.path)); + + await interaction.deferReply(); + + const attachment = new AttachmentBuilder(image, { name: randomCard.card.id }); + + const inventory = await Inventory.FetchOneByCardNumberAndUserId(interaction.user.id, randomCard.card.id); + const quantityClaimed = inventory ? inventory.Quantity : 0; + + const embed = CardDropHelperMetadata.GenerateDropEmbed(randomCard, quantityClaimed); + + const claimId = v4(); + + const row = CardDropHelperMetadata.GenerateDropButtons(randomCard, claimId, interaction.user.id); + + try { + await interaction.editReply({ + embeds: [ embed ], + files: [ attachment ], + components: [ row ], + }); + } catch (e) { + console.error(e); + + if (e instanceof DiscordAPIError) { + await interaction.editReply(`Unable to send next drop. Please try again, and report this if it keeps happening. Code: ${e.code}`); + } else { + await interaction.editReply(`Unable to send next drop. Please try again, and report this if it keeps happening. Code: UNKNOWN`); + } + } + + CoreClient.ClaimId = claimId; + } + + public async executeLegacy(interaction: CommandInteraction) { if (!CoreClient.AllowDrops) { await interaction.reply('Bot is currently syncing, please wait until its done.'); return; diff --git a/src/contracts/SeriesMetadata.ts b/src/contracts/SeriesMetadata.ts new file mode 100644 index 0000000..3ef95c0 --- /dev/null +++ b/src/contracts/SeriesMetadata.ts @@ -0,0 +1,19 @@ +import { CardRarity } from "../constants/CardRarity"; + +export default interface SeriesMetadata { + id: number, + name: string, + cards: CardMetadata[], +} + +export interface CardMetadata { + id: string, + name: string, + type: CardRarity, + path: string, +} + +export interface DropResult { + series: SeriesMetadata, + card: CardMetadata, +} \ No newline at end of file diff --git a/src/helpers/CardDropHelperMetadata.ts b/src/helpers/CardDropHelperMetadata.ts new file mode 100644 index 0000000..7802a41 --- /dev/null +++ b/src/helpers/CardDropHelperMetadata.ts @@ -0,0 +1,76 @@ +import { ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder } from "discord.js"; +import { CardRarity, CardRarityToColour, CardRarityToString } from "../constants/CardRarity"; +import CardRarityChances from "../constants/CardRarityChances"; +import Card from "../database/entities/card/Card"; +import SeriesMetadata, { CardMetadata, DropResult } from "../contracts/SeriesMetadata"; +import { CoreClient } from "../client/client"; + +export default class CardDropHelperMetadata { + public static GetRandomCard(): DropResult | undefined { + const randomRarity = Math.random() * 100; + + let cardRarity: CardRarity; + + const bronzeChance = CardRarityChances.Bronze; + const silverChance = bronzeChance + CardRarityChances.Silver; + const goldChance = silverChance + CardRarityChances.Gold; + const mangaChance = goldChance + CardRarityChances.Manga; + + if (randomRarity < bronzeChance) cardRarity = CardRarity.Bronze; + else if (randomRarity < silverChance) cardRarity = CardRarity.Silver; + else if (randomRarity < goldChance) cardRarity = CardRarity.Gold; + else if (randomRarity < mangaChance) cardRarity = CardRarity.Manga; + else cardRarity = CardRarity.Legendary; + + const randomCard = this.GetRandomCardByRarity(cardRarity); + + return randomCard; + } + + public static GetRandomCardByRarity(rarity: CardRarity): DropResult | undefined { + const allCards = CoreClient.Cards + .flatMap(x => x.cards) + .filter(x => x.type == rarity); + + const randomCardIndex = Math.floor(Math.random() * allCards.length); + + const card = allCards[randomCardIndex]; + const series = CoreClient.Cards + .find(x => x.cards.includes(card)); + + if (!series) { + return undefined; + } + + return { + series: series, + card: card, + }; + } + + public static GenerateDropEmbed(drop: DropResult, quantityClaimed: Number): EmbedBuilder { + let description = ""; + description += `Series: ${drop.series.name}\n`; + description += `Claimed: ${quantityClaimed}\n`; + + return new EmbedBuilder() + .setTitle(drop.card.name) + .setDescription(description) + .setFooter({ text: CardRarityToString(drop.card.type) }) + .setColor(CardRarityToColour(drop.card.type)) + .setImage(`attachment://${drop.card.id}`); + } + + public static GenerateDropButtons(drop: DropResult, claimId: string, userId: string): ActionRowBuilder { + return new ActionRowBuilder() + .addComponents( + new ButtonBuilder() + .setCustomId(`claim ${drop.card.id} ${claimId} ${userId}`) + .setLabel("Claim") + .setStyle(ButtonStyle.Primary), + new ButtonBuilder() + .setCustomId(`reroll`) + .setLabel("Reroll") + .setStyle(ButtonStyle.Secondary)); + } +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 2d6ed58..4ba19a0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -410,6 +410,18 @@ resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6" integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw== +"@isaacs/cliui@^8.0.2": + version "8.0.2" + resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" + integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== + dependencies: + string-width "^5.1.2" + string-width-cjs "npm:string-width@^4.2.0" + strip-ansi "^7.0.1" + strip-ansi-cjs "npm:strip-ansi@^6.0.1" + wrap-ansi "^8.1.0" + wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" + "@istanbuljs/load-nyc-config@^1.0.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" @@ -707,6 +719,11 @@ mkdirp "^1.0.4" rimraf "^3.0.2" +"@pkgjs/parseargs@^0.11.0": + version "0.11.0" + resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" + integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== + "@pnpm/config.env-replace@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz#ab29da53df41e8948a00f2433f085f54de8b3a4c" @@ -950,14 +967,7 @@ resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.5.tgz#1ef302e01cf7d2b5a0fa526790c9123bf1d06690" integrity sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w== -"@types/node@*": - version "20.10.3" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.10.3.tgz#4900adcc7fc189d5af5bb41da8f543cea6962030" - integrity sha512-XJavIpZqiXID5Yxnxv3RUDKTN5b81ddNC3ecsA0SoFXz/QU8OGBwZGMomiq0zw+uuqbL/krztv/DINAQ/EV4gg== - dependencies: - undici-types "~5.26.4" - -"@types/node@^20.0.0": +"@types/node@*", "@types/node@^20.0.0": version "20.10.3" resolved "https://registry.yarnpkg.com/@types/node/-/node-20.10.3.tgz#4900adcc7fc189d5af5bb41da8f543cea6962030" integrity sha512-XJavIpZqiXID5Yxnxv3RUDKTN5b81ddNC3ecsA0SoFXz/QU8OGBwZGMomiq0zw+uuqbL/krztv/DINAQ/EV4gg== @@ -1867,7 +1877,7 @@ create-jest@^29.7.0: jest-util "^29.7.0" prompts "^2.0.1" -cross-spawn@^7.0.3: +cross-spawn@^7.0.0, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== @@ -2378,6 +2388,14 @@ find-up@^6.3.0: locate-path "^7.1.0" path-exists "^5.0.0" +foreground-child@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.1.1.tgz#1d173e776d75d2772fed08efe4a0de1ea1b12d0d" + integrity sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg== + dependencies: + cross-spawn "^7.0.0" + signal-exit "^4.0.1" + form-data-encoder@^2.1.2: version "2.1.4" resolved "https://registry.yarnpkg.com/form-data-encoder/-/form-data-encoder-2.1.4.tgz#261ea35d2a70d48d30ec7a9603130fa5515e9cd5" @@ -2493,6 +2511,17 @@ glob-parent@^5.1.2: dependencies: is-glob "^4.0.1" +glob@^10.3.10: + version "10.3.10" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.10.tgz#0351ebb809fd187fe421ab96af83d3a70715df4b" + integrity sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g== + dependencies: + foreground-child "^3.1.0" + jackspeak "^2.3.5" + minimatch "^9.0.1" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" + path-scurry "^1.10.1" + glob@^7.1.3, glob@^7.1.4: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" @@ -3159,6 +3188,15 @@ istanbul-reports@^3.1.3: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" +jackspeak@^2.3.5: + version "2.3.6" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.3.6.tgz#647ecc472238aee4b06ac0e461acc21a8c505ca8" + integrity sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ== + dependencies: + "@isaacs/cliui" "^8.0.2" + optionalDependencies: + "@pkgjs/parseargs" "^0.11.0" + jest-changed-files@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.7.0.tgz#1c06d07e77c78e1585d020424dedc10d6e17ac3a" @@ -3766,6 +3804,11 @@ lru-cache@^7.5.1: resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.18.3.tgz#f793896e0fd0e954a59dfdd82f0773808df6aa89" integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA== +"lru-cache@^9.1.1 || ^10.0.0": + version "10.1.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.1.0.tgz#2098d41c2dc56500e6c88584aa656c84de7d0484" + integrity sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag== + magic-bytes.js@^1.5.0: version "1.6.0" resolved "https://registry.yarnpkg.com/magic-bytes.js/-/magic-bytes.js-1.6.0.tgz#ee4354ac41a9b86f410e2690bc25dc4c264fb55d" @@ -3904,7 +3947,7 @@ mimic-response@^4.0.0: resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-4.0.0.tgz#35468b19e7c75d10f5165ea25e75a5ceea7cf70f" integrity sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg== -minimatch@9.0.3, minimatch@^9.0.0: +minimatch@9.0.3, minimatch@^9.0.0, minimatch@^9.0.1: version "9.0.3" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== @@ -3981,6 +4024,11 @@ minipass@^5.0.0: resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d" integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0": + version "7.0.4" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.4.tgz#dbce03740f50a4786ba994c1fb908844d27b038c" + integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ== + minizlib@^2.0.0, minizlib@^2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" @@ -4515,6 +4563,14 @@ path-parse@^1.0.7: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== +path-scurry@^1.10.1: + version "1.10.1" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.10.1.tgz#9ba6bf5aa8500fe9fd67df4f0d9483b2b0bfc698" + integrity sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ== + dependencies: + lru-cache "^9.1.1 || ^10.0.0" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" + path-to-regexp@0.1.7: version "0.1.7" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" @@ -5007,6 +5063,11 @@ signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== +signal-exit@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== + sisteransi@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" @@ -5136,6 +5197,15 @@ string-length@^4.0.1: char-regex "^1.0.2" strip-ansi "^6.0.0" +"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + string-width@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" @@ -5145,15 +5215,6 @@ string-width@^1.0.1: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - string-width@^2.1.0, string-width@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" @@ -5185,6 +5246,13 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" @@ -5206,13 +5274,6 @@ strip-ansi@^5.1.0: dependencies: ansi-regex "^4.1.0" -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - strip-ansi@^7.0.1: version "7.1.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" @@ -5669,6 +5730,15 @@ widest-line@^4.0.1: dependencies: string-width "^5.0.1" +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrap-ansi@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-3.0.1.tgz#288a04d87eda5c286e060dfe8f135ce8d007f8ba" @@ -5686,15 +5756,6 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"