🔀 Merge: Version 0.0.6

This commit is contained in:
Manuel 2023-03-26 16:23:17 +02:00 committed by GitHub
commit 3be835790c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 387 additions and 132 deletions

View File

@ -1,6 +1,6 @@
{
"name": "jellyfin-discord-music-bot",
"version": "0.0.5",
"version": "0.0.6",
"description": "",
"author": "manuel-rw",
"private": true,
@ -26,11 +26,11 @@
"@discordjs/opus": "^0.9.0",
"@discordjs/voice": "^0.15.0",
"@jellyfin/sdk": "^0.7.0",
"@nestjs/common": "^9.0.0",
"@nestjs/common": "^9.3.10",
"@nestjs/config": "^2.2.0",
"@nestjs/core": "^9.0.0",
"@nestjs/core": "^9.3.11",
"@nestjs/event-emitter": "^1.3.1",
"@nestjs/platform-express": "^9.0.0",
"@nestjs/platform-express": "^9.3.10",
"@nestjs/schedule": "^2.1.0",
"@nestjs/serve-static": "^3.0.1",
"@nestjs/terminus": "^9.1.4",
@ -45,9 +45,9 @@
"ws": "^8.13.0"
},
"devDependencies": {
"@nestjs/cli": "^9.2.0",
"@nestjs/cli": "^9.3.0",
"@nestjs/schematics": "^9.0.0",
"@nestjs/testing": "^9.3.9",
"@nestjs/testing": "^9.3.10",
"@types/cron": "^2.0.0",
"@types/express": "^4.17.13",
"@types/jest": "28.1.8",

View File

@ -29,8 +29,9 @@ import { DiscordMessageService } from './discord.message.service';
@Injectable()
export class DiscordVoiceService {
private readonly logger = new Logger(DiscordVoiceService.name);
private audioPlayer: AudioPlayer;
private voiceConnection: VoiceConnection;
private audioPlayer: AudioPlayer | undefined;
private voiceConnection: VoiceConnection | undefined;
private audioResource: AudioResource | undefined;
constructor(
private readonly discordMessageService: DiscordMessageService,
@ -44,6 +45,9 @@ export class DiscordVoiceService {
handleOnNewTrack(track: Track) {
const resource = createAudioResource(
track.getStreamUrl(this.jellyfinStreamBuilder),
{
inlineVolume: true,
},
);
this.playResource(resource);
}
@ -99,9 +103,14 @@ export class DiscordVoiceService {
};
}
changeVolume(volume: number) {
this.audioResource.volume.setVolume(volume);
}
playResource(resource: AudioResource<unknown>) {
this.logger.debug(`Playing audio resource with volume ${resource.volume}`);
this.createAndReturnOrGetAudioPlayer().play(resource);
this.audioResource = resource;
}
/**

View File

@ -170,6 +170,30 @@ export class JellyfinSearchService {
}
}
async getRandomTracks(limit: number) {
const api = this.jellyfinService.getApi();
const searchApi = getItemsApi(api);
try {
const response = await searchApi.getItems({
includeItemTypes: [BaseItemKind.Audio],
limit: limit,
sortBy: ['random'],
userId: this.jellyfinService.getUserId(),
recursive: true,
});
return response.data.Items.map((item) => {
return SearchHint.constructFromBaseItem(item);
});
} catch (err) {
this.logger.error(
`Unabele to retrieve random items from Jellyfin: ${err}`,
);
return [];
}
}
private transformToSearchHint(jellyifnHint: JellyfinSearchHint) {
switch (jellyifnHint.Type) {
case BaseItemKind[BaseItemKind.Audio]:

View File

@ -15,6 +15,8 @@ import { StatusCommand } from './status.command';
import { StopPlaybackCommand } from './stop.command';
import { SummonCommand } from './summon.command';
import { PlaylistInteractionCollector } from './playlist/playlist.interaction-collector';
import { EnqueueRandomItemsCommand } from './random/random.command';
import { VolumeCommand } from './volume/volume.command';
@Module({
imports: [
@ -28,6 +30,7 @@ import { PlaylistInteractionCollector } from './playlist/playlist.interaction-co
PlaylistInteractionCollector,
HelpCommand,
StatusCommand,
EnqueueRandomItemsCommand,
PlaylistCommand,
DisconnectCommand,
PausePlaybackCommand,
@ -36,6 +39,7 @@ import { PlaylistInteractionCollector } from './playlist/playlist.interaction-co
SummonCommand,
PlayItemCommand,
PreviousTrackCommand,
VolumeCommand,
],
exports: [],
})

View File

@ -94,10 +94,14 @@ export class PlayItemCommand {
}
const tracks = await item.toTracks(this.jellyfinSearchService);
this.logger.debug(`Extracted ${tracks.length} tracks from the search item`);
const reducedDuration = tracks.reduce(
(sum, item) => sum + item.duration,
0,
);
this.logger.debug(
`Adding ${tracks.length} tracks with a duration of ${reducedDuration} ticks`,
);
this.playbackService.getPlaylistOrDefault().enqueueTracks(tracks);
const remoteImage: RemoteImageInfo | undefined = tracks

View File

@ -0,0 +1,76 @@
import { SlashCommandPipe } from '@discord-nestjs/common';
import { Command, Handler, IA, InteractionEvent } from '@discord-nestjs/core';
import { Injectable } from '@nestjs/common';
import {
CommandInteraction,
GuildMember,
InteractionReplyOptions,
} from 'discord.js';
import { DiscordMessageService } from 'src/clients/discord/discord.message.service';
import { DiscordVoiceService } from 'src/clients/discord/discord.voice.service';
import { JellyfinSearchService } from 'src/clients/jellyfin/jellyfin.search.service';
import { SearchHint } from 'src/models/search/SearchHint';
import { PlaybackService } from 'src/playback/playback.service';
import { RandomCommandParams } from './random.params';
@Command({
name: 'random',
description: 'Enqueues a random selection of tracks to your playlist',
})
@Injectable()
export class EnqueueRandomItemsCommand {
constructor(
private readonly playbackService: PlaybackService,
private readonly discordVoiceService: DiscordVoiceService,
private readonly discordMessageService: DiscordMessageService,
private readonly jellyfinSearchService: JellyfinSearchService,
) {}
@Handler()
async handler(
@InteractionEvent(SlashCommandPipe) dto: RandomCommandParams,
@IA() interaction: CommandInteraction,
): Promise<void> {
await interaction.deferReply();
const guildMember = interaction.member as GuildMember;
const tryResult =
this.discordVoiceService.tryJoinChannelAndEstablishVoiceConnection(
guildMember,
);
if (!tryResult.success) {
const replyOptions = tryResult.reply as InteractionReplyOptions;
await interaction.editReply({
embeds: replyOptions.embeds,
});
return;
}
const items = await this.jellyfinSearchService.getRandomTracks(dto.count);
const tracks = await this.getTracks(items);
this.playbackService.getPlaylistOrDefault().enqueueTracks(tracks);
await interaction.editReply({
embeds: [
this.discordMessageService.buildMessage({
title: `Added ${tracks.length} tracks to your playlist`,
description: 'Use ``/playlist`` to see them',
}),
],
});
}
private async getTracks(hints: SearchHint[]) {
const promises = await Promise.all(
hints.flatMap(async (item) => {
const tracks = await item.toTracks(this.jellyfinSearchService);
return tracks;
}),
);
return promises.flatMap((x) => x);
}
}

View File

@ -0,0 +1,12 @@
import { Param, ParamType } from '@discord-nestjs/core';
export class RandomCommandParams {
@Param({
required: false,
description: 'Count of items to search for',
type: ParamType.INTEGER,
minValue: 0,
maxValue: 10000,
})
count = 20;
}

View File

@ -0,0 +1,69 @@
import { SlashCommandPipe } from '@discord-nestjs/common';
import { Command, Handler, IA, InteractionEvent } from '@discord-nestjs/core';
import { Logger } from '@nestjs/common';
import { Injectable } from '@nestjs/common/decorators';
import { CommandInteraction } from 'discord.js';
import { DiscordMessageService } from 'src/clients/discord/discord.message.service';
import { DiscordVoiceService } from 'src/clients/discord/discord.voice.service';
import { PlaybackService } from 'src/playback/playback.service';
import { sleep } from 'src/utils/timeUtils';
import { VolumeCommandParams } from './volume.params';
@Injectable()
@Command({
name: 'volume',
description: 'Change the volume',
})
export class VolumeCommand {
private readonly logger = new Logger(VolumeCommand.name);
constructor(
private readonly discordVoiceService: DiscordVoiceService,
private readonly discordMessageService: DiscordMessageService,
private readonly playbackService: PlaybackService,
) {}
@Handler()
async handler(
@InteractionEvent(SlashCommandPipe) dto: VolumeCommandParams,
@IA() interaction: CommandInteraction,
): Promise<void> {
await interaction.deferReply();
if (!this.playbackService.getPlaylistOrDefault().hasActiveTrack()) {
await interaction.editReply({
embeds: [
this.discordMessageService.buildMessage({
title: `Unable to change your volume`,
description:
'The bot is not playing any music or is not straming to a channel',
}),
],
});
return;
}
const volume = dto.volume / 100;
this.logger.debug(
`Calculated volume ${volume} from dto param ${dto.volume}`,
);
this.discordVoiceService.changeVolume(volume);
// Discord takes some time to react. Confirmation message should appear after actual change
await sleep(1500);
await interaction.editReply({
embeds: [
this.discordMessageService.buildMessage({
title: `Sucessfully set volume to ${dto.volume.toFixed(0)}%`,
description:
'Updating may take a few seconds to take effect.\nPlease note that listening at a high volume for a long time may damage your hearing',
}),
],
});
}
}

View File

@ -0,0 +1,12 @@
import { Param, ParamType } from '@discord-nestjs/core';
export class VolumeCommandParams {
@Param({
required: true,
description: 'The desired volume',
type: ParamType.INTEGER,
minValue: 0,
maxValue: 150,
})
volume: number;
}

View File

@ -17,10 +17,17 @@ export class AlbumSearchHint extends SearchHint {
override async toTracks(
searchService: JellyfinSearchService,
): Promise<Track[]> {
const remoteImages = await searchService.getRemoteImageById(this.id);
const albumItems = await searchService.getAlbumItems(this.id);
const tracks = albumItems.map(async (x) =>
const tracks = await Promise.all(
albumItems.map(async (x) =>
(await x.toTracks(searchService)).find((x) => x !== null),
),
);
return await Promise.all(tracks);
return tracks.map((track): Track => {
track.remoteImages = remoteImages;
return track;
});
}
}

View File

@ -1,7 +1,10 @@
import { SearchHint as JellyfinSearchHint } from '@jellyfin/sdk/lib/generated-client/models';
import {
BaseItemDto,
SearchHint as JellyfinSearchHint,
} from '@jellyfin/sdk/lib/generated-client/models';
import { Track } from '../shared/Track';
import { JellyfinSearchService } from '../../clients/jellyfin/jellyfin.search.service';
import { Track } from '../shared/Track';
export class SearchHint {
constructor(
@ -15,10 +18,7 @@ export class SearchHint {
}
async toTracks(searchService: JellyfinSearchService): Promise<Track[]> {
const remoteImages = await searchService.getRemoteImageById(this.id);
return [
new Track(this.id, this.name, this.runtimeInMilliseconds, remoteImages),
];
return [new Track(this.id, this.name, this.runtimeInMilliseconds, {})];
}
getId(): string {
@ -28,4 +28,12 @@ export class SearchHint {
static constructFromHint(hint: JellyfinSearchHint) {
return new SearchHint(hint.Id, hint.Name, hint.RunTimeTicks / 10000);
}
static constructFromBaseItem(baseItem: BaseItemDto) {
return new SearchHint(
baseItem.Id,
baseItem.Name,
baseItem.RunTimeTicks / 10000,
);
}
}

View File

@ -84,6 +84,10 @@ export class Playlist {
* @returns the new lendth of the tracks in the playlist
*/
enqueueTracks(tracks: Track[]) {
if (tracks.length === 0) {
return 0;
}
this.eventEmitter.emit('controls.playlist.tracks.enqueued', {
count: tracks.length,
activeTrack: this.activeTrackIndex,

View File

@ -25,7 +25,7 @@ export class Track {
/**
* A result object that contains a collection of images that are available outside the current network.
*/
readonly remoteImages?: RemoteImageResult;
remoteImages?: RemoteImageResult;
constructor(
id: string,

View File

@ -1,6 +1,7 @@
import { Test } from '@nestjs/testing';
import axios from 'axios';
import { Client, GuildMember } from 'discord.js';
import { Constants } from '../utils/constants';
import { DiscordMessageService } from '../clients/discord/discord.message.service';
import { GithubRelease } from '../models/github-release';
import { useDefaultMockerToken } from '../utils/tests/defaultMockerToken';
@ -14,7 +15,6 @@ describe('UpdatesService', () => {
const OLD_ENV = process.env;
let updatesService: UpdatesService;
let discordClient: Client;
let discordMessageService: DiscordMessageService;
beforeEach(async () => {
@ -54,7 +54,6 @@ describe('UpdatesService', () => {
.compile();
updatesService = moduleRef.get<UpdatesService>(UpdatesService);
discordClient = moduleRef.get<Client>('__inject_discord_client__');
discordMessageService = moduleRef.get<DiscordMessageService>(
DiscordMessageService,
);
@ -88,6 +87,12 @@ describe('UpdatesService', () => {
it('handleCronShouldNotifyWhenNewRelease', async () => {
process.env.UPDATER_DISABLE_NOTIFICATIONS = 'false';
Constants.Metadata.Version = {
All: () => '0.0.5',
Major: 0,
Minor: 0,
Patch: 5,
};
mockedAxios.mockResolvedValue({
data: {

View File

@ -3,7 +3,7 @@ export const Constants = {
Version: {
Major: 0,
Minor: 0,
Patch: 5,
Patch: 6,
All: () =>
`${Constants.Metadata.Version.Major}.${Constants.Metadata.Version.Minor}.${Constants.Metadata.Version.Patch}`,
},

View File

@ -15,3 +15,7 @@ export const formatMillisecondsAsHumanReadable = (
);
return duration;
};
export function sleep(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms));
}

239
yarn.lock
View File

@ -21,10 +21,10 @@
rxjs "6.6.7"
source-map "0.7.4"
"@angular-devkit/core@15.1.4":
version "15.1.4"
resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-15.1.4.tgz#462f123d56f9298cb04b3fa31b425fc31abb76c5"
integrity sha512-PW5MRmd9DHJR4FaXchwQtj9pXnsghSTnwRvfZeCRNYgU2sv0DKyTV+YTSJB+kNXnoPNG1Je6amDEkiXecpspXg==
"@angular-devkit/core@15.2.4":
version "15.2.4"
resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-15.2.4.tgz#f7696f09c66d01568a07f0e71672e887fdf57280"
integrity sha512-yl+0j1bMwJLKShsyCXw77tbJG8Sd21+itisPLL2MgEpLNAO252kr9zG4TLlFRJyKVftm2l1h78KjqvM5nbOXNg==
dependencies:
ajv "8.12.0"
ajv-formats "2.1.1"
@ -32,13 +32,13 @@
rxjs "6.6.7"
source-map "0.7.4"
"@angular-devkit/schematics-cli@15.1.4":
version "15.1.4"
resolved "https://registry.yarnpkg.com/@angular-devkit/schematics-cli/-/schematics-cli-15.1.4.tgz#f2ea0379e27ddd6b05b302dd88b8d3f1b6c49ec8"
integrity sha512-qkM5Mfs28jZzNcJnSM6RlyrKkYvzhQmWFTxBXnn15k5T4EnSs1gI6O054Xn7jo/senfwNNt7h2Mlz2OmBLo6+w==
"@angular-devkit/schematics-cli@15.2.4":
version "15.2.4"
resolved "https://registry.yarnpkg.com/@angular-devkit/schematics-cli/-/schematics-cli-15.2.4.tgz#c3a4c162779773d312d36cb23f3dd44d741d7225"
integrity sha512-QTTKEH5HOkxvQtCxb2Lna2wubehkaIzA6DKUBISijPQliLomw74tzc7lXCywmMqRTbQPVRLG3kBK97hR4x67nA==
dependencies:
"@angular-devkit/core" "15.1.4"
"@angular-devkit/schematics" "15.1.4"
"@angular-devkit/core" "15.2.4"
"@angular-devkit/schematics" "15.2.4"
ansi-colors "4.1.3"
inquirer "8.2.4"
symbol-observable "4.0.0"
@ -55,14 +55,14 @@
ora "5.4.1"
rxjs "6.6.7"
"@angular-devkit/schematics@15.1.4":
version "15.1.4"
resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-15.1.4.tgz#30e38777f1bd98e20e6dbe1bfddabc3bcd42605f"
integrity sha512-jpddxo9Qd2yRQ1t9FLhAx5S+luz6HkyhDytq0LFKbxf9ikf1J4oy9riPBFl4pRmrNARWcHZ6GbD20/Ky8PjmXQ==
"@angular-devkit/schematics@15.2.4":
version "15.2.4"
resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-15.2.4.tgz#85129ebabcdb362f4b65a6e290bb2ae846f3d64c"
integrity sha512-/W7/vvn59PAVLzhcvD4/N/E8RDhub8ny1A7I96LTRjC5o+yvVV16YJ4YJzolrRrIEN01KmLVQJ9A58VCaweMgw==
dependencies:
"@angular-devkit/core" "15.1.4"
"@angular-devkit/core" "15.2.4"
jsonc-parser "3.2.0"
magic-string "0.27.0"
magic-string "0.29.0"
ora "5.4.1"
rxjs "6.6.7"
@ -795,38 +795,38 @@
resolved "https://registry.yarnpkg.com/@lukeed/csprng/-/csprng-1.0.1.tgz#625e93a0edb2c830e3c52ce2d67b9d53377c6a66"
integrity sha512-uSvJdwQU5nK+Vdf6zxcWAY2A8r7uqe+gePwLWzJ+fsQehq18pc0I2hJKwypZ2aLM90+Er9u1xn4iLJPZ+xlL4g==
"@nestjs/cli@^9.2.0":
version "9.2.0"
resolved "https://registry.yarnpkg.com/@nestjs/cli/-/cli-9.2.0.tgz#d174f54d7aaa6695b8e413093e3d18367bc8bec7"
integrity sha512-6B1IjDcJbrOu55oMF67L1x5lDUOZ3Zs9l7bKCBH9D78965m8wq/2rlEWl/gJto5TABLQWy3hVvV/s8VzUlRMxw==
"@nestjs/cli@^9.3.0":
version "9.3.0"
resolved "https://registry.yarnpkg.com/@nestjs/cli/-/cli-9.3.0.tgz#654ae6999d06c6da4ca17d5bdf68b7a85429938e"
integrity sha512-v/E8Y3zFk30+FljETvPgpoGIUiOfWuOe6WUFw3ExGfDeWrF/A8ceupDHPWNknBAqvNtz2kVrWu5mwsZUEKGIgg==
dependencies:
"@angular-devkit/core" "15.1.4"
"@angular-devkit/schematics" "15.1.4"
"@angular-devkit/schematics-cli" "15.1.4"
"@nestjs/schematics" "^9.0.0"
chalk "3.0.0"
"@angular-devkit/core" "15.2.4"
"@angular-devkit/schematics" "15.2.4"
"@angular-devkit/schematics-cli" "15.2.4"
"@nestjs/schematics" "^9.0.4"
chalk "4.1.2"
chokidar "3.5.3"
cli-table3 "0.6.3"
commander "4.1.1"
fork-ts-checker-webpack-plugin "7.3.0"
inquirer "7.3.3"
fork-ts-checker-webpack-plugin "8.0.0"
inquirer "8.2.5"
node-emoji "1.11.0"
ora "5.4.1"
os-name "4.0.1"
rimraf "4.1.2"
rimraf "4.4.0"
shelljs "0.8.5"
source-map-support "0.5.21"
tree-kill "1.2.2"
tsconfig-paths "4.1.2"
tsconfig-paths-webpack-plugin "4.0.0"
tsconfig-paths-webpack-plugin "4.0.1"
typescript "4.9.5"
webpack "5.75.0"
webpack "5.76.2"
webpack-node-externals "3.0.0"
"@nestjs/common@^9.0.0":
version "9.3.9"
resolved "https://registry.yarnpkg.com/@nestjs/common/-/common-9.3.9.tgz#170201ce1c2a8f73bd4babe74b64a2a0b37a95d0"
integrity sha512-GshTD9Xz+wD2em6NyzU4NXw5IXMUmapgDgD+iuj6XL0258hvDwODmNk37mBBnZvTZlqER+krvIUKnS34etqF/A==
"@nestjs/common@^9.3.10":
version "9.3.10"
resolved "https://registry.yarnpkg.com/@nestjs/common/-/common-9.3.10.tgz#c137402cad41123eaf5c74c2404e92490f9bbd50"
integrity sha512-wj2bM9TXBlAvzgznkID0s7bN/niVn90sZIDtRFDnvaB1qagEpkWA0Bt39qilIuqdReluIaCjeEW106U0oyz+mQ==
dependencies:
uid "2.0.1"
iterare "1.2.1"
@ -842,10 +842,10 @@
lodash "4.17.21"
uuid "9.0.0"
"@nestjs/core@^9.0.0":
version "9.3.9"
resolved "https://registry.yarnpkg.com/@nestjs/core/-/core-9.3.9.tgz#694caf785e0209175479637f11be79a930d0c0d6"
integrity sha512-9g1A1G9eirLXEpH21rc6dKb08zHc2+adhCRz8NW39hbejcsxxD72FApJzt4QBQAKvu862ixt/tdpStnFT7lOSw==
"@nestjs/core@^9.3.11":
version "9.3.11"
resolved "https://registry.yarnpkg.com/@nestjs/core/-/core-9.3.11.tgz#1be65db0e889f8f12b87aec12c9cf66ea6043205"
integrity sha512-CI27a2JFd5rvvbgkalWqsiwQNhcP4EAG5BUK8usjp29wVp1kx30ghfBT8FLqIgmkRVo65A0IcEnWsxeXMntkxQ==
dependencies:
uid "2.0.1"
"@nuxtjs/opencollective" "0.3.2"
@ -866,12 +866,12 @@
resolved "https://registry.yarnpkg.com/@nestjs/mapped-types/-/mapped-types-1.2.2.tgz#d9ddb143776e309dbc1a518ac1607fddac1e140e"
integrity sha512-3dHxLXs3M0GPiriAcCFFJQHoDFUuzTD5w6JDhE7TyfT89YKpe6tcCCIqOZWdXmt9AZjjK30RkHRSFF+QEnWFQg==
"@nestjs/platform-express@^9.0.0":
version "9.3.9"
resolved "https://registry.yarnpkg.com/@nestjs/platform-express/-/platform-express-9.3.9.tgz#557ace8589b54d4ee7bad87a1247a521058395d7"
integrity sha512-f8ja2sYuDGj2QSMmjg05n3WF19wJG5yTiYxRi64nsu5GKL0qLM1LzxNemehkni/knExlvF2bDpbKKpna9nC1JA==
"@nestjs/platform-express@^9.3.10":
version "9.3.10"
resolved "https://registry.yarnpkg.com/@nestjs/platform-express/-/platform-express-9.3.10.tgz#5493bd4dc3f5f28e3224afd56d113017b746f3d6"
integrity sha512-5aWokr8s0pipD5c/n40xC1iv3cMXfWrOhciX430p53cy4uyTAE+sTBk0PhB6tdG8NpK33aNqqHz/tyKlauQu/Q==
dependencies:
body-parser "1.20.1"
body-parser "1.20.2"
cors "2.8.5"
express "4.18.2"
multer "1.4.4-lts.1"
@ -885,7 +885,7 @@
cron "2.2.0"
uuid "9.0.0"
"@nestjs/schematics@^9.0.0":
"@nestjs/schematics@^9.0.0", "@nestjs/schematics@^9.0.4":
version "9.0.4"
resolved "https://registry.yarnpkg.com/@nestjs/schematics/-/schematics-9.0.4.tgz#ab612f5a8e006ca1d617eddc8143ee00b766312b"
integrity sha512-egurCfAc4e5i1r2TmeAF0UrOKejFmT5oTdv4b7HcOVPupc3QGU7CbEfGleL3mkM5AjrixTQeMxU9bJ00ttAbGg==
@ -911,10 +911,10 @@
boxen "5.1.2"
check-disk-space "3.3.1"
"@nestjs/testing@^9.3.9":
version "9.3.9"
resolved "https://registry.yarnpkg.com/@nestjs/testing/-/testing-9.3.9.tgz#f09a5df30cb1725a06f9fddd666543bbeb87eb35"
integrity sha512-+mPvSVvSC2SAkYgZZv1mOI2xsdGc1pmq7/sem7iin/JDoFtlvoGSK+pfZHD3IV3EpYtq1v/8/5gi+UFH9yZnDg==
"@nestjs/testing@^9.3.10":
version "9.3.10"
resolved "https://registry.yarnpkg.com/@nestjs/testing/-/testing-9.3.10.tgz#d0229d4d338806758dae824bdbeb935e097d4901"
integrity sha512-TGspJkzDx1YmJzlmNG5WrhFa7IGgXbCVt4UXvBVqEk2QRPmJFZnqd0T9waKZ+SxwH4gY5sdw2niTFvOgqGVfJw==
dependencies:
tslib "2.5.0"
@ -1777,6 +1777,24 @@ body-parser@1.20.1:
type-is "~1.6.18"
unpipe "1.0.0"
body-parser@1.20.2:
version "1.20.2"
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.2.tgz#6feb0e21c4724d06de7ff38da36dad4f57a747fd"
integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==
dependencies:
bytes "3.1.2"
content-type "~1.0.5"
debug "2.6.9"
depd "2.0.0"
destroy "1.2.0"
http-errors "2.0.0"
iconv-lite "0.4.24"
on-finished "2.4.1"
qs "6.11.0"
raw-body "2.5.2"
type-is "~1.6.18"
unpipe "1.0.0"
boxen@5.1.2:
version "5.1.2"
resolved "https://registry.yarnpkg.com/boxen/-/boxen-5.1.2.tgz#788cb686fc83c1f486dfa8a40c68fc2b831d2b50"
@ -1890,10 +1908,10 @@ caniuse-lite@^1.0.30001449:
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001466.tgz#c1e6197c540392e09709ecaa9e3e403428c53375"
integrity sha512-ewtFBSfWjEmxUgNBSZItFSmVtvk9zkwkl1OfRZlKA8slltRN+/C/tuGVrF9styXkN36Yu3+SeJ1qkXxDEyNZ5w==
chalk@3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4"
integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==
chalk@4.1.2, chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1, chalk@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
dependencies:
ansi-styles "^4.1.0"
supports-color "^7.1.0"
@ -1907,14 +1925,6 @@ chalk@^2.0.0:
escape-string-regexp "^1.0.5"
supports-color "^5.3.0"
chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1, chalk@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
dependencies:
ansi-styles "^4.1.0"
supports-color "^7.1.0"
char-regex@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf"
@ -2122,7 +2132,7 @@ content-disposition@0.5.4:
dependencies:
safe-buffer "5.2.1"
content-type@~1.0.4:
content-type@~1.0.4, content-type@~1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918"
integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==
@ -2762,10 +2772,10 @@ follow-redirects@^1.14.9:
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13"
integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==
fork-ts-checker-webpack-plugin@7.3.0:
version "7.3.0"
resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-7.3.0.tgz#a9c984a018493962360d7c7e77a67b44a2d5f3aa"
integrity sha512-IN+XTzusCjR5VgntYFgxbxVx3WraPRnKehBFrf00cMSrtUuW9MsG9dhL6MWpY6MkjC3wVwoujfCDgZZCQwbswA==
fork-ts-checker-webpack-plugin@8.0.0:
version "8.0.0"
resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-8.0.0.tgz#dae45dfe7298aa5d553e2580096ced79b6179504"
integrity sha512-mX3qW3idpueT2klaQXBzrIM/pHw+T0B/V9KHEvNrqijTq9NFnMZU6oreVxDYcf33P8a5cW+67PjodNHthGnNVg==
dependencies:
"@babel/code-frame" "^7.16.7"
chalk "^4.1.2"
@ -3097,25 +3107,6 @@ inherits@2, inherits@2.0.4, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3:
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
inquirer@7.3.3:
version "7.3.3"
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.3.3.tgz#04d176b2af04afc157a83fd7c100e98ee0aad003"
integrity sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==
dependencies:
ansi-escapes "^4.2.1"
chalk "^4.1.0"
cli-cursor "^3.1.0"
cli-width "^3.0.0"
external-editor "^3.0.3"
figures "^3.0.0"
lodash "^4.17.19"
mute-stream "0.0.8"
run-async "^2.4.0"
rxjs "^6.6.0"
string-width "^4.1.0"
strip-ansi "^6.0.0"
through "^2.3.6"
inquirer@8.2.4:
version "8.2.4"
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-8.2.4.tgz#ddbfe86ca2f67649a67daa6f1051c128f684f0b4"
@ -3137,6 +3128,27 @@ inquirer@8.2.4:
through "^2.3.6"
wrap-ansi "^7.0.0"
inquirer@8.2.5:
version "8.2.5"
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-8.2.5.tgz#d8654a7542c35a9b9e069d27e2df4858784d54f8"
integrity sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ==
dependencies:
ansi-escapes "^4.2.1"
chalk "^4.1.1"
cli-cursor "^3.1.0"
cli-width "^3.0.0"
external-editor "^3.0.3"
figures "^3.0.0"
lodash "^4.17.21"
mute-stream "0.0.8"
ora "^5.4.1"
run-async "^2.4.0"
rxjs "^7.5.5"
string-width "^4.1.0"
strip-ansi "^6.0.0"
through "^2.3.6"
wrap-ansi "^7.0.0"
interpret@^1.0.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e"
@ -3791,7 +3803,7 @@ lodash.snakecase@^4.1.1:
resolved "https://registry.yarnpkg.com/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz#39d714a35357147837aefd64b5dcbb16becd8f8d"
integrity sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==
lodash@4.17.21, lodash@^4.17.19, lodash@^4.17.21:
lodash@4.17.21, lodash@^4.17.21:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
@ -3840,10 +3852,10 @@ magic-string@0.26.7:
dependencies:
sourcemap-codec "^1.4.8"
magic-string@0.27.0:
version "0.27.0"
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.27.0.tgz#e4a3413b4bab6d98d2becffd48b4a257effdbbf3"
integrity sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==
magic-string@0.29.0:
version "0.29.0"
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.29.0.tgz#f034f79f8c43dba4ae1730ffb5e8c4e084b16cf3"
integrity sha512-WcfidHrDjMY+eLjlU+8OvwREqHwpgCeKVBUpQ3OhYYuvfaYCUgcbuBzappNzZvg/v8onU3oQj+BYpkOJe9Iw4Q==
dependencies:
"@jridgewell/sourcemap-codec" "^1.4.13"
@ -4413,6 +4425,16 @@ raw-body@2.5.1:
iconv-lite "0.4.24"
unpipe "1.0.0"
raw-body@2.5.2:
version "2.5.2"
resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a"
integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==
dependencies:
bytes "3.1.2"
http-errors "2.0.0"
iconv-lite "0.4.24"
unpipe "1.0.0"
react-is@^18.0.0:
version "18.2.0"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"
@ -4520,10 +4542,12 @@ reusify@^1.0.4:
resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
rimraf@4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-4.1.2.tgz#20dfbc98083bdfaa28b01183162885ef213dbf7c"
integrity sha512-BlIbgFryTbw3Dz6hyoWFhKk+unCcHMSkZGrTFVAx2WmttdBSonsdtRlwiuTbDqTKr+UlXIUqJVS4QT5tUzGENQ==
rimraf@4.4.0, rimraf@^4.4.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-4.4.0.tgz#c7a9f45bb2ec058d2e60ef9aca5167974313d605"
integrity sha512-X36S+qpCUR0HjXlkDe4NAOhS//aHH0Z+h8Ckf2auGJk3PTnx5rLmrHkwNdbVQuCSUhOyFrlRvFEllZOYE+yZGQ==
dependencies:
glob "^9.2.0"
rimraf@^3.0.0, rimraf@^3.0.2:
version "3.0.2"
@ -4532,13 +4556,6 @@ rimraf@^3.0.0, rimraf@^3.0.2:
dependencies:
glob "^7.1.3"
rimraf@^4.4.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-4.4.0.tgz#c7a9f45bb2ec058d2e60ef9aca5167974313d605"
integrity sha512-X36S+qpCUR0HjXlkDe4NAOhS//aHH0Z+h8Ckf2auGJk3PTnx5rLmrHkwNdbVQuCSUhOyFrlRvFEllZOYE+yZGQ==
dependencies:
glob "^9.2.0"
run-async@^2.4.0:
version "2.4.1"
resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455"
@ -4551,7 +4568,7 @@ run-parallel@^1.1.9:
dependencies:
queue-microtask "^1.2.2"
rxjs@6.6.7, rxjs@^6.6.0:
rxjs@6.6.7:
version "6.6.7"
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9"
integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==
@ -5034,16 +5051,16 @@ ts-node@^10.0.0:
v8-compile-cache-lib "^3.0.1"
yn "3.1.1"
tsconfig-paths-webpack-plugin@4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/tsconfig-paths-webpack-plugin/-/tsconfig-paths-webpack-plugin-4.0.0.tgz#84008fc3e3e0658fdb0262758b07b4da6265ff1a"
integrity sha512-fw/7265mIWukrSHd0i+wSwx64kYUSAKPfxRDksjKIYTxSAp9W9/xcZVBF4Kl0eqQd5eBpAQ/oQrc5RyM/0c1GQ==
tsconfig-paths-webpack-plugin@4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/tsconfig-paths-webpack-plugin/-/tsconfig-paths-webpack-plugin-4.0.1.tgz#a24651d0f69668a1abad38d3c2489855c257460d"
integrity sha512-m5//KzLoKmqu2MVix+dgLKq70MnFi8YL8sdzQZ6DblmCdfuq/y3OqvJd5vMndg2KEVCOeNz8Es4WVZhYInteLw==
dependencies:
chalk "^4.1.0"
enhanced-resolve "^5.7.0"
tsconfig-paths "^4.0.0"
tsconfig-paths "^4.1.2"
tsconfig-paths@4.1.2, tsconfig-paths@^4.0.0:
tsconfig-paths@4.1.2, tsconfig-paths@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-4.1.2.tgz#4819f861eef82e6da52fb4af1e8c930a39ed979a"
integrity sha512-uhxiMgnXQp1IR622dUXI+9Ehnws7i/y6xvpZB9IbUVOPy0muvdvgXeZOn88UcGPiT98Vp3rJPTa8bFoalZ3Qhw==
@ -5224,10 +5241,10 @@ webpack-sources@^3.2.3:
resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde"
integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==
webpack@5.75.0:
version "5.75.0"
resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.75.0.tgz#1e440468647b2505860e94c9ff3e44d5b582c152"
integrity sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ==
webpack@5.76.2:
version "5.76.2"
resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.76.2.tgz#6f80d1c1d1e3bf704db571b2504a0461fac80230"
integrity sha512-Th05ggRm23rVzEOlX8y67NkYCHa9nTNcwHPBhdg+lKG+mtiW7XgggjAeeLnADAe7mLjJ6LUNfgHAuRRh+Z6J7w==
dependencies:
"@types/eslint-scope" "^3.7.3"
"@types/estree" "^0.0.51"