diff --git a/README.md b/README.md index 8277c865..43504054 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,8 @@ Some available options: : | `userIdentifier` | `UserIdentifier` | | _Get user identity_ | | `onComplete` | `OnComplete` | | _On upload complete callback_ | | `expiration` | `ExpirationOptions` | | _Configuring the cleanup of abandoned and completed uploads_ | +| `logger` | `Logger` | | _Custom logger injection_ | +| `logLevel` | `LogLevel` | `"none"` | _Set built-in logger severity level_ | ## Contributing diff --git a/examples/.env.example b/examples/.env.example index 276ae02a..ba4d4a57 100644 --- a/examples/.env.example +++ b/examples/.env.example @@ -1,5 +1,4 @@ -# Enable debug log -DEBUG=uploadx:* +LOG_LEVEL=debug PORT=3002 diff --git a/examples/express-basic.ts b/examples/express-basic.ts index 182a60c2..be0dbe79 100644 --- a/examples/express-basic.ts +++ b/examples/express-basic.ts @@ -1,4 +1,4 @@ -import { DiskStorageOptions, uploadx } from '@uploadx/core'; +import { DiskStorageOptions, LogLevel, uploadx } from '@uploadx/core'; import * as express from 'express'; const PORT = process.env.PORT || 3002; @@ -12,6 +12,7 @@ const opts: DiskStorageOptions = { useRelativeLocation: true, filename: file => file.originalName, expiration: { maxAge: '1h', purgeInterval: '10min' }, + logLevel: process.env.LOG_LEVEL || 'info', onComplete: file => { console.log('File upload complete: ', file); return file; diff --git a/examples/express-s3.ts b/examples/express-s3.ts index af299c5e..bf2f81a7 100644 --- a/examples/express-s3.ts +++ b/examples/express-s3.ts @@ -1,5 +1,5 @@ import * as express from 'express'; -import { uploadx } from '@uploadx/core'; +import { LogLevel, uploadx } from '@uploadx/core'; import { S3Storage } from '@uploadx/s3'; const PORT = process.env.PORT || 3002; @@ -22,7 +22,9 @@ const storage = new S3Storage({ endpoint: 'http://127.0.0.1:9000', forcePathStyle: true, expiration: { maxAge: '1h', purgeInterval: '15min' }, - onComplete: file => console.log('File upload complete: ', file) + onComplete: file => console.log('File upload complete: ', file), + // logger: console + logLevel: process.env.LOG_LEVEL || 'info' }); app.use('/files', uploadx({ storage })); diff --git a/examples/express-tus.ts b/examples/express-tus.ts index f0d4219e..d118e92c 100644 --- a/examples/express-tus.ts +++ b/examples/express-tus.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ import * as express from 'express'; import { DiskFile, DiskStorageOptions, tus } from '@uploadx/core'; diff --git a/examples/express.ts b/examples/express.ts index 2513d778..583446d2 100644 --- a/examples/express.ts +++ b/examples/express.ts @@ -1,6 +1,13 @@ /* eslint-disable @typescript-eslint/no-non-null-assertion */ import { DiskFile, uploadx } from '@uploadx/core'; import * as express from 'express'; +import { createLogger, format, transports } from 'winston'; + +const logger = createLogger({ + format: format.combine(format.splat(), format.simple()), + transports: [new transports.Console()], + level: 'info' +}); const PORT = process.env.PORT || 3002; type UserInfo = { user?: { id: string; email: string } }; @@ -27,9 +34,10 @@ app.use( uploadx.upload({ directory: 'upload', expiration: { maxAge: '1h', purgeInterval: '10min' }, - userIdentifier: (req: express.Request & UserInfo) => `${req.user!.id}-${req.user!.email}` + userIdentifier: (req: express.Request & UserInfo) => `${req.user!.id}-${req.user!.email}`, + logger }), onComplete ); -app.listen(PORT, () => console.log('listening on port:', PORT)); +app.listen(PORT, () => logger.info('listening on port: %d', PORT)); diff --git a/examples/fastify.ts b/examples/fastify.ts index a44999ec..7d07fa80 100644 --- a/examples/fastify.ts +++ b/examples/fastify.ts @@ -2,11 +2,14 @@ import fastify from 'fastify'; import middie from 'middie'; import { Uploadx } from '@uploadx/core'; import { join } from 'path'; +import pino from 'pino'; + +const logger = pino({ level: process.env.LOG_LEVEL || 'info', name: 'uploadx' }); const PORT = process.env.PORT || 3002; const server = fastify({ logger: true }); -const uploadx = new Uploadx({ directory: 'upload' }); +const uploadx = new Uploadx({ directory: 'upload', logger }); uploadx.on('completed', ({ name, originalName }) => server.log.info( `upload complete, path: ${join('files', name)}, original filename: ${originalName}` diff --git a/examples/package.json b/examples/package.json index 3d536a58..457ceb9c 100644 --- a/examples/package.json +++ b/examples/package.json @@ -21,7 +21,9 @@ "fastify": "3.29.0", "middie": "6.1.0", "node-uploadx": "^5.1.5", - "ts-node-dev": "2.0.0" + "pino": "8.4.0", + "ts-node-dev": "2.0.0", + "winston": "3.8.1" }, "devDependencies": { "@types/express": "4.17.13" diff --git a/packages/core/src/handlers/base-handler.ts b/packages/core/src/handlers/base-handler.ts index 85472eb5..3e643f7c 100644 --- a/packages/core/src/handlers/base-handler.ts +++ b/packages/core/src/handlers/base-handler.ts @@ -75,7 +75,7 @@ export abstract class BaseHandler responseType: ResponseBodyType = 'json'; storage: BaseStorage; registeredHandlers = new Map(); - protected log = Logger.get(this.constructor.name); + logger: Logger; protected _errorResponses = {} as ErrorResponses; constructor(config: UploadxOptions = {}) { @@ -88,10 +88,10 @@ export abstract class BaseHandler if (config.userIdentifier) { this.getUserId = config.userIdentifier; } + this.logger = this.storage.logger; this.assembleErrors(); this.compose(); - - this.log('options: %o', config); + this.logger.debug('Config:', config); } /** @@ -115,7 +115,7 @@ export abstract class BaseHandler handler && this.registeredHandlers.set(method.toUpperCase(), handler); // handler && this.cors.allowedMethods.push(method.toUpperCase()); }); - this.log('Handlers', this.registeredHandlers); + this.logger.debug('Registered handlers: %s', [...this.registeredHandlers.keys()].join(', ')); } assembleErrors(customErrors = {}): void { @@ -130,9 +130,9 @@ export abstract class BaseHandler handle = (req: http.IncomingMessage, res: http.ServerResponse): void => this.upload(req, res); upload = (req: http.IncomingMessage, res: http.ServerResponse, next?: () => void): void => { - req.on('error', err => this.log(`[request error]: %o`, err)); + req.on('error', err => this.logger.error(`[request error]: %o`, err)); this.cors.preflight(req, res); - this.log(`[request]: %s`, req.method, req.url); + this.logger.debug(`[request]: %s %s`, req.method, req.url); const handler = this.registeredHandlers.get(req.method as string); if (!handler) { return this.sendError(res, { uploadxErrorCode: ERRORS.METHOD_NOT_ALLOWED } as UploadxError); @@ -145,7 +145,13 @@ export abstract class BaseHandler .call(this, req, res) .then(async (file: TFile | UploadList): Promise => { if ('status' in file && file.status) { - this.log('[%s]: %s', file.status, file.name); + this.logger.debug( + '[%s]: %s: %d/%d', + file.status, + file.name, + file.bytesWritten, + file.size + ); this.listenerCount(file.status) && this.emit(file.status, { ...file, request: pick(req, ['headers', 'method', 'url']) }); if (file.status === 'completed') { @@ -169,7 +175,7 @@ export abstract class BaseHandler ]) as UploadxError; const errorEvent = { ...err, request: pick(req, ['headers', 'method', 'url']) }; this.listenerCount('error') && this.emit('error', errorEvent); - this.log('[error]: %o', errorEvent); + this.logger.error('[error]: %o', errorEvent); if ('aborted' in req && req['aborted']) return; return this.sendError(res, error); }); diff --git a/packages/core/src/storages/config.ts b/packages/core/src/storages/config.ts index d5e286a0..0e055f28 100644 --- a/packages/core/src/storages/config.ts +++ b/packages/core/src/storages/config.ts @@ -1,3 +1,4 @@ +import { logger, Logger } from '../utils'; import { File } from './file'; import { BaseStorageOptions } from './storage'; @@ -10,7 +11,8 @@ class ConfigHandler { onComplete: () => null, path: '/files', validation: {}, - maxMetadataSize: '4MB' + maxMetadataSize: '4MB', + logger: logger }; private _config = this.set(ConfigHandler.defaults); @@ -22,6 +24,10 @@ class ConfigHandler { get(): Required> { return this._config as unknown as Required>; } + + getLogger(): Logger { + return this._config.logger; + } } export const configHandler = new ConfigHandler(); diff --git a/packages/core/src/storages/disk-storage.ts b/packages/core/src/storages/disk-storage.ts index 006238b8..229be1b5 100644 --- a/packages/core/src/storages/disk-storage.ts +++ b/packages/core/src/storages/disk-storage.ts @@ -66,8 +66,7 @@ export class DiskStorage extends BaseStorage { } this.accessCheck().catch(err => { this.isReady = false; - // eslint-disable-next-line no-console - console.error('ERROR: Could not write to directory: %o', err); + this.logger.error('[error]: Could not write to directory: %o', err); }); } diff --git a/packages/core/src/storages/local-meta-storage.ts b/packages/core/src/storages/local-meta-storage.ts index af01b32a..9961f011 100644 --- a/packages/core/src/storages/local-meta-storage.ts +++ b/packages/core/src/storages/local-meta-storage.ts @@ -21,8 +21,7 @@ export class LocalMetaStorage extends MetaStorage { super(config); this.directory = (config?.directory || join(tmpdir(), 'uploadx_meta')).replace(/\\/g, '/'); this.accessCheck().catch(err => { - // eslint-disable-next-line no-console - console.error('ERROR: Could not write to directory: %o', err); + this.logger.error('[error]: Could not write to directory: %o', err); }); } diff --git a/packages/core/src/storages/meta-storage.ts b/packages/core/src/storages/meta-storage.ts index 8d212230..f38965b5 100644 --- a/packages/core/src/storages/meta-storage.ts +++ b/packages/core/src/storages/meta-storage.ts @@ -1,4 +1,5 @@ import { FileName } from './file'; +import { configHandler } from './config'; /** @experimental */ export interface UploadListEntry { @@ -26,6 +27,7 @@ export interface MetaStorageOptions { export class MetaStorage { prefix = ''; suffix = ''; + logger = configHandler.getLogger(); constructor(config?: MetaStorageOptions) { this.prefix = config?.prefix || ''; diff --git a/packages/core/src/storages/storage.ts b/packages/core/src/storages/storage.ts index 682f4515..e37e7572 100644 --- a/packages/core/src/storages/storage.ts +++ b/packages/core/src/storages/storage.ts @@ -11,6 +11,7 @@ import { isEqual, Locker, Logger, + LogLevel, toMilliseconds, typeis, Validation, @@ -81,6 +82,13 @@ export interface BaseStorageOptions { * ``` */ expiration?: ExpirationOptions; + /** Custom logger injection */ + logger?: Logger; + /** + * Set built-in logger severity level + * @defaultValue 'none' + */ + logLevel?: LogLevel; } const LOCK_TIMEOUT = 300; // seconds @@ -96,7 +104,7 @@ export abstract class BaseStorage { checksumTypes: string[] = []; errorResponses = {} as ErrorResponses; cache: Cache; - protected log = Logger.get(`${this.constructor.name}`); + logger: Logger; protected namingFunction: (file: TFile, req: any) => string; protected validation = new Validator(); abstract meta: MetaStorage; @@ -109,8 +117,11 @@ export abstract class BaseStorage { this.maxUploadSize = bytes.parse(opts.maxUploadSize); this.maxMetadataSize = bytes.parse(opts.maxMetadataSize); this.cache = new Cache(1000, 300); - - const purgeInterval = toMilliseconds(this.config.expiration?.purgeInterval); + this.logger = opts.logger; + if (opts.logLevel && 'logLevel' in this.logger) { + this.logger.logLevel = opts.logLevel; + } + const purgeInterval = toMilliseconds(opts.expiration?.purgeInterval); if (purgeInterval) { this.startAutoPurge(purgeInterval); } @@ -216,7 +227,7 @@ export abstract class BaseStorage { const [deleted] = await this.delete({ id }); purged.items.push({ ...deleted, ...rest }); } - purged.items.length && this.log(`Purge: removed ${purged.items.length} uploads`); + purged.items.length && this.logger.info(`Purge: removed ${purged.items.length} uploads`); } return purged; } @@ -265,7 +276,7 @@ export abstract class BaseStorage { protected startAutoPurge(purgeInterval: number): void { if (purgeInterval >= 2147483647) throw Error('“purgeInterval” must be less than 2147483647 ms'); - setInterval(() => void this.purge().catch(this.log), purgeInterval); + setInterval(() => void this.purge().catch(e => this.logger.error(e)), purgeInterval); } protected updateTimestamps(file: TFile): TFile { diff --git a/packages/core/src/utils/logger.ts b/packages/core/src/utils/logger.ts index 8f6fc83d..78d7401d 100644 --- a/packages/core/src/utils/logger.ts +++ b/packages/core/src/utils/logger.ts @@ -1,9 +1,80 @@ -import { debug } from 'debug'; +import { formatWithOptions } from 'util'; -type LoggerInstance = ((label?: any, ...data: any[]) => void) & { enabled?: boolean }; +export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'none'; +const levels = ['debug', 'info', 'warn', 'error', 'none']; -export class Logger { - static get(namespace: string): LoggerInstance { - return debug('uploadx').extend(namespace.toLowerCase()); +enum PriorityOf { + debug, + info, + warn, + error, + none +} + +export interface LoggerOptions { + logger?: Logger; + logLevel?: LogLevel; + label?: string; + write?: (data: unknown[], level?: LogLevel) => void; +} + +export interface Logger { + logLevel?: LogLevel; + debug(...data: any[]): void; + info(...data: any[]): void; + warn(...data: any[]): void; + error(...data: any[]): void; +} + +/** + * Basic logger implementation + */ +export class BasicLogger implements Logger { + label: string; + private readonly logger: Logger; + private _logLevel: LogLevel = 'none'; + + constructor(readonly options: LoggerOptions = {}) { + this.logger = options.logger || console; + this.label = options.label ?? 'uploadx:'; + if (options.logLevel) this.logLevel = options.logLevel; + if (options.write) this.write = options.write; + } + + get logLevel(): LogLevel { + return this._logLevel; + } + + set logLevel(value: LogLevel) { + if (value && !levels.includes(value)) { + throw new Error(`Invalid log level: ${value}, supported levels are: ${levels.join(', ')}.`); + } + this._logLevel = value; + } + + write = (data: unknown[], level: Exclude): void => { + if (PriorityOf[level] >= PriorityOf[this._logLevel]) { + const message = formatWithOptions({ colors: true, depth: 1, maxStringLength: 80 }, ...data); + const timestamp = new Date().toISOString(); + this.logger[level](`${timestamp} ${level.toUpperCase()} ${this.label} ${message}`); + } + }; + + info(...data: unknown[]): void { + this.write(data, 'info'); + } + + warn(...data: unknown[]): void { + this.write(data, 'warn'); + } + + error(...data: unknown[]): void { + this.write(data, 'error'); + } + + debug(...data: unknown[]): void { + this.write(data, 'debug'); } } + +export const logger = new BasicLogger({}); diff --git a/packages/gcs/src/gcs-storage.ts b/packages/gcs/src/gcs-storage.ts index 76a59257..c590d6ee 100644 --- a/packages/gcs/src/gcs-storage.ts +++ b/packages/gcs/src/gcs-storage.ts @@ -124,8 +124,7 @@ export class GCStorage extends BaseStorage { this.accessCheck().catch((err: ClientError) => { this.isReady = false; - // eslint-disable-next-line no-console - console.error('ERROR: Unable to open bucket: %o', err); + this.logger.error('Unable to open bucket: %o', err); }); } @@ -168,7 +167,7 @@ export class GCStorage extends BaseStorage { file.uri = res.headers.location as string; if (this.config.clientDirectUpload) { file.GCSUploadURI = file.uri; - this.log('send uploadURI to client: %s', file.GCSUploadURI); + this.logger.debug('send uploadURI to client: %s', file.GCSUploadURI); file.status = 'created'; return file; } @@ -227,7 +226,7 @@ export class GCStorage extends BaseStorage { return range ? getRangeEnd(range) : 0; } else if (res.ok) { const data = (await res.json()) as Record; - this.log('uploaded %o', data); + this.logger.debug('uploaded %o', data); return size; } const message = await res.text(); @@ -238,7 +237,7 @@ export class GCStorage extends BaseStorage { name: 'FetchError' }); } catch (err) { - this.log(uri, err); + this.logger.error(uri, err); return NaN; } } diff --git a/packages/s3/src/s3-storage.ts b/packages/s3/src/s3-storage.ts index 87f600f5..9baf94d2 100644 --- a/packages/s3/src/s3-storage.ts +++ b/packages/s3/src/s3-storage.ts @@ -114,8 +114,7 @@ export class S3Storage extends BaseStorage { } this.accessCheck().catch((err: AWSError) => { this.isReady = false; - // eslint-disable-next-line no-console - console.error('ERROR: Unable to open bucket: %o', err); + this.logger.error('Unable to open bucket: %o', err); }); } @@ -243,7 +242,7 @@ export class S3Storage extends BaseStorage { const params = { Bucket: this.bucket, Key: file.name, UploadId: file.UploadId }; await this.client.send(new AbortMultipartUploadCommand(params)); } catch (err) { - this.log('_abortMultipartUploadError: ', err); + this.logger.error('_abortMultipartUploadError: ', err); } } diff --git a/test/shared/uploader.ts b/test/shared/uploader.ts index 711412d1..423541f4 100644 --- a/test/shared/uploader.ts +++ b/test/shared/uploader.ts @@ -14,8 +14,8 @@ export class TestStorage extends BaseStorage { path = '/files'; isReady = true; meta = new MetaStorage(); - constructor() { - super({}); + constructor(config = {}) { + super(config); } create(req: any, file: FileInit): Promise { diff --git a/test/storage.spec.ts b/test/storage.spec.ts index a88df1ab..d57f4d84 100644 --- a/test/storage.spec.ts +++ b/test/storage.spec.ts @@ -26,4 +26,24 @@ describe('BaseStorage', () => { storage.checkIfExpired({ ...metafile, expiredAt: Date.now() - 100 }) ).rejects.toHaveProperty('uploadxErrorCode', 'Gone'); }); + + it('should support logger', () => { + jest.useFakeTimers().setSystemTime(new Date('2022-02-02')); + storage = new TestStorage({ logLevel: 'warn' }); + const consoleWarnMock = jest.spyOn(console, 'warn').mockImplementation(); + storage.logger.warn('some', 'warning'); + expect(consoleWarnMock).toHaveBeenCalledWith( + '2022-02-02T00:00:00.000Z WARN uploadx: some warning' + ); + consoleWarnMock.mockRestore(); + jest.useRealTimers(); + }); + + it('should support custom logger', () => { + storage = new TestStorage({ logger: console }); + const consoleDebugMock = jest.spyOn(console, 'debug').mockImplementation(); + storage.logger.debug('some', 'value'); + expect(consoleDebugMock).toHaveBeenCalledWith('some', 'value'); + consoleDebugMock.mockRestore(); + }); }); diff --git a/test/util.spec.ts b/test/util.spec.ts index 9e3d6655..a7deae3d 100644 --- a/test/util.spec.ts +++ b/test/util.spec.ts @@ -189,4 +189,38 @@ describe('utils', () => { expect(fnvCached('123456')).toBe('9995b6aa'); }); }); + + describe('BasicLogger', () => { + it('should default silent', () => { + const logger = utils.logger; + const consoleErrorMock = jest.spyOn(console, 'error').mockImplementation(); + logger.error('test'); + expect(consoleErrorMock).not.toHaveBeenCalled(); + consoleErrorMock.mockRestore(); + }); + + it('should support logLevels', () => { + const logger = utils.logger; + const consoleErrorMock = jest.spyOn(console, 'error').mockImplementation(); + const consoleDebugMock = jest.spyOn(console, 'debug').mockImplementation(); + logger.logLevel = 'info'; + logger.error('test'); + logger.debug('test'); + expect(consoleErrorMock).toHaveBeenCalledTimes(1); + expect(consoleDebugMock).not.toHaveBeenCalled(); + consoleErrorMock.mockRestore(); + consoleDebugMock.mockRestore(); + }); + + it('should format log', () => { + jest.useFakeTimers().setSystemTime(new Date('2022-02-02')); + const logger = utils.logger; + logger.logLevel = 'info'; + const consoleErrorMock = jest.spyOn(console, 'error').mockImplementation(); + logger.error('test'); + expect(consoleErrorMock).toHaveBeenCalledWith('2022-02-02T00:00:00.000Z ERROR uploadx: test'); + consoleErrorMock.mockRestore(); + jest.useRealTimers(); + }); + }); }); diff --git a/yarn.lock b/yarn.lock index 2fdb0889..814732d8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1318,6 +1318,11 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== +"@colors/colors@1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" + integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ== + "@cspotcode/source-map-support@^0.8.0": version "0.8.1" resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" @@ -1325,6 +1330,15 @@ dependencies: "@jridgewell/trace-mapping" "0.3.9" +"@dabh/diagnostics@^2.0.2": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@dabh/diagnostics/-/diagnostics-2.0.3.tgz#7f7e97ee9a725dffc7808d93668cc984e1dc477a" + integrity sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA== + dependencies: + colorspace "1.1.x" + enabled "2.0.x" + kuler "^2.0.0" + "@eslint/eslintrc@^1.3.0": version "1.3.0" resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.3.0.tgz#29f92c30bb3e771e4a2048c95fa6855392dfac4f" @@ -2297,6 +2311,11 @@ async-kit@^2.2.3: nextgen-events "^0.14.5" tree-kit "^0.5.27" +async@^3.2.3: + version "3.2.4" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.4.tgz#2d22e00f8cddeb5fde5dd33522b56d1cf569a81c" + integrity sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ== + asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -2650,7 +2669,7 @@ collect-v8-coverage@^1.0.0: resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz#cc2c8e94fc18bbdffe64d6534570c8a673b27f59" integrity sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg== -color-convert@^1.9.0: +color-convert@^1.9.0, color-convert@^1.9.3: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== @@ -2669,16 +2688,40 @@ color-name@1.1.3: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= -color-name@~1.1.4: +color-name@^1.0.0, color-name@~1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +color-string@^1.6.0: + version "1.9.1" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.9.1.tgz#4467f9146f036f855b764dfb5bf8582bf342c7a4" + integrity sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg== + dependencies: + color-name "^1.0.0" + simple-swizzle "^0.2.2" + +color@^3.1.3: + version "3.2.1" + resolved "https://registry.yarnpkg.com/color/-/color-3.2.1.tgz#3544dc198caf4490c3ecc9a790b54fe9ff45e164" + integrity sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA== + dependencies: + color-convert "^1.9.3" + color-string "^1.6.0" + colorette@^2.0.16: version "2.0.16" resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.16.tgz#713b9af84fdb000139f04546bd4a93f62a5085da" integrity sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g== +colorspace@1.1.x: + version "1.1.4" + resolved "https://registry.yarnpkg.com/colorspace/-/colorspace-1.1.4.tgz#8d442d1186152f60453bf8070cd66eb364e59243" + integrity sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w== + dependencies: + color "^3.1.3" + text-hex "1.0.x" + combined-stream@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" @@ -2928,6 +2971,11 @@ emoji-regex@^9.2.2: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== +enabled@2.0.x: + version "2.0.0" + resolved "https://registry.yarnpkg.com/enabled/-/enabled-2.0.0.tgz#f9dd92ec2d6f4bbc0d5d1e64e21d61cd4665e7c2" + integrity sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ== + encodeurl@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" @@ -3262,7 +3310,7 @@ fast-levenshtein@^2.0.6: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= -fast-redact@^3.0.0: +fast-redact@^3.0.0, fast-redact@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/fast-redact/-/fast-redact-3.1.1.tgz#790fcff8f808c2e12fabbfb2be5cb2deda448fa0" integrity sha512-odVmjC8x8jNeMZ3C+rPMESzXVSEU8tSWSHv9HFxP2mm89G/1WwqhrerJDQm9Zus8X6aoRgQDThKqptdNA6bt+A== @@ -3322,6 +3370,11 @@ fb-watchman@^2.0.0: dependencies: bser "2.1.1" +fecha@^4.2.0: + version "4.2.3" + resolved "https://registry.yarnpkg.com/fecha/-/fecha-4.2.3.tgz#4d9ccdbc61e8629b259fdca67e65891448d569fd" + integrity sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw== + figures@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" @@ -3392,6 +3445,11 @@ flatted@^3.1.0: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.5.tgz#76c8584f4fc843db64702a6bd04ab7a8bd666da3" integrity sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg== +fn.name@1.x.x: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fn.name/-/fn.name-1.1.0.tgz#26cad8017967aea8731bc42961d04a3d5988accc" + integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw== + form-data@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" @@ -3780,6 +3838,11 @@ is-arrayish@^0.2.1: resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= +is-arrayish@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" + integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== + is-binary-path@~2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" @@ -4364,6 +4427,11 @@ kleur@^3.0.3: resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== +kuler@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/kuler/-/kuler-2.0.0.tgz#e2c570a3800388fb44407e851531c1d670b061b3" + integrity sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A== + leven@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" @@ -4468,6 +4536,17 @@ log-update@^4.0.0: slice-ansi "^4.0.0" wrap-ansi "^6.2.0" +logform@^2.3.2, logform@^2.4.0: + version "2.4.2" + resolved "https://registry.yarnpkg.com/logform/-/logform-2.4.2.tgz#a617983ac0334d0c3b942c34945380062795b47c" + integrity sha512-W4c9himeAwXEdZ05dQNerhFz2XG80P9Oj0loPUMV23VC2it0orMHQhJm4hdnnor3rd1HsGf6a2lPwBM1zeXHGw== + dependencies: + "@colors/colors" "1.5.0" + fecha "^4.2.0" + ms "^2.1.1" + safe-stable-stringify "^2.3.1" + triple-beam "^1.3.0" + lru-cache@^4.0.1: version "4.1.5" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" @@ -4610,7 +4689,7 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@2.1.3: +ms@2.1.3, ms@^2.1.1: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -4762,6 +4841,11 @@ object-inspect@^1.9.0: resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.0.tgz#6e2c120e868fd1fd18cb4f18c31741d0d6e776f0" integrity sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g== +on-exit-leak-free@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/on-exit-leak-free/-/on-exit-leak-free-2.1.0.tgz#5c703c968f7e7f851885f6459bf8a8a57edc9cc4" + integrity sha512-VuCaZZAjReZ3vUwgOB8LxAosIurDiAW0s13rI1YwmaP++jvcxP77AWoQvenZebpCA2m8WC1/EosPYPMjnRAp/w== + on-finished@2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" @@ -4776,6 +4860,13 @@ once@1.4.0, once@^1.3.0: dependencies: wrappy "1" +one-time@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/one-time/-/one-time-1.0.0.tgz#e06bc174aed214ed58edede573b433bbf827cb45" + integrity sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g== + dependencies: + fn.name "1.x.x" + onetime@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" @@ -4958,11 +5049,41 @@ pinkie@^2.0.0: resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= +pino-abstract-transport@v1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/pino-abstract-transport/-/pino-abstract-transport-1.0.0.tgz#cc0d6955fffcadb91b7b49ef220a6cc111d48bb3" + integrity sha512-c7vo5OpW4wIS42hUVcT5REsL8ZljsUfBjqV/e2sFxmFEFZiq1XLUp5EYLtuDH6PEHq9W1egWqRbnLUP5FuZmOA== + dependencies: + readable-stream "^4.0.0" + split2 "^4.0.0" + pino-std-serializers@^3.1.0: version "3.2.0" resolved "https://registry.yarnpkg.com/pino-std-serializers/-/pino-std-serializers-3.2.0.tgz#b56487c402d882eb96cd67c257868016b61ad671" integrity sha512-EqX4pwDPrt3MuOAAUBMU0Tk5kR/YcCM5fNPEzgCO2zJ5HfX0vbiH9HbJglnyeQsN96Kznae6MWD47pZB5avTrg== +pino-std-serializers@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/pino-std-serializers/-/pino-std-serializers-6.0.0.tgz#4c20928a1bafca122fdc2a7a4a171ca1c5f9c526" + integrity sha512-mMMOwSKrmyl+Y12Ri2xhH1lbzQxwwpuru9VjyJpgFIH4asSj88F2csdMwN6+M5g1Ll4rmsYghHLQJw81tgZ7LQ== + +pino@8.4.0: + version "8.4.0" + resolved "https://registry.yarnpkg.com/pino/-/pino-8.4.0.tgz#fb8622b70670068cc9d10ccf04c168580cef00c0" + integrity sha512-R95U66WOb4Ggtb1RPGnC2uvtc8T0i1FSbrKHrAudRtiLDrlNxKjM1MyCJu+V4gL0qdE/7/LoXAmkEY/TlX6ELA== + dependencies: + atomic-sleep "^1.0.0" + fast-redact "^3.1.1" + on-exit-leak-free "^2.1.0" + pino-abstract-transport v1.0.0 + pino-std-serializers "^6.0.0" + process-warning "^2.0.0" + quick-format-unescaped "^4.0.3" + real-require "^0.2.0" + safe-stable-stringify "^2.3.1" + sonic-boom "^3.1.0" + thread-stream "^2.0.0" + pino@^6.13.0: version "6.14.0" resolved "https://registry.yarnpkg.com/pino/-/pino-6.14.0.tgz#b745ea87a99a6c4c9b374e4f29ca7910d4c69f78" @@ -5034,6 +5155,11 @@ process-warning@^1.0.0: resolved "https://registry.yarnpkg.com/process-warning/-/process-warning-1.0.0.tgz#980a0b25dc38cd6034181be4b7726d89066b4616" integrity sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q== +process-warning@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/process-warning/-/process-warning-2.0.0.tgz#341dbeaac985b90a04ebcd844d50097c7737b2ee" + integrity sha512-+MmoAXoUX+VTHAlwns0h+kFUWFs/3FZy+ZuchkgjyOu3oioLAo2LB5aCfKPh2+P9O18i3m43tUEv3YqttSy0Ww== + prompts@^2.0.1: version "2.4.2" resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" @@ -5112,7 +5238,7 @@ react-is@^18.0.0: resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.1.0.tgz#61aaed3096d30eacf2a2127118b5b41387d32a67" integrity sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg== -readable-stream@^3.6.0: +readable-stream@^3.4.0, readable-stream@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== @@ -5121,6 +5247,13 @@ readable-stream@^3.6.0: string_decoder "^1.1.1" util-deprecate "^1.0.1" +readable-stream@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-4.1.0.tgz#280d0a29f559d3fb684a277254e02b6f61ae0631" + integrity sha512-sVisi3+P2lJ2t0BPbpK629j8wRW06yKGJUcaLAGXPAUhyUxVJm7VsCTit1PFgT4JHUDMrGNR+ZjSKpzGaRF3zw== + dependencies: + abort-controller "^3.0.0" + readdirp@~3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" @@ -5128,6 +5261,11 @@ readdirp@~3.6.0: dependencies: picomatch "^2.2.1" +real-require@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/real-require/-/real-require-0.2.0.tgz#209632dea1810be2ae063a6ac084fee7e33fba78" + integrity sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg== + rechoir@^0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" @@ -5276,6 +5414,11 @@ safe-regex2@^2.0.0: dependencies: ret "~0.2.0" +safe-stable-stringify@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.3.1.tgz#ab67cbe1fe7d40603ca641c5e765cb942d04fc73" + integrity sha512-kYBSfT+troD9cDA85VDnHZ1rpHC50O0g1e6WlGHVCz/g+JS+9WKLj+XwFYyR8UbrZN8ll9HUpDAAddY58MGisg== + "safer-buffer@>= 2.1.2 < 3": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" @@ -5406,6 +5549,13 @@ signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== +simple-swizzle@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" + integrity sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg== + dependencies: + is-arrayish "^0.3.1" + sinon@^11.1.1: version "11.1.2" resolved "https://registry.yarnpkg.com/sinon/-/sinon-11.1.2.tgz#9e78850c747241d5c59d1614d8f9cbe8840e8674" @@ -5462,6 +5612,13 @@ sonic-boom@^1.0.2: atomic-sleep "^1.0.0" flatstr "^1.0.12" +sonic-boom@^3.1.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/sonic-boom/-/sonic-boom-3.2.0.tgz#ce9f2de7557e68be2e52c8df6d9b052e7d348143" + integrity sha512-SbbZ+Kqj/XIunvIAgUZRlqd6CGQYq71tRRbXR92Za8J/R3Yh4Av+TWENiSiEgnlwckYLyP0YZQWVfyNC0dzLaA== + dependencies: + atomic-sleep "^1.0.0" + source-map-support@0.5.13: version "0.5.13" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" @@ -5488,6 +5645,11 @@ source-map@^0.6.0, source-map@^0.6.1: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== +split2@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/split2/-/split2-4.1.0.tgz#101907a24370f85bb782f08adaabe4e281ecf809" + integrity sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ== + split@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9" @@ -5500,6 +5662,11 @@ sprintf-js@~1.0.2: resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= +stack-trace@0.0.x: + version "0.0.10" + resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" + integrity sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg== + stack-utils@^2.0.3: version "2.0.5" resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.5.tgz#d25265fca995154659dbbfba3b49254778d2fdd5" @@ -5771,11 +5938,23 @@ test-exclude@^6.0.0: glob "^7.1.4" minimatch "^3.0.4" +text-hex@1.0.x: + version "1.0.0" + resolved "https://registry.yarnpkg.com/text-hex/-/text-hex-1.0.0.tgz#69dc9c1b17446ee79a92bf5b884bb4b9127506f5" + integrity sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg== + text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= +thread-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/thread-stream/-/thread-stream-2.0.1.tgz#3fa74e2223e661a48f836494f7a64eeac5ac03c0" + integrity sha512-X7vWOdsHLkBq0si20ruEE2ttpS7WOVyD52xKu+TOjrRP9Qi9uB9ynHYpzZUbBptArBSuKYUn4mH+jEBnO2CRGg== + dependencies: + real-require "^0.2.0" + throat@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/throat/-/throat-6.0.1.tgz#d514fedad95740c12c2d7fc70ea863eb51ade375" @@ -5840,6 +6019,11 @@ tree-kit@^0.5.24, tree-kit@^0.5.26, tree-kit@^0.5.27: resolved "https://registry.yarnpkg.com/tree-kit/-/tree-kit-0.5.27.tgz#d055a7ae6a087dda918cd92ac8c8c2abf5cfaea3" integrity sha512-0AtAzYDYaKSzeEPK3SI72lg/io5jrBxnT1gIRxEQasJycpQf5iXGh6YAl1kkh9wHmLlNRhDx0oj+GZEQHVe+cw== +triple-beam@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.3.0.tgz#a595214c7298db8339eeeee083e4d10bd8cb8dd9" + integrity sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw== + ts-jest@28.0.4: version "28.0.4" resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-28.0.4.tgz#0ab705a60fc4b9f3506f35e26edfa9e9c915c31b" @@ -6057,6 +6241,31 @@ which@^2.0.1: dependencies: isexe "^2.0.0" +winston-transport@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/winston-transport/-/winston-transport-4.5.0.tgz#6e7b0dd04d393171ed5e4e4905db265f7ab384fa" + integrity sha512-YpZzcUzBedhlTAfJg6vJDlyEai/IFMIVcaEZZyl3UXIl4gmqRpU7AE89AHLkbzLUsv0NVmw7ts+iztqKxxPW1Q== + dependencies: + logform "^2.3.2" + readable-stream "^3.6.0" + triple-beam "^1.3.0" + +winston@3.8.1: + version "3.8.1" + resolved "https://registry.yarnpkg.com/winston/-/winston-3.8.1.tgz#76f15b3478cde170b780234e0c4cf805c5a7fb57" + integrity sha512-r+6YAiCR4uI3N8eQNOg8k3P3PqwAm20cLKlzVD9E66Ch39+LZC+VH1UKf9JemQj2B3QoUHfKD7Poewn0Pr3Y1w== + dependencies: + "@dabh/diagnostics" "^2.0.2" + async "^3.2.3" + is-stream "^2.0.0" + logform "^2.4.0" + one-time "^1.0.0" + readable-stream "^3.4.0" + safe-stable-stringify "^2.3.1" + stack-trace "0.0.x" + triple-beam "^1.3.0" + winston-transport "^4.5.0" + word-wrap@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"