diff options
-rw-r--r-- | package.json | 1 | ||||
-rw-r--r-- | src/config/example-options.ts | 3 | ||||
-rw-r--r-- | src/lib/common/AutoMod.ts | 163 | ||||
-rw-r--r-- | src/lib/extensions/discord-akairo/BushClient.ts | 8 | ||||
-rw-r--r-- | src/lib/models/instance/Guild.ts | 17 | ||||
-rw-r--r-- | src/lib/utils/Config.ts | 1 | ||||
-rw-r--r-- | yarn.lock | 220 |
7 files changed, 351 insertions, 62 deletions
diff --git a/package.json b/package.json index 7094016..424062c 100644 --- a/package.json +++ b/package.json @@ -67,6 +67,7 @@ "discord-api-types-next": "npm:discord-api-types@next", "discord.js": "npm:@notenoughupdates/discord.js@dev", "fuse.js": "^6.5.3", + "googleapis": "^95.0.0", "got": "^12.0.1", "lodash": "^4.17.21", "mathjs": "^10.1.1", diff --git a/src/config/example-options.ts b/src/config/example-options.ts index 338428e..1b384c4 100644 --- a/src/config/example-options.ts +++ b/src/config/example-options.ts @@ -9,7 +9,8 @@ export default new Config({ wolframAlphaAppId: '[APP_ID]', imgurClientId: '[CLIENT_ID]', imgurClientSecret: '[CLIENT_SECRET]', - sentryDsn: 'SENTRY_DSN' + sentryDsn: 'SENTRY_DSN', + perspectiveApiKey: '[PERSPECTIVE_API_KEY]' }, environment: 'development', owners: [ diff --git a/src/lib/common/AutoMod.ts b/src/lib/common/AutoMod.ts index 784085d..fc5532b 100644 --- a/src/lib/common/AutoMod.ts +++ b/src/lib/common/AutoMod.ts @@ -1,14 +1,7 @@ import { banResponse, Moderation, type BushButtonInteraction, type BushMessage } from '#lib'; -import { - ActionRow, - ButtonComponent, - ButtonStyle, - ChannelType, - Embed, - GuildMember, - PermissionFlagsBits, - type TextChannel -} from 'discord.js'; +import assert from 'assert'; +import chalk from 'chalk'; +import { ActionRow, ButtonComponent, ButtonStyle, Embed, GuildMember, PermissionFlagsBits, type TextChannel } from 'discord.js'; /** * Handles auto moderation functionality. @@ -33,59 +26,77 @@ export class AutoMod { void this.handle(); } + private get isImmune() { + if (!this.message.inGuild()) return false; + assert(this.message.member); + + if (this.message.author.isOwner()) return true; + if (this.message.guild.ownerId === this.message.author.id) return true; + if (this.message.member.permissions.has('Administrator')) return true; + + return false; + } + /** * Handles the auto moderation */ private async handle() { - if (this.message.channel.type === ChannelType.DM || !this.message.guild) return; + if (!this.message.inGuild()) return; if (!(await this.message.guild.hasFeature('automod'))) return; if (this.message.author.bot) return; - if (this.message.author.isOwner()) return; - - const badLinksArray = util.getShared('badLinks'); - const badLinksSecretArray = util.getShared('badLinksSecret'); - const badWordsRaw = util.getShared('badWords'); - - const customAutomodPhrases = (await this.message.guild.getSetting('autoModPhases')) ?? []; - const uniqueLinks = [...new Set([...badLinksArray, ...badLinksSecretArray])]; - - const badLinks: BadWordDetails[] = uniqueLinks.map((link) => ({ - match: link, - severity: Severity.PERM_MUTE, - ignoreSpaces: false, - ignoreCapitalization: true, - reason: 'malicious link', - regex: false - })); - - const parsedBadWords = Object.values(badWordsRaw).flat(); - const result = [ - ...this.checkWords(customAutomodPhrases), - ...this.checkWords((await this.message.guild.hasFeature('excludeDefaultAutomod')) ? [] : parsedBadWords), - ...this.checkWords((await this.message.guild.hasFeature('excludeAutomodScamLinks')) ? [] : badLinks) - ]; - - if (result.length === 0) return; - - const highestOffence = result.sort((a, b) => b.severity - a.severity)[0]; + traditional: { + if (this.isImmune) break traditional; + const badLinksArray = util.getShared('badLinks'); + const badLinksSecretArray = util.getShared('badLinksSecret'); + const badWordsRaw = util.getShared('badWords'); + + const customAutomodPhrases = (await this.message.guild.getSetting('autoModPhases')) ?? []; + const uniqueLinks = [...new Set([...badLinksArray, ...badLinksSecretArray])]; + + const badLinks: BadWordDetails[] = uniqueLinks.map((link) => ({ + match: link, + severity: Severity.PERM_MUTE, + ignoreSpaces: false, + ignoreCapitalization: true, + reason: 'malicious link', + regex: false + })); + + const parsedBadWords = Object.values(badWordsRaw).flat(); + + const result = [ + ...this.checkWords(customAutomodPhrases), + ...this.checkWords((await this.message.guild.hasFeature('excludeDefaultAutomod')) ? [] : parsedBadWords), + ...this.checkWords((await this.message.guild.hasFeature('excludeAutomodScamLinks')) ? [] : badLinks) + ]; + + if (result.length === 0) break traditional; + + const highestOffence = result.sort((a, b) => b.severity - a.severity)[0]; + + if (highestOffence.severity === undefined || highestOffence.severity === null) { + void this.message.guild.sendLogChannel('error', { + embeds: [ + { + title: 'AutoMod Error', + description: `Unable to find severity information for ${util.format.inlineCode(highestOffence.match)}`, + color: util.colors.error + } + ] + }); + } else { + const color = this.punish(highestOffence); + void this.log(highestOffence, color, result); + } + } - if (highestOffence.severity === undefined || highestOffence.severity === null) { - void this.message.guild.sendLogChannel('error', { - embeds: [ - { - title: 'AutoMod Error', - description: `Unable to find severity information for ${util.format.inlineCode(highestOffence.match)}`, - color: util.colors.error - } - ] - }); - } else { - const color = this.punish(highestOffence); - void this.log(highestOffence, color, result); + other: { + if (this.isImmune) break other; + if (!this.punished && (await this.message.guild.hasFeature('delScamMentions'))) void this.checkScamMentions(); } - if (!this.punished && (await this.message.guild.hasFeature('delScamMentions'))) void this.checkScamMentions(); + if (!this.punished && (await this.message.guild.hasFeature('perspectiveApi'))) void this.checkPerspectiveApi(); } /** @@ -166,6 +177,52 @@ export class AutoMod { } } + private async checkPerspectiveApi() { + if (!client.config.isDevelopment) return; + + if (!this.message.content) return; + client.perspective.comments.analyze( + { + key: client.config.credentials.perspectiveApiKey, + resource: { + comment: { + text: this.message.content + }, + requestedAttributes: { + TOXICITY: {}, + SEVERE_TOXICITY: {}, + IDENTITY_ATTACK: {}, + INSULT: {}, + PROFANITY: {}, + THREAT: {}, + SEXUALLY_EXPLICIT: {}, + FLIRTATION: {} + } + } + }, + (err: any, response: any) => { + if (err) return console.log(err?.message); + + const normalize = (val: number, min: number, max: number) => (val - min) / (max - min); + + const color = (val: number) => { + if (val >= 0.5) { + const x = 194 - Math.round(normalize(val, 0.5, 1) * 194); + return chalk.rgb(194, x, 0)(val); + } else { + const x = Math.round(normalize(val, 0, 0.5) * 194); + return chalk.rgb(x, 194, 0)(val); + } + }; + + console.log(chalk.cyan(this.message.content)); + Object.entries(response.data.attributeScores) + .sort(([a], [b]) => a.localeCompare(b)) + .forEach(([key, value]: any[]) => console.log(chalk.white(key), color(value.summaryScore.value))); + } + ); + } + /** * Format a string according to the word options * @param string The string to format diff --git a/src/lib/extensions/discord-akairo/BushClient.ts b/src/lib/extensions/discord-akairo/BushClient.ts index 904ab51..43ae139 100644 --- a/src/lib/extensions/discord-akairo/BushClient.ts +++ b/src/lib/extensions/discord-akairo/BushClient.ts @@ -41,6 +41,7 @@ import { type WebhookEditMessageOptions } from 'discord.js'; import EventEmitter from 'events'; +import { google } from 'googleapis'; import path from 'path'; import readline from 'readline'; import type { Options as SequelizeOptions, Sequelize as SequelizeType } from 'sequelize'; @@ -191,6 +192,11 @@ export class BushClient<Ready extends boolean = boolean> extends AkairoClient<Re public highlightManager = new HighlightManager(); /** + * The perspective api + */ + public perspective: any; + + /** * @param config The configuration for the bot. */ public constructor(config: Config) { @@ -335,6 +341,8 @@ export class BushClient<Ready extends boolean = boolean> extends AkairoClient<Re process.exit(2); } + this.perspective = await google.discoverAPI<any>('https://commentanalyzer.googleapis.com/$discovery/rest?version=v1alpha1'); + this.commandHandler.useInhibitorHandler(this.inhibitorHandler); this.commandHandler.useListenerHandler(this.listenerHandler); this.commandHandler.useTaskHandler(this.taskHandler); diff --git a/src/lib/models/instance/Guild.ts b/src/lib/models/instance/Guild.ts index 4d7f208..cdf3552 100644 --- a/src/lib/models/instance/Guild.ts +++ b/src/lib/models/instance/Guild.ts @@ -342,11 +342,12 @@ export const guildFeaturesObj = asGuildFeature({ default: false }, // todo implement a better auto thread system - // autoThread: { - // name: 'Auto Thread', - // description: 'Creates a new thread for messages in configured channels.', - // default: false - // }, + autoThread: { + name: 'Auto Thread', + description: 'Creates a new thread for messages in configured channels.', + default: false, + notConfigurable: true + }, blacklistedFile: { name: 'Blacklisted File', description: 'Automatically deletes malicious files.', @@ -392,6 +393,12 @@ export const guildFeaturesObj = asGuildFeature({ description: 'Allow users to appeal their punishments and send the appeal to the configured channel.', default: false, notConfigurable: true + }, + perspectiveApi: { + name: 'Perspective API', + description: 'Use the Perspective API to detect toxicity.', + default: false, + notConfigurable: true } }); diff --git a/src/lib/utils/Config.ts b/src/lib/utils/Config.ts index bc31964..ce5ec06 100644 --- a/src/lib/utils/Config.ts +++ b/src/lib/utils/Config.ts @@ -62,6 +62,7 @@ interface Credentials { imgurClientId: string; imgurClientSecret: string; sentryDsn: string; + perspectiveApiKey: string; } type Environment = 'production' | 'beta' | 'development'; @@ -722,6 +722,15 @@ __metadata: languageName: node linkType: hard +"abort-controller@npm:^3.0.0": + version: 3.0.0 + resolution: "abort-controller@npm:3.0.0" + dependencies: + event-target-shim: ^5.0.0 + checksum: 170bdba9b47b7e65906a28c8ce4f38a7a369d78e2271706f020849c1bfe0ee2067d4261df8bbb66eb84f79208fd5b710df759d64191db58cfba7ce8ef9c54b75 + languageName: node + linkType: hard + "acorn-jsx@npm:^5.3.1": version: 5.3.2 resolution: "acorn-jsx@npm:5.3.2" @@ -870,6 +879,13 @@ __metadata: languageName: node linkType: hard +"arrify@npm:^2.0.0": + version: 2.0.1 + resolution: "arrify@npm:2.0.1" + checksum: 067c4c1afd182806a82e4c1cb8acee16ab8b5284fbca1ce29408e6e91281c36bb5b612f6ddfbd40a0f7a7e0c75bf2696eb94c027f6e328d6e9c52465c98e4209 + languageName: node + linkType: hard + "asynckit@npm:^0.4.0": version: 0.4.0 resolution: "asynckit@npm:0.4.0" @@ -884,6 +900,20 @@ __metadata: languageName: node linkType: hard +"base64-js@npm:^1.3.0": + version: 1.5.1 + resolution: "base64-js@npm:1.5.1" + checksum: 669632eb3745404c2f822a18fc3a0122d2f9a7a13f7fb8b5823ee19d1d2ff9ee5b52c53367176ea4ad093c332fd5ab4bd0ebae5a8e27917a4105a4cfc86b1005 + languageName: node + linkType: hard + +"bignumber.js@npm:^9.0.0": + version: 9.0.2 + resolution: "bignumber.js@npm:9.0.2" + checksum: 8637b71d0a99104b20413c47578953970006fec6b4df796b9dcfd9835ea9c402ea0e727eba9a5ca9f9a393c1d88b6168c5bbe0887598b708d4f8b4870ad62e1f + languageName: node + linkType: hard + "brace-expansion@npm:^1.1.7": version: 1.1.11 resolution: "brace-expansion@npm:1.1.11" @@ -903,6 +933,13 @@ __metadata: languageName: node linkType: hard +"buffer-equal-constant-time@npm:1.0.1": + version: 1.0.1 + resolution: "buffer-equal-constant-time@npm:1.0.1" + checksum: 80bb945f5d782a56f374b292770901065bad21420e34936ecbe949e57724b4a13874f735850dd1cc61f078773c4fb5493a41391e7bda40d1fa388d6bd80daaab + languageName: node + linkType: hard + "buffer-writer@npm:2.0.0": version: 2.0.0 resolution: "buffer-writer@npm:2.0.0" @@ -949,6 +986,7 @@ __metadata: eslint-plugin-deprecation: ^1.3.2 eslint-plugin-import: ^2.25.4 fuse.js: ^6.5.3 + googleapis: ^95.0.0 got: ^12.0.1 lodash: ^4.17.21 mathjs: ^10.1.1 @@ -1351,6 +1389,15 @@ __metadata: languageName: node linkType: hard +"ecdsa-sig-formatter@npm:1.0.11, ecdsa-sig-formatter@npm:^1.0.11": + version: 1.0.11 + resolution: "ecdsa-sig-formatter@npm:1.0.11" + dependencies: + safe-buffer: ^5.0.1 + checksum: 207f9ab1c2669b8e65540bce29506134613dd5f122cccf1e6a560f4d63f2732d427d938f8481df175505aad94583bcb32c688737bb39a6df0625f903d6d93c03 + languageName: node + linkType: hard + "emoji-regex@npm:^8.0.0": version: 8.0.0 resolution: "emoji-regex@npm:8.0.0" @@ -1651,6 +1698,20 @@ __metadata: languageName: node linkType: hard +"event-target-shim@npm:^5.0.0": + version: 5.0.1 + resolution: "event-target-shim@npm:5.0.1" + checksum: 1ffe3bb22a6d51bdeb6bf6f7cf97d2ff4a74b017ad12284cc9e6a279e727dc30a5de6bb613e5596ff4dc3e517841339ad09a7eec44266eccb1aa201a30448166 + languageName: node + linkType: hard + +"extend@npm:^3.0.2": + version: 3.0.2 + resolution: "extend@npm:3.0.2" + checksum: a50a8309ca65ea5d426382ff09f33586527882cf532931cb08ca786ea3146c0553310bda688710ff61d7668eba9f96b923fe1420cdf56a2c3eaf30fcab87b515 + languageName: node + linkType: hard + "fast-deep-equal@npm:^3.1.1, fast-deep-equal@npm:^3.1.3": version: 3.1.3 resolution: "fast-deep-equal@npm:3.1.3" @@ -1685,6 +1746,13 @@ __metadata: languageName: node linkType: hard +"fast-text-encoding@npm:^1.0.0": + version: 1.0.3 + resolution: "fast-text-encoding@npm:1.0.3" + checksum: 3e51365896f06d0dcab128092d095a0037d274deec419fecbd2388bc236d7b387610e0c72f920c6126e00c885ab096fbfaa3645712f5b98f721bef6b064916a8 + languageName: node + linkType: hard + "fastq@npm:^1.6.0": version: 1.13.0 resolution: "fastq@npm:1.13.0" @@ -1864,6 +1932,29 @@ __metadata: languageName: node linkType: hard +"gaxios@npm:^4.0.0": + version: 4.3.2 + resolution: "gaxios@npm:4.3.2" + dependencies: + abort-controller: ^3.0.0 + extend: ^3.0.2 + https-proxy-agent: ^5.0.0 + is-stream: ^2.0.0 + node-fetch: ^2.6.1 + checksum: 1305fc6a4b9f888a7424ed160084d1f253a54bec04b4986ecb7929d8aa52382e737fc65feb03f0b0b47c524575286d765806d829868ec49fd383a1be8a973870 + languageName: node + linkType: hard + +"gcp-metadata@npm:^4.2.0": + version: 4.3.1 + resolution: "gcp-metadata@npm:4.3.1" + dependencies: + gaxios: ^4.0.0 + json-bigint: ^1.0.0 + checksum: b0b1b85ea2efee1d640a1d4ead0937fdcceffd43ab4cacfdd66fd086fcfe5c3d09ad850ee14f43f2dc73244b2617b166adfa09a2a85e0652a8c56bed194f01fe + languageName: node + linkType: hard + "get-intrinsic@npm:^1.0.2, get-intrinsic@npm:^1.1.0, get-intrinsic@npm:^1.1.1": version: 1.1.1 resolution: "get-intrinsic@npm:1.1.1" @@ -1956,6 +2047,58 @@ __metadata: languageName: node linkType: hard +"google-auth-library@npm:^7.0.2": + version: 7.12.0 + resolution: "google-auth-library@npm:7.12.0" + dependencies: + arrify: ^2.0.0 + base64-js: ^1.3.0 + ecdsa-sig-formatter: ^1.0.11 + fast-text-encoding: ^1.0.0 + gaxios: ^4.0.0 + gcp-metadata: ^4.2.0 + gtoken: ^5.0.4 + jws: ^4.0.0 + lru-cache: ^6.0.0 + checksum: 0c2970ca9b2b5672c7c217e677370f66bccd757e1e70629d9287bfee220fe9ff38e65d3e8377db2abb96a7c86142c32a93a1a817b816d0ba486af84dc1af68e4 + languageName: node + linkType: hard + +"google-p12-pem@npm:^3.1.3": + version: 3.1.3 + resolution: "google-p12-pem@npm:3.1.3" + dependencies: + node-forge: ^1.0.0 + bin: + gp12-pem: build/src/bin/gp12-pem.js + checksum: 8628f2bf9b4c9b3bfc7220906c15af2b306e2ef30c7c398327a9cff9d4a12285f104545f00c46b716dd23966615f446d7e5efde44d590f9483d345be78ea115e + languageName: node + linkType: hard + +"googleapis-common@npm:^5.0.2": + version: 5.0.5 + resolution: "googleapis-common@npm:5.0.5" + dependencies: + extend: ^3.0.2 + gaxios: ^4.0.0 + google-auth-library: ^7.0.2 + qs: ^6.7.0 + url-template: ^2.0.8 + uuid: ^8.0.0 + checksum: 1669c8bf6b29a3929b5e22bd78bd9f7203bdcb108fc42b6a91c2f9308f7cda03ac155ab274cdc4a6a24ef1d4f2cdfa4d8b55aac391480410f177659c019eecd5 + languageName: node + linkType: hard + +"googleapis@npm:^95.0.0": + version: 95.0.0 + resolution: "googleapis@npm:95.0.0" + dependencies: + google-auth-library: ^7.0.2 + googleapis-common: ^5.0.2 + checksum: a304d97fd93a6772bd302ab605d2daee3c57f087b5a3c98774446ac16e98e645b4a4b2214621d99b869b1680c3fa3be87bff7e9b3a50a06446e8938e7787ea08 + languageName: node + linkType: hard + "got@npm:^12.0.1": version: 12.0.1 resolution: "got@npm:12.0.1" @@ -1984,6 +2127,17 @@ __metadata: languageName: node linkType: hard +"gtoken@npm:^5.0.4": + version: 5.3.2 + resolution: "gtoken@npm:5.3.2" + dependencies: + gaxios: ^4.0.0 + google-p12-pem: ^3.1.3 + jws: ^4.0.0 + checksum: 1fd640e98afcb3d5c77026fd4ff0671dce724acad11169e5b63701a853e1f5a03f4c76fe6eb95500db80f8444753ce212701d396186ef006088d08be4174f2d7 + languageName: node + linkType: hard + "has-bigints@npm:^1.0.1": version: 1.0.1 resolution: "has-bigints@npm:1.0.1" @@ -2294,6 +2448,13 @@ __metadata: languageName: node linkType: hard +"is-stream@npm:^2.0.0": + version: 2.0.1 + resolution: "is-stream@npm:2.0.1" + checksum: b8e05ccdf96ac330ea83c12450304d4a591f9958c11fd17bed240af8d5ffe08aedafa4c0f4cfccd4d28dc9d4d129daca1023633d5c11601a6cbc77521f6fae66 + languageName: node + linkType: hard + "is-string@npm:^1.0.5, is-string@npm:^1.0.7": version: 1.0.7 resolution: "is-string@npm:1.0.7" @@ -2346,6 +2507,15 @@ __metadata: languageName: node linkType: hard +"json-bigint@npm:^1.0.0": + version: 1.0.0 + resolution: "json-bigint@npm:1.0.0" + dependencies: + bignumber.js: ^9.0.0 + checksum: c67bb93ccb3c291e60eb4b62931403e378906aab113ec1c2a8dd0f9a7f065ad6fd9713d627b732abefae2e244ac9ce1721c7a3142b2979532f12b258634ce6f6 + languageName: node + linkType: hard + "json-buffer@npm:3.0.1": version: 3.0.1 resolution: "json-buffer@npm:3.0.1" @@ -2378,6 +2548,27 @@ __metadata: languageName: node linkType: hard +"jwa@npm:^2.0.0": + version: 2.0.0 + resolution: "jwa@npm:2.0.0" + dependencies: + buffer-equal-constant-time: 1.0.1 + ecdsa-sig-formatter: 1.0.11 + safe-buffer: ^5.0.1 + checksum: 8f00b71ad5fe94cb55006d0d19202f8f56889109caada2f7eeb63ca81755769ce87f4f48101967f398462e3b8ae4faebfbd5a0269cb755dead5d63c77ba4d2f1 + languageName: node + linkType: hard + +"jws@npm:^4.0.0": + version: 4.0.0 + resolution: "jws@npm:4.0.0" + dependencies: + jwa: ^2.0.0 + safe-buffer: ^5.0.1 + checksum: d68d07aa6d1b8cb35c363a9bd2b48f15064d342a5d9dc18a250dbbce8dc06bd7e4792516c50baa16b8d14f61167c19e851fd7f66b59ecc68b7f6a013759765f7 + languageName: node + linkType: hard + "keyv@npm:^4.0.0": version: 4.1.1 resolution: "keyv@npm:4.1.1" @@ -2746,7 +2937,7 @@ __metadata: languageName: node linkType: hard -"node-fetch@npm:^2.6.5, node-fetch@npm:^2.6.7": +"node-fetch@npm:^2.6.1, node-fetch@npm:^2.6.5, node-fetch@npm:^2.6.7": version: 2.6.7 resolution: "node-fetch@npm:2.6.7" dependencies: @@ -2771,6 +2962,13 @@ __metadata: languageName: node linkType: hard +"node-forge@npm:^1.0.0": + version: 1.2.1 + resolution: "node-forge@npm:1.2.1" + checksum: af4f88c3f69362359f35f6a9e231b35c96d906eeb6e976fb92742afe7fcdd76439dc22b41ce3755389d171f6320756ec7505bdfa7b252466c091b8c519a22674 + languageName: node + linkType: hard + "node-gyp@npm:latest": version: 8.4.1 resolution: "node-gyp@npm:8.4.1" @@ -3181,6 +3379,15 @@ __metadata: languageName: node linkType: hard +"qs@npm:^6.7.0": + version: 6.10.3 + resolution: "qs@npm:6.10.3" + dependencies: + side-channel: ^1.0.4 + checksum: 0fac5e6c7191d0295a96d0e83c851aeb015df7e990e4d3b093897d3ac6c94e555dbd0a599739c84d7fa46d7fee282d94ba76943983935cf33bba6769539b8019 + languageName: node + linkType: hard + "queue-microtask@npm:^1.2.2": version: 1.2.3 resolution: "queue-microtask@npm:1.2.3" @@ -3310,7 +3517,7 @@ __metadata: languageName: node linkType: hard -"safe-buffer@npm:~5.2.0": +"safe-buffer@npm:^5.0.1, safe-buffer@npm:~5.2.0": version: 5.2.1 resolution: "safe-buffer@npm:5.2.1" checksum: b99c4b41fdd67a6aaf280fcd05e9ffb0813654894223afb78a31f14a19ad220bba8aba1cb14eddce1fcfb037155fe6de4e861784eb434f7d11ed58d1e70dd491 @@ -3778,6 +3985,13 @@ __metadata: languageName: node linkType: hard +"url-template@npm:^2.0.8": + version: 2.0.8 + resolution: "url-template@npm:2.0.8" + checksum: 4183fccd74e3591e4154134d4443dccecba9c455c15c7df774f1f1e3fa340fd9bffb903b5beec347196d15ce49c34edf6dec0634a95d170ad6e78c0467d6e13e + languageName: node + linkType: hard + "util-deprecate@npm:^1.0.1": version: 1.0.2 resolution: "util-deprecate@npm:1.0.2" @@ -3785,7 +3999,7 @@ __metadata: languageName: node linkType: hard -"uuid@npm:^8.3.2": +"uuid@npm:^8.0.0, uuid@npm:^8.3.2": version: 8.3.2 resolution: "uuid@npm:8.3.2" bin: |