diff --git a/backend/.env.example b/backend/.env.example index c0c68b1c..165b7a29 100644 --- a/backend/.env.example +++ b/backend/.env.example @@ -1 +1,11 @@ -PORT=3000 \ No newline at end of file +# +# Basic configuration +# + +PORT=3000 # The port the backend will listen on + +# +# Advanced configuration +# + +# LOKI_HOST=http://localhost:3102 # The address of the Loki instance, used for logging diff --git a/backend/package.json b/backend/package.json index 29c7ecbc..478b26e6 100644 --- a/backend/package.json +++ b/backend/package.json @@ -5,9 +5,9 @@ "private": true, "type": "module", "scripts": { - "build": "tsc --project tsconfig.json", - "dev": "tsx watch --env-file=.env.development.local src/app.ts", - "start": "node --env-file=.env dist/app.js", + "build": "NODE_ENV=production tsc --project tsconfig.json", + "dev": "NODE_ENV=development tsx watch --env-file=.env.development.local src/app.ts", + "start": "NODE_ENV=production node --env-file=.env dist/app.js", "format": "prettier --write src/", "format-check": "prettier --check src/", "lint": "eslint . --fix", @@ -17,19 +17,23 @@ "@mikro-orm/core": "^6.4.6", "@mikro-orm/postgresql": "^6.4.6", "@mikro-orm/reflection": "^6.4.6", + "@mikro-orm/sqlite": "6.4.6", "@types/js-yaml": "^4.0.9", "axios": "^1.8.1", - "@mikro-orm/sqlite": "6.4.6", "dotenv": "^16.4.7", "express": "^5.0.1", - "uuid": "^11.1.0", "js-yaml": "^4.1.0", - "@types/js-yaml": "^4.0.9" + "loki-logger-ts": "^1.0.2", + "response-time": "^2.3.3", + "uuid": "^11.1.0", + "winston": "^3.17.0", + "winston-loki": "^6.1.3" }, "devDependencies": { "@mikro-orm/cli": "^6.4.6", "@types/express": "^5.0.0", "@types/node": "^22.13.4", + "@types/response-time": "^2.3.8", "globals": "^15.15.0", "ts-node": "^10.9.2", "tsx": "^4.19.3", diff --git a/backend/src/app.ts b/backend/src/app.ts index cf50860e..5769e360 100644 --- a/backend/src/app.ts +++ b/backend/src/app.ts @@ -1,6 +1,5 @@ import express, { Express, Response } from 'express'; import { initORM } from './orm.js'; -import { EnvVars, getNumericEnvVar } from './util/envvars.js'; import themeRoutes from './routes/themes.js'; import learningPathRoutes from './routes/learningPaths.js'; @@ -13,12 +12,22 @@ import submissionRouter from './routes/submission.js'; import classRouter from './routes/class.js'; import questionRouter from './routes/question.js'; import loginRouter from './routes/login.js'; +import { getLogger, Logger } from './logging/initalize.js'; +import { responseTimeLogger } from './logging/responseTimeLogger.js'; +import responseTime from 'response-time'; +import { EnvVars, getNumericEnvVar } from './util/envvars.js'; + +const logger: Logger = getLogger(); const app: Express = express(); const port: string | number = getNumericEnvVar(EnvVars.Port); +app.use(express.json()); +app.use(responseTime(responseTimeLogger)); + // TODO Replace with Express routes app.get('/', (_, res: Response) => { + logger.debug('GET /'); res.json({ message: 'Hello Dwengo!🚀', }); @@ -40,7 +49,7 @@ async function startServer() { await initORM(); app.listen(port, () => { - console.log(`Server is running at http://localhost:${port}`); + logger.info(`Server is running at http://localhost:${port}`); }); } diff --git a/backend/src/config.ts b/backend/src/config.ts index 8fd8ec3f..b972a1bd 100644 --- a/backend/src/config.ts +++ b/backend/src/config.ts @@ -1,10 +1,12 @@ -// Can be placed in dotenv but found it redundant +export const FALLBACK_LANG: string = 'nl'; -// Import dotenv from "dotenv"; +// API -// Load .env file -// Dotenv.config(); +export const DWENGO_API_BASE: string = 'https://dwengo.org/backend/api'; -export const DWENGO_API_BASE = 'https://dwengo.org/backend/api'; +// Logging -export const FALLBACK_LANG = 'nl'; +export const LOG_LEVEL: string = + 'development' === process.env.NODE_ENV ? 'debug' : 'info'; +export const LOKI_HOST: string = + process.env.LOKI_HOST || 'http://localhost:3102'; diff --git a/backend/src/controllers/learningObjects.ts b/backend/src/controllers/learningObjects.ts index 4295326a..6fde1208 100644 --- a/backend/src/controllers/learningObjects.ts +++ b/backend/src/controllers/learningObjects.ts @@ -5,7 +5,8 @@ import { getLearningObjectsFromPath, } from '../services/learningObjects.js'; import { FALLBACK_LANG } from '../config.js'; -import { FilteredLearningObject } from '../interfaces/learningPath'; +import { FilteredLearningObject } from '../interfaces/learningPath.js'; +import { getLogger } from '../logging/initalize.js'; export async function getAllLearningObjects( req: Request, @@ -33,7 +34,7 @@ export async function getAllLearningObjects( res.json(learningObjects); } catch (error) { - console.error('Error fetching learning objects:', error); + getLogger().error('Error fetching learning objects:', error); res.status(500).json({ error: 'Internal server error' }); } } @@ -54,7 +55,7 @@ export async function getLearningObject( const learningObject = await getLearningObjectById(hruid, language); res.json(learningObject); } catch (error) { - console.error('Error fetching learning object:', error); + getLogger().error('Error fetching learning object:', error); res.status(500).json({ error: 'Internal server error' }); } } diff --git a/backend/src/controllers/learningPaths.ts b/backend/src/controllers/learningPaths.ts index 903451be..247877e7 100644 --- a/backend/src/controllers/learningPaths.ts +++ b/backend/src/controllers/learningPaths.ts @@ -5,6 +5,7 @@ import { fetchLearningPaths, searchLearningPaths, } from '../services/learningPaths.js'; +import { getLogger } from '../logging/initalize.js'; /** * Fetch learning paths based on query parameters. */ @@ -56,7 +57,10 @@ export async function getLearningPaths( ); res.json(learningPaths.data); } catch (error) { - console.error('❌ Unexpected error fetching learning paths:', error); + getLogger().error( + '❌ Unexpected error fetching learning paths:', + error + ); res.status(500).json({ error: 'Internal server error' }); } } diff --git a/backend/src/controllers/themes.ts b/backend/src/controllers/themes.ts index 8d2e34d7..a85cac21 100644 --- a/backend/src/controllers/themes.ts +++ b/backend/src/controllers/themes.ts @@ -1,7 +1,6 @@ import { Request, Response } from 'express'; import { themes } from '../data/themes.js'; import { loadTranslations } from '../util/translationHelper.js'; -import { FALLBACK_LANG } from '../config.js'; interface Translations { curricula_page: { diff --git a/backend/src/logging/initalize.ts b/backend/src/logging/initalize.ts new file mode 100644 index 00000000..18166408 --- /dev/null +++ b/backend/src/logging/initalize.ts @@ -0,0 +1,60 @@ +import { + createLogger, + format, + Logger as WinstonLogger, + transports, +} from 'winston'; +import LokiTransport from 'winston-loki'; +import { LokiLabels } from 'loki-logger-ts'; +import { LOG_LEVEL, LOKI_HOST } from '../config.js'; + +export class Logger extends WinstonLogger { + constructor() { + super(); + } +} + +const Labels: LokiLabels = { + source: 'Dwengo-Backend', + service: 'API', + host: 'localhost', +}; + +let logger: Logger; + +function initializeLogger(): Logger { + if (logger !== undefined) { + return logger; + } + + const lokiTransport: LokiTransport = new LokiTransport({ + host: LOKI_HOST, + labels: Labels, + level: LOG_LEVEL, + json: true, + format: format.combine(format.timestamp(), format.json()), + onConnectionError: (err) => { + // eslint-disable-next-line no-console + console.error(`Connection error: ${err}`); + }, + }); + + const consoleTransport = new transports.Console({ + level: LOG_LEVEL, + format: format.combine(format.cli(), format.colorize()), + }); + + logger = createLogger({ + transports: [lokiTransport, consoleTransport], + }); + + logger.debug( + `Logger initialized with level ${LOG_LEVEL}, Loki host ${LOKI_HOST}` + ); + return logger; +} + +export function getLogger(): Logger { + logger ||= initializeLogger(); + return logger; +} diff --git a/backend/src/logging/mikroOrmLogger.ts b/backend/src/logging/mikroOrmLogger.ts new file mode 100644 index 00000000..e8bc1fad --- /dev/null +++ b/backend/src/logging/mikroOrmLogger.ts @@ -0,0 +1,87 @@ +import { DefaultLogger, LogContext, LoggerNamespace } from '@mikro-orm/core'; +import { getLogger, Logger } from './initalize.js'; +import { LokiLabels } from 'loki-logger-ts'; + +export class MikroOrmLogger extends DefaultLogger { + private logger: Logger = getLogger(); + + log(namespace: LoggerNamespace, message: string, context?: LogContext) { + if (!this.isEnabled(namespace, context)) { + return; + } + + switch (namespace) { + case 'query': + this.logger.debug( + this.createMessage(namespace, message, context) + ); + break; + case 'query-params': + // TODO Which log level should this be? + this.logger.info( + this.createMessage(namespace, message, context) + ); + break; + case 'schema': + this.logger.info( + this.createMessage(namespace, message, context) + ); + break; + case 'discovery': + this.logger.debug( + this.createMessage(namespace, message, context) + ); + break; + case 'info': + this.logger.info( + this.createMessage(namespace, message, context) + ); + break; + case 'deprecated': + this.logger.warn( + this.createMessage(namespace, message, context) + ); + break; + default: + switch (context?.level) { + case 'info': + this.logger.info( + this.createMessage(namespace, message, context) + ); + break; + case 'warning': + this.logger.warn(message); + break; + case 'error': + this.logger.error(message); + break; + default: + this.logger.debug(message); + break; + } + } + } + + private createMessage( + namespace: LoggerNamespace, + messageArg: string, + context?: LogContext + ) { + const labels: LokiLabels = { + service: 'ORM', + }; + + let message: string; + if (context?.label) { + message = `[${namespace}] (${context?.label}) ${messageArg}`; + } else { + message = `[${namespace}] ${messageArg}`; + } + + return { + message: message, + labels: labels, + context: context, + }; + } +} diff --git a/backend/src/logging/responseTimeLogger.ts b/backend/src/logging/responseTimeLogger.ts new file mode 100644 index 00000000..c1bb1e33 --- /dev/null +++ b/backend/src/logging/responseTimeLogger.ts @@ -0,0 +1,21 @@ +import { getLogger, Logger } from './initalize.js'; +import { Request, Response } from 'express'; + +export function responseTimeLogger(req: Request, res: Response, time: number) { + const logger: Logger = getLogger(); + + const method = req.method; + const url = req.url; + const status = res.statusCode; + + logger.info({ + message: 'Request completed', + method: method, + url: url, + status: status, + responseTime: Number(time), + labels: { + type: 'responseTime', + }, + }); +} diff --git a/backend/src/mikro-orm.config.ts b/backend/src/mikro-orm.config.ts index 05b68fef..f9629bef 100644 --- a/backend/src/mikro-orm.config.ts +++ b/backend/src/mikro-orm.config.ts @@ -1,7 +1,9 @@ -import { Options } from '@mikro-orm/core'; +import { LoggerOptions, Options } from '@mikro-orm/core'; import { PostgreSqlDriver } from '@mikro-orm/postgresql'; import { EnvVars, getEnvVar, getNumericEnvVar } from './util/envvars.js'; import { SqliteDriver } from '@mikro-orm/sqlite'; +import { MikroOrmLogger } from './logging/mikroOrmLogger.js'; +import { LOG_LEVEL } from './config.js'; // Import alle entity-bestanden handmatig import { User } from './entities/users/user.entity.js'; @@ -55,6 +57,7 @@ function config(testingMode: boolean = false): Options { }, }; } + return { driver: PostgreSqlDriver, host: getEnvVar(EnvVars.DbHost), @@ -63,8 +66,13 @@ function config(testingMode: boolean = false): Options { user: getEnvVar(EnvVars.DbUsername), password: getEnvVar(EnvVars.DbPassword), entities: entities, - //EntitiesTs: entitiesTs, - debug: true, + // EntitiesTs: entitiesTs, + + // Logging + debug: LOG_LEVEL === 'debug', + loggerFactory: (options: LoggerOptions) => { + return new MikroOrmLogger(options); + }, }; } diff --git a/backend/src/orm.ts b/backend/src/orm.ts index 37f83d8f..88decd92 100644 --- a/backend/src/orm.ts +++ b/backend/src/orm.ts @@ -1,9 +1,15 @@ import { EntityManager, MikroORM } from '@mikro-orm/core'; import config from './mikro-orm.config.js'; import { EnvVars, getEnvVar } from './util/envvars.js'; +import { getLogger, Logger } from './logging/initalize.js'; let orm: MikroORM | undefined; export async function initORM(testingMode: boolean = false) { + const logger: Logger = getLogger(); + + logger.info('Initializing ORM'); + logger.debug('MikroORM config is', config); + orm = await MikroORM.init(config(testingMode)); // Update the database scheme if necessary and enabled. if (getEnvVar(EnvVars.DbUpdate)) { diff --git a/backend/src/services/learningObjects.ts b/backend/src/services/learningObjects.ts index d1d34ad2..59cf6d31 100644 --- a/backend/src/services/learningObjects.ts +++ b/backend/src/services/learningObjects.ts @@ -7,6 +7,9 @@ import { LearningPathResponse, } from '../interfaces/learningPath.js'; import { fetchLearningPaths } from './learningPaths.js'; +import { getLogger, Logger } from '../logging/initalize.js'; + +const logger: Logger = getLogger(); function filterData( data: LearningObjectMetadata, @@ -49,7 +52,7 @@ export async function getLearningObjectById( ); if (!metadata) { - console.error(`⚠️ WARNING: Learning object "${hruid}" not found.`); + logger.warn(`⚠️ WARNING: Learning object "${hruid}" not found.`); return null; } @@ -77,7 +80,7 @@ async function fetchLearningObjects( !learningPathResponse.success || !learningPathResponse.data?.length ) { - console.error( + logger.warn( `⚠️ WARNING: Learning path "${hruid}" exists but contains no learning objects.` ); return []; @@ -104,7 +107,7 @@ async function fetchLearningObjects( }); }); } catch (error) { - console.error('❌ Error fetching learning objects:', error); + logger.error('❌ Error fetching learning objects:', error); return []; } } diff --git a/backend/src/services/learningPaths.ts b/backend/src/services/learningPaths.ts index 2a9f15a3..52b168ee 100644 --- a/backend/src/services/learningPaths.ts +++ b/backend/src/services/learningPaths.ts @@ -4,6 +4,9 @@ import { LearningPath, LearningPathResponse, } from '../interfaces/learningPath.js'; +import { getLogger, Logger } from '../logging/initalize.js'; + +const logger: Logger = getLogger(); export async function fetchLearningPaths( hruids: string[], @@ -29,7 +32,7 @@ export async function fetchLearningPaths( ); if (!learningPaths || learningPaths.length === 0) { - console.error(`⚠️ WARNING: No learning paths found for ${source}.`); + logger.warn(`⚠️ WARNING: No learning paths found for ${source}.`); return { success: false, source, diff --git a/backend/src/util/apiHelper.ts b/backend/src/util/apiHelper.ts index 76d166c8..83c3e975 100644 --- a/backend/src/util/apiHelper.ts +++ b/backend/src/util/apiHelper.ts @@ -1,6 +1,7 @@ import axios, { AxiosRequestConfig } from 'axios'; +import { getLogger, Logger } from '../logging/initalize.js'; -// !!!! when logger is done -> change +const logger: Logger = getLogger(); /** * Utility function to fetch data from an API endpoint with error handling. @@ -24,16 +25,16 @@ export async function fetchWithLogging( } catch (error: any) { if (error.response) { if (error.response.status === 404) { - console.error( + logger.debug( `❌ ERROR: ${description} not found (404) at "${url}".` ); } else { - console.error( + logger.debug( `❌ ERROR: Failed to fetch ${description}. Status: ${error.response.status} - ${error.response.statusText} (URL: "${url}")` ); } } else { - console.error( + logger.debug( `❌ ERROR: Network or unexpected error when fetching ${description}:`, error.message ); diff --git a/backend/src/util/translationHelper.ts b/backend/src/util/translationHelper.ts index 6ac590e6..650d9843 100644 --- a/backend/src/util/translationHelper.ts +++ b/backend/src/util/translationHelper.ts @@ -1,7 +1,10 @@ import fs from 'fs'; import path from 'path'; import yaml from 'js-yaml'; -import { FALLBACK_LANG } from '../../config'; +import { FALLBACK_LANG } from '../../config.js'; +import { getLogger, Logger } from '../logging/initalize.js'; + +const logger: Logger = getLogger(); export function loadTranslations(language: string): T { try { @@ -9,10 +12,10 @@ export function loadTranslations(language: string): T { const yamlFile = fs.readFileSync(filePath, 'utf8'); return yaml.load(yamlFile) as T; } catch (error) { - console.error( - `Cannot load translation for ${language}, fallen back to dutch` + logger.warn( + `Cannot load translation for ${language}, fallen back to dutch`, + error ); - console.error(error); const fallbackPath = path.join( process.cwd(), '_i18n', diff --git a/config/loki/config.yml b/config/loki/config.yml new file mode 100644 index 00000000..b84377bd --- /dev/null +++ b/config/loki/config.yml @@ -0,0 +1,29 @@ +# This is a complete configuration to deploy Loki backed by the filesystem. +# The index will be shipped to the storage via tsdb-shipper. + +auth_enabled: false + +server: + http_listen_port: 3102 + +common: + ring: + instance_addr: 127.0.0.1 + kvstore: + store: inmemory + replication_factor: 1 + path_prefix: /tmp/loki + +schema_config: + configs: + - from: 2020-05-15 + store: tsdb + object_store: filesystem + schema: v13 + index: + prefix: index_ + period: 24h + +storage_config: + filesystem: + directory: /tmp/loki/chunks diff --git a/docker-compose.yml b/docker-compose.yml index 6be29180..0f8219af 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,7 +8,28 @@ services: ports: - '5431:5432' volumes: - - postgres_data:/var/lib/postgresql/data + - dwengo_postgres_data:/var/lib/postgresql/data + + logging: + image: grafana/loki:latest + ports: + - '3102:3102' + - '9095:9095' + volumes: + - ./config/loki/config.yml:/etc/loki/config.yaml + - dwengo_loki_data:/loki + command: -config.file=/etc/loki/config.yaml + restart: unless-stopped + + dashboards: + image: grafana/grafana:latest + ports: + - '3100:3000' + volumes: + - dwengo_grafana_data:/var/lib/grafana + restart: unless-stopped volumes: - postgres_data: + dwengo_postgres_data: + dwengo_loki_data: + dwengo_grafana_data: diff --git a/package-lock.json b/package-lock.json index 4679ab57..92bf5a8e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,10 +12,6 @@ "backend", "frontend" ], - "dependencies": { - "@types/js-yaml": "^4.0.9", - "vue-i18n": "^10.0.5" - }, "devDependencies": { "@eslint/compat": "^1.2.6", "@eslint/js": "^9.20.0", @@ -41,12 +37,17 @@ "dotenv": "^16.4.7", "express": "^5.0.1", "js-yaml": "^4.1.0", - "uuid": "^11.1.0" + "loki-logger-ts": "^1.0.2", + "response-time": "^2.3.3", + "uuid": "^11.1.0", + "winston": "^3.17.0", + "winston-loki": "^6.1.3" }, "devDependencies": { "@mikro-orm/cli": "^6.4.6", "@types/express": "^5.0.0", "@types/node": "^22.13.4", + "@types/response-time": "^2.3.8", "globals": "^15.15.0", "ts-node": "^10.9.2", "tsx": "^4.19.3", @@ -589,6 +590,15 @@ "node": ">=6.9.0" } }, + "node_modules/@colors/colors": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", + "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", + "license": "MIT", + "engines": { + "node": ">=0.1.90" + } + }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", "dev": true, @@ -705,6 +715,17 @@ "node": ">=18" } }, + "node_modules/@dabh/diagnostics": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", + "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", + "license": "MIT", + "dependencies": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, "node_modules/@esbuild/linux-x64": { "version": "0.25.0", "cpu": [ @@ -937,44 +958,6 @@ "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@intlify/core-base": { - "version": "10.0.5", - "license": "MIT", - "dependencies": { - "@intlify/message-compiler": "10.0.5", - "@intlify/shared": "10.0.5" - }, - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://github.com/sponsors/kazupon" - } - }, - "node_modules/@intlify/message-compiler": { - "version": "10.0.5", - "license": "MIT", - "dependencies": { - "@intlify/shared": "10.0.5", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://github.com/sponsors/kazupon" - } - }, - "node_modules/@intlify/shared": { - "version": "10.0.5", - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://github.com/sponsors/kazupon" - } - }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "dev": true, @@ -1151,6 +1134,214 @@ "@mikro-orm/core": "^6.0.0" } }, + "node_modules/@napi-rs/snappy-android-arm-eabi": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@napi-rs/snappy-android-arm-eabi/-/snappy-android-arm-eabi-7.2.2.tgz", + "integrity": "sha512-H7DuVkPCK5BlAr1NfSU8bDEN7gYs+R78pSHhDng83QxRnCLmVIZk33ymmIwurmoA1HrdTxbkbuNl+lMvNqnytw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/snappy-android-arm64": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@napi-rs/snappy-android-arm64/-/snappy-android-arm64-7.2.2.tgz", + "integrity": "sha512-2R/A3qok+nGtpVK8oUMcrIi5OMDckGYNoBLFyli3zp8w6IArPRfg1yOfVUcHvpUDTo9T7LOS1fXgMOoC796eQw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/snappy-darwin-arm64": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@napi-rs/snappy-darwin-arm64/-/snappy-darwin-arm64-7.2.2.tgz", + "integrity": "sha512-USgArHbfrmdbuq33bD5ssbkPIoT7YCXCRLmZpDS6dMDrx+iM7eD2BecNbOOo7/v1eu6TRmQ0xOzeQ6I/9FIi5g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/snappy-darwin-x64": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@napi-rs/snappy-darwin-x64/-/snappy-darwin-x64-7.2.2.tgz", + "integrity": "sha512-0APDu8iO5iT0IJKblk2lH0VpWSl9zOZndZKnBYIc+ei1npw2L5QvuErFOTeTdHBtzvUHASB+9bvgaWnQo4PvTQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/snappy-freebsd-x64": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@napi-rs/snappy-freebsd-x64/-/snappy-freebsd-x64-7.2.2.tgz", + "integrity": "sha512-mRTCJsuzy0o/B0Hnp9CwNB5V6cOJ4wedDTWEthsdKHSsQlO7WU9W1yP7H3Qv3Ccp/ZfMyrmG98Ad7u7lG58WXA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/snappy-linux-arm-gnueabihf": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@napi-rs/snappy-linux-arm-gnueabihf/-/snappy-linux-arm-gnueabihf-7.2.2.tgz", + "integrity": "sha512-v1uzm8+6uYjasBPcFkv90VLZ+WhLzr/tnfkZ/iD9mHYiULqkqpRuC8zvc3FZaJy5wLQE9zTDkTJN1IvUcZ+Vcg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/snappy-linux-arm64-gnu": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@napi-rs/snappy-linux-arm64-gnu/-/snappy-linux-arm64-gnu-7.2.2.tgz", + "integrity": "sha512-LrEMa5pBScs4GXWOn6ZYXfQ72IzoolZw5txqUHVGs8eK4g1HR9HTHhb2oY5ySNaKakG5sOgMsb1rwaEnjhChmQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/snappy-linux-arm64-musl": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@napi-rs/snappy-linux-arm64-musl/-/snappy-linux-arm64-musl-7.2.2.tgz", + "integrity": "sha512-3orWZo9hUpGQcB+3aTLW7UFDqNCQfbr0+MvV67x8nMNYj5eAeUtMmUE/HxLznHO4eZ1qSqiTwLbVx05/Socdlw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/snappy-linux-x64-gnu": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@napi-rs/snappy-linux-x64-gnu/-/snappy-linux-x64-gnu-7.2.2.tgz", + "integrity": "sha512-jZt8Jit/HHDcavt80zxEkDpH+R1Ic0ssiVCoueASzMXa7vwPJeF4ZxZyqUw4qeSy7n8UUExomu8G8ZbP6VKhgw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/snappy-linux-x64-musl": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@napi-rs/snappy-linux-x64-musl/-/snappy-linux-x64-musl-7.2.2.tgz", + "integrity": "sha512-Dh96IXgcZrV39a+Tej/owcd9vr5ihiZ3KRix11rr1v0MWtVb61+H1GXXlz6+Zcx9y8jM1NmOuiIuJwkV4vZ4WA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/snappy-win32-arm64-msvc": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@napi-rs/snappy-win32-arm64-msvc/-/snappy-win32-arm64-msvc-7.2.2.tgz", + "integrity": "sha512-9No0b3xGbHSWv2wtLEn3MO76Yopn1U2TdemZpCaEgOGccz1V+a/1d16Piz3ofSmnA13HGFz3h9NwZH9EOaIgYA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/snappy-win32-ia32-msvc": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@napi-rs/snappy-win32-ia32-msvc/-/snappy-win32-ia32-msvc-7.2.2.tgz", + "integrity": "sha512-QiGe+0G86J74Qz1JcHtBwM3OYdTni1hX1PFyLRo3HhQUSpmi13Bzc1En7APn+6Pvo7gkrcy81dObGLDSxFAkQQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/snappy-win32-x64-msvc": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@napi-rs/snappy-win32-x64-msvc/-/snappy-win32-x64-msvc-7.2.2.tgz", + "integrity": "sha512-a43cyx1nK0daw6BZxVcvDEXxKMFLSBSDTAhsFD0VqSKcC7MGUBMaqyoWUcMiI7LBSz4bxUmxDWKfCYzpEmeb3w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "license": "MIT", @@ -1245,6 +1436,70 @@ "dev": true, "license": "MIT" }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", + "license": "BSD-3-Clause" + }, "node_modules/@rollup/pluginutils": { "version": "5.1.4", "dev": true, @@ -1439,7 +1694,6 @@ }, "node_modules/@types/node": { "version": "22.13.4", - "dev": true, "license": "MIT", "dependencies": { "undici-types": "~6.20.0" @@ -1455,6 +1709,17 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/response-time": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/@types/response-time/-/response-time-2.3.8.tgz", + "integrity": "sha512-7qGaNYvdxc0zRab8oHpYx7AW17qj+G0xuag1eCrw3M2VWPJQ/HyKaaghWygiaOUl0y9x7QGQwppDpqLJ5V9pzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*", + "@types/node": "*" + } + }, "node_modules/@types/send": { "version": "0.17.4", "dev": true, @@ -1479,6 +1744,12 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/triple-beam": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", + "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==", + "license": "MIT" + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "8.24.1", "dev": true, @@ -2262,6 +2533,21 @@ "node": ">=12" } }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "license": "MIT" + }, + "node_modules/async-exit-hook": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/async-exit-hook/-/async-exit-hook-2.0.1.tgz", + "integrity": "sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, "node_modules/asynckit": { "version": "0.4.0", "license": "MIT" @@ -2405,6 +2691,18 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/btoa": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz", + "integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==", + "license": "(MIT OR Apache-2.0)", + "bin": { + "btoa": "bin/btoa.js" + }, + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/buffer": { "version": "5.7.1", "funding": [ @@ -2725,6 +3023,16 @@ "version": "13.0.3", "license": "MIT" }, + "node_modules/color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + } + }, "node_modules/color-convert": { "version": "2.0.1", "dev": true, @@ -2738,9 +3046,18 @@ }, "node_modules/color-name": { "version": "1.1.4", - "dev": true, "license": "MIT" }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "license": "MIT", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, "node_modules/color-support": { "version": "1.1.3", "license": "ISC", @@ -2749,10 +3066,35 @@ "color-support": "bin.js" } }, + "node_modules/color/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "license": "MIT" + }, "node_modules/colorette": { "version": "2.0.19", "license": "MIT" }, + "node_modules/colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "license": "MIT", + "dependencies": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } + }, "node_modules/combined-stream": { "version": "1.0.8", "license": "MIT", @@ -3127,6 +3469,12 @@ "dev": true, "license": "MIT" }, + "node_modules/enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==", + "license": "MIT" + }, "node_modules/encodeurl": { "version": "2.0.0", "license": "MIT", @@ -3760,6 +4108,12 @@ "reusify": "^1.0.4" } }, + "node_modules/fecha": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==", + "license": "MIT" + }, "node_modules/figlet": { "version": "1.8.0", "dev": true, @@ -3876,6 +4230,12 @@ "dev": true, "license": "ISC" }, + "node_modules/fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==", + "license": "MIT" + }, "node_modules/follow-redirects": { "version": "1.15.9", "funding": [ @@ -4487,6 +4847,12 @@ "node": ">= 0.10" } }, + "node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "license": "MIT" + }, "node_modules/is-core-module": { "version": "2.16.1", "license": "MIT", @@ -4900,6 +5266,12 @@ "dev": true, "license": "MIT" }, + "node_modules/kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==", + "license": "MIT" + }, "node_modules/levn": { "version": "0.4.1", "dev": true, @@ -4935,6 +5307,37 @@ "dev": true, "license": "MIT" }, + "node_modules/logform": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz", + "integrity": "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==", + "license": "MIT", + "dependencies": { + "@colors/colors": "1.6.0", + "@types/triple-beam": "^1.3.2", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/loki-logger-ts": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/loki-logger-ts/-/loki-logger-ts-1.0.2.tgz", + "integrity": "sha512-SV/B5o+9jaxiThcU5N3LUxCNTx20IgR9xjCjx/ED/pVc/097mqKSRpmvSjvx9ezFcjJlUF7GBkrBBpR6veNp7Q==", + "dependencies": { + "axios": "^1.4.0" + } + }, + "node_modules/long": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.1.tgz", + "integrity": "sha512-ka87Jz3gcx/I7Hal94xaN2tZEOPoUOEVftkQqZx2EeQRN7LGdfLlI3FvZ+7WDplm+vK2Urx9ULrvSowtdCieng==", + "license": "Apache-2.0" + }, "node_modules/loupe": { "version": "3.1.3", "dev": true, @@ -5661,6 +6064,15 @@ "node": ">= 0.8" } }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/once": { "version": "1.4.0", "license": "ISC", @@ -5668,6 +6080,15 @@ "wrappy": "1" } }, + "node_modules/one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "license": "MIT", + "dependencies": { + "fn.name": "1.x.x" + } + }, "node_modules/open": { "version": "10.1.0", "dev": true, @@ -6188,6 +6609,30 @@ "dev": true, "license": "ISC" }, + "node_modules/protobufjs": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.4.0.tgz", + "integrity": "sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw==", + "hasInstallScript": true, + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/proxy-addr": { "version": "2.0.7", "license": "MIT", @@ -6380,6 +6825,19 @@ "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" } }, + "node_modules/response-time": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/response-time/-/response-time-2.3.3.tgz", + "integrity": "sha512-SsjjOPHl/FfrTQNgmc5oen8Hr1Jxpn6LlHNXxCIFdYMHuK1kMeYMobb9XN3mvxaGQm3dbegqYFMX4+GDORfbWg==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "on-headers": "~1.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/retry": { "version": "0.12.0", "license": "MIT", @@ -6558,6 +7016,15 @@ ], "license": "MIT" }, + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "license": "MIT" @@ -6801,6 +7268,15 @@ "simple-concat": "^1.0.0" } }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, "node_modules/sirv": { "version": "3.0.1", "dev": true, @@ -6830,6 +7306,35 @@ "npm": ">= 3.0.0" } }, + "node_modules/snappy": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/snappy/-/snappy-7.2.2.tgz", + "integrity": "sha512-iADMq1kY0v3vJmGTuKcFWSXt15qYUz7wFkArOrsSg0IFfI3nJqIJvK2/ZbEIndg7erIJLtAVX2nSOqPz7DcwbA==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "optionalDependencies": { + "@napi-rs/snappy-android-arm-eabi": "7.2.2", + "@napi-rs/snappy-android-arm64": "7.2.2", + "@napi-rs/snappy-darwin-arm64": "7.2.2", + "@napi-rs/snappy-darwin-x64": "7.2.2", + "@napi-rs/snappy-freebsd-x64": "7.2.2", + "@napi-rs/snappy-linux-arm-gnueabihf": "7.2.2", + "@napi-rs/snappy-linux-arm64-gnu": "7.2.2", + "@napi-rs/snappy-linux-arm64-musl": "7.2.2", + "@napi-rs/snappy-linux-x64-gnu": "7.2.2", + "@napi-rs/snappy-linux-x64-musl": "7.2.2", + "@napi-rs/snappy-win32-arm64-msvc": "7.2.2", + "@napi-rs/snappy-win32-ia32-msvc": "7.2.2", + "@napi-rs/snappy-win32-x64-msvc": "7.2.2" + } + }, "node_modules/socks": { "version": "2.8.4", "license": "MIT", @@ -6957,6 +7462,15 @@ "license": "ISC", "optional": true }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "license": "MIT", + "engines": { + "node": "*" + } + }, "node_modules/stackback": { "version": "0.0.2", "dev": true, @@ -7216,6 +7730,12 @@ "node": ">=8.0.0" } }, + "node_modules/text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==", + "license": "MIT" + }, "node_modules/tildify": { "version": "2.0.0", "license": "MIT", @@ -7320,6 +7840,15 @@ "node": ">=18" } }, + "node_modules/triple-beam": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", + "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", + "license": "MIT", + "engines": { + "node": ">= 14.0.0" + } + }, "node_modules/ts-api-utils": { "version": "2.0.1", "dev": true, @@ -7496,7 +8025,6 @@ }, "node_modules/undici-types": { "version": "6.20.0", - "dev": true, "license": "MIT" }, "node_modules/unicorn-magic": { @@ -7577,6 +8105,12 @@ "punycode": "^2.1.0" } }, + "node_modules/url-polyfill": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/url-polyfill/-/url-polyfill-1.1.13.tgz", + "integrity": "sha512-tXzkojrv2SujumYthZ/WjF7jaSfNhSXlYMpE5AYdL2I3D7DCeo+mch8KtW2rUuKjDg+3VXODXHVgipt8yGY/eQ==", + "license": "MIT" + }, "node_modules/util-deprecate": { "version": "1.0.2", "license": "MIT" @@ -7987,24 +8521,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/vue-i18n": { - "version": "10.0.5", - "license": "MIT", - "dependencies": { - "@intlify/core-base": "10.0.5", - "@intlify/shared": "10.0.5", - "@vue/devtools-api": "^6.5.0" - }, - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://github.com/sponsors/kazupon" - }, - "peerDependencies": { - "vue": "^3.0.0" - } - }, "node_modules/vue-router": { "version": "4.5.0", "license": "MIT", @@ -8204,6 +8720,70 @@ "node": ">=8" } }, + "node_modules/winston": { + "version": "3.17.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.17.0.tgz", + "integrity": "sha512-DLiFIXYC5fMPxaRg832S6F5mJYvePtmO5G9v9IgUFPhXm9/GkXarH/TUrBAVzhTCzAj9anE/+GjrgXp/54nOgw==", + "license": "MIT", + "dependencies": { + "@colors/colors": "^1.6.0", + "@dabh/diagnostics": "^2.0.2", + "async": "^3.2.3", + "is-stream": "^2.0.0", + "logform": "^2.7.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.9.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/winston-loki": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/winston-loki/-/winston-loki-6.1.3.tgz", + "integrity": "sha512-DjWtJ230xHyYQWr9mZJa93yhwHttn3JEtSYWP8vXZWJOahiQheUhf+88dSIidbGXB3u0oLweV6G1vkL/ouT62Q==", + "license": "MIT", + "dependencies": { + "async-exit-hook": "2.0.1", + "btoa": "^1.2.1", + "protobufjs": "^7.2.4", + "url-polyfill": "^1.1.12", + "winston-transport": "^4.3.0" + }, + "optionalDependencies": { + "snappy": "^7.2.2" + } + }, + "node_modules/winston-transport": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.9.0.tgz", + "integrity": "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==", + "license": "MIT", + "dependencies": { + "logform": "^2.7.0", + "readable-stream": "^3.6.2", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/winston/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/word-wrap": { "version": "1.2.5", "dev": true, diff --git a/package.json b/package.json index 7287d706..db7f5ba3 100644 --- a/package.json +++ b/package.json @@ -35,9 +35,5 @@ "eslint-config-prettier": "^10.0.1", "jiti": "^2.4.2", "typescript-eslint": "^8.24.1" - }, - "dependencies": { - "@types/js-yaml": "^4.0.9", - "vue-i18n": "^10.0.5" } }