diff --git a/.gitignore b/.gitignore index 8fb0bbf..307ee13 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ node_modules/ +node_modules logs/ dist/ config.toml diff --git a/.tool-versions b/.tool-versions index 6296c3e..41bc83d 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,3 +1,3 @@ nodejs 18.16.0 -pnpm 6.24.4 +pnpm 9.15.2 python 3.12.0 diff --git a/bun.lockb b/bun.lockb index 8f61770..54c2443 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/core/base.ts b/core/base.ts new file mode 100644 index 0000000..54bf162 --- /dev/null +++ b/core/base.ts @@ -0,0 +1,8 @@ +import type { Logger } from 'winston'; +import { config } from '@core/config'; +import { logger } from '@core/logger'; + +export class ServiceBase { + public log: Logger = logger; + public config = config; +} diff --git a/core/bot.ts b/core/bot.ts index ccd85b8..beea2a5 100644 --- a/core/bot.ts +++ b/core/bot.ts @@ -6,36 +6,22 @@ import { Mwn, type MwnOptions } from "mwn"; import { version, dependencies } from '../package.json' import { Command } from "@commander-js/extra-typings" +import { Replica } from '@core/replica'; import { Cron, type CronOptions } from 'croner'; import chalk from 'chalk'; -import { Replica } from './replica'; +import { ServiceBase } from './base'; -interface ScheduleOptions { - pattern: string | Date; - options: CronOptions; -} - -if (!Bun.file('../config.toml').exists()) { - throw new Error('Please create config.toml') -} - -const config = await import('../config.toml') - -if (!config.oauth.consumerToken || !config.oauth.consumerSecret || !config.oauth.accessToken || !config.oauth.accessSecret) { - throw new Error('Please fill in the OAuth credentials in config.toml') -} - -export class Bot { +export class Bot extends ServiceBase { private _botOptions: MwnOptions = { - apiUrl: config.bot.apiUrl || "https://th.wikipedia.org/w/api.php", + apiUrl: this.config.bot.apiUrl || "https://th.wikipedia.org/w/api.php", OAuthCredentials: { - consumerToken: config.oauth.consumerToken || process.env.BOT_CONSUMER_TOKEN, - consumerSecret: config.oauth.consumerSecret || process.env.BOT_CONSUMER_SECRET, - accessToken: config.oauth.accessToken || process.env.BOT_ACCESS_TOKEN, - accessSecret: config.oauth.accessSecret || process.env.BOT_ACCESS_SECRET, + consumerToken: this.config.oauth.consumerToken, + consumerSecret: this.config.oauth.consumerSecret, + accessToken: this.config.oauth.accessToken, + accessSecret: this.config.oauth.accessSecret, }, // Set your user agent (required for WMF wikis, see https://meta.wikimedia.org/wiki/User-Agent_policy): - userAgent: `${config.bot.username}/${version} (${config.bot.contact}) mwn/${dependencies.mwn}`, + userAgent: `${this.config.bot.username}/${version} (${this.config.bot.contact}) mwn/${dependencies.mwn}`, defaultParams: { assert: "user", }, @@ -49,10 +35,6 @@ export class Bot { public job?: Cron - public log(obj: any) { - return Mwn.log(obj) - } - public bot = new Mwn({ ...this._botOptions }); @@ -62,6 +44,7 @@ export class Bot { public replica = new Replica() constructor() { + super() this.info = { id: "bot", name: "Bot", @@ -102,10 +85,13 @@ export class Bot { } } - async schedule(options: ScheduleOptions) { + async schedule(options: { + pattern: string | Date; + options: CronOptions; + }) { this.job = new Cron(options.pattern, { name: this.info.id, - timezone: config.bot.timezone, + timezone: this.config.bot.timezone, ...options.options }) this.job.schedule(() => this.run()) diff --git a/core/config.ts b/core/config.ts new file mode 100644 index 0000000..9642274 --- /dev/null +++ b/core/config.ts @@ -0,0 +1,46 @@ +import { z } from 'zod' + +if (!Bun.file('../config.toml').exists()) { + throw new Error('Please create config.toml') +} + +export const config = await z.object({ + oauth: z.object({ + consumerToken: z.string(), + consumerSecret: z.string(), + accessToken: z.string(), + accessSecret: z.string(), + }), + bot: z.object({ + apiUrl: z.string(), + username: z.string(), + contact: z.string(), + timezone: z.string(), + }), + toolforge: z.object({ + login: z.string(), + tooluser: z.string(), + deploykey: z.string(), + }), + replica: z.object({ + username: z.string(), + password: z.string(), + dbname: z.string(), + cluster: z.string(), + port: z.number(), + }), + scripts: z.object({ + archive: z.object({ + key_salt: z.string().optional(), + }), + }), + logger: z.object({ + logPath: z.string(), + level: z.string().default("info"), + }), + discord: z.object({ + logger: z.object({ + webhook: z.string().optional(), + }), + }), +}).parseAsync(await import('../config.toml')) diff --git a/core/logger.ts b/core/logger.ts new file mode 100644 index 0000000..fb119b5 --- /dev/null +++ b/core/logger.ts @@ -0,0 +1,36 @@ +import { createLogger, transports, format } from 'winston'; +import { config } from '@core/config'; +import chalk from 'chalk'; + +export const logger = createLogger({ + level: config.logger.level, + format: format.combine( + format.timestamp(), + format.errors({ + stack: true, + }), + format.splat(), + format.json(), + ), + transports: [ + new transports.File({ + filename: `${config.logger.logPath}/output.log`, + maxsize: 5242880, // 5MB + }), + new transports.File({ filename: 'error.log', level: 'error' }), + new transports.Console({ + format: format.combine( + format.colorize(), + format.printf(({ level, message, timestamp, durationMs }) => { + return `${chalk.dim(`[${timestamp}]`)} ${level}: ${message}${durationMs ? ` ${chalk.dim(`(${durationMs}ms)`)}` : ''}`; + }) + ) + }), + ], + exceptionHandlers: [ + new transports.File({ filename: `${config.logger.logPath}/exceptions.log` }) + ], + rejectionHandlers: [ + new transports.File({ filename: 'rejections.log' }) + ] +}); diff --git a/core/replica.ts b/core/replica.ts index b07feab..8b649e2 100644 --- a/core/replica.ts +++ b/core/replica.ts @@ -1,15 +1,7 @@ import mysql from "mysql2/promise"; -import { $, type Server } from "bun" - -const config = await import('../config.toml') - -if (!config.replica) { - throw new Error("No replica config found."); -} - -if (!config.replica.username || !config.replica.password) { - throw new Error("Please fill in the replica credentials in config.toml"); -} +import { $ } from "bun" +import { ServiceBase } from '@core/base'; +import { config } from '@core/config'; function getReplicaHost(dbname: string, cluster: string = "web") { if (!['web', 'analytics'].includes(cluster)) { @@ -27,22 +19,24 @@ function getReplicaHost(dbname: string, cluster: string = "web") { } -export class Replica { +export class Replica extends ServiceBase { private _replicaOptions: mysql.PoolOptions = { - user: config.replica.username, - password: config.replica.password, - port: Number(config.replica.port || 3306), + user: this.config.replica.username, + password: this.config.replica.password, + port: Number(this.config.replica.port || 3306), waitForConnections: true, } public conn: mysql.Connection | null = null - constructor() { } + constructor() { + super() + } public async init() { if (!this.isRunOnToolforge()) { console.warn("Not running on Toolforge, don't forget to set up SSH tunnel using `. replica-tunnel` in separate terminal.") - const database = config.replica.dbname + const database = this.config.replica.dbname this._replicaOptions = { ...this._replicaOptions, host: '127.0.0.1', @@ -51,8 +45,8 @@ export class Replica { } else { this._replicaOptions = { ...this._replicaOptions, - host: getReplicaHost(config.replica.dbname), - database: config.replica.dbname, + host: getReplicaHost(this.config.replica.dbname), + database: this.config.replica.dbname, } } this.conn = await mysql.createConnection(this._replicaOptions) @@ -60,7 +54,7 @@ export class Replica { public static async createReplicaTunnel(dbname: string, cluster: string = "web", port: number = 3306) { if (!config.toolforge.login) { - throw new Error('Please fill in the Toolforge login in config.toml') + throw new Error('Please fill in the Toolforge login in this.config.toml') } const host = getReplicaHost(dbname, cluster) @@ -71,7 +65,7 @@ export class Replica { } private isRunOnToolforge() { - return process.env.USER == config.toolforge.tooluser + return process.env.USER == this.config.toolforge.tooluser } public async query(sql: string, values: any[] = []) { diff --git a/core/run.ts b/core/run.ts index 090b724..7d2f9c8 100644 --- a/core/run.ts +++ b/core/run.ts @@ -1,24 +1,34 @@ +import { Bot } from '@core/bot' +import { Replica } from '@core/replica' +import { createId } from '@paralleldrive/cuid2' import { Command, InvalidArgumentError, Option } from '@commander-js/extra-typings' -import { Bot } from './bot' import { version } from "../package.json" -import { $ } from "bun" -import { Replica } from './replica' +import { ServiceBase } from './base' -class ScriptRunner { +class ScriptRunner extends ServiceBase { private cli = new Command() async scriptModule(scriptName: string) { if (!scriptName) { throw new Error('No script name provided') } - if (!scriptName.match(/^[a-z0-9-]+$/)) { + if (!scriptName.match(/^[a-z0-9-\/]+$/)) { throw new Error('Invalid script name') } - if (!Bun.file(`./scripts/${scriptName}.ts`).exists()) { + if (!Bun.file(`@scripts/${scriptName}.ts`).exists()) { throw new Error('Script not found') } - const scriptModule = await import(`../scripts/${scriptName}.ts`) + const scriptModule = await import(`@scripts/${scriptName}.ts`) + + if (!scriptModule.default) { + throw new Error('Script must have a default export') + } + + // check if scriptModule is a Bot instance + if (!(Object.getPrototypeOf(scriptModule.default) === Bot || Object.getPrototypeOf(scriptModule.default.prototype) === Bot)) { + throw new Error('Script must be a Bot instance') + } return (new scriptModule.default) as unknown as Bot } @@ -39,7 +49,17 @@ class ScriptRunner { scriptModule.cli .name('run ' + scriptName) .description(scriptModule.scriptDescription) + // Global cli options + scriptModule.cli.option("-v, --verbose", "Show debug logging") scriptModule.cli.parse(process.argv.slice(2)) + scriptModule.log.defaultMeta = { + script: scriptName, + rid: createId(), + } + // @ts-ignore + if (scriptModule.cli.opts().verbose) { + scriptModule.log.level = 'debug' + } try { await scriptModule.beforeRun() await scriptModule.run() diff --git a/package.json b/package.json index 4a5c9bb..eb52b92 100644 --- a/package.json +++ b/package.json @@ -15,24 +15,25 @@ "dependencies": { "@commander-js/extra-typings": "^13.0.0", "@paralleldrive/cuid2": "^2.2.2", - "bun": "^1.1.42", "chalk": "^5.4.1", + "commander": "^13.0.0", "cors": "^2.8.5", "croner": "^9.0.0", "cronstrue": "^2.52.0", "moment": "^2.30.1", "mwn": "^2.0.4", "mysql2": "^3.12.0", - "winston": "^3.17.0" + "winston": "^3.17.0", + "zod": "^3.24.1" }, "devDependencies": { "@types/bun": "^1.1.14", "@types/cors": "^2.8.17", - "@types/cron": "^2.4.3", "@types/express": "^5.0.0", "@types/js-yaml": "^4.0.9", "@types/node": "^22.10.3", "@types/ssh2": "^1.15.1", + "bun": "^1.1.42", "husky": "^9.1.7", "lint-staged": "^15.3.0", "prettier": "3.4.2", @@ -59,9 +60,10 @@ "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "format": "prettier --write . --ignore-unknown", - "start": "bun core/web.ts", - "build": "sh ./build.sh", + "build": "bun i", + "start": "bun ./core/web.ts", "prepare": "husky" }, - "type": "module" + "type": "module", + "packageManager": "pnpm@9.15.2" } \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..e42050f --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,1595 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@commander-js/extra-typings': + specifier: ^13.0.0 + version: 13.0.0(commander@13.0.0) + '@paralleldrive/cuid2': + specifier: ^2.2.2 + version: 2.2.2 + chalk: + specifier: ^5.4.1 + version: 5.4.1 + commander: + specifier: ^13.0.0 + version: 13.0.0 + cors: + specifier: ^2.8.5 + version: 2.8.5 + croner: + specifier: ^9.0.0 + version: 9.0.0 + cronstrue: + specifier: ^2.52.0 + version: 2.52.0 + moment: + specifier: ^2.30.1 + version: 2.30.1 + mwn: + specifier: ^2.0.4 + version: 2.0.4(typescript@5.7.2) + mysql2: + specifier: ^3.12.0 + version: 3.12.0 + winston: + specifier: ^3.17.0 + version: 3.17.0 + devDependencies: + '@types/bun': + specifier: ^1.1.14 + version: 1.1.14 + '@types/cors': + specifier: ^2.8.17 + version: 2.8.17 + '@types/express': + specifier: ^5.0.0 + version: 5.0.0 + '@types/js-yaml': + specifier: ^4.0.9 + version: 4.0.9 + '@types/node': + specifier: ^22.10.3 + version: 22.10.5 + '@types/ssh2': + specifier: ^1.15.1 + version: 1.15.1 + bun: + specifier: ^1.1.42 + version: 1.1.42 + husky: + specifier: ^9.1.7 + version: 9.1.7 + lint-staged: + specifier: ^15.3.0 + version: 15.3.0 + prettier: + specifier: 3.4.2 + version: 3.4.2 + tslib: + specifier: ^2.8.1 + version: 2.8.1 + typescript: + specifier: ^5.7.2 + version: 5.7.2 + +packages: + + '@babel/helper-string-parser@7.25.9': + resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.25.9': + resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.26.3': + resolution: {integrity: sha512-WJ/CvmY8Mea8iDXo6a7RK2wbmJITT5fN3BEkRuFlxVyNx8jOKIIhmC4fSkTcPcf8JyavbBwIe6OpiCOBXt/IcA==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/types@7.26.3': + resolution: {integrity: sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==} + engines: {node: '>=6.9.0'} + + '@colors/colors@1.6.0': + resolution: {integrity: sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==} + engines: {node: '>=0.1.90'} + + '@commander-js/extra-typings@13.0.0': + resolution: {integrity: sha512-4or44L3saI49QRBvdSzfCtzqONlFg0/qy0Cfl+LRynDaxlGs7r2KRTLCELaAoKh4oQguICxRwQfm77/Up+0wTw==} + peerDependencies: + commander: ~13.0.0 + + '@dabh/diagnostics@2.0.3': + resolution: {integrity: sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==} + + '@jridgewell/sourcemap-codec@1.5.0': + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + + '@noble/hashes@1.7.0': + resolution: {integrity: sha512-HXydb0DgzTpDPwbVeDGCG1gIu7X6+AuU6Zl6av/E/KG8LMsvPntvq+w17CHRpKBmN6Ybdrt1eP3k4cj8DJa78w==} + engines: {node: ^14.21.3 || >=16} + + '@oven/bun-darwin-aarch64@1.1.42': + resolution: {integrity: sha512-7kQkTVr99ndcU72xlIzA2QLavvT/DnEhvwTAq7LKi9/P3GtSAkhoA6UWZUa7pYw7OYHpUrEGXlV+PR3LllkGnw==} + cpu: [arm64] + os: [darwin] + + '@oven/bun-darwin-x64-baseline@1.1.42': + resolution: {integrity: sha512-26mtzVRLp/x89s27fXExG1vCCBOOFHLdqVYg/lHZMdDNHSh7Q7UiUhDRa+aVBlbsaGfw1LzoXdhh7Zy2hlF/6w==} + cpu: [x64] + os: [darwin] + + '@oven/bun-darwin-x64@1.1.42': + resolution: {integrity: sha512-2IPJnLvwLlD8YaXPbWwlpw2UvVrZE6/0uRbcSJNzZQAAZjEfN8AodqNRhggptn0A9vDmAw6q1U07QbiE4ilofw==} + cpu: [x64] + os: [darwin] + + '@oven/bun-linux-aarch64-musl@1.1.42': + resolution: {integrity: sha512-PwbNLoirazjTYTSydn2AnId0jBJexZ99cwftOfdzIGCF5anEWvNEZ8PL4o79jHIhE0t01qGc8br9fQbiQ+iArw==} + cpu: [aarch64] + os: [linux] + + '@oven/bun-linux-aarch64@1.1.42': + resolution: {integrity: sha512-qkoqI+oMcQ8GUej71qkAVj/VLlVpoBRyiYBQYq4yWsy+FU2jr2KWTeNZWrsY2crDiZj38AMNXJiKBr/EMy4MRg==} + cpu: [arm64] + os: [linux] + + '@oven/bun-linux-x64-baseline@1.1.42': + resolution: {integrity: sha512-UzRNXgHEARFECgz30eot23OnPzd0J2L5SEsGhnGRhfJ706kjz0XmuGMnb9nmnoyHBcd2iSjk4nci1BlGmu4wCA==} + cpu: [x64] + os: [linux] + + '@oven/bun-linux-x64-musl-baseline@1.1.42': + resolution: {integrity: sha512-zgeiYJRGO3K4uK6Qdj1B5ZbU9NJxLwF9YGDFu9MtqEplyGNq7SpeuamvcP6SlZGgrVnc3AWrHFEYrVlv5Lqt+w==} + cpu: [x64] + os: [linux] + + '@oven/bun-linux-x64-musl@1.1.42': + resolution: {integrity: sha512-Djye8lPlhVNXdGbMF4bShVop8qvqPhPuPrhxEHfYJ8qhudSs2MiOWR5stvBWe8KLKahqDAWfWXuxByAXVhqb2Q==} + cpu: [x64] + os: [linux] + + '@oven/bun-linux-x64@1.1.42': + resolution: {integrity: sha512-rV8Eqnvo/1z0nwYSiLrbl0F4G8uFQxlGA4P0zggW9W4PSiSHSRhG1aazG/8esBLzJI9CdFNncrtmiRTmWl1mIg==} + cpu: [x64] + os: [linux] + + '@oven/bun-windows-x64-baseline@1.1.42': + resolution: {integrity: sha512-xnlYa1jKknImCw7xmSD91H8e+w3BC6mIShOfHhFWfNhdyvEtundXhIu7VddwxKBMs5S/iiFJiutnZ2EyLq4CAQ==} + cpu: [x64] + os: [win32] + + '@oven/bun-windows-x64@1.1.42': + resolution: {integrity: sha512-6eyHs6fVRCy0ujltYTwSX3bug+PqlgZRBv8x0PPekviaCJWYrFKVpHodA2972+Mih2pATurBSX2sLVq5uJUU7Q==} + cpu: [x64] + os: [win32] + + '@paralleldrive/cuid2@2.2.2': + resolution: {integrity: sha512-ZOBkgDwEdoYVlSeRbYYXs0S9MejQofiVYoTbKzy/6GQa39/q5tQU2IX46+shYnUkpEl3wc+J6wRlar7r2EK2xA==} + + '@types/body-parser@1.19.5': + resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==} + + '@types/bun@1.1.14': + resolution: {integrity: sha512-opVYiFGtO2af0dnWBdZWlioLBoxSdDO5qokaazLhq8XQtGZbY4pY3/JxY8Zdf/hEwGubbp7ErZXoN1+h2yesxA==} + + '@types/connect@3.4.38': + resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} + + '@types/cors@2.8.17': + resolution: {integrity: sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==} + + '@types/express-serve-static-core@5.0.3': + resolution: {integrity: sha512-JEhMNwUJt7bw728CydvYzntD0XJeTmDnvwLlbfbAhE7Tbslm/ax6bdIiUwTgeVlZTsJQPwZwKpAkyDtIjsvx3g==} + + '@types/express@5.0.0': + resolution: {integrity: sha512-DvZriSMehGHL1ZNLzi6MidnsDhUZM/x2pRdDIKdwbUNqqwHxMlRdkxtn6/EPKyqKpHqTl/4nRZsRNLpZxZRpPQ==} + + '@types/http-errors@2.0.4': + resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==} + + '@types/jquery@3.5.32': + resolution: {integrity: sha512-b9Xbf4CkMqS02YH8zACqN1xzdxc3cO735Qe5AbSUFmyOiaWAbcpqh9Wna+Uk0vgACvoQHpWDg2rGdHkYPLmCiQ==} + + '@types/js-yaml@4.0.9': + resolution: {integrity: sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==} + + '@types/mime@1.3.5': + resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==} + + '@types/node@14.18.63': + resolution: {integrity: sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==} + + '@types/node@18.19.69': + resolution: {integrity: sha512-ECPdY1nlaiO/Y6GUnwgtAAhLNaQ53AyIVz+eILxpEo5OvuqE6yWkqWBIb5dU0DqhKQtMeny+FBD3PK6lm7L5xQ==} + + '@types/node@20.12.14': + resolution: {integrity: sha512-scnD59RpYD91xngrQQLGkE+6UrHUPzeKZWhhjBSa3HSkwjbQc38+q3RoIVEwxQGRw3M+j5hpNAM+lgV3cVormg==} + + '@types/node@22.10.5': + resolution: {integrity: sha512-F8Q+SeGimwOo86fiovQh8qiXfFEh2/ocYv7tU5pJ3EXMSSxk1Joj5wefpFK2fHTf/N6HKGSxIDBT9f3gCxXPkQ==} + + '@types/oojs-ui@0.46.4': + resolution: {integrity: sha512-tpQyPjxr6FhMRNaactbjNXkr4uCsKNQMOVNJiAO5AvzxoPddChNZp4gG37Pm80jAeDP11k9ww4durnEjzqqKsQ==} + + '@types/oojs@7.0.7': + resolution: {integrity: sha512-l99Ab1s+EhCWR/38z5VI3aimTT9QZNjpd3JlJnECHXq6uJ/osLchkkhVfY7ANeOMVT978LawYO4JyOYPQO7VLQ==} + + '@types/qs@6.9.17': + resolution: {integrity: sha512-rX4/bPcfmvxHDv0XjfJELTTr+iB+tn032nPILqHm5wbthUUUuVtNGGqzhya9XUxjTP8Fpr0qYgSZZKxGY++svQ==} + + '@types/range-parser@1.2.7': + resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} + + '@types/send@0.17.4': + resolution: {integrity: sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==} + + '@types/serve-static@1.15.7': + resolution: {integrity: sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==} + + '@types/sizzle@2.3.9': + resolution: {integrity: sha512-xzLEyKB50yqCUPUJkIsrVvoWNfFUbIZI+RspLWt8u+tIW/BetMBZtgV2LY/2o+tYH8dRvQ+eoPf3NdhQCcLE2w==} + + '@types/ssh2@1.15.1': + resolution: {integrity: sha512-ZIbEqKAsi5gj35y4P4vkJYly642wIbY6PqoN0xiyQGshKUGXR9WQjF/iF9mXBQ8uBKy3ezfsCkcoHKhd0BzuDA==} + + '@types/tough-cookie@4.0.5': + resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==} + + '@types/triple-beam@1.3.5': + resolution: {integrity: sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==} + + '@types/ws@8.5.13': + resolution: {integrity: sha512-osM/gWBTPKgHV8XkTunnegTRIsvF6owmf5w+JtAfOw472dptdm0dlGv4xCt6GwQRcC2XVOvvRE/0bAoQcL2QkA==} + + '@vue/compiler-core@3.3.9': + resolution: {integrity: sha512-+/Lf68Vr/nFBA6ol4xOtJrW+BQWv3QWKfRwGSm70jtXwfhZNF4R/eRgyVJYoxFRhdCTk/F6g99BP0ffPgZihfQ==} + + '@vue/compiler-dom@3.3.9': + resolution: {integrity: sha512-nfWubTtLXuT4iBeDSZ5J3m218MjOy42Vp2pmKVuBKo2/BLcrFUX8nCSr/bKRFiJ32R8qbdnnnBgRn9AdU5v0Sg==} + + '@vue/compiler-sfc@3.3.9': + resolution: {integrity: sha512-wy0CNc8z4ihoDzjASCOCsQuzW0A/HP27+0MDSSICMjVIFzk/rFViezkR3dzH+miS2NDEz8ywMdbjO5ylhOLI2A==} + + '@vue/compiler-ssr@3.3.9': + resolution: {integrity: sha512-NO5oobAw78R0G4SODY5A502MGnDNiDjf6qvhn7zD7TJGc8XDeIEw4fg6JU705jZ/YhuokBKz0A5a/FL/XZU73g==} + + '@vue/reactivity-transform@3.3.9': + resolution: {integrity: sha512-HnUFm7Ry6dFa4Lp63DAxTixUp8opMtQr6RxQCpDI1vlh12rkGIeYqMvJtK+IKyEfEOa2I9oCkD1mmsPdaGpdVg==} + + '@vue/reactivity@3.3.9': + resolution: {integrity: sha512-VmpIqlNp+aYDg2X0xQhJqHx9YguOmz2UxuUJDckBdQCNkipJvfk9yA75woLWElCa0Jtyec3lAAt49GO0izsphw==} + + '@vue/runtime-core@3.3.9': + resolution: {integrity: sha512-xxaG9KvPm3GTRuM4ZyU8Tc+pMVzcu6eeoSRQJ9IE7NmCcClW6z4B3Ij6L4EDl80sxe/arTtQ6YmgiO4UZqRc+w==} + + '@vue/runtime-dom@3.3.9': + resolution: {integrity: sha512-e7LIfcxYSWbV6BK1wQv9qJyxprC75EvSqF/kQKe6bdZEDNValzeRXEVgiX7AHI6hZ59HA4h7WT5CGvm69vzJTQ==} + + '@vue/server-renderer@3.3.9': + resolution: {integrity: sha512-w0zT/s5l3Oa3ZjtLW88eO4uV6AQFqU8X5GOgzq7SkQQu6vVr+8tfm+OI2kDBplS/W/XgCBuFXiPw6T5EdwXP0A==} + peerDependencies: + vue: 3.3.9 + + '@vue/shared@3.3.9': + resolution: {integrity: sha512-ZE0VTIR0LmYgeyhurPTpy4KzKsuDyQbMSdM49eKkMnT5X4VfFBLysMzjIZhLEFQYjjOVVfbvUDHckwjDFiO2eA==} + + ansi-escapes@7.0.0: + resolution: {integrity: sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==} + engines: {node: '>=18'} + + ansi-regex@2.1.1: + resolution: {integrity: sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==} + engines: {node: '>=0.10.0'} + + ansi-regex@6.1.0: + resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} + engines: {node: '>=12'} + + ansi-styles@2.2.1: + resolution: {integrity: sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==} + engines: {node: '>=0.10.0'} + + ansi-styles@6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} + + async@3.2.6: + resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + aws-ssl-profiles@1.1.2: + resolution: {integrity: sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==} + engines: {node: '>= 6.0.0'} + + axios-cookiejar-support@1.0.1: + resolution: {integrity: sha512-IZJxnAJ99XxiLqNeMOqrPbfR7fRyIfaoSLdPUf4AMQEGkH8URs0ghJK/xtqBsD+KsSr3pKl4DEQjCn834pHMig==} + engines: {node: '>= 10.0.0'} + peerDependencies: + '@types/tough-cookie': '>=2.3.3' + axios: '>=0.16.2' + tough-cookie: '>=2.3.3' + + axios@0.25.0: + resolution: {integrity: sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + bun-types@1.1.37: + resolution: {integrity: sha512-C65lv6eBr3LPJWFZ2gswyrGZ82ljnH8flVE03xeXxKhi2ZGtFiO4isRKTKnitbSqtRAcaqYSR6djt1whI66AbA==} + + bun@1.1.42: + resolution: {integrity: sha512-PckeNolMEBaBEzixTMvp0jJD9r/9lly8AfctILi1ve14zwwChFjsxI4TJLQO2yezzOjVeG0u7xf8WQFbS7GjAA==} + os: [darwin, linux, win32] + hasBin: true + + chalk@1.1.3: + resolution: {integrity: sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==} + engines: {node: '>=0.10.0'} + + chalk@5.4.1: + resolution: {integrity: sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + + cli-cursor@5.0.0: + resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} + engines: {node: '>=18'} + + cli-truncate@4.0.0: + resolution: {integrity: sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==} + engines: {node: '>=18'} + + color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + + color-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + color-string@1.9.1: + resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} + + color@3.2.1: + resolution: {integrity: sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==} + + colorette@2.0.20: + resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + + colorspace@1.1.4: + resolution: {integrity: sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==} + + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + commander@12.1.0: + resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} + engines: {node: '>=18'} + + commander@13.0.0: + resolution: {integrity: sha512-oPYleIY8wmTVzkvQq10AEok6YcTC4sRUBl8F9gVuwchGVUCTbl/vhLTaQqutuuySYOsu8YTgV+OxKc/8Yvx+mQ==} + engines: {node: '>=18'} + + cors@2.8.5: + resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} + engines: {node: '>= 0.10'} + + croner@9.0.0: + resolution: {integrity: sha512-onMB0OkDjkXunhdW9htFjEhqrD54+M94i6ackoUkjHKbRnXdyEyKRelp4nJ1kAz32+s27jP1FsebpJCVl0BsvA==} + engines: {node: '>=18.0'} + + cronstrue@2.52.0: + resolution: {integrity: sha512-NKgHbWkSZXJUcaBHSsyzC8eegD6bBd4O0oCI6XMIJ+y4Bq3v4w7sY3wfWoKPuVlq9pQHRB6od0lmKpIqi8TlKA==} + hasBin: true + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + csstype@3.1.3: + resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + + debug@4.4.0: + resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + denque@2.1.0: + resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} + engines: {node: '>=0.10'} + + emoji-regex@10.4.0: + resolution: {integrity: sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==} + + enabled@2.0.0: + resolution: {integrity: sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==} + + environment@1.1.0: + resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} + engines: {node: '>=18'} + + escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + + estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + + eventemitter3@5.0.1: + resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + + execa@8.0.1: + resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} + engines: {node: '>=16.17'} + + fecha@4.2.3: + resolution: {integrity: sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + fn.name@1.1.0: + resolution: {integrity: sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==} + + follow-redirects@1.15.9: + resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + + form-data@4.0.1: + resolution: {integrity: sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==} + engines: {node: '>= 6'} + + generate-function@2.3.1: + resolution: {integrity: sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==} + + get-east-asian-width@1.3.0: + resolution: {integrity: sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==} + engines: {node: '>=18'} + + get-stream@8.0.1: + resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} + engines: {node: '>=16'} + + has-ansi@2.0.0: + resolution: {integrity: sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==} + engines: {node: '>=0.10.0'} + + human-signals@5.0.0: + resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} + engines: {node: '>=16.17.0'} + + husky@9.1.7: + resolution: {integrity: sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==} + engines: {node: '>=18'} + hasBin: true + + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + is-arrayish@0.3.2: + resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} + + is-fullwidth-code-point@4.0.0: + resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} + engines: {node: '>=12'} + + is-fullwidth-code-point@5.0.0: + resolution: {integrity: sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==} + engines: {node: '>=18'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-property@1.0.2: + resolution: {integrity: sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==} + + is-redirect@1.0.0: + resolution: {integrity: sha512-cr/SlUEe5zOGmzvj9bUyC4LVvkNVAXu4GytXLNMr1pny+a65MpQ9IJzFHD5vi7FyJgb4qt27+eS3TuQnqB+RQw==} + engines: {node: '>=0.10.0'} + + is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + + is-stream@3.0.0: + resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + kuler@2.0.0: + resolution: {integrity: sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==} + + lilconfig@3.1.3: + resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} + engines: {node: '>=14'} + + lint-staged@15.3.0: + resolution: {integrity: sha512-vHFahytLoF2enJklgtOtCtIjZrKD/LoxlaUusd5nh7dWv/dkKQJY74ndFSzxCdv7g0ueGg1ORgTSt4Y9LPZn9A==} + engines: {node: '>=18.12.0'} + hasBin: true + + listr2@8.2.5: + resolution: {integrity: sha512-iyAZCeyD+c1gPyE9qpFu8af0Y+MRtmKOncdGoA2S5EY8iFq99dmmvkNnHiWo+pj0s7yH7l3KPIgee77tKpXPWQ==} + engines: {node: '>=18.0.0'} + + log-update@6.1.0: + resolution: {integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==} + engines: {node: '>=18'} + + logform@2.7.0: + resolution: {integrity: sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==} + engines: {node: '>= 12.0.0'} + + long@5.2.3: + resolution: {integrity: sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==} + + lru-cache@7.18.3: + resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} + engines: {node: '>=12'} + + lru.min@1.1.1: + resolution: {integrity: sha512-FbAj6lXil6t8z4z3j0E5mfRlPzxkySotzUHwRXjlpRh10vc6AI6WN62ehZj82VG7M20rqogJ0GLwar2Xa05a8Q==} + engines: {bun: '>=1.0.0', deno: '>=1.30.0', node: '>=8.0.0'} + + magic-string@0.30.17: + resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} + + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + mimic-fn@4.0.0: + resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} + engines: {node: '>=12'} + + mimic-function@5.0.1: + resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} + engines: {node: '>=18'} + + moment@2.30.1: + resolution: {integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + mwn@2.0.4: + resolution: {integrity: sha512-WLsWuJIwIVGIrDWX60NwzIg1L1mhqpf9b/u/+FYBEsKIflmh71lacCe6m7bRor6IUj7ofJ8w0EiDVeZuQLO+/A==} + engines: {node: '>=10'} + + mysql2@3.12.0: + resolution: {integrity: sha512-C8fWhVysZoH63tJbX8d10IAoYCyXy4fdRFz2Ihrt9jtPILYynFEKUUzpp1U7qxzDc3tMbotvaBH+sl6bFnGZiw==} + engines: {node: '>= 8.0'} + + named-placeholders@1.1.3: + resolution: {integrity: sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==} + engines: {node: '>=12.0.0'} + + nanoid@3.3.8: + resolution: {integrity: sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + npm-run-path@5.3.0: + resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + oauth-1.0a@2.2.6: + resolution: {integrity: sha512-6bkxv3N4Gu5lty4viIcIAnq5GbxECviMBeKR3WX/q87SPQ8E8aursPZUtsXDnxCs787af09WPRBLqYrf/lwoYQ==} + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + one-time@1.0.0: + resolution: {integrity: sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==} + + onetime@6.0.0: + resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} + engines: {node: '>=12'} + + onetime@7.0.0: + resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} + engines: {node: '>=18'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-key@4.0.0: + resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} + engines: {node: '>=12'} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + pidtree@0.6.0: + resolution: {integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==} + engines: {node: '>=0.10'} + hasBin: true + + pify@5.0.0: + resolution: {integrity: sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==} + engines: {node: '>=10'} + + postcss@8.4.49: + resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==} + engines: {node: ^10 || ^12 || >=14} + + prettier@3.4.2: + resolution: {integrity: sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==} + engines: {node: '>=14'} + hasBin: true + + psl@1.15.0: + resolution: {integrity: sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + querystringify@2.2.0: + resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} + + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + + requires-port@1.0.0: + resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} + + restore-cursor@5.1.0: + resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} + engines: {node: '>=18'} + + rfdc@1.4.1: + resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} + + 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'} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + seq-queue@0.0.5: + resolution: {integrity: sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + simple-swizzle@0.2.2: + resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} + + slice-ansi@5.0.0: + resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} + engines: {node: '>=12'} + + slice-ansi@7.1.0: + resolution: {integrity: sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==} + engines: {node: '>=18'} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + sqlstring@2.3.3: + resolution: {integrity: sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==} + engines: {node: '>= 0.6'} + + stack-trace@0.0.10: + resolution: {integrity: sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==} + + string-argv@0.3.2: + resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} + engines: {node: '>=0.6.19'} + + string-width@7.2.0: + resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} + engines: {node: '>=18'} + + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + + strip-ansi@3.0.1: + resolution: {integrity: sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==} + engines: {node: '>=0.10.0'} + + strip-ansi@7.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + engines: {node: '>=12'} + + strip-final-newline@3.0.0: + resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} + engines: {node: '>=12'} + + supports-color@2.0.0: + resolution: {integrity: sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==} + engines: {node: '>=0.8.0'} + + text-hex@1.0.0: + resolution: {integrity: sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + tough-cookie@4.1.4: + resolution: {integrity: sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==} + engines: {node: '>=6'} + + triple-beam@1.4.1: + resolution: {integrity: sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==} + engines: {node: '>= 14.0.0'} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + types-mediawiki@1.9.1: + resolution: {integrity: sha512-RgYOy0xlWauOwTv3dIJU9FEetjf8+54fHzAL614rseYC3ZrPP086OxIqaG9EfLM7FqqZd6yoPHdEfrFRpLQ4Fg==} + + typescript@5.7.2: + resolution: {integrity: sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==} + engines: {node: '>=14.17'} + hasBin: true + + undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + + undici-types@6.20.0: + resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} + + universalify@0.2.0: + resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} + engines: {node: '>= 4.0.0'} + + url-parse@1.5.10: + resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + + vue@3.3.9: + resolution: {integrity: sha512-sy5sLCTR8m6tvUk1/ijri3Yqzgpdsmxgj6n6yl7GXXCXqVbmW2RCXe9atE4cEI6Iv7L89v5f35fZRRr5dChP9w==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + winston-transport@4.9.0: + resolution: {integrity: sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==} + engines: {node: '>= 12.0.0'} + + winston@3.17.0: + resolution: {integrity: sha512-DLiFIXYC5fMPxaRg832S6F5mJYvePtmO5G9v9IgUFPhXm9/GkXarH/TUrBAVzhTCzAj9anE/+GjrgXp/54nOgw==} + engines: {node: '>= 12.0.0'} + + wrap-ansi@9.0.0: + resolution: {integrity: sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==} + engines: {node: '>=18'} + + yaml@2.6.1: + resolution: {integrity: sha512-7r0XPzioN/Q9kXBro/XPnA6kznR73DHq+GXh5ON7ZozRO6aMjbmiBuKste2wslTFkC5d1dw0GooOCepZXJ2SAg==} + engines: {node: '>= 14'} + hasBin: true + +snapshots: + + '@babel/helper-string-parser@7.25.9': {} + + '@babel/helper-validator-identifier@7.25.9': {} + + '@babel/parser@7.26.3': + dependencies: + '@babel/types': 7.26.3 + + '@babel/types@7.26.3': + dependencies: + '@babel/helper-string-parser': 7.25.9 + '@babel/helper-validator-identifier': 7.25.9 + + '@colors/colors@1.6.0': {} + + '@commander-js/extra-typings@13.0.0(commander@13.0.0)': + dependencies: + commander: 13.0.0 + + '@dabh/diagnostics@2.0.3': + dependencies: + colorspace: 1.1.4 + enabled: 2.0.0 + kuler: 2.0.0 + + '@jridgewell/sourcemap-codec@1.5.0': {} + + '@noble/hashes@1.7.0': {} + + '@oven/bun-darwin-aarch64@1.1.42': + optional: true + + '@oven/bun-darwin-x64-baseline@1.1.42': + optional: true + + '@oven/bun-darwin-x64@1.1.42': + optional: true + + '@oven/bun-linux-aarch64-musl@1.1.42': + optional: true + + '@oven/bun-linux-aarch64@1.1.42': + optional: true + + '@oven/bun-linux-x64-baseline@1.1.42': + optional: true + + '@oven/bun-linux-x64-musl-baseline@1.1.42': + optional: true + + '@oven/bun-linux-x64-musl@1.1.42': + optional: true + + '@oven/bun-linux-x64@1.1.42': + optional: true + + '@oven/bun-windows-x64-baseline@1.1.42': + optional: true + + '@oven/bun-windows-x64@1.1.42': + optional: true + + '@paralleldrive/cuid2@2.2.2': + dependencies: + '@noble/hashes': 1.7.0 + + '@types/body-parser@1.19.5': + dependencies: + '@types/connect': 3.4.38 + '@types/node': 22.10.5 + + '@types/bun@1.1.14': + dependencies: + bun-types: 1.1.37 + + '@types/connect@3.4.38': + dependencies: + '@types/node': 22.10.5 + + '@types/cors@2.8.17': + dependencies: + '@types/node': 22.10.5 + + '@types/express-serve-static-core@5.0.3': + dependencies: + '@types/node': 22.10.5 + '@types/qs': 6.9.17 + '@types/range-parser': 1.2.7 + '@types/send': 0.17.4 + + '@types/express@5.0.0': + dependencies: + '@types/body-parser': 1.19.5 + '@types/express-serve-static-core': 5.0.3 + '@types/qs': 6.9.17 + '@types/serve-static': 1.15.7 + + '@types/http-errors@2.0.4': {} + + '@types/jquery@3.5.32': + dependencies: + '@types/sizzle': 2.3.9 + + '@types/js-yaml@4.0.9': {} + + '@types/mime@1.3.5': {} + + '@types/node@14.18.63': {} + + '@types/node@18.19.69': + dependencies: + undici-types: 5.26.5 + + '@types/node@20.12.14': + dependencies: + undici-types: 5.26.5 + + '@types/node@22.10.5': + dependencies: + undici-types: 6.20.0 + + '@types/oojs-ui@0.46.4': + dependencies: + '@types/jquery': 3.5.32 + '@types/oojs': 7.0.7 + + '@types/oojs@7.0.7': {} + + '@types/qs@6.9.17': {} + + '@types/range-parser@1.2.7': {} + + '@types/send@0.17.4': + dependencies: + '@types/mime': 1.3.5 + '@types/node': 22.10.5 + + '@types/serve-static@1.15.7': + dependencies: + '@types/http-errors': 2.0.4 + '@types/node': 22.10.5 + '@types/send': 0.17.4 + + '@types/sizzle@2.3.9': {} + + '@types/ssh2@1.15.1': + dependencies: + '@types/node': 18.19.69 + + '@types/tough-cookie@4.0.5': {} + + '@types/triple-beam@1.3.5': {} + + '@types/ws@8.5.13': + dependencies: + '@types/node': 22.10.5 + + '@vue/compiler-core@3.3.9': + dependencies: + '@babel/parser': 7.26.3 + '@vue/shared': 3.3.9 + estree-walker: 2.0.2 + source-map-js: 1.2.1 + + '@vue/compiler-dom@3.3.9': + dependencies: + '@vue/compiler-core': 3.3.9 + '@vue/shared': 3.3.9 + + '@vue/compiler-sfc@3.3.9': + dependencies: + '@babel/parser': 7.26.3 + '@vue/compiler-core': 3.3.9 + '@vue/compiler-dom': 3.3.9 + '@vue/compiler-ssr': 3.3.9 + '@vue/reactivity-transform': 3.3.9 + '@vue/shared': 3.3.9 + estree-walker: 2.0.2 + magic-string: 0.30.17 + postcss: 8.4.49 + source-map-js: 1.2.1 + + '@vue/compiler-ssr@3.3.9': + dependencies: + '@vue/compiler-dom': 3.3.9 + '@vue/shared': 3.3.9 + + '@vue/reactivity-transform@3.3.9': + dependencies: + '@babel/parser': 7.26.3 + '@vue/compiler-core': 3.3.9 + '@vue/shared': 3.3.9 + estree-walker: 2.0.2 + magic-string: 0.30.17 + + '@vue/reactivity@3.3.9': + dependencies: + '@vue/shared': 3.3.9 + + '@vue/runtime-core@3.3.9': + dependencies: + '@vue/reactivity': 3.3.9 + '@vue/shared': 3.3.9 + + '@vue/runtime-dom@3.3.9': + dependencies: + '@vue/runtime-core': 3.3.9 + '@vue/shared': 3.3.9 + csstype: 3.1.3 + + '@vue/server-renderer@3.3.9(vue@3.3.9(typescript@5.7.2))': + dependencies: + '@vue/compiler-ssr': 3.3.9 + '@vue/shared': 3.3.9 + vue: 3.3.9(typescript@5.7.2) + + '@vue/shared@3.3.9': {} + + ansi-escapes@7.0.0: + dependencies: + environment: 1.1.0 + + ansi-regex@2.1.1: {} + + ansi-regex@6.1.0: {} + + ansi-styles@2.2.1: {} + + ansi-styles@6.2.1: {} + + async@3.2.6: {} + + asynckit@0.4.0: {} + + aws-ssl-profiles@1.1.2: {} + + axios-cookiejar-support@1.0.1(@types/tough-cookie@4.0.5)(axios@0.25.0)(tough-cookie@4.1.4): + dependencies: + '@types/tough-cookie': 4.0.5 + axios: 0.25.0 + is-redirect: 1.0.0 + pify: 5.0.0 + tough-cookie: 4.1.4 + + axios@0.25.0: + dependencies: + follow-redirects: 1.15.9 + transitivePeerDependencies: + - debug + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + bun-types@1.1.37: + dependencies: + '@types/node': 20.12.14 + '@types/ws': 8.5.13 + + bun@1.1.42: + optionalDependencies: + '@oven/bun-darwin-aarch64': 1.1.42 + '@oven/bun-darwin-x64': 1.1.42 + '@oven/bun-darwin-x64-baseline': 1.1.42 + '@oven/bun-linux-aarch64': 1.1.42 + '@oven/bun-linux-aarch64-musl': 1.1.42 + '@oven/bun-linux-x64': 1.1.42 + '@oven/bun-linux-x64-baseline': 1.1.42 + '@oven/bun-linux-x64-musl': 1.1.42 + '@oven/bun-linux-x64-musl-baseline': 1.1.42 + '@oven/bun-windows-x64': 1.1.42 + '@oven/bun-windows-x64-baseline': 1.1.42 + + chalk@1.1.3: + dependencies: + ansi-styles: 2.2.1 + escape-string-regexp: 1.0.5 + has-ansi: 2.0.0 + strip-ansi: 3.0.1 + supports-color: 2.0.0 + + chalk@5.4.1: {} + + cli-cursor@5.0.0: + dependencies: + restore-cursor: 5.1.0 + + cli-truncate@4.0.0: + dependencies: + slice-ansi: 5.0.0 + string-width: 7.2.0 + + color-convert@1.9.3: + dependencies: + color-name: 1.1.3 + + color-name@1.1.3: {} + + color-name@1.1.4: {} + + color-string@1.9.1: + dependencies: + color-name: 1.1.4 + simple-swizzle: 0.2.2 + + color@3.2.1: + dependencies: + color-convert: 1.9.3 + color-string: 1.9.1 + + colorette@2.0.20: {} + + colorspace@1.1.4: + dependencies: + color: 3.2.1 + text-hex: 1.0.0 + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + commander@12.1.0: {} + + commander@13.0.0: {} + + cors@2.8.5: + dependencies: + object-assign: 4.1.1 + vary: 1.1.2 + + croner@9.0.0: {} + + cronstrue@2.52.0: {} + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + csstype@3.1.3: {} + + debug@4.4.0: + dependencies: + ms: 2.1.3 + + delayed-stream@1.0.0: {} + + denque@2.1.0: {} + + emoji-regex@10.4.0: {} + + enabled@2.0.0: {} + + environment@1.1.0: {} + + escape-string-regexp@1.0.5: {} + + estree-walker@2.0.2: {} + + eventemitter3@5.0.1: {} + + execa@8.0.1: + dependencies: + cross-spawn: 7.0.6 + get-stream: 8.0.1 + human-signals: 5.0.0 + is-stream: 3.0.0 + merge-stream: 2.0.0 + npm-run-path: 5.3.0 + onetime: 6.0.0 + signal-exit: 4.1.0 + strip-final-newline: 3.0.0 + + fecha@4.2.3: {} + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + fn.name@1.1.0: {} + + follow-redirects@1.15.9: {} + + form-data@4.0.1: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + + generate-function@2.3.1: + dependencies: + is-property: 1.0.2 + + get-east-asian-width@1.3.0: {} + + get-stream@8.0.1: {} + + has-ansi@2.0.0: + dependencies: + ansi-regex: 2.1.1 + + human-signals@5.0.0: {} + + husky@9.1.7: {} + + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + + inherits@2.0.4: {} + + is-arrayish@0.3.2: {} + + is-fullwidth-code-point@4.0.0: {} + + is-fullwidth-code-point@5.0.0: + dependencies: + get-east-asian-width: 1.3.0 + + is-number@7.0.0: {} + + is-property@1.0.2: {} + + is-redirect@1.0.0: {} + + is-stream@2.0.1: {} + + is-stream@3.0.0: {} + + isexe@2.0.0: {} + + kuler@2.0.0: {} + + lilconfig@3.1.3: {} + + lint-staged@15.3.0: + dependencies: + chalk: 5.4.1 + commander: 12.1.0 + debug: 4.4.0 + execa: 8.0.1 + lilconfig: 3.1.3 + listr2: 8.2.5 + micromatch: 4.0.8 + pidtree: 0.6.0 + string-argv: 0.3.2 + yaml: 2.6.1 + transitivePeerDependencies: + - supports-color + + listr2@8.2.5: + dependencies: + cli-truncate: 4.0.0 + colorette: 2.0.20 + eventemitter3: 5.0.1 + log-update: 6.1.0 + rfdc: 1.4.1 + wrap-ansi: 9.0.0 + + log-update@6.1.0: + dependencies: + ansi-escapes: 7.0.0 + cli-cursor: 5.0.0 + slice-ansi: 7.1.0 + strip-ansi: 7.1.0 + wrap-ansi: 9.0.0 + + logform@2.7.0: + dependencies: + '@colors/colors': 1.6.0 + '@types/triple-beam': 1.3.5 + fecha: 4.2.3 + ms: 2.1.3 + safe-stable-stringify: 2.5.0 + triple-beam: 1.4.1 + + long@5.2.3: {} + + lru-cache@7.18.3: {} + + lru.min@1.1.1: {} + + magic-string@0.30.17: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + + merge-stream@2.0.0: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + mimic-fn@4.0.0: {} + + mimic-function@5.0.1: {} + + moment@2.30.1: {} + + ms@2.1.3: {} + + mwn@2.0.4(typescript@5.7.2): + dependencies: + '@types/node': 14.18.63 + '@types/tough-cookie': 4.0.5 + axios: 0.25.0 + axios-cookiejar-support: 1.0.1(@types/tough-cookie@4.0.5)(axios@0.25.0)(tough-cookie@4.1.4) + chalk: 1.1.3 + form-data: 4.0.1 + oauth-1.0a: 2.2.6 + tough-cookie: 4.1.4 + types-mediawiki: 1.9.1(typescript@5.7.2) + transitivePeerDependencies: + - debug + - typescript + + mysql2@3.12.0: + dependencies: + aws-ssl-profiles: 1.1.2 + denque: 2.1.0 + generate-function: 2.3.1 + iconv-lite: 0.6.3 + long: 5.2.3 + lru.min: 1.1.1 + named-placeholders: 1.1.3 + seq-queue: 0.0.5 + sqlstring: 2.3.3 + + named-placeholders@1.1.3: + dependencies: + lru-cache: 7.18.3 + + nanoid@3.3.8: {} + + npm-run-path@5.3.0: + dependencies: + path-key: 4.0.0 + + oauth-1.0a@2.2.6: {} + + object-assign@4.1.1: {} + + one-time@1.0.0: + dependencies: + fn.name: 1.1.0 + + onetime@6.0.0: + dependencies: + mimic-fn: 4.0.0 + + onetime@7.0.0: + dependencies: + mimic-function: 5.0.1 + + path-key@3.1.1: {} + + path-key@4.0.0: {} + + picocolors@1.1.1: {} + + picomatch@2.3.1: {} + + pidtree@0.6.0: {} + + pify@5.0.0: {} + + postcss@8.4.49: + dependencies: + nanoid: 3.3.8 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prettier@3.4.2: {} + + psl@1.15.0: + dependencies: + punycode: 2.3.1 + + punycode@2.3.1: {} + + querystringify@2.2.0: {} + + readable-stream@3.6.2: + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + + requires-port@1.0.0: {} + + restore-cursor@5.1.0: + dependencies: + onetime: 7.0.0 + signal-exit: 4.1.0 + + rfdc@1.4.1: {} + + safe-buffer@5.2.1: {} + + safe-stable-stringify@2.5.0: {} + + safer-buffer@2.1.2: {} + + seq-queue@0.0.5: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + signal-exit@4.1.0: {} + + simple-swizzle@0.2.2: + dependencies: + is-arrayish: 0.3.2 + + slice-ansi@5.0.0: + dependencies: + ansi-styles: 6.2.1 + is-fullwidth-code-point: 4.0.0 + + slice-ansi@7.1.0: + dependencies: + ansi-styles: 6.2.1 + is-fullwidth-code-point: 5.0.0 + + source-map-js@1.2.1: {} + + sqlstring@2.3.3: {} + + stack-trace@0.0.10: {} + + string-argv@0.3.2: {} + + string-width@7.2.0: + dependencies: + emoji-regex: 10.4.0 + get-east-asian-width: 1.3.0 + strip-ansi: 7.1.0 + + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + + strip-ansi@3.0.1: + dependencies: + ansi-regex: 2.1.1 + + strip-ansi@7.1.0: + dependencies: + ansi-regex: 6.1.0 + + strip-final-newline@3.0.0: {} + + supports-color@2.0.0: {} + + text-hex@1.0.0: {} + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + tough-cookie@4.1.4: + dependencies: + psl: 1.15.0 + punycode: 2.3.1 + universalify: 0.2.0 + url-parse: 1.5.10 + + triple-beam@1.4.1: {} + + tslib@2.8.1: {} + + types-mediawiki@1.9.1(typescript@5.7.2): + dependencies: + '@types/jquery': 3.5.32 + '@types/oojs-ui': 0.46.4 + vue: 3.3.9(typescript@5.7.2) + transitivePeerDependencies: + - typescript + + typescript@5.7.2: {} + + undici-types@5.26.5: {} + + undici-types@6.20.0: {} + + universalify@0.2.0: {} + + url-parse@1.5.10: + dependencies: + querystringify: 2.2.0 + requires-port: 1.0.0 + + util-deprecate@1.0.2: {} + + vary@1.1.2: {} + + vue@3.3.9(typescript@5.7.2): + dependencies: + '@vue/compiler-dom': 3.3.9 + '@vue/compiler-sfc': 3.3.9 + '@vue/runtime-dom': 3.3.9 + '@vue/server-renderer': 3.3.9(vue@3.3.9(typescript@5.7.2)) + '@vue/shared': 3.3.9 + optionalDependencies: + typescript: 5.7.2 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + winston-transport@4.9.0: + dependencies: + logform: 2.7.0 + readable-stream: 3.6.2 + triple-beam: 1.4.1 + + winston@3.17.0: + dependencies: + '@colors/colors': 1.6.0 + '@dabh/diagnostics': 2.0.3 + async: 3.2.6 + is-stream: 2.0.1 + logform: 2.7.0 + one-time: 1.0.0 + readable-stream: 3.6.2 + safe-stable-stringify: 2.5.0 + stack-trace: 0.0.10 + triple-beam: 1.4.1 + winston-transport: 4.9.0 + + wrap-ansi@9.0.0: + dependencies: + ansi-styles: 6.2.1 + string-width: 7.2.0 + strip-ansi: 7.1.0 + + yaml@2.6.1: {} diff --git a/scripts/afccat.ts b/scripts/afccat.ts index 575bca8..e7fa050 100644 --- a/scripts/afccat.ts +++ b/scripts/afccat.ts @@ -1,4 +1,4 @@ -import { Bot } from '../core/bot'; +import { Bot } from '@core/bot'; import { Command } from '@commander-js/extra-typings'; export default class Afccat extends Bot { @@ -41,11 +41,11 @@ export default class Afccat extends Bot { .filter((c, i, a) => a.indexOf(c) === i); if (isNaN(categories.length) || categories.length === 0) { - this.log("[I] No categories to create."); + this.log.info("No categories to create."); process.exit(0); } - this.log(`[D] categories ${JSON.stringify(categories)}`); + this.log.info(`Creating categories for categories ${JSON.stringify(categories)}`); this.bot .batchOperation( @@ -54,8 +54,8 @@ export default class Afccat extends Bot { if (!page) return Promise.reject(); return new Promise((resolve, reject) => { if (this.cli.opts().dryRun) { - this.log("[W] Dry run, not creating category: " + page); - resolve("dryrun"); + this.log.warn("Dry run, not creating category: " + page); + return resolve("dryrun"); } if ( page.indexOf("หมวดหมู่:ฉบับร่างเรียงตามวันที่ส่ง/") === -1 || @@ -74,7 +74,7 @@ export default class Afccat extends Bot { ) .then(resolve) .catch((error) => { - this.log(`[E] ${error.message} ${page}`); + this.log.error(`${error.message} ${page}`); reject(error); }); }); @@ -83,10 +83,10 @@ export default class Afccat extends Bot { 1 ) .then(() => { - this.log("[I] done"); + this.log.info("done"); }) .catch((err) => { - this.log(`[E] ${err.message}`); + this.log.error(`${err.message}`); }); } } diff --git a/scripts/database-report/index.ts b/scripts/database-report/index.ts new file mode 100644 index 0000000..4eac63e --- /dev/null +++ b/scripts/database-report/index.ts @@ -0,0 +1,16 @@ +import { Bot } from '@core/bot'; + +export class DatabaseReportBot extends Bot { + reportPage: string = "" + reportDescription: string = "" + reportFrequency: string = '@weekly' + reportFrequencyText: string = 'สัปดาห์ละครั้ง' + + get pageDescription() { + return `${this.reportDescription} รายงานนี้อัปเดต${this.reportFrequencyText} อัปเดตล่าสุดเมื่อ {{subst:#timel:r}}\n\n` + } + + async run() { + console.log('Generating database report...') + } +} \ No newline at end of file diff --git a/scripts/database-report/long-stubs.ts b/scripts/database-report/long-stubs.ts new file mode 100644 index 0000000..9fa032c --- /dev/null +++ b/scripts/database-report/long-stubs.ts @@ -0,0 +1,10 @@ +import { DatabaseReportBot } from '@scripts/database-report'; + +export default class LongStubs extends DatabaseReportBot { + reportPage = "บทความโครงขนาดยาว" + reportDescription = 'รายการที่มีแม่แบบโครงแต่มีขนาดยาว (จำกัดจำนวน 1000 อันดับแรก)' + reportFrequency = '@weekly' // cron schedule + reportFrequencyText = 'สัปดาห์ละครั้ง' + + +} \ No newline at end of file diff --git a/scripts/login.ts b/scripts/login.ts index 14379fc..8deab74 100644 --- a/scripts/login.ts +++ b/scripts/login.ts @@ -1,5 +1,5 @@ import chalk from 'chalk'; -import { Bot } from '../core/bot' +import { Bot } from '@core/bot' import { version } from '../package.json' import moment from 'moment'; diff --git a/scripts/topedits.ts b/scripts/topedits.ts index 20090f6..8d5118b 100644 --- a/scripts/topedits.ts +++ b/scripts/topedits.ts @@ -1,5 +1,5 @@ import { Command, Option } from '@commander-js/extra-typings'; -import { Bot } from '../core/bot'; +import { Bot } from '@core/bot'; interface UserEdit { user_name: string @@ -41,9 +41,8 @@ export default class TopEdits extends Bot { } async getTopEdits() { - console.debug('Getting top edits') - console.time('getTopEdits') - let start = Date.now() + this.log.info('Getting top edits') + this.log.profile('getTopEdits') const results = await this.replica.query(` /* topedits.ts SLOW_OK */ SELECT @@ -54,7 +53,7 @@ export default class TopEdits extends Bot { ORDER BY user_editcount DESC LIMIT ${this.options.maxQuerySize}; `) - console.timeEnd('getTopEdits') + this.log.profile('getTopEdits') if (!results) { throw new Error('Query returned no results'); } @@ -66,8 +65,8 @@ export default class TopEdits extends Bot { } async getBotUserList() { - console.debug('Getting bot user list') - console.time('getBotUserList') + this.log.info('Getting bot user list') + this.log.profile('getBotUserList') const results = await this.replica.query(` /* editcount.rs SLOW_OK */ SELECT @@ -77,7 +76,7 @@ export default class TopEdits extends Bot { ON user_id = ug_user WHERE ug_group = 'bot'; `) - console.timeEnd('getBotUserList') + this.log.profile('getBotUserList') if (!results) { throw new Error('Query returned no results'); } @@ -86,10 +85,10 @@ export default class TopEdits extends Bot { } async getUserAnonymousList() { - console.debug('Getting anonymous user list') - console.time('getUserAnonymousList') + this.log.info('Getting anonymous user list') + this.log.profile('getUserAnonymousList') const page = await this.bot.read(this.options.anonymousList) - console.timeEnd('getUserAnonymousList') + this.log.profile('getUserAnonymousList') if (!page.revisions) { throw new Error('Failed to get page content') } @@ -98,7 +97,7 @@ export default class TopEdits extends Bot { } async getUserGroup(user: string) { - console.time('getUserGroup ' + user) + this.log.profile('getUserGroup ' + user, { level: 'debug' }) const results = await this.replica.query(` /* topedits.rs SLOW_OK */ SELECT @@ -108,7 +107,7 @@ export default class TopEdits extends Bot { ON user_id = ug_user WHERE user_name = ?; `, [user]) - console.timeEnd('getUserGroup ' + user) + this.log.profile('getUserGroup ' + user, { level: 'debug' }) if (!results) { throw new Error('Query returned no results'); } @@ -118,8 +117,8 @@ export default class TopEdits extends Bot { async getActiveUsers() { let activeusers: string[] = []; - console.debug('Getting active users') - console.time('getActiveUsers') + this.log.info('Getting active users') + this.log.profile('getActiveUsers') for await (let json of this.bot.continuedQueryGen({ action: "query", list: "allusers", @@ -129,7 +128,7 @@ export default class TopEdits extends Bot { let users = json.query?.allusers.map((user: { name: string }) => user.name) as string[]; activeusers = activeusers.concat(users); } - console.timeEnd('getActiveUsers') + this.log.profile('getActiveUsers') return activeusers } @@ -180,8 +179,7 @@ export default class TopEdits extends Bot { const withBotContent = this.createTable(userList, this.options.listTop) if (this.cli.opts().dryRun) { - console.log('Dry run enabled, skipping edit') - console.log('No bot content:') + this.log.warn('Dry run enabled, skipping edit') const noBotRead = (await this.bot.read(this.options.targetPage.noBot)).revisions?.[0].content if (!noBotRead) { throw new Error('Failed to get page content') @@ -189,7 +187,6 @@ export default class TopEdits extends Bot { console.table({ noBotContent: this.processListPageContent(noBotRead, noBotContent), }) - console.log('With bot content:') const withBotRead = (await this.bot.read(this.options.targetPage.withBot)).revisions?.[0].content if (!withBotRead) { throw new Error('Failed to get page content') @@ -223,8 +220,8 @@ export default class TopEdits extends Bot { let userList: UserEdit[] = [] let noBotCount = 0 - console.log('Processing top edits') - console.time('processTopEdits') + this.log.info('Processing top edits') + this.log.profile('processTopEdits') for (let user of topEdits) { const userGroup = await this.getUserGroup(user.user_name) userList.push({ @@ -241,9 +238,8 @@ export default class TopEdits extends Bot { noBotCount++ } } - console.timeEnd('processTopEdits') - console.log('Saving to wiki') + this.log.profile('processTopEdits') + this.log.info('Saving to wiki') await this.saveToWiki(userList) - await this.replica.end() } } diff --git a/tsconfig.json b/tsconfig.json index 238655f..948b2fa 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,27 +1,35 @@ { "compilerOptions": { // Enable latest features - "lib": ["ESNext", "DOM"], + "lib": [ + "ESNext", + "DOM" + ], "target": "ESNext", "module": "ESNext", "moduleDetection": "force", "jsx": "react-jsx", "allowJs": true, - // Bundler mode "moduleResolution": "bundler", "allowImportingTsExtensions": true, "verbatimModuleSyntax": true, "noEmit": true, - // Best practices "strict": true, "skipLibCheck": true, "noFallthroughCasesInSwitch": true, - // Some stricter flags (disabled by default) "noUnusedLocals": false, "noUnusedParameters": false, - "noPropertyAccessFromIndexSignature": false + "noPropertyAccessFromIndexSignature": false, + "paths": { + "@core/*": [ + "./core/*" + ], + "@scripts/*": [ + "./scripts/*" + ], + } } -} +} \ No newline at end of file