mirror of
https://github.com/BluemediaGER/muse.git
synced 2024-11-12 21:05:29 +01:00
Merge pull request #415 from codetheweb/feature/better-file-caching
This commit is contained in:
commit
9afca25866
|
@ -3,3 +3,6 @@ DATA_DIR=./data
|
|||
YOUTUBE_API_KEY=
|
||||
SPOTIFY_CLIENT_ID=
|
||||
SPOTIFY_CLIENT_SECRET=
|
||||
|
||||
# Optional
|
||||
# CACHE_LIMIT=2GB
|
||||
|
|
|
@ -69,3 +69,7 @@ services:
|
|||
5. `yarn start` (or `npm run start`)
|
||||
|
||||
**Note**: if you're on Windows, you may need to manually set the ffmpeg path. See [#345](https://github.com/codetheweb/muse/issues/345) for details.
|
||||
|
||||
#### Advanced
|
||||
|
||||
By default, Muse limits the total cache size to around 2 GB. If you want to change this, set the environment variable `CACHE_LIMIT`. For example, `CACHE_LIMIT=512MB` or `CACHE_LIMIT=10GB`.
|
||||
|
|
11
package.json
11
package.json
|
@ -25,7 +25,7 @@
|
|||
"watch": "tsc --watch",
|
||||
"prepack": "npm run clean && npm run build",
|
||||
"start": "node dist/index.js",
|
||||
"dev": "nodemon",
|
||||
"dev": "concurrently nodemon 'tsc --watch'",
|
||||
"docker-publish": "docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t codetheweb/muse:latest --push ."
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -40,12 +40,14 @@
|
|||
"@types/ws": "^8.2.0",
|
||||
"@typescript-eslint/eslint-plugin": "^4.31.1",
|
||||
"@typescript-eslint/parser": "^4.31.1",
|
||||
"concurrently": "^6.4.0",
|
||||
"eslint": "^7.32.0",
|
||||
"eslint-config-xo": "^0.38.0",
|
||||
"eslint-config-xo-typescript": "^0.44.0",
|
||||
"husky": "^4.3.8",
|
||||
"nodemon": "^2.0.7",
|
||||
"ts-node": "^10.4.0",
|
||||
"type-fest": "^2.5.4",
|
||||
"typescript": "^4.4.3"
|
||||
},
|
||||
"eslintConfig": {
|
||||
|
@ -79,7 +81,7 @@
|
|||
"discord.js": "^13.3.0",
|
||||
"dotenv": "^8.5.1",
|
||||
"fluent-ffmpeg": "^2.1.2",
|
||||
"fs-capacitor": "^6.2.0",
|
||||
"fs-capacitor": "^7.0.1",
|
||||
"get-youtube-id": "^1.0.1",
|
||||
"got": "^11.8.2",
|
||||
"hasha": "^5.2.2",
|
||||
|
@ -92,11 +94,12 @@
|
|||
"p-limit": "^3.1.0",
|
||||
"p-queue": "^7.1.0",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"sequelize": "^5.22.4",
|
||||
"sequelize-typescript": "^1.1.0",
|
||||
"sequelize": "^6.11.0",
|
||||
"sequelize-typescript": "^2.1.1",
|
||||
"spotify-uri": "^2.2.0",
|
||||
"spotify-web-api-node": "^5.0.2",
|
||||
"sqlite3": "^5.0.2",
|
||||
"xbytes": "^1.7.0",
|
||||
"youtube.ts": "^0.2.2",
|
||||
"ytdl-core": "^4.9.1",
|
||||
"ytsr": "^3.5.3"
|
||||
|
|
|
@ -5,6 +5,7 @@ import {TYPES} from './types.js';
|
|||
import Bot from './bot.js';
|
||||
import {sequelize} from './utils/db.js';
|
||||
import Config from './services/config.js';
|
||||
import FileCacheProvider from './services/file-cache.js';
|
||||
|
||||
const bot = container.get<Bot>(TYPES.Bot);
|
||||
|
||||
|
@ -18,5 +19,7 @@ const bot = container.get<Bot>(TYPES.Bot);
|
|||
|
||||
await sequelize.sync({alter: true});
|
||||
|
||||
await container.get<FileCacheProvider>(TYPES.FileCache).cleanup();
|
||||
|
||||
await bot.listen();
|
||||
})();
|
||||
|
|
|
@ -29,7 +29,8 @@ import Shuffle from './commands/shuffle.js';
|
|||
import Skip from './commands/skip.js';
|
||||
import Unskip from './commands/unskip.js';
|
||||
import ThirdParty from './services/third-party.js';
|
||||
import CacheProvider from './services/cache.js';
|
||||
import FileCacheProvider from './services/file-cache.js';
|
||||
import KeyValueCacheProvider from './services/key-value-cache.js';
|
||||
|
||||
const container = new Container();
|
||||
|
||||
|
@ -78,6 +79,7 @@ container.bind(TYPES.Config).toConstantValue(new ConfigProvider());
|
|||
// Static libraries
|
||||
container.bind(TYPES.ThirdParty).to(ThirdParty);
|
||||
|
||||
container.bind(TYPES.Cache).to(CacheProvider);
|
||||
container.bind(TYPES.FileCache).to(FileCacheProvider);
|
||||
container.bind(TYPES.KeyValueCache).to(KeyValueCacheProvider);
|
||||
|
||||
export default container;
|
||||
|
|
|
@ -2,25 +2,25 @@ import {inject, injectable} from 'inversify';
|
|||
import {Client} from 'discord.js';
|
||||
import {TYPES} from '../types.js';
|
||||
import Player from '../services/player.js';
|
||||
import Config from '../services/config.js';
|
||||
import FileCacheProvider from '../services/file-cache.js';
|
||||
|
||||
@injectable()
|
||||
export default class {
|
||||
private readonly guildPlayers: Map<string, Player>;
|
||||
private readonly cacheDir: string;
|
||||
private readonly discordClient: Client;
|
||||
private readonly fileCache: FileCacheProvider;
|
||||
|
||||
constructor(@inject(TYPES.Config) config: Config, @inject(TYPES.Client) client: Client) {
|
||||
constructor(@inject(TYPES.FileCache) fileCache: FileCacheProvider, @inject(TYPES.Client) client: Client) {
|
||||
this.guildPlayers = new Map();
|
||||
this.cacheDir = config.CACHE_DIR;
|
||||
this.discordClient = client;
|
||||
this.fileCache = fileCache;
|
||||
}
|
||||
|
||||
get(guildId: string): Player {
|
||||
let player = this.guildPlayers.get(guildId);
|
||||
|
||||
if (!player) {
|
||||
player = new Player(this.cacheDir, this.discordClient);
|
||||
player = new Player(this.discordClient, this.fileCache);
|
||||
|
||||
this.guildPlayers.set(guildId, player);
|
||||
}
|
||||
|
|
14
src/models/file-cache.ts
Normal file
14
src/models/file-cache.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
import {Table, Column, PrimaryKey, Model} from 'sequelize-typescript';
|
||||
|
||||
@Table
|
||||
export default class FileCache extends Model {
|
||||
@PrimaryKey
|
||||
@Column
|
||||
hash!: string;
|
||||
|
||||
@Column
|
||||
bytes!: number;
|
||||
|
||||
@Column
|
||||
accessedAt!: Date;
|
||||
}
|
|
@ -1,9 +1,11 @@
|
|||
import Cache from './cache.js';
|
||||
import FileCache from './file-cache.js';
|
||||
import KeyValueCache from './key-value-cache.js';
|
||||
import Settings from './settings.js';
|
||||
import Shortcut from './shortcut.js';
|
||||
|
||||
export {
|
||||
Cache,
|
||||
FileCache,
|
||||
KeyValueCache,
|
||||
Settings,
|
||||
Shortcut,
|
||||
};
|
||||
|
|
|
@ -2,7 +2,7 @@ import {Table, Column, PrimaryKey, Model} from 'sequelize-typescript';
|
|||
import sequelize from 'sequelize';
|
||||
|
||||
@Table
|
||||
export default class Cache extends Model<Cache> {
|
||||
export default class KeyValueCache extends Model {
|
||||
@PrimaryKey
|
||||
@Column
|
||||
key!: string;
|
|
@ -1,7 +1,7 @@
|
|||
import {Table, Column, PrimaryKey, Model, Default} from 'sequelize-typescript';
|
||||
|
||||
@Table
|
||||
export default class Settings extends Model<Settings> {
|
||||
export default class Settings extends Model {
|
||||
@PrimaryKey
|
||||
@Column
|
||||
guildId!: string;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import {Table, Column, PrimaryKey, Model, AutoIncrement, Index} from 'sequelize-typescript';
|
||||
|
||||
@Table
|
||||
export default class Shortcut extends Model<Shortcut> {
|
||||
export default class Shortcut extends Model {
|
||||
@PrimaryKey
|
||||
@AutoIncrement
|
||||
@Column
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import dotenv from 'dotenv';
|
||||
import {injectable} from 'inversify';
|
||||
import path from 'path';
|
||||
import xbytes from 'xbytes';
|
||||
import {ConditionalKeys} from 'type-fest';
|
||||
dotenv.config();
|
||||
|
||||
export const DATA_DIR = path.resolve(process.env.DATA_DIR ? process.env.DATA_DIR : './data');
|
||||
|
@ -12,6 +14,7 @@ const CONFIG_MAP = {
|
|||
SPOTIFY_CLIENT_SECRET: process.env.SPOTIFY_CLIENT_SECRET,
|
||||
DATA_DIR,
|
||||
CACHE_DIR: path.join(DATA_DIR, 'cache'),
|
||||
CACHE_LIMIT_IN_BYTES: xbytes.parseSize(process.env.CACHE_LIMIT ?? '2GB'),
|
||||
} as const;
|
||||
|
||||
@injectable()
|
||||
|
@ -22,6 +25,7 @@ export default class Config {
|
|||
readonly SPOTIFY_CLIENT_SECRET!: string;
|
||||
readonly DATA_DIR!: string;
|
||||
readonly CACHE_DIR!: string;
|
||||
readonly CACHE_LIMIT_IN_BYTES!: number;
|
||||
|
||||
constructor() {
|
||||
for (const [key, value] of Object.entries(CONFIG_MAP)) {
|
||||
|
@ -30,7 +34,13 @@ export default class Config {
|
|||
process.exit(1);
|
||||
}
|
||||
|
||||
this[key as keyof typeof CONFIG_MAP] = value;
|
||||
if (typeof value === 'number') {
|
||||
this[key as ConditionalKeys<typeof CONFIG_MAP, number>] = value;
|
||||
} else if (typeof value === 'string') {
|
||||
this[key as ConditionalKeys<typeof CONFIG_MAP, string>] = value;
|
||||
} else {
|
||||
throw new Error(`Unsupported type for ${key}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
117
src/services/file-cache.ts
Normal file
117
src/services/file-cache.ts
Normal file
|
@ -0,0 +1,117 @@
|
|||
import {promises as fs, createWriteStream} from 'fs';
|
||||
import path from 'path';
|
||||
import {inject, injectable} from 'inversify';
|
||||
import sequelize from 'sequelize';
|
||||
import {FileCache} from '../models/index.js';
|
||||
import {TYPES} from '../types.js';
|
||||
import Config from './config.js';
|
||||
|
||||
@injectable()
|
||||
export default class FileCacheProvider {
|
||||
private readonly config: Config;
|
||||
|
||||
constructor(@inject(TYPES.Config) config: Config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns path to cached file if it exists, otherwise throws an error.
|
||||
* Updates the `accessedAt` property of the cached file.
|
||||
* @param hash lookup key
|
||||
*/
|
||||
async getPathFor(hash: string): Promise<string> {
|
||||
const model = await FileCache.findByPk(hash);
|
||||
|
||||
if (!model) {
|
||||
throw new Error('File is not cached');
|
||||
}
|
||||
|
||||
const resolvedPath = path.join(this.config.CACHE_DIR, hash);
|
||||
|
||||
try {
|
||||
await fs.access(resolvedPath);
|
||||
} catch (_: unknown) {
|
||||
await FileCache.destroy({where: {hash}});
|
||||
|
||||
throw new Error('File is not cached');
|
||||
}
|
||||
|
||||
await model.update({accessedAt: new Date()});
|
||||
|
||||
return resolvedPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a write stream for the given hash key.
|
||||
* The stream handles saving a new file and will
|
||||
* update the database after the stream is closed.
|
||||
* @param hash lookup key
|
||||
*/
|
||||
createWriteStream(hash: string) {
|
||||
const tmpPath = path.join(this.config.CACHE_DIR, 'tmp', hash);
|
||||
const finalPath = path.join(this.config.CACHE_DIR, hash);
|
||||
|
||||
const stream = createWriteStream(tmpPath);
|
||||
|
||||
stream.on('close', async () => {
|
||||
// Only move if size is non-zero (may have errored out)
|
||||
const stats = await fs.stat(tmpPath);
|
||||
|
||||
if (stats.size !== 0) {
|
||||
await fs.rename(tmpPath, finalPath);
|
||||
}
|
||||
|
||||
await FileCache.create({hash, bytes: stats.size, accessedAt: new Date()});
|
||||
|
||||
await this.evictOldestIfNecessary();
|
||||
});
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes orphaned cache files and evicts files if
|
||||
* necessary. Should be run on program startup so files
|
||||
* will be evicted if the cache limit has changed.
|
||||
*/
|
||||
async cleanup() {
|
||||
await this.removeOrphans();
|
||||
await this.evictOldestIfNecessary();
|
||||
}
|
||||
|
||||
private async evictOldestIfNecessary() {
|
||||
const [{dataValues: {totalSizeBytes}}] = await FileCache.findAll({
|
||||
attributes: [
|
||||
[sequelize.fn('sum', sequelize.col('bytes')), 'totalSizeBytes'],
|
||||
],
|
||||
}) as unknown as [{dataValues: {totalSizeBytes: number}}];
|
||||
|
||||
if (totalSizeBytes > this.config.CACHE_LIMIT_IN_BYTES) {
|
||||
const oldest = await FileCache.findOne({
|
||||
order: [
|
||||
['accessedAt', 'ASC'],
|
||||
],
|
||||
});
|
||||
|
||||
if (oldest) {
|
||||
await oldest.destroy();
|
||||
await fs.unlink(path.join(this.config.CACHE_DIR, oldest.hash));
|
||||
}
|
||||
|
||||
// Continue to evict until we're under the limit
|
||||
await this.evictOldestIfNecessary();
|
||||
}
|
||||
}
|
||||
|
||||
private async removeOrphans() {
|
||||
for await (const dirent of await fs.opendir(this.config.CACHE_DIR)) {
|
||||
if (dirent.isFile()) {
|
||||
const model = await FileCache.findByPk(dirent.name);
|
||||
|
||||
if (!model) {
|
||||
await fs.unlink(path.join(this.config.CACHE_DIR, dirent.name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,7 +14,7 @@ import {TYPES} from '../types.js';
|
|||
import {cleanUrl} from '../utils/url.js';
|
||||
import ThirdParty from './third-party.js';
|
||||
import Config from './config.js';
|
||||
import CacheProvider from './cache.js';
|
||||
import KeyValueCacheProvider from './key-value-cache.js';
|
||||
|
||||
type QueuedSongWithoutChannel = Except<QueuedSong, 'addedInChannelId'>;
|
||||
|
||||
|
@ -26,14 +26,14 @@ export default class {
|
|||
private readonly youtube: YouTube;
|
||||
private readonly youtubeKey: string;
|
||||
private readonly spotify: Spotify;
|
||||
private readonly cache: CacheProvider;
|
||||
private readonly cache: KeyValueCacheProvider;
|
||||
|
||||
private readonly ytsrQueue: PQueue;
|
||||
|
||||
constructor(
|
||||
@inject(TYPES.ThirdParty) thirdParty: ThirdParty,
|
||||
@inject(TYPES.Config) config: Config,
|
||||
@inject(TYPES.Cache) cache: CacheProvider) {
|
||||
@inject(TYPES.KeyValueCache) cache: KeyValueCacheProvider) {
|
||||
this.youtube = thirdParty.youtube;
|
||||
this.youtubeKey = config.YOUTUBE_API_KEY;
|
||||
this.spotify = thirdParty.spotify;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import {injectable} from 'inversify';
|
||||
import {Cache} from '../models/index.js';
|
||||
import {KeyValueCache} from '../models/index.js';
|
||||
import debug from '../utils/debug.js';
|
||||
|
||||
type Seconds = number;
|
||||
|
@ -12,7 +12,7 @@ type Options = {
|
|||
const futureTimeToDate = (time: Seconds) => new Date(new Date().getTime() + (time * 1000));
|
||||
|
||||
@injectable()
|
||||
export default class CacheProvider {
|
||||
export default class KeyValueCacheProvider {
|
||||
async wrap<T extends [...any[], Options], F>(func: (...options: any) => Promise<F>, ...options: T): Promise<F> {
|
||||
if (options.length === 0) {
|
||||
throw new Error('Missing cache options');
|
||||
|
@ -29,7 +29,7 @@ export default class CacheProvider {
|
|||
throw new Error(`Cache key ${key} is too short.`);
|
||||
}
|
||||
|
||||
const cachedResult = await Cache.findByPk(key);
|
||||
const cachedResult = await KeyValueCache.findByPk(key);
|
||||
|
||||
if (cachedResult) {
|
||||
if (new Date() < cachedResult.expiresAt) {
|
||||
|
@ -45,7 +45,7 @@ export default class CacheProvider {
|
|||
const result = await func(...options as any[]);
|
||||
|
||||
// Save result
|
||||
await Cache.upsert({
|
||||
await KeyValueCache.upsert({
|
||||
key,
|
||||
value: JSON.stringify(result),
|
||||
expiresAt: futureTimeToDate(expiresIn),
|
|
@ -1,7 +1,5 @@
|
|||
import {VoiceChannel, Snowflake, Client, TextChannel} from 'discord.js';
|
||||
import {promises as fs, createWriteStream} from 'fs';
|
||||
import {Readable, PassThrough} from 'stream';
|
||||
import path from 'path';
|
||||
import {Readable} from 'stream';
|
||||
import hasha from 'hasha';
|
||||
import ytdl from 'ytdl-core';
|
||||
import {WriteStream} from 'fs-capacitor';
|
||||
|
@ -9,6 +7,7 @@ import ffmpeg from 'fluent-ffmpeg';
|
|||
import shuffle from 'array-shuffle';
|
||||
import errorMsg from '../utils/error-msg.js';
|
||||
import {AudioPlayer, AudioPlayerStatus, createAudioPlayer, createAudioResource, joinVoiceChannel, StreamType, VoiceConnection, VoiceConnectionStatus} from '@discordjs/voice';
|
||||
import FileCacheProvider from './file-cache.js';
|
||||
|
||||
export interface QueuedPlaylist {
|
||||
title: string;
|
||||
|
@ -35,7 +34,6 @@ export default class {
|
|||
public voiceConnection: VoiceConnection | null = null;
|
||||
private queue: QueuedSong[] = [];
|
||||
private queuePosition = 0;
|
||||
private readonly cacheDir: string;
|
||||
private audioPlayer: AudioPlayer | null = null;
|
||||
private nowPlaying: QueuedSong | null = null;
|
||||
private playPositionInterval: NodeJS.Timeout | undefined;
|
||||
|
@ -44,10 +42,11 @@ export default class {
|
|||
private positionInSeconds = 0;
|
||||
|
||||
private readonly discordClient: Client;
|
||||
private readonly fileCache: FileCacheProvider;
|
||||
|
||||
constructor(cacheDir: string, client: Client) {
|
||||
this.cacheDir = cacheDir;
|
||||
constructor(client: Client, fileCache: FileCacheProvider) {
|
||||
this.discordClient = client;
|
||||
this.fileCache = fileCache;
|
||||
}
|
||||
|
||||
async connect(channel: VoiceChannel): Promise<void> {
|
||||
|
@ -287,40 +286,24 @@ export default class {
|
|||
return this.queueSize() === 0;
|
||||
}
|
||||
|
||||
private getCachedPath(url: string): string {
|
||||
return path.join(this.cacheDir, hasha(url));
|
||||
}
|
||||
|
||||
private getCachedPathTemp(url: string): string {
|
||||
return path.join(this.cacheDir, 'tmp', hasha(url));
|
||||
}
|
||||
|
||||
private async isCached(url: string): Promise<boolean> {
|
||||
try {
|
||||
await fs.access(this.getCachedPath(url));
|
||||
|
||||
return true;
|
||||
} catch (_: unknown) {
|
||||
return false;
|
||||
}
|
||||
private getHashForCache(url: string): string {
|
||||
return hasha(url);
|
||||
}
|
||||
|
||||
private async getStream(url: string, options: {seek?: number} = {}): Promise<Readable> {
|
||||
const cachedPath = this.getCachedPath(url);
|
||||
|
||||
let ffmpegInput = '';
|
||||
const ffmpegInputOptions: string[] = [];
|
||||
let shouldCacheVideo = false;
|
||||
|
||||
let format: ytdl.videoFormat | undefined;
|
||||
|
||||
if (await this.isCached(url)) {
|
||||
ffmpegInput = cachedPath;
|
||||
try {
|
||||
ffmpegInput = await this.fileCache.getPathFor(this.getHashForCache(url));
|
||||
|
||||
if (options.seek) {
|
||||
ffmpegInputOptions.push('-ss', options.seek.toString());
|
||||
}
|
||||
} else {
|
||||
} catch {
|
||||
// Not yet cached, must download
|
||||
const info = await ytdl.getInfo(url);
|
||||
|
||||
|
@ -371,7 +354,6 @@ export default class {
|
|||
'1',
|
||||
'-reconnect_delay_max',
|
||||
'5',
|
||||
'-re',
|
||||
]);
|
||||
|
||||
if (options.seek) {
|
||||
|
@ -382,6 +364,17 @@ export default class {
|
|||
|
||||
// Create stream and pipe to capacitor
|
||||
return new Promise((resolve, reject) => {
|
||||
const capacitor = new WriteStream();
|
||||
|
||||
// Cache video if necessary
|
||||
if (shouldCacheVideo) {
|
||||
const cacheStream = this.fileCache.createWriteStream(this.getHashForCache(url));
|
||||
|
||||
capacitor.createReadStream().pipe(cacheStream);
|
||||
} else {
|
||||
ffmpegInputOptions.push('-re');
|
||||
}
|
||||
|
||||
const youtubeStream = ffmpeg(ffmpegInput)
|
||||
.inputOptions(ffmpegInputOptions)
|
||||
.noVideo()
|
||||
|
@ -390,29 +383,9 @@ export default class {
|
|||
.on('error', error => {
|
||||
console.error(error);
|
||||
reject(error);
|
||||
})
|
||||
.pipe() as PassThrough;
|
||||
|
||||
const capacitor = new WriteStream();
|
||||
|
||||
youtubeStream.pipe(capacitor);
|
||||
|
||||
// Cache video if necessary
|
||||
if (shouldCacheVideo) {
|
||||
const cacheTempPath = this.getCachedPathTemp(url);
|
||||
const cacheStream = createWriteStream(cacheTempPath);
|
||||
|
||||
cacheStream.on('finish', async () => {
|
||||
// Only move if size is non-zero (may have errored out)
|
||||
const stats = await fs.stat(cacheTempPath);
|
||||
|
||||
if (stats.size !== 0) {
|
||||
await fs.rename(cacheTempPath, cachedPath);
|
||||
}
|
||||
});
|
||||
|
||||
capacitor.createReadStream().pipe(cacheStream);
|
||||
}
|
||||
youtubeStream.pipe(capacitor);
|
||||
|
||||
resolve(capacitor.createReadStream());
|
||||
});
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
export const TYPES = {
|
||||
Bot: Symbol('Bot'),
|
||||
Cache: Symbol('Cache'),
|
||||
KeyValueCache: Symbol('KeyValueCache'),
|
||||
FileCache: Symbol('FileCache'),
|
||||
Client: Symbol('Client'),
|
||||
Config: Symbol('Config'),
|
||||
Command: Symbol('Command'),
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import {Sequelize} from 'sequelize-typescript';
|
||||
import path from 'path';
|
||||
import {DATA_DIR} from '../services/config.js';
|
||||
import {Cache, Settings, Shortcut} from '../models/index.js';
|
||||
import {FileCache, KeyValueCache, Settings, Shortcut} from '../models/index.js';
|
||||
|
||||
export const sequelize = new Sequelize({
|
||||
dialect: 'sqlite',
|
||||
database: 'muse',
|
||||
storage: path.join(DATA_DIR, 'db.sqlite'),
|
||||
models: [Cache, Settings, Shortcut],
|
||||
models: [FileCache, KeyValueCache, Settings, Shortcut],
|
||||
logging: false,
|
||||
});
|
||||
|
|
238
yarn.lock
238
yarn.lock
|
@ -610,11 +610,6 @@ block-stream@*:
|
|||
dependencies:
|
||||
inherits "~2.0.0"
|
||||
|
||||
bluebird@^3.5.0:
|
||||
version "3.7.2"
|
||||
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f"
|
||||
integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==
|
||||
|
||||
boxen@^5.0.0:
|
||||
version "5.1.2"
|
||||
resolved "https://registry.yarnpkg.com/boxen/-/boxen-5.1.2.tgz#788cb686fc83c1f486dfa8a40c68fc2b831d2b50"
|
||||
|
@ -750,6 +745,15 @@ cli-boxes@^2.2.1:
|
|||
resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f"
|
||||
integrity sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==
|
||||
|
||||
cliui@^7.0.2:
|
||||
version "7.0.4"
|
||||
resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f"
|
||||
integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==
|
||||
dependencies:
|
||||
string-width "^4.2.0"
|
||||
strip-ansi "^6.0.0"
|
||||
wrap-ansi "^7.0.0"
|
||||
|
||||
clone-response@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b"
|
||||
|
@ -757,14 +761,6 @@ clone-response@^1.0.2:
|
|||
dependencies:
|
||||
mimic-response "^1.0.0"
|
||||
|
||||
cls-bluebird@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/cls-bluebird/-/cls-bluebird-2.1.0.tgz#37ef1e080a8ffb55c2f4164f536f1919e7968aee"
|
||||
integrity sha1-N+8eCAqP+1XC9BZPU28ZGeeWiu4=
|
||||
dependencies:
|
||||
is-bluebird "^1.0.2"
|
||||
shimmer "^1.1.0"
|
||||
|
||||
code-point-at@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
|
||||
|
@ -821,6 +817,20 @@ concat-map@0.0.1:
|
|||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
||||
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
|
||||
|
||||
concurrently@^6.4.0:
|
||||
version "6.4.0"
|
||||
resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-6.4.0.tgz#5387ee86be435a0eb51c292ade8a00acf479f170"
|
||||
integrity sha512-HZ3D0RTQMH3oS4gvtYj1P+NBc6PzE2McEra6yEFcQKrUQ9HvtTGU4Dbne083F034p+LRb7kWU0tPRNvSGs1UCQ==
|
||||
dependencies:
|
||||
chalk "^4.1.0"
|
||||
date-fns "^2.16.1"
|
||||
lodash "^4.17.21"
|
||||
rxjs "^6.6.3"
|
||||
spawn-command "^0.0.2-1"
|
||||
supports-color "^8.1.0"
|
||||
tree-kill "^1.2.2"
|
||||
yargs "^16.2.0"
|
||||
|
||||
configstore@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/configstore/-/configstore-5.0.1.tgz#d365021b5df4b98cdd187d6a3b0e3f6a7cc5ed96"
|
||||
|
@ -895,6 +905,11 @@ dashdash@^1.12.0:
|
|||
dependencies:
|
||||
assert-plus "^1.0.0"
|
||||
|
||||
date-fns@^2.16.1:
|
||||
version "2.25.0"
|
||||
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.25.0.tgz#8c5c8f1d958be3809a9a03f4b742eba894fc5680"
|
||||
integrity sha512-ovYRFnTrbGPD4nqaEqescPEv1mNwvt+UTqI3Ay9SzNtey9NZnYu6E2qCcBBgJ6/2VF1zGGygpyTDITqpQQ5e+w==
|
||||
|
||||
debug@4, debug@^4.0.1, debug@^4.1.1, debug@^4.3.1:
|
||||
version "4.3.2"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b"
|
||||
|
@ -1072,6 +1087,11 @@ error-ex@^1.3.1:
|
|||
dependencies:
|
||||
is-arrayish "^0.2.1"
|
||||
|
||||
escalade@^3.1.1:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
|
||||
integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
|
||||
|
||||
escape-goat@^2.0.0:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675"
|
||||
|
@ -1365,10 +1385,10 @@ formidable@^1.2.2:
|
|||
resolved "https://registry.yarnpkg.com/formidable/-/formidable-1.2.6.tgz#d2a51d60162bbc9b4a055d8457a7c75315d1a168"
|
||||
integrity sha512-KcpbcpuLNOwrEjnbpMC0gS+X8ciDoZE1kkqzat4a8vrprf+s9pKNQ/QIwWfbfs4ltgmFl3MD177SNTkve3BwGQ==
|
||||
|
||||
fs-capacitor@^6.2.0:
|
||||
version "6.2.0"
|
||||
resolved "https://registry.yarnpkg.com/fs-capacitor/-/fs-capacitor-6.2.0.tgz#fa79ac6576629163cb84561995602d8999afb7f5"
|
||||
integrity sha512-nKcE1UduoSKX27NSZlg879LdQc94OtbOsEmKMN2MBNudXREvijRKx2GEBsTMTfws+BrbkJoEuynbGSVRSpauvw==
|
||||
fs-capacitor@^7.0.1:
|
||||
version "7.0.1"
|
||||
resolved "https://registry.yarnpkg.com/fs-capacitor/-/fs-capacitor-7.0.1.tgz#351fa0224d74ae5ee17fdd165055082426ac60a3"
|
||||
integrity sha512-YjxAAorsFA/pK3PTLuYJO+FlZ7wvGTIwGPbpGzVAJ+DUp6uof0zZjG6dcYsrGX864BMeUCj9R6lmkYZ5uY5lWQ==
|
||||
|
||||
fs-minipass@^1.2.7:
|
||||
version "1.2.7"
|
||||
|
@ -1443,6 +1463,11 @@ gauge@~2.7.3:
|
|||
strip-ansi "^3.0.1"
|
||||
wide-align "^1.1.0"
|
||||
|
||||
get-caller-file@^2.0.5:
|
||||
version "2.0.5"
|
||||
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
|
||||
integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
|
||||
|
||||
get-intrinsic@^1.0.2:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6"
|
||||
|
@ -1485,19 +1510,7 @@ glob-parent@^5.1.2, glob-parent@~5.1.2:
|
|||
dependencies:
|
||||
is-glob "^4.0.1"
|
||||
|
||||
glob@7.1.2:
|
||||
version "7.1.2"
|
||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15"
|
||||
integrity sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==
|
||||
dependencies:
|
||||
fs.realpath "^1.0.0"
|
||||
inflight "^1.0.4"
|
||||
inherits "2"
|
||||
minimatch "^3.0.4"
|
||||
once "^1.3.0"
|
||||
path-is-absolute "^1.0.0"
|
||||
|
||||
glob@^7.0.3, glob@^7.1.3:
|
||||
glob@7.2.0, glob@^7.0.3, glob@^7.1.3:
|
||||
version "7.2.0"
|
||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023"
|
||||
integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==
|
||||
|
@ -1720,10 +1733,10 @@ imurmurhash@^0.1.4:
|
|||
resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
|
||||
integrity sha1-khi5srkoojixPcT7a21XbyMUU+o=
|
||||
|
||||
inflection@1.12.0:
|
||||
version "1.12.0"
|
||||
resolved "https://registry.yarnpkg.com/inflection/-/inflection-1.12.0.tgz#a200935656d6f5f6bc4dc7502e1aecb703228416"
|
||||
integrity sha1-ogCTVlbW9fa8TcdQLhrstwMihBY=
|
||||
inflection@1.13.1:
|
||||
version "1.13.1"
|
||||
resolved "https://registry.yarnpkg.com/inflection/-/inflection-1.13.1.tgz#c5cadd80888a90cf84c2e96e340d7edc85d5f0cb"
|
||||
integrity sha512-dldYtl2WlN0QDkIDtg8+xFwOS2Tbmp12t1cHa5/YClU6ZQjTFm7B66UcVbh9NQB+HvT5BAd2t5+yKsBkw5pcqA==
|
||||
|
||||
inflight@^1.0.4:
|
||||
version "1.0.6"
|
||||
|
@ -1765,11 +1778,6 @@ is-binary-path@~2.1.0:
|
|||
dependencies:
|
||||
binary-extensions "^2.0.0"
|
||||
|
||||
is-bluebird@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/is-bluebird/-/is-bluebird-1.0.2.tgz#096439060f4aa411abee19143a84d6a55346d6e2"
|
||||
integrity sha1-CWQ5Bg9KpBGr7hkUOoTWpVNG1uI=
|
||||
|
||||
is-ci@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c"
|
||||
|
@ -2005,7 +2013,7 @@ lodash.truncate@^4.4.2:
|
|||
resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193"
|
||||
integrity sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=
|
||||
|
||||
lodash@^4.17.15, lodash@^4.17.21:
|
||||
lodash@^4.17.20, lodash@^4.17.21:
|
||||
version "4.17.21"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
|
||||
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
|
||||
|
@ -2151,14 +2159,14 @@ mkdirp@^1.0.3:
|
|||
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
|
||||
integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
|
||||
|
||||
moment-timezone@^0.5.21:
|
||||
moment-timezone@^0.5.31:
|
||||
version "0.5.34"
|
||||
resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.34.tgz#a75938f7476b88f155d3504a9343f7519d9a405c"
|
||||
integrity sha512-3zAEHh2hKUs3EXLESx/wsgw6IQdusOT8Bxm3D9UrHPQR7zlMmzwybC8zHEM1tQ4LJwP7fcxrWr8tuBg05fFCbg==
|
||||
dependencies:
|
||||
moment ">= 2.9.0"
|
||||
|
||||
"moment@>= 2.9.0", moment@^2.24.0:
|
||||
"moment@>= 2.9.0", moment@^2.26.0:
|
||||
version "2.29.1"
|
||||
resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3"
|
||||
integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==
|
||||
|
@ -2533,6 +2541,11 @@ performance-now@^2.1.0:
|
|||
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
|
||||
integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=
|
||||
|
||||
pg-connection-string@^2.5.0:
|
||||
version "2.5.0"
|
||||
resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.5.0.tgz#538cadd0f7e603fc09a12590f3b8a452c2c0cf34"
|
||||
integrity sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==
|
||||
|
||||
picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972"
|
||||
|
@ -2718,6 +2731,11 @@ request@^2.87.0:
|
|||
tunnel-agent "^0.6.0"
|
||||
uuid "^3.3.2"
|
||||
|
||||
require-directory@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
|
||||
integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I=
|
||||
|
||||
require-from-string@^2.0.2:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909"
|
||||
|
@ -2780,6 +2798,13 @@ run-parallel@^1.1.9:
|
|||
dependencies:
|
||||
queue-microtask "^1.2.2"
|
||||
|
||||
rxjs@^6.6.3:
|
||||
version "6.6.7"
|
||||
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9"
|
||||
integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==
|
||||
dependencies:
|
||||
tslib "^1.9.0"
|
||||
|
||||
safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@^5.2.1, safe-buffer@~5.2.0:
|
||||
version "5.2.1"
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
|
||||
|
@ -2839,38 +2864,37 @@ semver@~5.3.0:
|
|||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
|
||||
integrity sha1-myzl094C0XxgEq0yaqa00M9U+U8=
|
||||
|
||||
sequelize-pool@^2.3.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/sequelize-pool/-/sequelize-pool-2.3.0.tgz#64f1fe8744228172c474f530604b6133be64993d"
|
||||
integrity sha512-Ibz08vnXvkZ8LJTiUOxRcj1Ckdn7qafNZ2t59jYHMX1VIebTAOYefWdRYFt6z6+hy52WGthAHAoLc9hvk3onqA==
|
||||
sequelize-pool@^6.0.0:
|
||||
version "6.1.0"
|
||||
resolved "https://registry.yarnpkg.com/sequelize-pool/-/sequelize-pool-6.1.0.tgz#caaa0c1e324d3c2c3a399fed2c7998970925d668"
|
||||
integrity sha512-4YwEw3ZgK/tY/so+GfnSgXkdwIJJ1I32uZJztIEgZeAO6HMgj64OzySbWLgxj+tXhZCJnzRfkY9gINw8Ft8ZMg==
|
||||
|
||||
sequelize-typescript@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/sequelize-typescript/-/sequelize-typescript-1.1.0.tgz#d5c2945e7fbfe55a934917b27d84589858d79123"
|
||||
integrity sha512-FAPEQPeAhIaFQNLAcf9Q2IWcqWhNcvn5OZZ7BzGB0CJMtImIsGg4E/EAb7huMmPaPwDArxJUWGqk1KurphTNRA==
|
||||
sequelize-typescript@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/sequelize-typescript/-/sequelize-typescript-2.1.1.tgz#92445632062db868b760cd20215406403da737a2"
|
||||
integrity sha512-4am/5O6dlAvtR/akH2KizcECm4rRAjWr+oc5mo9vFVMez8hrbOhQlDNzk0H6VMOQASCN7yBF+qOnSEN60V6/vA==
|
||||
dependencies:
|
||||
glob "7.1.2"
|
||||
glob "7.2.0"
|
||||
|
||||
sequelize@^5.22.4:
|
||||
version "5.22.4"
|
||||
resolved "https://registry.yarnpkg.com/sequelize/-/sequelize-5.22.4.tgz#4dbd8a1a735e98150880d43a95d45e9f46d151fa"
|
||||
integrity sha512-xFQQ38HPg7EyDRDA+NdzMSRWbo9m6Z/RxpjnkBl3ggyQG+jRrup48x0jaw4Ox42h56wFnXOBC2NZOkTJfZeWCw==
|
||||
sequelize@^6.11.0:
|
||||
version "6.11.0"
|
||||
resolved "https://registry.yarnpkg.com/sequelize/-/sequelize-6.11.0.tgz#11620b02ab2ca02af59ec652dd22bef7ccd348af"
|
||||
integrity sha512-+j3N5lr+FR1eicMRGR3bRsGOl9HMY0UGb2PyB2i1yZ64XBgsz3xejMH0UD45LcUitj40soDGIa9CyvZG0dfzKg==
|
||||
dependencies:
|
||||
bluebird "^3.5.0"
|
||||
cls-bluebird "^2.1.0"
|
||||
debug "^4.1.1"
|
||||
dottie "^2.0.0"
|
||||
inflection "1.12.0"
|
||||
lodash "^4.17.15"
|
||||
moment "^2.24.0"
|
||||
moment-timezone "^0.5.21"
|
||||
inflection "1.13.1"
|
||||
lodash "^4.17.20"
|
||||
moment "^2.26.0"
|
||||
moment-timezone "^0.5.31"
|
||||
pg-connection-string "^2.5.0"
|
||||
retry-as-promised "^3.2.0"
|
||||
semver "^6.3.0"
|
||||
sequelize-pool "^2.3.0"
|
||||
semver "^7.3.2"
|
||||
sequelize-pool "^6.0.0"
|
||||
toposort-class "^1.0.1"
|
||||
uuid "^3.3.3"
|
||||
validator "^10.11.0"
|
||||
wkx "^0.4.8"
|
||||
uuid "^8.1.0"
|
||||
validator "^13.7.0"
|
||||
wkx "^0.5.0"
|
||||
|
||||
set-blocking@^2.0.0, set-blocking@~2.0.0:
|
||||
version "2.0.0"
|
||||
|
@ -2889,11 +2913,6 @@ shebang-regex@^3.0.0:
|
|||
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
|
||||
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
|
||||
|
||||
shimmer@^1.1.0:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/shimmer/-/shimmer-1.2.1.tgz#610859f7de327b587efebf501fb43117f9aff337"
|
||||
integrity sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==
|
||||
|
||||
side-channel@^1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf"
|
||||
|
@ -2922,6 +2941,11 @@ slice-ansi@^4.0.0:
|
|||
astral-regex "^2.0.0"
|
||||
is-fullwidth-code-point "^3.0.0"
|
||||
|
||||
spawn-command@^0.0.2-1:
|
||||
version "0.0.2-1"
|
||||
resolved "https://registry.yarnpkg.com/spawn-command/-/spawn-command-0.0.2-1.tgz#62f5e9466981c1b796dc5929937e11c9c6921bd0"
|
||||
integrity sha1-YvXpRmmBwbeW3Fkpk34RycaSG9A=
|
||||
|
||||
spotify-uri@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/spotify-uri/-/spotify-uri-2.2.0.tgz#8db641615cf6e122284874287fe39e89595922df"
|
||||
|
@ -2981,7 +3005,7 @@ string-width@^1.0.1:
|
|||
is-fullwidth-code-point "^2.0.0"
|
||||
strip-ansi "^4.0.0"
|
||||
|
||||
"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.2, string-width@^4.2.3:
|
||||
"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, 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==
|
||||
|
@ -3066,6 +3090,13 @@ supports-color@^7.1.0:
|
|||
dependencies:
|
||||
has-flag "^4.0.0"
|
||||
|
||||
supports-color@^8.1.0:
|
||||
version "8.1.1"
|
||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c"
|
||||
integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==
|
||||
dependencies:
|
||||
has-flag "^4.0.0"
|
||||
|
||||
table@^6.0.9:
|
||||
version "6.7.3"
|
||||
resolved "https://registry.yarnpkg.com/table/-/table-6.7.3.tgz#255388439715a738391bd2ee4cbca89a4d05a9b7"
|
||||
|
@ -3158,6 +3189,11 @@ tr46@~0.0.3:
|
|||
resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
|
||||
integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=
|
||||
|
||||
tree-kill@^1.2.2:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc"
|
||||
integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==
|
||||
|
||||
ts-mixer@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ts-mixer/-/ts-mixer-6.0.0.tgz#4e631d3a36e3fa9521b973b132e8353bc7267f9f"
|
||||
|
@ -3181,7 +3217,7 @@ ts-node@^10.4.0:
|
|||
make-error "^1.1.1"
|
||||
yn "3.1.1"
|
||||
|
||||
tslib@^1.8.1:
|
||||
tslib@^1.8.1, tslib@^1.9.0:
|
||||
version "1.14.1"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
|
||||
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
|
||||
|
@ -3232,6 +3268,11 @@ type-fest@^1.2.1:
|
|||
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-1.4.0.tgz#e9fb813fe3bf1744ec359d55d1affefa76f14be1"
|
||||
integrity sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==
|
||||
|
||||
type-fest@^2.5.4:
|
||||
version "2.5.4"
|
||||
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.5.4.tgz#1613bf29a172ff1c66c29325466af9096fe505b5"
|
||||
integrity sha512-zyPomVvb6u7+gJ/GPYUH6/nLDNiTtVOqXVUHtxFv5PmZQh6skgfeRtFYzWC01T5KeNWNIx5/0P111rKFLlkFvA==
|
||||
|
||||
typedarray-to-buffer@^3.1.5:
|
||||
version "3.1.5"
|
||||
resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080"
|
||||
|
@ -3295,11 +3336,16 @@ util-deprecate@^1.0.1, util-deprecate@~1.0.1:
|
|||
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
|
||||
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
|
||||
|
||||
uuid@^3.3.2, uuid@^3.3.3:
|
||||
uuid@^3.3.2:
|
||||
version "3.4.0"
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
|
||||
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
|
||||
|
||||
uuid@^8.1.0:
|
||||
version "8.3.2"
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
|
||||
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
|
||||
|
||||
v8-compile-cache@^2.0.3:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee"
|
||||
|
@ -3310,10 +3356,10 @@ vali-date@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/vali-date/-/vali-date-1.0.0.tgz#1b904a59609fb328ef078138420934f6b86709a6"
|
||||
integrity sha1-G5BKWWCfsyjvB4E4Qgk09rhnCaY=
|
||||
|
||||
validator@^10.11.0:
|
||||
version "10.11.0"
|
||||
resolved "https://registry.yarnpkg.com/validator/-/validator-10.11.0.tgz#003108ea6e9a9874d31ccc9e5006856ccd76b228"
|
||||
integrity sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw==
|
||||
validator@^13.7.0:
|
||||
version "13.7.0"
|
||||
resolved "https://registry.yarnpkg.com/validator/-/validator-13.7.0.tgz#4f9658ba13ba8f3d82ee881d3516489ea85c0857"
|
||||
integrity sha512-nYXQLCBkpJ8X6ltALua9dRrZDHVYxjJ1wgskNt1lH9fzGjs3tgojGSCBjmEPwkWS1y29+DrizMTW19Pr9uB2nw==
|
||||
|
||||
verror@1.10.0:
|
||||
version "1.10.0"
|
||||
|
@ -3370,10 +3416,10 @@ widest-line@^3.1.0:
|
|||
dependencies:
|
||||
string-width "^4.0.0"
|
||||
|
||||
wkx@^0.4.8:
|
||||
version "0.4.8"
|
||||
resolved "https://registry.yarnpkg.com/wkx/-/wkx-0.4.8.tgz#a092cf088d112683fdc7182fd31493b2c5820003"
|
||||
integrity sha512-ikPXMM9IR/gy/LwiOSqWlSL3X/J5uk9EO2hHNRXS41eTLXaUFEVw9fn/593jW/tE5tedNg8YjT5HkCa4FqQZyQ==
|
||||
wkx@^0.5.0:
|
||||
version "0.5.0"
|
||||
resolved "https://registry.yarnpkg.com/wkx/-/wkx-0.5.0.tgz#c6c37019acf40e517cc6b94657a25a3d4aa33e8c"
|
||||
integrity sha512-Xng/d4Ichh8uN4l0FToV/258EjMGU9MGcA0HV2d9B/ZpZB3lqQm7nkOdZdm5GhKtLLhAE7PiVQwN4eN+2YJJUg==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
|
@ -3411,11 +3457,21 @@ ws@^8.2.3:
|
|||
resolved "https://registry.yarnpkg.com/ws/-/ws-8.2.3.tgz#63a56456db1b04367d0b721a0b80cae6d8becbba"
|
||||
integrity sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==
|
||||
|
||||
xbytes@^1.7.0:
|
||||
version "1.7.0"
|
||||
resolved "https://registry.yarnpkg.com/xbytes/-/xbytes-1.7.0.tgz#a44ca476af66c54e79f744756a035326c697bb8d"
|
||||
integrity sha512-iZglBXuHoC1F7jRz7746QhicNE167tEVq2H/iYQ1jIFdYIjqL8OfM86K52csfRZm+d83/VJO8bu37jN/G1ekKQ==
|
||||
|
||||
xdg-basedir@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13"
|
||||
integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==
|
||||
|
||||
y18n@^5.0.5:
|
||||
version "5.0.8"
|
||||
resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"
|
||||
integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==
|
||||
|
||||
yallist@^3.0.0, yallist@^3.1.1:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd"
|
||||
|
@ -3431,6 +3487,24 @@ yaml@^1.10.0:
|
|||
resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
|
||||
integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==
|
||||
|
||||
yargs-parser@^20.2.2:
|
||||
version "20.2.9"
|
||||
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee"
|
||||
integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==
|
||||
|
||||
yargs@^16.2.0:
|
||||
version "16.2.0"
|
||||
resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66"
|
||||
integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==
|
||||
dependencies:
|
||||
cliui "^7.0.2"
|
||||
escalade "^3.1.1"
|
||||
get-caller-file "^2.0.5"
|
||||
require-directory "^2.1.1"
|
||||
string-width "^4.2.0"
|
||||
y18n "^5.0.5"
|
||||
yargs-parser "^20.2.2"
|
||||
|
||||
yn@3.1.1:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
|
||||
|
|
Loading…
Reference in a new issue