diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..660fe15 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,9 @@ +{ + "useTabs": false, + "tabWidth": 2, + "printWidth": 100, + "singleQuote": true, + "trailingComma": "all", + "bracketSpacing": true, + "semi": false +} diff --git a/eslint.config.mjs b/eslint.config.mjs index f40dc2b..120fecb 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,4 +1,5 @@ import neostandard from 'neostandard' +import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended' /** 尾随逗号 */ const commaDangle = (val) => { @@ -33,6 +34,9 @@ const options = neostandard({ ts: true, ignores, globals: ['logger'], + plugins: { + ...eslintPluginPrettierRecommended.plugins, + }, }).map(commaDangle) export default options diff --git a/package.json b/package.json index f9a31c4..158bd5a 100644 --- a/package.json +++ b/package.json @@ -5,12 +5,14 @@ "main": "", "type": "module", "scripts": { - "dev:": "cd packages/core && pnpm run dev" + "dev": "cd packages/core && pnpm run dev" }, "devDependencies": { "@types/node": "^22.5.0", "eslint": "^9.12.0", + "eslint-plugin-prettier": "^5.2.2", "neostandard": "^0.11.6", + "prettier": "^3.4.2", "sort-json": "^2.0.1", "sort-package-json": "^2.10.0", "tsup": "^8.3.5", @@ -23,4 +25,4 @@ "keywords": [], "author": "shijin", "license": "MIT" -} \ No newline at end of file +} diff --git a/packages/core/src/server/api/console.ts b/packages/core/src/server/api/console.ts index 4602f48..b221fa8 100644 --- a/packages/core/src/server/api/console.ts +++ b/packages/core/src/server/api/console.ts @@ -6,6 +6,13 @@ import { adapter } from '@/utils/config/adapter' import { isLocalRequest } from '@/utils/system/ip' import type { RequestHandler } from 'express' +import { + createBadRequestResponse, + createForbiddenResponse, + createNotFoundResponse, + createPayloadTooLargeResponse, + createServerErrorResponse, +} from '../utils/response' /** 允许的文件类型及其对应的 Content-Type */ const ALLOWED_TYPES = { @@ -36,38 +43,32 @@ const consoleRouter: RequestHandler = async (req, res) => { url = url.split('/').pop() || '' if (!url) { - res.status(400).json({ error: '无效的请求', message: '文件名不能为空' }) - return + return createBadRequestResponse(res, '文件名不能为空') } /** 防止路径穿越 */ if (url.includes('..') || url.includes('~') || !url.match(/^[a-zA-Z0-9-_.]+$/)) { - res.status(403).json({ error: '禁止访问', message: '非法请求' }) - return + return createForbiddenResponse(res, '非法请求') } const ext = path.extname(url).toLowerCase() if (!ALLOWED_TYPES[ext as keyof typeof ALLOWED_TYPES]) { - res.status(403).json({ error: '禁止访问', message: '不支持的文件类型' }) - return + return createBadRequestResponse(res, '不支持的文件类型') } const isLocal = await isLocalRequest(req) if (cfg.console.isLocal) { if (!isLocal) { - res.status(403).json({ error: '禁止访问', message: '无效的请求' }) - return + return createForbiddenResponse(res, '非法请求') } } else { if (!cfg.console.token) { - res.status(500).json({ error: '配置错误', message: '缺少 token 配置' }) - return + return createServerErrorResponse(res, '缺少 token 配置') } const token = req.query.token if (!token || token !== cfg.console.token) { - res.status(403).json({ error: '禁止访问', message: '无效的 token' }) - return + return createForbiddenResponse(res, '无效的 token') } } @@ -76,18 +77,15 @@ const consoleRouter: RequestHandler = async (req, res) => { try { /** 组合路径之后 判断一下文件是否处于 consolePath 目录下 */ if (!file.startsWith(consolePath)) { - res.status(403).json({ error: '禁止访问', message: '非法请求' }) - return + return createForbiddenResponse(res, '非法请求') } const stats = await fs.stat(file) if (stats.size > MAX_FILE_SIZE) { - res.status(413).json({ error: '文件过大', message: '文件大小超过限制' }) - return + return createPayloadTooLargeResponse(res, '文件过大') } } catch { - res.status(404).json({ error: '文件不存在', message: '文件不存在' }) - return + return createNotFoundResponse(res, '文件不存在') } const data = await fs.readFile(file) @@ -97,7 +95,7 @@ const consoleRouter: RequestHandler = async (req, res) => { res.send(data) } catch (error) { console.error('Console router error:', error) - res.status(500).json({ error: '内部错误', message: '服务器错误' }) + return createServerErrorResponse(res, '服务器错误') } } diff --git a/packages/core/src/server/api/exit.ts b/packages/core/src/server/api/exit.ts index c4c7408..f2ba585 100644 --- a/packages/core/src/server/api/exit.ts +++ b/packages/core/src/server/api/exit.ts @@ -1,15 +1,10 @@ import { router } from './router' -import { auth } from '../auth' import type { RequestHandler } from 'express' +import { createSuccessResponse } from '../utils/response' -const exitRouter: RequestHandler = async (req, res) => { - if (!auth.getAuth(req)) { - res.status(401).json({ message: '无效的token' }) - return - } - +const exitRouter: RequestHandler = async (_req, res) => { logger.mark('收到退出请求,正在退出...') - res.json({ message: '退出成功' }) + createSuccessResponse(res, null, '退出成功') const { processExit } = await import('@/core/internal/process') await processExit(0) } diff --git a/packages/core/src/server/api/web/file.ts b/packages/core/src/server/api/file.ts similarity index 73% rename from packages/core/src/server/api/web/file.ts rename to packages/core/src/server/api/file.ts index 1be2fbf..75ff987 100644 --- a/packages/core/src/server/api/web/file.ts +++ b/packages/core/src/server/api/file.ts @@ -1,18 +1,10 @@ import { router } from './router' -import { auth } from '../../auth' import { setYaml, getYaml } from '@/utils/config/config' import type { RequestHandler } from 'express' import type { FileList } from '@/types/config' +import { createSuccessResponse } from '../utils/response' -const list: FileList[] = [ - 'adapter', - 'config', - 'groups', - 'pm2', - 'privates', - 'redis', - 'render', -] +const list: FileList[] = ['adapter', 'config', 'groups', 'pm2', 'privates', 'redis', 'render'] const nameMap = { adapter: '适配器配置', @@ -29,19 +21,14 @@ const nameMap = { * @param req 请求 * @param res 响应 */ -const fileRouter: RequestHandler = async (req, res) => { - if (!auth.getAuth(req)) { - res.status(401).json({ message: '无效的token' }) - return - } - +const fileRouter: RequestHandler = async (_req, res) => { // 组合文件列表 - const files = list.map(name => ({ + const files = list.map((name) => ({ name, title: nameMap[name], })) - res.json(files) + createSuccessResponse(res, files) } /** @@ -57,7 +44,7 @@ const setFileRouter: RequestHandler = async (req, res) => { } setYaml(name, data) - res.json({ message: '设置成功' }) + createSuccessResponse(res, null, '设置成功') } /** @@ -69,10 +56,10 @@ const getFileRouter: RequestHandler = async (req, res) => { const { name } = req.body if (!name || !list.includes(name)) { res.status(400).json({ message: '参数错误' }) - return + return createSuccessResponse(res, null, '获取成功') } - res.json(getYaml(name, 'user')) + createSuccessResponse(res, getYaml(name, 'user'), '获取成功') } router.get('/file', fileRouter) diff --git a/packages/core/src/server/api/index.ts b/packages/core/src/server/api/index.ts index 5342b95..f44b9ba 100644 --- a/packages/core/src/server/api/index.ts +++ b/packages/core/src/server/api/index.ts @@ -3,4 +3,5 @@ import './ping' import './root' import './console' import './restart' -import './web' +import './file' +import './login' diff --git a/packages/core/src/server/api/login.ts b/packages/core/src/server/api/login.ts new file mode 100644 index 0000000..d53165c --- /dev/null +++ b/packages/core/src/server/api/login.ts @@ -0,0 +1,9 @@ +import { createSuccessResponse } from '../utils/response' +import { router } from './router' +import type { RequestHandler } from 'express' + +const loginRouter: RequestHandler = async (_req, res) => { + createSuccessResponse(res, null, '登录成功') +} + +router.get('/login', loginRouter) diff --git a/packages/core/src/server/api/ping.ts b/packages/core/src/server/api/ping.ts index 7a1974d..516cb85 100644 --- a/packages/core/src/server/api/ping.ts +++ b/packages/core/src/server/api/ping.ts @@ -1,19 +1,18 @@ -import { auth } from '../auth' +import { createSuccessResponse } from '../utils/response' import { router } from './router' import type { RequestHandler } from 'express' -const pingRouter: RequestHandler = (req, res) => { - res.send({ - ping: 'pong', - }) +const pingRouter: RequestHandler = (_req, res) => { + createSuccessResponse( + res, + { + ping: 'pong', + }, + '成功', + ) } -const statusRouter: RequestHandler = (req, res) => { - if (!auth.getAuth(req)) { - res.status(401).json({ message: '无效的token' }) - return - } - +const statusRouter: RequestHandler = (_req, res) => { const data = { name: 'karin', pid: process.pid, @@ -25,7 +24,7 @@ const statusRouter: RequestHandler = (req, res) => { karin_runtime: process.env.RUNTIME, } - res.status(200).json(data) + createSuccessResponse(res, data, '成功') } router.get('/ping', pingRouter) diff --git a/packages/core/src/server/api/restart.ts b/packages/core/src/server/api/restart.ts index 1c88b70..35c71b8 100644 --- a/packages/core/src/server/api/restart.ts +++ b/packages/core/src/server/api/restart.ts @@ -1,15 +1,10 @@ import { router } from './router' -import { auth } from '../auth' import { restartDirect } from '@/utils/system/restart' import type { RequestHandler } from 'express' +import { createSuccessResponse } from '../utils/response' -const restartRouter: RequestHandler = async (req, res) => { - if (!auth.getAuth(req)) { - res.status(401).json({ message: '无效的token' }) - return - } - - res.status(200).end() +const restartRouter: RequestHandler = async (_req, res) => { + createSuccessResponse(res, null, '指令发送成功') restartDirect() } diff --git a/packages/core/src/server/api/root.ts b/packages/core/src/server/api/root.ts index 0222cf9..8a3f540 100644 --- a/packages/core/src/server/api/root.ts +++ b/packages/core/src/server/api/root.ts @@ -1,8 +1,6 @@ import { app } from '../app' +import { createSuccessResponse } from '../utils/response' -app.get('/', (req, res) => { - res.send({ - code: 200, - msg: '雪霁银妆素,桔高映琼枝。', - }) +app.get('/', (_req, res) => { + createSuccessResponse(res, null, '雪霁银妆素,桔高映琼枝。') }) diff --git a/packages/core/src/server/api/web/index.ts b/packages/core/src/server/api/web/index.ts deleted file mode 100644 index 7222725..0000000 --- a/packages/core/src/server/api/web/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -import './login' -import './file' diff --git a/packages/core/src/server/api/web/login.ts b/packages/core/src/server/api/web/login.ts deleted file mode 100644 index 5feea95..0000000 --- a/packages/core/src/server/api/web/login.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { router } from './router' -import { auth } from '../../auth' -import type { RequestHandler } from 'express' - -const loginRouter: RequestHandler = async (req, res) => { - if (!auth.getAuth(req)) { - res.status(401).json({ message: '无效的token' }) - return - } - - res.json({ message: '登录成功' }) -} - -router.get('/login', loginRouter) diff --git a/packages/core/src/server/api/web/router.ts b/packages/core/src/server/api/web/router.ts deleted file mode 100644 index b707438..0000000 --- a/packages/core/src/server/api/web/router.ts +++ /dev/null @@ -1,8 +0,0 @@ -import express from 'express' -import { Router } from 'express' - -/** - * karin-web 路由 - */ -export const router: Router = Router() -router.use(express.json()) diff --git a/packages/core/src/server/app.ts b/packages/core/src/server/app.ts index 638eb58..e01020b 100644 --- a/packages/core/src/server/app.ts +++ b/packages/core/src/server/app.ts @@ -2,21 +2,24 @@ import path from 'node:path' import express from 'express' import { createServer } from 'node:http' import { router } from './api/router' -import { router as webRouter } from './api/web/router' import { listeners } from '@/core/internal' import type { Express } from 'express' +import { authMiddleware } from './middleware' /** express 服务 */ export const app: Express = express() /** http 服务 */ export const server = createServer(app) +/** 中间件鉴权 */ +app.use(authMiddleware) + // TODO: WEB app.use('/web', express.static(path.join(process.cwd(), 'web'))) -app.use('/api/web', webRouter) +app.use('/web/*', express.static(path.join(process.cwd(), 'web'))) -app.use('/v1', router) +app.use('/api/v1', router) /** * 监听端口 diff --git a/packages/core/src/server/middleware.ts b/packages/core/src/server/middleware.ts new file mode 100644 index 0000000..51e7b0d --- /dev/null +++ b/packages/core/src/server/middleware.ts @@ -0,0 +1,17 @@ +import { Request, Response, NextFunction } from 'express' +import { auth } from './auth' + +export const authMiddleware = async (req: Request, res: Response, next: NextFunction) => { + if (req.path.startsWith('/api')) { + if (req.path === '/api/v1/ping' || req.path.startsWith('/api/v1/console')) { + next() + return + } + if (!auth.getAuth(req)) { + res.status(401).json({ message: '无效的token' }) + return + } + } + + next() +} diff --git a/packages/core/src/server/utils/response.ts b/packages/core/src/server/utils/response.ts new file mode 100644 index 0000000..71f712f --- /dev/null +++ b/packages/core/src/server/utils/response.ts @@ -0,0 +1,140 @@ +import { Response } from 'express' + +/** HTTP状态码 */ +export enum HTTPStatusCode { + OK = 200, + BadRequest = 400, + Unauthorized = 401, + Forbidden = 403, + NotFound = 404, + MethodNotAllowed = 405, + PayloadTooLarge = 413, + InternalServerError = 500, +} + +/** + * 创建响应 + * @param res 响应 + * @param code 状态码 + * @param data 数据 + * @param message 消息 + * @returns 响应 + * @template T 数据类型 + * @example createResponse(res, HTTPStatusCode.OK, { message: '成功' }) + * @example createResponse(res, HTTPStatusCode.BadRequest, { message: '参数错误' }) + * @example createResponse(res, HTTPStatusCode.InternalServerError, { message: '服务器错误' }) + */ +export const createResponse = (res: Response, code: HTTPStatusCode, data?: T, message = '') => { + res.status(code).json({ + code, + data, + message, + }) +} + +/** + * 创建成功响应 + * @param res 响应 + * @param data 数据 + * @param message 消息 + * @returns 响应 + * @template T 数据类型 + * @example createSuccessResponse(res, null, '成功') + * @example createSuccessResponse(res, data) + */ +export const createSuccessResponse = (res: Response, data?: T, message = '成功') => { + return createResponse(res, HTTPStatusCode.OK, data, message) +} + +/** + * 创建未鉴权响应 + * @param res 响应 + * @param message 消息 + * @returns 响应 + * @example createUnauthorizedResponse(res) + * @example createUnauthorizedResponse(res, '未授权') + * @example createUnauthorizedResponse(res, '登录已过期') + * @example createUnauthorizedResponse(res, '登录信息已失效') + */ +export const createUnauthorizedResponse = (res: Response, message = '未登录') => { + return createResponse(res, HTTPStatusCode.Unauthorized, null, message) +} + +/** + * 创建未找到响应 + * @param res 响应 + * @param message 消息 + * @returns 响应 + * @example createNotFoundResponse(res) + * @example createNotFoundResponse(res, '未找到') + * @example createNotFoundResponse(res, '数据不存在') + * @example createNotFoundResponse(res, '资源不存在') + */ +export const createNotFoundResponse = (res: Response, message = '未找到') => { + return createResponse(res, HTTPStatusCode.NotFound, null, message) +} + +/** + * 创建服务器错误响应 + * @param res 响应 + * @param message 消息 + * @returns 响应 + * @example createServerErrorResponse(res) + * @example createServerErrorResponse(res, '服务器错误') + * @example createServerErrorResponse(res, '系统错误') + * @example createServerErrorResponse(res, '未知错误') + */ +export const createServerErrorResponse = (res: Response, message = '服务器错误') => { + return createResponse(res, HTTPStatusCode.InternalServerError, null, message) +} + +/** + * 创建参数错误响应 + * @param res 响应 + * @param message 消息 + * @returns 响应 + * @example createBadRequestResponse(res) + * @example createBadRequestResponse(res, '参数错误') + * @example createBadRequestResponse(res, '请求参数错误') + * @example createBadRequestResponse(res, '参数不正确') + */ +export const createBadRequestResponse = (res: Response, message = '参数错误') => { + return createResponse(res, HTTPStatusCode.BadRequest, null, message) +} + +/** + * 创建请求过大响应 + * @param res 响应 + * @param message 消息 + * @returns 响应 + * @example createPayloadTooLargeResponse(res) + * @example createPayloadTooLargeResponse(res, '请求体过大') + */ +export const createPayloadTooLargeResponse = (res: Response, message = '请求体过大') => { + return createResponse(res, HTTPStatusCode.PayloadTooLarge, null, message) +} + +/** + * 创建方法不允许响应 + * @param res 响应 + * @param message 消息 + * @returns 响应 + * @example createMethodNotAllowedResponse(res) + */ +export const createMethodNotAllowedResponse = (res: Response, message = '方法不允许') => { + return createResponse(res, HTTPStatusCode.MethodNotAllowed, null, message) +} + +/** + * 创建禁止访问响应 + * @param res 响应 + * @param message 消息 + * @returns 响应 + * @example createForbiddenResponse(res) + * @example createForbiddenResponse(res, '禁止访问') + * @example createForbiddenResponse(res, '无权限访问') + * @example createForbiddenResponse(res, '权限不足') + */ +export const createForbiddenResponse = (res: Response, message = '禁止访问') => { + return createResponse(res, HTTPStatusCode.Forbidden, null, message) +} diff --git a/packages/core/src/utils/logger/logger.ts b/packages/core/src/utils/logger/logger.ts index e249721..29c36e7 100644 --- a/packages/core/src/utils/logger/logger.ts +++ b/packages/core/src/utils/logger/logger.ts @@ -4,7 +4,10 @@ import { logsPath } from '@/root' import log4js, { type Configuration } from 'log4js' import type { Logger, LoggerOptions } from '@/types/system' -if (!fs.existsSync(logsPath)) fs.mkdirSync(logsPath) +if (!fs.existsSync(logsPath)) + fs.mkdirSync(logsPath, { + recursive: true, + }) /** * 创建日志记录器 @@ -14,11 +17,7 @@ const initLogger = (options: LoggerOptions = {}) => { /** 如果有传参直接用 无传参走默认 */ if (options.config) return log4js.configure(options.config) - const { - level = 'info', - daysToKeep = 14, - maxLogSize = 0, - } = options.log4jsCfg || {} + const { level = 'info', daysToKeep = 14, maxLogSize = 0 } = options.log4jsCfg || {} const config: Configuration = { appenders: { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 54cdf32..dbce5ce 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -18,9 +18,15 @@ importers: eslint: specifier: ^9.12.0 version: 9.13.0 + eslint-plugin-prettier: + specifier: ^5.2.2 + version: 5.2.2(eslint@9.13.0)(prettier@3.4.2) neostandard: specifier: ^0.11.6 version: 0.11.7(eslint@9.13.0)(typescript@5.7.3) + prettier: + specifier: ^3.4.2 + version: 3.4.2 sort-json: specifier: ^2.0.1 version: 2.0.1 @@ -131,12 +137,6 @@ importers: specifier: ^0.12.0 version: 0.12.0(eslint@9.13.0)(typescript@5.7.3) - packages/create-karin/templates/production: - devDependencies: - node-karin: - specifier: 0.12.2-5.pr.206.fd03f9f - version: 0.12.2-5.pr.206.fd03f9f - packages/create-karin/templates/ts-plugin: devDependencies: '@types/node': @@ -554,6 +554,10 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} + '@pkgr/core@0.1.1': + resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + '@redis/bloom@1.2.0': resolution: {integrity: sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==} peerDependencies: @@ -1319,6 +1323,20 @@ packages: peerDependencies: eslint: '>=8.23.0' + eslint-plugin-prettier@5.2.2: + resolution: {integrity: sha512-1yI3/hf35wmlq66C8yOyrujQnel+v5l1Vop5Cl2I6ylyNTT1JbuUUnV3/41PzwTzcyDp/oF0jWE3HXvcH5AQOQ==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + '@types/eslint': '>=8.0.0' + eslint: '>=8.0.0' + eslint-config-prettier: '*' + prettier: '>=3.0.0' + peerDependenciesMeta: + '@types/eslint': + optional: true + eslint-config-prettier: + optional: true + eslint-plugin-promise@7.1.0: resolution: {integrity: sha512-8trNmPxdAy3W620WKDpaS65NlM5yAumod6XeC4LOb+jxlkG4IVcp68c6dXY2ev+uT4U1PtG57YDV6EGAXN0GbQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1399,6 +1417,9 @@ packages: fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + fast-diff@1.3.0: + resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} + fast-glob@3.3.2: resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} engines: {node: '>=8.6.0'} @@ -2134,6 +2155,15 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} + prettier-linter-helpers@1.0.0: + resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} + engines: {node: '>=6.0.0'} + + prettier@3.4.2: + resolution: {integrity: sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==} + engines: {node: '>=14'} + hasBin: true + prompts@2.4.2: resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} engines: {node: '>= 6'} @@ -2389,6 +2419,10 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} + synckit@0.9.2: + resolution: {integrity: sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==} + engines: {node: ^14.18.0 || >=16.0.0} + tapable@2.2.1: resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} engines: {node: '>=6'} @@ -2864,6 +2898,8 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true + '@pkgr/core@0.1.1': {} + '@redis/bloom@1.2.0(@redis/client@1.6.0)': dependencies: '@redis/client': 1.6.0 @@ -3890,6 +3926,13 @@ snapshots: minimatch: 9.0.5 semver: 7.6.3 + eslint-plugin-prettier@5.2.2(eslint@9.13.0)(prettier@3.4.2): + dependencies: + eslint: 9.13.0 + prettier: 3.4.2 + prettier-linter-helpers: 1.0.0 + synckit: 0.9.2 + eslint-plugin-promise@7.1.0(eslint@9.13.0): dependencies: eslint: 9.13.0 @@ -4032,6 +4075,8 @@ snapshots: fast-deep-equal@3.1.3: {} + fast-diff@1.3.0: {} + fast-glob@3.3.2: dependencies: '@nodelib/fs.stat': 2.0.5 @@ -4787,6 +4832,12 @@ snapshots: prelude-ls@1.2.1: {} + prettier-linter-helpers@1.0.0: + dependencies: + fast-diff: 1.3.0 + + prettier@3.4.2: {} + prompts@2.4.2: dependencies: kleur: 3.0.3 @@ -5116,6 +5167,11 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} + synckit@0.9.2: + dependencies: + '@pkgr/core': 0.1.1 + tslib: 2.8.1 + tapable@2.2.1: {} text-table@0.2.0: {}