diff --git a/apps/ebitemp-api/src/app/app.module.ts b/apps/ebitemp-api/src/app/app.module.ts index 4cff5bd..a6484ee 100644 --- a/apps/ebitemp-api/src/app/app.module.ts +++ b/apps/ebitemp-api/src/app/app.module.ts @@ -2,9 +2,10 @@ import { Module } from '@nestjs/common'; import { AppConfigModule } from './modules/config/config.module'; import { AppController } from './app.controller'; import { AppService } from './app.service'; +import { AppLoggerModule } from './modules/logger/logger.module'; @Module({ - imports: [AppConfigModule], + imports: [AppConfigModule, AppLoggerModule], controllers: [AppController], providers: [AppService], }) diff --git a/apps/ebitemp-api/src/app/app.service.ts b/apps/ebitemp-api/src/app/app.service.ts index 605880b..b474014 100644 --- a/apps/ebitemp-api/src/app/app.service.ts +++ b/apps/ebitemp-api/src/app/app.service.ts @@ -1,7 +1,9 @@ -import { Injectable } from '@nestjs/common'; +import { Injectable, Logger } from '@nestjs/common'; @Injectable() export class AppService { + logger = new Logger(AppService.name); + getData(): { message: string } { return ({ message: 'Hello API' }); } diff --git a/apps/ebitemp-api/src/app/config/logger.config.ts b/apps/ebitemp-api/src/app/config/logger.config.ts new file mode 100644 index 0000000..3de98b0 --- /dev/null +++ b/apps/ebitemp-api/src/app/config/logger.config.ts @@ -0,0 +1,21 @@ +import coerceRecordTypes from '../modules/config/coerce-record-types'; +import { registerAs } from '@nestjs/config'; +import { z } from 'zod'; + +export const loggerSchema = z.object({ + seqServerHost: z.string(), + seqServerPort: z.number().finite().positive(), + seqApiKey: z.string(), +}); +export type LoggerConfig = z.infer; + +export const loggerConfig = registerAs('logger', () => { + const env = coerceRecordTypes(process.env); + + const config: LoggerConfig = loggerSchema.strict().parse({ + seqServerHost: env['SEQ_SERVER_HOST'], + seqServerPort: env['SEQ_SERVER_PORT'], + seqApiKey: env['SEQ_API_KEY'], + }); + return config; +}); diff --git a/apps/ebitemp-api/src/app/modules/config/config.module.ts b/apps/ebitemp-api/src/app/modules/config/config.module.ts index b0bccde..a5daccf 100644 --- a/apps/ebitemp-api/src/app/modules/config/config.module.ts +++ b/apps/ebitemp-api/src/app/modules/config/config.module.ts @@ -2,13 +2,14 @@ import { Module } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; import { localConfig } from '../../config/local.config'; +import { loggerConfig } from '../../config/logger.config'; @Module({ imports: [ ConfigModule.forRoot({ isGlobal: true, expandVariables: true, - load: [localConfig], + load: [localConfig, loggerConfig], }), ], }) diff --git a/apps/ebitemp-api/src/app/modules/logger/logger.module.ts b/apps/ebitemp-api/src/app/modules/logger/logger.module.ts new file mode 100644 index 0000000..c9549f1 --- /dev/null +++ b/apps/ebitemp-api/src/app/modules/logger/logger.module.ts @@ -0,0 +1,56 @@ +import { Module } from '@nestjs/common'; +import { NestApplication } from '@nestjs/core'; +import { LoggerModule } from 'nestjs-pino'; +import { LoggerConfig, loggerConfig } from '../../config/logger.config'; + +@Module({ + imports: [ + LoggerModule.forRootAsync({ + useFactory: (loggerConfig: LoggerConfig) => ({ + pinoHttp: { + autoLogging: true, + quietReqLogger: true, + quietResLogger: true, + level: 'trace', + useLevel: 'trace', + mixin() { + return { context: NestApplication.name }; + }, + customSuccessMessage: (req, res) => { return `${req.method} ${req.url}: ${res.statusCode} request succedeed` }, + customErrorMessage: (req, res) => { return `${req.method} ${req.url}: ${res.statusCode} request errored` }, + name: 'ebitemp-api', + transport: { + targets: [ + ...(process.env['NODE_ENV'] !== 'production' + ? [ + { + target: 'pino-pretty', + level: 'debug', + options: { + colorize: true, + messageFormat: '[{context}] {msg}', + ignore: 'pid,hostname,context', + translateTime: 'SYS:yyyy-mm-dd HH:MM:ss o', + }, + }, + ] + : []), + { + target: '@autotelic/pino-seq-transport', + level: 'trace', + options: { + loggerOpts: { + serverUrl: `${loggerConfig.seqServerHost}:${loggerConfig.seqServerPort}`, + apiKey: loggerConfig.seqApiKey, + }, + }, + }, + ], + }, + }, + }), + inject: [loggerConfig.KEY], + }), + ], +}) +export class AppLoggerModule {} diff --git a/apps/ebitemp-api/src/main.ts b/apps/ebitemp-api/src/main.ts index fdd9a27..6493adc 100644 --- a/apps/ebitemp-api/src/main.ts +++ b/apps/ebitemp-api/src/main.ts @@ -4,20 +4,33 @@ */ import { Logger } from '@nestjs/common'; +import { Logger as PinoLogger } from 'nestjs-pino'; + import { NestFactory } from '@nestjs/core'; import { AppModule } from './app/app.module'; import { LocalConfig, localConfig } from './app/config/local.config'; async function bootstrap() { - const app = await NestFactory.create(AppModule); + const appOpts = (() => { + const loggerOpts = { bufferLogs: true }; + return { + forceCloseConnections: true, + ...loggerOpts, + }; + })(); + const app = await NestFactory.create(AppModule, appOpts); const globalPrefix = 'api'; app.setGlobalPrefix(globalPrefix); const config = app.get(localConfig.KEY); const port = config.port || 3000; + app.useLogger(app.get(PinoLogger)); + await app.listen(port); - Logger.log(`🚀 Application is running on: http://localhost:${port}/${globalPrefix}`); + Logger.log( + `🚀 Application is running on: http://localhost:${port}/${globalPrefix}` + ); } void bootstrap(); diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..f75ecf6 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,17 @@ +services: + seq: + image: datalust/seq:latest + ports: + - ${SEQ_UI_PORT}:80 + - ${SEQ_SERVER_PORT}:5341 + environment: + - ACCEPT_EULA=Y + - SEQ_FIRSTRUN_ADMINPASSWORDHASH=QCxh/LN52rQ/pGlajPfJpqdopsx7IX9KAi+5rcU2hETBxfjjHQXydaN9kO9h2n/yKB1DbxnmGULOSlfgsTZRbjUF/wQBrBpbELhUTybNwhAw + - BASE_URI=${SEQ_UI_HOST}:${SEQ_UI_PORT} + restart: unless-stopped + deploy: + resources: + limits: + memory: 4096M + reservations: + memory: 2048M diff --git a/package.json b/package.json index 8307bff..01f9fea 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ }, "private": true, "dependencies": { + "@autotelic/pino-seq-transport": "^0.1.0", "@nestjs/common": "^10.0.2", "@nestjs/config": "^4.0.0", "@nestjs/core": "^10.0.2", @@ -17,7 +18,10 @@ "@nx/devkit": "20.4.1", "axios": "^1.6.0", "lodash": "^4.17.21", + "nestjs-pino": "^4.3.0", "patch-package": "^8.0.0", + "pino-http": "^10.4.0", + "pino-pretty": "^13.0.0", "reflect-metadata": "^0.1.13", "rxjs": "^7.8.0", "zod": "^3.24.1" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4c4c8e9..8a8e848 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,6 +5,9 @@ settings: excludeLinksFromLockfile: false dependencies: + '@autotelic/pino-seq-transport': + specifier: ^0.1.0 + version: 0.1.0 '@nestjs/common': specifier: ^10.0.2 version: 10.4.15(reflect-metadata@0.1.14)(rxjs@7.8.1) @@ -26,9 +29,18 @@ dependencies: lodash: specifier: ^4.17.21 version: 4.17.21 + nestjs-pino: + specifier: ^4.3.0 + version: 4.3.0(@nestjs/common@10.4.15)(pino-http@10.4.0) patch-package: specifier: ^8.0.0 version: 8.0.0 + pino-http: + specifier: ^10.4.0 + version: 10.4.0 + pino-pretty: + specifier: ^13.0.0 + version: 13.0.0 reflect-metadata: specifier: ^0.1.13 version: 0.1.14 @@ -219,6 +231,13 @@ packages: - chokidar dev: true + /@autotelic/pino-seq-transport@0.1.0: + resolution: {integrity: sha512-ECgQEKsuFmi9irUK3dMhsZl18oOpEb/XVJcGVcQcgtftf30EbvXq8MUVWobD6RPede9Oa2AINX4R2Viq/qnfLg==} + dependencies: + pino-abstract-transport: 0.5.0 + seq-logging: 1.1.2 + dev: false + /@azure/abort-controller@2.1.2: resolution: {integrity: sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==} engines: {node: '>=18.0.0'} @@ -4047,6 +4066,11 @@ packages: resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} engines: {node: '>= 4.0.0'} + /atomic-sleep@1.0.0: + resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} + engines: {node: '>=8.0.0'} + dev: false + /autoprefixer@10.4.20(postcss@8.5.1): resolution: {integrity: sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==} engines: {node: ^10 || ^12 || >=14} @@ -5036,6 +5060,10 @@ packages: css-tree: 2.2.1 dev: true + /dateformat@4.6.3: + resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==} + dev: false + /debug@2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} peerDependencies: @@ -5266,6 +5294,15 @@ packages: es-errors: 1.3.0 gopd: 1.2.0 + /duplexify@4.1.3: + resolution: {integrity: sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA==} + dependencies: + end-of-stream: 1.4.4 + inherits: 2.0.4 + readable-stream: 3.6.2 + stream-shift: 1.0.3 + dev: false + /eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} dev: true @@ -5670,6 +5707,10 @@ packages: tmp: 0.0.33 dev: true + /fast-copy@3.0.2: + resolution: {integrity: sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==} + dev: false + /fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} dev: true @@ -5693,6 +5734,11 @@ packages: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} dev: true + /fast-redact@3.5.0: + resolution: {integrity: sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==} + engines: {node: '>=6'} + dev: false + /fast-safe-stringify@2.1.1: resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} @@ -6172,6 +6218,10 @@ packages: tslib: 2.8.1 dev: true + /help-me@5.0.0: + resolution: {integrity: sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==} + dev: false + /highlight.js@10.7.3: resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==} dev: true @@ -7076,6 +7126,11 @@ packages: - ts-node dev: true + /joycon@3.1.1: + resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} + engines: {node: '>=10'} + dev: false + /js-md4@0.3.2: resolution: {integrity: sha512-/GDnfQYsltsjRswQhN9fhv3EMw2sCpUdrdxyWDOUK7eyD++r3gRhzgiQgc/x4MAv2i1iuQ4lxO5mvqM3vj4bwA==} dev: true @@ -7718,6 +7773,18 @@ packages: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} dev: true + /nestjs-pino@4.3.0(@nestjs/common@10.4.15)(pino-http@10.4.0): + resolution: {integrity: sha512-u/FRi+eRH+ER6cccyr9BBNaHg71qxLgWwDT7a0eGbSVZrSUzQ04O5zTNqydgzihNNHfuam6TBTz1wWdapOWYnQ==} + engines: {node: '>= 14'} + requiresBuild: true + peerDependencies: + '@nestjs/common': ^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0 + pino-http: ^6.4.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0 + dependencies: + '@nestjs/common': 10.4.15(reflect-metadata@0.1.14)(rxjs@7.8.1) + pino-http: 10.4.0 + dev: false + /no-case@3.0.4: resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} dependencies: @@ -7886,6 +7953,11 @@ packages: resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==} dev: true + /on-exit-leak-free@2.1.2: + resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==} + engines: {node: '>=14.0.0'} + dev: false + /on-finished@2.4.1: resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} engines: {node: '>= 0.8'} @@ -8228,6 +8300,68 @@ packages: dev: true optional: true + /pino-abstract-transport@0.5.0: + resolution: {integrity: sha512-+KAgmVeqXYbTtU2FScx1XS3kNyfZ5TrXY07V96QnUSFqo2gAqlvmaxH67Lj7SWazqsMabf+58ctdTcBgnOLUOQ==} + dependencies: + duplexify: 4.1.3 + split2: 4.2.0 + dev: false + + /pino-abstract-transport@2.0.0: + resolution: {integrity: sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==} + dependencies: + split2: 4.2.0 + dev: false + + /pino-http@10.4.0: + resolution: {integrity: sha512-vjQsKBE+VN1LVchjbfLE7B6nBeGASZNRNKsR68VS0DolTm5R3zo+47JX1wjm0O96dcbvA7vnqt8YqOWlG5nN0w==} + dependencies: + get-caller-file: 2.0.5 + pino: 9.6.0 + pino-std-serializers: 7.0.0 + process-warning: 4.0.1 + dev: false + + /pino-pretty@13.0.0: + resolution: {integrity: sha512-cQBBIVG3YajgoUjo1FdKVRX6t9XPxwB9lcNJVD5GCnNM4Y6T12YYx8c6zEejxQsU0wrg9TwmDulcE9LR7qcJqA==} + hasBin: true + dependencies: + colorette: 2.0.20 + dateformat: 4.6.3 + fast-copy: 3.0.2 + fast-safe-stringify: 2.1.1 + help-me: 5.0.0 + joycon: 3.1.1 + minimist: 1.2.8 + on-exit-leak-free: 2.1.2 + pino-abstract-transport: 2.0.0 + pump: 3.0.2 + secure-json-parse: 2.7.0 + sonic-boom: 4.2.0 + strip-json-comments: 3.1.1 + dev: false + + /pino-std-serializers@7.0.0: + resolution: {integrity: sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==} + dev: false + + /pino@9.6.0: + resolution: {integrity: sha512-i85pKRCt4qMjZ1+L7sy2Ag4t1atFcdbEt76+7iRJn1g2BvsnRMGu9p8pivl9fs63M2kF/A0OacFZhTub+m/qMg==} + hasBin: true + dependencies: + atomic-sleep: 1.0.0 + fast-redact: 3.5.0 + on-exit-leak-free: 2.1.2 + pino-abstract-transport: 2.0.0 + pino-std-serializers: 7.0.0 + process-warning: 4.0.1 + quick-format-unescaped: 4.0.4 + real-require: 0.2.0 + safe-stable-stringify: 2.5.0 + sonic-boom: 4.2.0 + thread-stream: 3.1.0 + dev: false + /pirates@4.0.6: resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} engines: {node: '>= 6'} @@ -8673,6 +8807,10 @@ packages: /process-nextick-args@2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + /process-warning@4.0.1: + resolution: {integrity: sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q==} + dev: false + /process@0.11.10: resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} engines: {node: '>= 0.6.0'} @@ -8711,7 +8849,6 @@ packages: dependencies: end-of-stream: 1.4.4 once: 1.4.0 - dev: true /punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} @@ -8739,6 +8876,10 @@ packages: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} dev: true + /quick-format-unescaped@4.0.4: + resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} + dev: false + /quick-lru@5.1.1: resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} engines: {node: '>=10'} @@ -8822,6 +8963,11 @@ packages: engines: {node: '>= 14.18.0'} dev: true + /real-require@0.2.0: + resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} + engines: {node: '>= 12.13.0'} + dev: false + /rechoir@0.8.0: resolution: {integrity: sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==} engines: {node: '>= 10.13.0'} @@ -8998,6 +9144,11 @@ packages: /safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + /safe-stable-stringify@2.5.0: + resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==} + engines: {node: '>=10'} + dev: false + /safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} @@ -9065,6 +9216,10 @@ packages: resolution: {integrity: sha512-AckIIV90rPDcBcglUwXPF3kg0P0qmPsPXAj6BBEENQE1p5yA1xfmDJzfi1Tappj37Pv2mVbKpL3Z1T+Nn7k1Qw==} dev: true + /secure-json-parse@2.7.0: + resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} + dev: false + /select-hose@2.0.0: resolution: {integrity: sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==} dev: true @@ -9134,6 +9289,10 @@ packages: upper-case-first: 2.0.2 dev: true + /seq-logging@1.1.2: + resolution: {integrity: sha512-9n7bCIHiMdBene104oSEa2917OcNBw+uee2v+we4AQxmjqt/aeQkWy1296IvGsogbj5fK6wuDNhVhm/DYmauVA==} + dev: false + /serialize-javascript@6.0.2: resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} dependencies: @@ -9305,6 +9464,12 @@ packages: websocket-driver: 0.7.4 dev: true + /sonic-boom@4.2.0: + resolution: {integrity: sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww==} + dependencies: + atomic-sleep: 1.0.0 + dev: false + /sort-keys-length@1.0.1: resolution: {integrity: sha512-GRbEOUqCxemTAk/b32F2xa8wDTs+Z1QHOkbhJDQTvv/6G3ZkbJ+frYWsTcc7cBB3Fu4wy4XlLCuNtJuMn7Gsvw==} engines: {node: '>=0.10.0'} @@ -9390,6 +9555,11 @@ packages: - supports-color dev: true + /split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + dev: false + /sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} @@ -9418,6 +9588,10 @@ packages: engines: {node: '>=4', npm: '>=6'} dev: true + /stream-shift@1.0.3: + resolution: {integrity: sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==} + dev: false + /streamsearch@1.1.0: resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} engines: {node: '>=10.0.0'} @@ -9492,7 +9666,6 @@ packages: /strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} - dev: true /strip-outer@2.0.0: resolution: {integrity: sha512-A21Xsm1XzUkK0qK1ZrytDUvqsQWict2Cykhvi0fBQntGG5JSprESasEyV1EZ/4CiR5WB5KjzLTrP/bO37B0wPg==} @@ -9691,6 +9864,12 @@ packages: tslib: 2.8.1 dev: true + /thread-stream@3.1.0: + resolution: {integrity: sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==} + dependencies: + real-require: 0.2.0 + dev: false + /through@2.3.8: resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} dev: true