From 31e9d8914308b64a5fb3443695ebc849a4b0e147 Mon Sep 17 00:00:00 2001 From: youxia <243802688@qq.com> Date: Wed, 13 Mar 2024 10:49:41 +0800 Subject: [PATCH] feat: move feiyun-handler to this project, rename to @feiyun/handler --- class-transformer/index.js | 1 + class-validator/index.js | 1 + packages/handler/.gitignore | 1 + packages/handler/class-transformer/index.ts | 1 + .../handler/class-transformer/package.json | 6 + packages/handler/class-validator/index.ts | 1 + packages/handler/class-validator/package.json | 6 + packages/handler/package.json | 69 +++ packages/handler/rollup.config.js | 53 ++ packages/handler/src/index.ts | 208 ++++++++ packages/handler/tsconfig.json | 15 + pnpm-lock.yaml | 475 ++++++++++++++++-- src/index.js | 177 +++++++ 13 files changed, 983 insertions(+), 31 deletions(-) create mode 100644 class-transformer/index.js create mode 100644 class-validator/index.js create mode 100644 packages/handler/.gitignore create mode 100644 packages/handler/class-transformer/index.ts create mode 100644 packages/handler/class-transformer/package.json create mode 100644 packages/handler/class-validator/index.ts create mode 100644 packages/handler/class-validator/package.json create mode 100644 packages/handler/package.json create mode 100644 packages/handler/rollup.config.js create mode 100644 packages/handler/src/index.ts create mode 100644 packages/handler/tsconfig.json create mode 100644 src/index.js diff --git a/class-transformer/index.js b/class-transformer/index.js new file mode 100644 index 0000000..7f510ff --- /dev/null +++ b/class-transformer/index.js @@ -0,0 +1 @@ +export * from 'class-transformer'; diff --git a/class-validator/index.js b/class-validator/index.js new file mode 100644 index 0000000..6bb336a --- /dev/null +++ b/class-validator/index.js @@ -0,0 +1 @@ +export * from 'class-validator'; diff --git a/packages/handler/.gitignore b/packages/handler/.gitignore new file mode 100644 index 0000000..b903bd8 --- /dev/null +++ b/packages/handler/.gitignore @@ -0,0 +1 @@ +/types \ No newline at end of file diff --git a/packages/handler/class-transformer/index.ts b/packages/handler/class-transformer/index.ts new file mode 100644 index 0000000..51e4643 --- /dev/null +++ b/packages/handler/class-transformer/index.ts @@ -0,0 +1 @@ +export * from 'class-transformer' \ No newline at end of file diff --git a/packages/handler/class-transformer/package.json b/packages/handler/class-transformer/package.json new file mode 100644 index 0000000..8000a39 --- /dev/null +++ b/packages/handler/class-transformer/package.json @@ -0,0 +1,6 @@ +{ + "type": "module", + "main": "./dist/index.cjs", + "module": "./dist/index.mjs", + "types": "../types/class-transformer/index.d.ts" +} \ No newline at end of file diff --git a/packages/handler/class-validator/index.ts b/packages/handler/class-validator/index.ts new file mode 100644 index 0000000..48242b3 --- /dev/null +++ b/packages/handler/class-validator/index.ts @@ -0,0 +1 @@ +export * from 'class-validator' \ No newline at end of file diff --git a/packages/handler/class-validator/package.json b/packages/handler/class-validator/package.json new file mode 100644 index 0000000..a80ea6e --- /dev/null +++ b/packages/handler/class-validator/package.json @@ -0,0 +1,6 @@ +{ + "type": "module", + "main": "./dist/index.cjs", + "module": "./dist/index.mjs", + "types": "../types/class-validator/index.d.ts" +} \ No newline at end of file diff --git a/packages/handler/package.json b/packages/handler/package.json new file mode 100644 index 0000000..0dc4186 --- /dev/null +++ b/packages/handler/package.json @@ -0,0 +1,69 @@ +{ + "name": "feiyun-handler", + "version": "0.0.21", + "license": "MIT", + "type": "module", + "main": "./src/index.ts", + "publishConfig": { + "main": "./dist/index.cjs", + "module": "./dist/index.mjs", + "types": "./types/src/index.d.ts", + "exports": { + ".": { + "types": "./types/src/index.d.ts", + "import": "./dist/index.mjs", + "require": "./dist/index.cjs" + }, + "./class-validator": { + "types": "./types/class-validator/index.d.ts", + "import": "./class-validator/dist/index.mjs", + "require": "./class-validator/dist/index.cjs" + }, + "./class-transformer": { + "types": "./types/class-transformer/index.d.ts", + "import": "./class-transformer/dist/index.mjs", + "require": "./class-transformer/dist/index.cjs" + } + } + }, + "files": [ + "dist", + "class-validator/dist", + "class-validator/package.json", + "class-transformer/dist", + "class-transformer/package.json", + "types" + ], + "exports": { + ".": { + "import": "./src/index.ts" + }, + "./class-validator": { + "import": "./class-validator/index.ts" + }, + "./class-transformer": { + "import": "./class-transformer/index.ts" + } + }, + "scripts": { + "build": "rimraf **/dist && tsc && rollup -c", + "prepublishOnly": "pnpm build" + }, + "devDependencies": { + "@feiyun/server": "workspace:^", + "@rollup/plugin-node-resolve": "^15.2.3", + "@rollup/plugin-typescript": "^11.1.6", + "@types/node": "^20.11.19", + "feiyun": "^0.2.3", + "reflect-metadata": "^0.2.1", + "rollup": "^4.12.0", + "rollup-plugin-ts": "^3.4.5", + "tslib": "^2.6.2", + "typescript": "^5.3.3" + }, + "dependencies": { + "class-transformer": "^0.5.1", + "class-validator": "^0.14.0", + "glob": "^10.3.10" + } +} \ No newline at end of file diff --git a/packages/handler/rollup.config.js b/packages/handler/rollup.config.js new file mode 100644 index 0000000..8826913 --- /dev/null +++ b/packages/handler/rollup.config.js @@ -0,0 +1,53 @@ +import typescript from '@rollup/plugin-typescript'; +import resolve from '@rollup/plugin-node-resolve'; + +import { defineConfig } from 'rollup'; +export default defineConfig([{ + input: 'src/index.ts', + output: [{ + file: 'dist/index.cjs', + format: 'cjs' + }, { + file: 'dist/index.mjs', + format: 'esm' + }], + plugins: [typescript({ + compilerOptions: { + outDir: "./dist", + declaration: false, + declarationDir: undefined + } + })] +}, { + input: 'class-transformer/index.ts', + output: [{ + file: 'class-transformer/dist/index.cjs', + format: 'cjs' + }, { + file: 'class-transformer/dist/index.mjs', + format: 'esm' + }], + plugins: [typescript({ + compilerOptions: { + outDir: "./class-validator/dist", + declaration: false, + declarationDir: undefined + } + })] +}, { + input: 'class-validator/index.ts', + output: [{ + file: 'class-validator/dist/index.cjs', + format: 'cjs' + }, { + file: 'class-validator/dist/index.mjs', + format: 'esm' + }], + plugins: [typescript({ + compilerOptions: { + outDir: "./class-validator/dist", + declaration: false, + declarationDir: undefined + } + })] +}]); \ No newline at end of file diff --git a/packages/handler/src/index.ts b/packages/handler/src/index.ts new file mode 100644 index 0000000..90e3d59 --- /dev/null +++ b/packages/handler/src/index.ts @@ -0,0 +1,208 @@ +import "reflect-metadata"; +import { glob } from "glob"; +import path from "node:path"; +import { plainToInstance } from "class-transformer"; +import { validate } from "class-validator"; + +import type { Context, FeiyunMiddleware } from 'feiyun' +const PATH_METADATA = 'path'; +const METHOD_METADATA = 'method'; +const PARAM_METADATA = 'param'; +const PARAM_VALIDATE_METADATA = 'param_validate' + +/** + * 类装饰 + * @param path 路径 + * @returns + */ +export const Handler = (path?: string): ClassDecorator => { + return target => { + path = typeof path === 'undefined' ? target.name : path; + Reflect.defineMetadata(PATH_METADATA, path, target); + } +} + +/** + * 方法装饰 + * @param path 路径 + * @returns + */ +export const Method = (path?: string): MethodDecorator => { + return (target, key, descriptor: any) => { + if (typeof key === 'string') { + path = typeof path === 'undefined' ? key : path; + Reflect.defineMetadata(METHOD_METADATA, path, descriptor.value); + } + } +} + +/** + * 参数装饰 + * @param name 参数名 + * @param checker 检查器/处理器 + * @returns + */ +export const Param = (name: string, checker?: (val: any) => void): ParameterDecorator => { + return (target, key, index) => { + if (!key) { + return; + } + + const param = Reflect.get(target, key); + let params = Reflect.getMetadata(PARAM_METADATA, param); + if (!params) { + params = []; + } + params.push([index, name, checker]); + Reflect.defineMetadata(PARAM_METADATA, params, param); + } +} + +/** + * 声明参数需要进行校验,并用目标类型重新实例 + * @param target + * @param key + * @param index + */ +export const ParamType: ParameterDecorator = (target, key, index) => { + if (!key) { + return; + } + const types = Reflect.getMetadata("design:paramtypes", target, key); + // console.log(Object.getOwnPropertyDescriptors(Reflect.ownKeys(types[index].prototype))); + Reflect.defineMetadata(PARAM_VALIDATE_METADATA, types[index], Reflect.get(target, key)); +} + + +const METHOD_DOC_METADATA = 'method_doc'; + +type Options = { + /** + * 标题 + */ + title: string + /** + * 描述 + */ + description: string +} +/** + * 文档 + */ +export const ApiDoc = (options: Options): MethodDecorator => { + return (target, key, descriptor: any) => { + Reflect.defineMetadata(METHOD_DOC_METADATA, options, descriptor.value); + } +} + + +export const useMapRoute = (handlers: any[]) => { + + const all = new Map(); + + for (let i = 0; i < handlers.length; i++) { + console.log(handlers[i]); + const handler = new handlers[i](); + const prototype = Object.getPrototypeOf(handler) as ClassDecorator; + // 取出路径 + const handlerPathMeta = Reflect.getMetadata(PATH_METADATA, prototype.constructor); + const methods = Object.getOwnPropertyNames(prototype).filter(item => { + // 构造函数,暂时不处理 + if (item === 'constructor') { + return false; + } + return typeof Reflect.get(prototype, item) === 'function'; + }); + + methods.forEach(methodName => { + const method = Reflect.get(prototype, methodName); + const methodPath = Reflect.getMetadata(METHOD_METADATA, method); + if (!methodPath) { + return; + } + const path = handlerPathMeta + '/' + methodPath; + + all.set(path, { + method: method.bind(handler), + validate: Reflect.getMetadata(PARAM_VALIDATE_METADATA, method), + doc: Reflect.getMetadata(METHOD_DOC_METADATA, method), + }); + }) + } + + return all; +} + +/** + * 异常抛出基类 + */ +export class ResponseError extends Error { + constructor(msg: string, public code = 500) { + super(msg); + } +} + +const runHandler = async (handler: any, ctx: Context) => { + if (handler.validate) { + const errors = await validate(plainToInstance(handler.validate, ctx.request.data)); + if (errors.length > 0) { + console.error(errors); + ctx.response.data = { + code: 500, + msg: Object.values(errors![0].constraints!)[0] + } + } + return; + } + + try { + const res = await handler.method(ctx.request.data, ctx.socket); + if (res) { + ctx.response.data = { + data: res + }; + } + } catch (e) { + if (e instanceof ResponseError) { + ctx.response.data = { + code: e.code, + msg: e.message + } + } else { + console.error(e); + } + } +} + +/** + * 自动导入应用文件 + * @param baseDir 应用文件夹 + * @param rule 导入路径规则 + * @returns + */ +export const include = async (baseDir: string, rule = '**/*.handler.ts'): Promise => { + // const dirs = await readdir(path); + // const files = await findUp(path + '/' + rule); + // console.log(files); + console.log(path.resolve(baseDir, rule)); + const handlerPaths = await glob(path.resolve(baseDir, rule)); + + const handlers = []; + + for (let i = 0; i < handlerPaths.length; i++) { + const handler = await import(handlerPaths[i]); + if (handler.default) { + handlers.push(handler.default); + } + } + + const mapRoute = useMapRoute(handlers); + + return async (ctx, next) => { + const handler = mapRoute.get(ctx.request.url); + if (handler) { + await runHandler(handler, ctx); + } + next(); + }; +} \ No newline at end of file diff --git a/packages/handler/tsconfig.json b/packages/handler/tsconfig.json new file mode 100644 index 0000000..c067635 --- /dev/null +++ b/packages/handler/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "noUnusedLocals": false, + "noUnusedParameters": false, + "noImplicitReturns": false, + "declaration": true, + "declarationDir": "./types", + }, + "include": [ + "src", + "class-validator", + "class-transformer", + ] +} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7ffa75b..415e231 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -58,6 +58,49 @@ importers: specifier: workspace:^ version: link:../server + packages/handler: + dependencies: + class-transformer: + specifier: ^0.5.1 + version: 0.5.1 + class-validator: + specifier: ^0.14.0 + version: 0.14.0 + glob: + specifier: ^10.3.10 + version: 10.3.10 + devDependencies: + '@feiyun/server': + specifier: workspace:^ + version: link:../server + '@rollup/plugin-node-resolve': + specifier: ^15.2.3 + version: 15.2.3(rollup@4.12.0) + '@rollup/plugin-typescript': + specifier: ^11.1.6 + version: 11.1.6(rollup@4.12.0)(tslib@2.6.2)(typescript@5.3.3) + '@types/node': + specifier: ^20.11.19 + version: 20.11.26 + feiyun: + specifier: ^0.2.3 + version: link:../feiyun + reflect-metadata: + specifier: ^0.2.1 + version: 0.2.1 + rollup: + specifier: ^4.12.0 + version: 4.12.0 + rollup-plugin-ts: + specifier: ^3.4.5 + version: 3.4.5(rollup@4.12.0)(typescript@5.3.3) + tslib: + specifier: ^2.6.2 + version: 2.6.2 + typescript: + specifier: ^5.3.3 + version: 5.3.3 + packages/server: devDependencies: '@types/bun': @@ -290,7 +333,6 @@ packages: strip-ansi-cjs: /strip-ansi@6.0.1 wrap-ansi: 8.1.0 wrap-ansi-cjs: /wrap-ansi@7.0.0 - dev: true /@jridgewell/sourcemap-codec@1.4.15: resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} @@ -316,6 +358,10 @@ packages: read-yaml-file: 1.1.0 dev: true + /@mdn/browser-compat-data@5.5.14: + resolution: {integrity: sha512-K7e35i4XtNWpiOr+aPiy3UccAhFop0HsfVz9RSzlcgaaHb2aD/nN0J3uPPLedyTokMiebxN0gxkL/WXpzNQuKg==} + dev: true + /@nodelib/fs.scandir@2.1.5: resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -341,9 +387,26 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} requiresBuild: true - dev: true optional: true + /@rollup/plugin-node-resolve@15.2.3(rollup@4.12.0): + resolution: {integrity: sha512-j/lym8nf5E21LwBT4Df1VD6hRO2L2iwUeUmP7litikRsVp1H6NWx20NEp0Y7su+7XGc476GnXXc4kFeZNGmaSQ==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^2.78.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + dependencies: + '@rollup/pluginutils': 5.1.0(rollup@4.12.0) + '@types/resolve': 1.20.2 + deepmerge: 4.3.1 + is-builtin-module: 3.2.1 + is-module: 1.0.0 + resolve: 1.22.8 + rollup: 4.12.0 + dev: true + /@rollup/plugin-typescript@11.1.3(rollup@3.29.1)(tslib@2.6.2)(typescript@5.2.2): resolution: {integrity: sha512-8o6cNgN44kQBcpsUJTbTXMTtb87oR1O0zgP3Dxm71hrNgparap3VujgofEilTYJo+ivf2ke6uy3/E5QEaiRlDA==} engines: {node: '>=14.0.0'} @@ -364,6 +427,26 @@ packages: typescript: 5.2.2 dev: true + /@rollup/plugin-typescript@11.1.6(rollup@4.12.0)(tslib@2.6.2)(typescript@5.3.3): + resolution: {integrity: sha512-R92yOmIACgYdJ7dJ97p4K69I8gg6IEHt8M7dUBxN3W6nrO8uUxX5ixl0yU/N3aZTi8WhPuICvOHXQvF6FaykAA==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^2.14.0||^3.0.0||^4.0.0 + tslib: '*' + typescript: '>=3.7.0' + peerDependenciesMeta: + rollup: + optional: true + tslib: + optional: true + dependencies: + '@rollup/pluginutils': 5.1.0(rollup@4.12.0) + resolve: 1.22.8 + rollup: 4.12.0 + tslib: 2.6.2 + typescript: 5.3.3 + dev: true + /@rollup/pluginutils@5.1.0(rollup@3.29.1): resolution: {integrity: sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==} engines: {node: '>=14.0.0'} @@ -379,6 +462,125 @@ packages: rollup: 3.29.1 dev: true + /@rollup/pluginutils@5.1.0(rollup@4.12.0): + resolution: {integrity: sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + dependencies: + '@types/estree': 1.0.5 + estree-walker: 2.0.2 + picomatch: 2.3.1 + rollup: 4.12.0 + dev: true + + /@rollup/rollup-android-arm-eabi@4.12.0: + resolution: {integrity: sha512-+ac02NL/2TCKRrJu2wffk1kZ+RyqxVUlbjSagNgPm94frxtr+XDL12E5Ll1enWskLrtrZ2r8L3wED1orIibV/w==} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-android-arm64@4.12.0: + resolution: {integrity: sha512-OBqcX2BMe6nvjQ0Nyp7cC90cnumt8PXmO7Dp3gfAju/6YwG0Tj74z1vKrfRz7qAv23nBcYM8BCbhrsWqO7PzQQ==} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-darwin-arm64@4.12.0: + resolution: {integrity: sha512-X64tZd8dRE/QTrBIEs63kaOBG0b5GVEd3ccoLtyf6IdXtHdh8h+I56C2yC3PtC9Ucnv0CpNFJLqKFVgCYe0lOQ==} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-darwin-x64@4.12.0: + resolution: {integrity: sha512-cc71KUZoVbUJmGP2cOuiZ9HSOP14AzBAThn3OU+9LcA1+IUqswJyR1cAJj3Mg55HbjZP6OLAIscbQsQLrpgTOg==} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm-gnueabihf@4.12.0: + resolution: {integrity: sha512-a6w/Y3hyyO6GlpKL2xJ4IOh/7d+APaqLYdMf86xnczU3nurFTaVN9s9jOXQg97BE4nYm/7Ga51rjec5nfRdrvA==} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm64-gnu@4.12.0: + resolution: {integrity: sha512-0fZBq27b+D7Ar5CQMofVN8sggOVhEtzFUwOwPppQt0k+VR+7UHMZZY4y+64WJ06XOhBTKXtQB/Sv0NwQMXyNAA==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm64-musl@4.12.0: + resolution: {integrity: sha512-eTvzUS3hhhlgeAv6bfigekzWZjaEX9xP9HhxB0Dvrdbkk5w/b+1Sxct2ZuDxNJKzsRStSq1EaEkVSEe7A7ipgQ==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-riscv64-gnu@4.12.0: + resolution: {integrity: sha512-ix+qAB9qmrCRiaO71VFfY8rkiAZJL8zQRXveS27HS+pKdjwUfEhqo2+YF2oI+H/22Xsiski+qqwIBxVewLK7sw==} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-x64-gnu@4.12.0: + resolution: {integrity: sha512-TenQhZVOtw/3qKOPa7d+QgkeM6xY0LtwzR8OplmyL5LrgTWIXpTQg2Q2ycBf8jm+SFW2Wt/DTn1gf7nFp3ssVA==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-x64-musl@4.12.0: + resolution: {integrity: sha512-LfFdRhNnW0zdMvdCb5FNuWlls2WbbSridJvxOvYWgSBOYZtgBfW9UGNJG//rwMqTX1xQE9BAodvMH9tAusKDUw==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-win32-arm64-msvc@4.12.0: + resolution: {integrity: sha512-JPDxovheWNp6d7AHCgsUlkuCKvtu3RB55iNEkaQcf0ttsDU/JZF+iQnYcQJSk/7PtT4mjjVG8N1kpwnI9SLYaw==} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-win32-ia32-msvc@4.12.0: + resolution: {integrity: sha512-fjtuvMWRGJn1oZacG8IPnzIV6GF2/XG+h71FKn76OYFqySXInJtseAqdprVTDTyqPxQOG9Exak5/E9Z3+EJ8ZA==} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-win32-x64-msvc@4.12.0: + resolution: {integrity: sha512-ZYmr5mS2wd4Dew/JjT0Fqi2NPB/ZhZ2VvPp7SmvPZb4Y1CG/LRcS6tcRo2cYU7zLK5A7cdbhWnnWmUjoI4qapg==} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + /@types/bun@1.0.8: resolution: {integrity: sha512-E6UWZuN4ymAxzUBWVIGDHJ3Zey7I8cMzDZ+cB1BqhZsmd1uPb9iAQzpWMruY1mKzsuD3R+dZPoBkZz8QL1KhSA==} dependencies: @@ -397,6 +599,10 @@ packages: resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} dev: true + /@types/node@17.0.45: + resolution: {integrity: sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==} + dev: true + /@types/node@20.11.26: resolution: {integrity: sha512-YwOMmyhNnAWijOBQweOJnQPl068Oqd4K3OFbTc6AHJwzweUwwWG3GIFY74OKks2PJUDkQPeddOQES9mLn1CTEQ==} dependencies: @@ -407,10 +613,26 @@ packages: resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} dev: true + /@types/object-path@0.11.4: + resolution: {integrity: sha512-4tgJ1Z3elF/tOMpA8JLVuR9spt9Ynsf7+JjqsQ2IqtiPJtcLoHoXcT6qU4E10cPFqyXX5HDm9QwIzZhBSkLxsw==} + dev: true + + /@types/resolve@1.20.2: + resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} + dev: true + /@types/semver@7.5.8: resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} dev: true + /@types/ua-parser-js@0.7.39: + resolution: {integrity: sha512-P/oDfpofrdtF5xw433SPALpdSchtJmY7nsJItf8h3KXqOslkbySh8zq4dSWXH2oTjRvJ5PczVEoCZPow6GicLg==} + dev: true + + /@types/validator@13.11.9: + resolution: {integrity: sha512-FCTsikRozryfayPuiI46QzH3fnrOoctTjvOYZkho9BTFLCOZ2rgZJHMOVgCOfttjPJcgOx52EpkY0CMfy87MIw==} + dev: false + /@types/ws@8.5.10: resolution: {integrity: sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==} dependencies: @@ -423,6 +645,11 @@ packages: '@types/node': 20.11.26 dev: true + /@wessberg/stringutil@1.0.19: + resolution: {integrity: sha512-9AZHVXWlpN8Cn9k5BC/O0Dzb9E9xfEMXzYrNunwvkUTvuK7xgQPVRZpLo+jWCOZ5r8oBa8NIrHuPEu1hzbb6bg==} + engines: {node: '>=8.0.0'} + dev: true + /ansi-colors@4.1.3: resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} engines: {node: '>=6'} @@ -431,12 +658,10 @@ packages: /ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} - dev: true /ansi-regex@6.0.1: resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} engines: {node: '>=12'} - dev: true /ansi-styles@3.2.1: resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} @@ -451,12 +676,10 @@ packages: engines: {node: '>=8'} dependencies: color-convert: 2.0.1 - dev: true /ansi-styles@6.2.1: resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} engines: {node: '>=12'} - dev: true /argparse@1.0.10: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} @@ -515,7 +738,6 @@ packages: /balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - dev: true /better-path-resolve@1.0.0: resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} @@ -528,7 +750,6 @@ packages: resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} dependencies: balanced-match: 1.0.2 - dev: true /braces@3.0.2: resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} @@ -543,6 +764,38 @@ packages: wcwidth: 1.0.1 dev: true + /browserslist-generator@2.1.0: + resolution: {integrity: sha512-ZFz4mAOgqm0cbwKaZsfJbYDbTXGoPANlte7qRsRJOfjB9KmmISQrXJxAVrnXG8C8v/QHNzXyeJt0Cfcks6zZvQ==} + engines: {node: '>=16.15.1', npm: '>=7.0.0', pnpm: '>=3.2.0', yarn: '>=1.13'} + dependencies: + '@mdn/browser-compat-data': 5.5.14 + '@types/object-path': 0.11.4 + '@types/semver': 7.5.8 + '@types/ua-parser-js': 0.7.39 + browserslist: 4.23.0 + caniuse-lite: 1.0.30001597 + isbot: 3.8.0 + object-path: 0.11.8 + semver: 7.6.0 + ua-parser-js: 1.0.37 + dev: true + + /browserslist@4.23.0: + resolution: {integrity: sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + dependencies: + caniuse-lite: 1.0.30001597 + electron-to-chromium: 1.4.702 + node-releases: 2.0.14 + update-browserslist-db: 1.0.13(browserslist@4.23.0) + dev: true + + /builtin-modules@3.3.0: + resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} + engines: {node: '>=6'} + dev: true + /bun-types@1.0.29: resolution: {integrity: sha512-Z+U1ORr/2UCwxelIZxE83pyPLclviYL9UewQCNEUmGeLObY8ao+3WF3D8N1+NMv2+S+hUWsdBJam+4GoPEz35g==} dependencies: @@ -575,6 +828,10 @@ packages: engines: {node: '>=6'} dev: true + /caniuse-lite@1.0.30001597: + resolution: {integrity: sha512-7LjJvmQU6Sj7bL0j5b5WY/3n7utXUJvAe1lxhsHDbLmwX9mdL86Yjtr+5SRCyf8qME4M7pU2hswj0FpyBVCv9w==} + dev: true + /chalk@2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} engines: {node: '>=4'} @@ -602,6 +859,18 @@ packages: engines: {node: '>=8'} dev: true + /class-transformer@0.5.1: + resolution: {integrity: sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==} + dev: false + + /class-validator@0.14.0: + resolution: {integrity: sha512-ct3ltplN8I9fOwUd8GrP8UQixwff129BkEtuWDKL5W45cQuLd19xqmTLu5ge78YDm/fdje6FMt0hGOhl0lii3A==} + dependencies: + '@types/validator': 13.11.9 + libphonenumber-js: 1.10.58 + validator: 13.11.0 + dev: false + /cliui@6.0.0: resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} dependencies: @@ -636,7 +905,6 @@ packages: engines: {node: '>=7.0.0'} dependencies: color-name: 1.1.4 - dev: true /color-name@1.1.3: resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} @@ -645,6 +913,15 @@ packages: /color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + /compatfactory@3.0.0(typescript@5.3.3): + resolution: {integrity: sha512-WD5kF7koPwVoyKL8p0LlrmIZtilrD46sQStyzzxzTFinMKN2Dxk1hN+sddLSQU1mGIZvQfU8c+ONSghvvM40jg==} + engines: {node: '>=14.9.0'} + peerDependencies: + typescript: '>=3.x || >= 4.x || >= 5.x' + dependencies: + helpertypes: 0.0.19 + typescript: 5.3.3 dev: true /cross-spawn@5.1.0: @@ -662,6 +939,12 @@ packages: path-key: 3.1.1 shebang-command: 2.0.0 which: 2.0.2 + + /crosspath@2.0.0: + resolution: {integrity: sha512-ju88BYCQ2uvjO2bR+SsgLSTwTSctU+6Vp2ePbKPgSCZyy4MWZxYsT738DlKVRE5utUjobjPRm1MkTYKJxCmpTA==} + engines: {node: '>=14.9.0'} + dependencies: + '@types/node': 17.0.45 dev: true /csv-generate@3.4.3: @@ -699,6 +982,11 @@ packages: engines: {node: '>=0.10.0'} dev: true + /deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + dev: true + /defaults@1.0.4: resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} dependencies: @@ -737,15 +1025,16 @@ packages: /eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + + /electron-to-chromium@1.4.702: + resolution: {integrity: sha512-LYLXyEUsZ3nNSwiOWjI88N1PJUAMU2QphQSgGLVkFnb3FxZxNui2Vzi2PaKPgPWbsWbZstZnh6BMf/VQJamjiQ==} dev: true /emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - dev: true /emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - dev: true /enquirer@2.4.1: resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} @@ -941,7 +1230,6 @@ packages: dependencies: cross-spawn: 7.0.3 signal-exit: 4.1.0 - dev: true /fs-extra@7.0.1: resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} @@ -1029,7 +1317,6 @@ packages: minimatch: 9.0.3 minipass: 7.0.4 path-scurry: 1.10.1 - dev: true /globalthis@1.0.3: resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} @@ -1114,6 +1401,11 @@ packages: function-bind: 1.1.2 dev: true + /helpertypes@0.0.19: + resolution: {integrity: sha512-J00e55zffgi3yVnUp0UdbMztNkr2PnizEkOe9URNohnrNhW5X0QpegkuLpOmFQInpi93Nb8MCjQRHAiCDF42NQ==} + engines: {node: '>=10.0.0'} + dev: true + /hosted-git-info@2.8.9: resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} dev: true @@ -1174,6 +1466,13 @@ packages: has-tostringtag: 1.0.2 dev: true + /is-builtin-module@3.2.1: + resolution: {integrity: sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==} + engines: {node: '>=6'} + dependencies: + builtin-modules: 3.3.0 + dev: true + /is-callable@1.2.7: resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} engines: {node: '>= 0.4'} @@ -1200,7 +1499,6 @@ packages: /is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} - dev: true /is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} @@ -1209,6 +1507,10 @@ packages: is-extglob: 2.1.1 dev: true + /is-module@1.0.0: + resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==} + dev: true + /is-negative-zero@2.0.3: resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} engines: {node: '>= 0.4'} @@ -1289,9 +1591,13 @@ packages: resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} dev: true + /isbot@3.8.0: + resolution: {integrity: sha512-vne1mzQUTR+qsMLeCBL9+/tgnDXRyc2pygLGl/WsgA+EZKIiB5Ehu0CiVTHIIk30zhJ24uGz4M5Ppse37aR0Hg==} + engines: {node: '>=12'} + dev: true + /isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - dev: true /jackspeak@2.3.6: resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==} @@ -1300,7 +1606,6 @@ packages: '@isaacs/cliui': 8.0.2 optionalDependencies: '@pkgjs/parseargs': 0.11.0 - dev: true /js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -1335,6 +1640,10 @@ packages: engines: {node: '>=6'} dev: true + /libphonenumber-js@1.10.58: + resolution: {integrity: sha512-53A0IpJFL9LdHbpeatwizf8KSwPICrqn9H0g3Y7WQ+Jgeu9cQ4Ew3WrRtrLBu/CX2lXd5+rgT01/tGlkbkzOjw==} + dev: false + /lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} dev: true @@ -1370,7 +1679,6 @@ packages: /lru-cache@10.2.0: resolution: {integrity: sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==} engines: {node: 14 || >=16.14} - dev: true /lru-cache@4.1.5: resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==} @@ -1443,7 +1751,6 @@ packages: engines: {node: '>=16 || 14 >=14.17'} dependencies: brace-expansion: 2.0.1 - dev: true /minimist-options@4.1.0: resolution: {integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==} @@ -1457,13 +1764,16 @@ packages: /minipass@7.0.4: resolution: {integrity: sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==} engines: {node: '>=16 || 14 >=14.17'} - dev: true /mixme@0.5.10: resolution: {integrity: sha512-5H76ANWinB1H3twpJ6JY8uvAtpmFvHNArpilJAjXRKXSDDLPIMoZArw5SH0q9z+lLs8IrMw7Q2VWpWimFKFT1Q==} engines: {node: '>= 8.0.0'} dev: true + /node-releases@2.0.14: + resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} + dev: true + /normalize-package-data@2.5.0: resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} dependencies: @@ -1482,6 +1792,11 @@ packages: engines: {node: '>= 0.4'} dev: true + /object-path@0.11.8: + resolution: {integrity: sha512-YJjNZrlXJFM42wTBn6zgOJVar9KFJvzx6sTWDte8sWZF//cnjl0BxHNpfZx+ZffXX63A9q0b1zsFiBX4g4X5KA==} + engines: {node: '>= 10.12.0'} + dev: true + /object.assign@4.1.5: resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==} engines: {node: '>= 0.4'} @@ -1564,7 +1879,6 @@ packages: /path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} - dev: true /path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} @@ -1576,13 +1890,16 @@ packages: dependencies: lru-cache: 10.2.0 minipass: 7.0.4 - dev: true /path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} dev: true + /picocolors@1.0.0: + resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + dev: true + /picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} @@ -1675,6 +1992,10 @@ packages: strip-indent: 3.0.0 dev: true + /reflect-metadata@0.2.1: + resolution: {integrity: sha512-i5lLI6iw9AU3Uu4szRNPPEkomnkjRTaVt9hy/bn5g/oSzekBSMeLZblcjP74AW0vBabqERLLIrz+gR8QYR54Tw==} + dev: true + /regenerator-runtime@0.14.1: resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} dev: true @@ -1739,6 +2060,49 @@ packages: '@babel/code-frame': 7.23.5 dev: true + /rollup-plugin-ts@3.4.5(rollup@4.12.0)(typescript@5.3.3): + resolution: {integrity: sha512-9iCstRJpEZXSRQuXitlSZAzcGlrqTbJg1pE4CMbEi6xYldxVncdPyzA2I+j6vnh73wBymZckerS+Q/iEE/M3Ow==} + engines: {node: '>=16.15.1', npm: '>=7.0.0', pnpm: '>=3.2.0', yarn: '>=1.13'} + peerDependencies: + '@babel/core': '>=7.x' + '@babel/plugin-transform-runtime': '>=7.x' + '@babel/preset-env': '>=7.x' + '@babel/preset-typescript': '>=7.x' + '@babel/runtime': '>=7.x' + '@swc/core': '>=1.x' + '@swc/helpers': '>=0.2' + rollup: '>=1.x || >=2.x || >=3.x' + typescript: '>=3.2.x || >= 4.x || >= 5.x' + peerDependenciesMeta: + '@babel/core': + optional: true + '@babel/plugin-transform-runtime': + optional: true + '@babel/preset-env': + optional: true + '@babel/preset-typescript': + optional: true + '@babel/runtime': + optional: true + '@swc/core': + optional: true + '@swc/helpers': + optional: true + dependencies: + '@rollup/pluginutils': 5.1.0(rollup@4.12.0) + '@wessberg/stringutil': 1.0.19 + ansi-colors: 4.1.3 + browserslist: 4.23.0 + browserslist-generator: 2.1.0 + compatfactory: 3.0.0(typescript@5.3.3) + crosspath: 2.0.0 + magic-string: 0.30.8 + rollup: 4.12.0 + ts-clone-node: 3.0.0(typescript@5.3.3) + tslib: 2.6.2 + typescript: 5.3.3 + dev: true + /rollup@3.29.1: resolution: {integrity: sha512-c+ebvQz0VIH4KhhCpDsI+Bik0eT8ZFEVZEYw0cGMVqIP8zc+gnwl7iXCamTw7vzv2MeuZFZfdx5JJIq+ehzDlg==} engines: {node: '>=14.18.0', npm: '>=8.0.0'} @@ -1747,6 +2111,29 @@ packages: fsevents: 2.3.3 dev: true + /rollup@4.12.0: + resolution: {integrity: sha512-wz66wn4t1OHIJw3+XU7mJJQV/2NAfw5OAk6G6Hoo3zcvz/XOfQ52Vgi+AN4Uxoxi0KBBwk2g8zPrTDA4btSB/Q==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + dependencies: + '@types/estree': 1.0.5 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.12.0 + '@rollup/rollup-android-arm64': 4.12.0 + '@rollup/rollup-darwin-arm64': 4.12.0 + '@rollup/rollup-darwin-x64': 4.12.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.12.0 + '@rollup/rollup-linux-arm64-gnu': 4.12.0 + '@rollup/rollup-linux-arm64-musl': 4.12.0 + '@rollup/rollup-linux-riscv64-gnu': 4.12.0 + '@rollup/rollup-linux-x64-gnu': 4.12.0 + '@rollup/rollup-linux-x64-musl': 4.12.0 + '@rollup/rollup-win32-arm64-msvc': 4.12.0 + '@rollup/rollup-win32-ia32-msvc': 4.12.0 + '@rollup/rollup-win32-x64-msvc': 4.12.0 + fsevents: 2.3.3 + dev: true + /run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} dependencies: @@ -1827,7 +2214,6 @@ packages: engines: {node: '>=8'} dependencies: shebang-regex: 3.0.0 - dev: true /shebang-regex@1.0.0: resolution: {integrity: sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==} @@ -1837,7 +2223,6 @@ packages: /shebang-regex@3.0.0: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} - dev: true /side-channel@1.0.6: resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} @@ -1856,7 +2241,6 @@ packages: /signal-exit@4.1.0: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} - dev: true /slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} @@ -1922,7 +2306,6 @@ packages: emoji-regex: 8.0.0 is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 - dev: true /string-width@5.1.2: resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} @@ -1931,7 +2314,6 @@ packages: eastasianwidth: 0.2.0 emoji-regex: 9.2.2 strip-ansi: 7.1.0 - dev: true /string.prototype.trim@1.2.8: resolution: {integrity: sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==} @@ -1963,14 +2345,12 @@ packages: engines: {node: '>=8'} dependencies: ansi-regex: 5.0.1 - dev: true /strip-ansi@7.1.0: resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} engines: {node: '>=12'} dependencies: ansi-regex: 6.0.1 - dev: true /strip-bom@3.0.0: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} @@ -2028,6 +2408,16 @@ packages: engines: {node: '>=8'} dev: true + /ts-clone-node@3.0.0(typescript@5.3.3): + resolution: {integrity: sha512-egavvyHbIoelkgh1IC2agNB1uMNjB8VJgh0g/cn0bg2XXTcrtjrGMzEk4OD3Fi2hocICjP3vMa56nkzIzq0FRg==} + engines: {node: '>=14.9.0'} + peerDependencies: + typescript: ^3.x || ^4.x || ^5.x + dependencies: + compatfactory: 3.0.0(typescript@5.3.3) + typescript: 5.3.3 + dev: true + /tslib@2.6.2: resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} dev: true @@ -2111,6 +2501,16 @@ packages: hasBin: true dev: true + /typescript@5.3.3: + resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==} + engines: {node: '>=14.17'} + hasBin: true + dev: true + + /ua-parser-js@1.0.37: + resolution: {integrity: sha512-bhTyI94tZofjo+Dn8SN6Zv8nBDvyXTymAdM3LDI/0IboIUwTu1rEhW7v2TfiVsoYWgkQ4kOVqnI8APUFbIQIFQ==} + dev: true + /unbox-primitive@1.0.2: resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} dependencies: @@ -2129,6 +2529,17 @@ packages: engines: {node: '>= 4.0.0'} dev: true + /update-browserslist-db@1.0.13(browserslist@4.23.0): + resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + dependencies: + browserslist: 4.23.0 + escalade: 3.1.2 + picocolors: 1.0.0 + dev: true + /validate-npm-package-license@3.0.4: resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} dependencies: @@ -2136,6 +2547,11 @@ packages: spdx-expression-parse: 3.0.1 dev: true + /validator@13.11.0: + resolution: {integrity: sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ==} + engines: {node: '>= 0.10'} + dev: false + /wcwidth@1.0.1: resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} dependencies: @@ -2188,7 +2604,6 @@ packages: hasBin: true dependencies: isexe: 2.0.0 - dev: true /wrap-ansi@6.2.0: resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} @@ -2206,7 +2621,6 @@ packages: ansi-styles: 4.3.0 string-width: 4.2.3 strip-ansi: 6.0.1 - dev: true /wrap-ansi@8.1.0: resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} @@ -2215,7 +2629,6 @@ packages: ansi-styles: 6.2.1 string-width: 5.1.2 strip-ansi: 7.1.0 - dev: true /ws@8.14.1: resolution: {integrity: sha512-4OOseMUq8AzRBI/7SLMUwO+FEDnguetSk7KMb1sHwvF2w2Wv5Hoj0nlifx8vtGsftE/jWHojPy8sMMzYLJ2G/A==} diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..e0ad999 --- /dev/null +++ b/src/index.js @@ -0,0 +1,177 @@ +import "reflect-metadata"; +import { glob } from "glob"; +import path from "node:path"; +import { plainToInstance } from "class-transformer"; +import { validate } from "class-validator"; +const PATH_METADATA = 'path'; +const METHOD_METADATA = 'method'; +const PARAM_METADATA = 'param'; +const PARAM_VALIDATE_METADATA = 'param_validate'; +/** + * 类装饰 + * @param path 路径 + * @returns + */ +export const Handler = (path) => { + return target => { + path = typeof path === 'undefined' ? target.name : path; + Reflect.defineMetadata(PATH_METADATA, path, target); + }; +}; +/** + * 方法装饰 + * @param path 路径 + * @returns + */ +export const Method = (path) => { + return (target, key, descriptor) => { + if (typeof key === 'string') { + path = typeof path === 'undefined' ? key : path; + Reflect.defineMetadata(METHOD_METADATA, path, descriptor.value); + } + }; +}; +/** + * 参数装饰 + * @param name 参数名 + * @param checker 检查器/处理器 + * @returns + */ +export const Param = (name, checker) => { + return (target, key, index) => { + if (!key) { + return; + } + const param = Reflect.get(target, key); + let params = Reflect.getMetadata(PARAM_METADATA, param); + if (!params) { + params = []; + } + params.push([index, name, checker]); + Reflect.defineMetadata(PARAM_METADATA, params, param); + }; +}; +/** + * 声明参数需要进行校验,并用目标类型重新实例 + * @param target + * @param key + * @param index + */ +export const ParamType = (target, key, index) => { + if (!key) { + return; + } + const types = Reflect.getMetadata("design:paramtypes", target, key); + // console.log(Object.getOwnPropertyDescriptors(Reflect.ownKeys(types[index].prototype))); + Reflect.defineMetadata(PARAM_VALIDATE_METADATA, types[index], Reflect.get(target, key)); +}; +const METHOD_DOC_METADATA = 'method_doc'; +/** + * 文档 + */ +export const ApiDoc = (options) => { + return (target, key, descriptor) => { + Reflect.defineMetadata(METHOD_DOC_METADATA, options, descriptor.value); + }; +}; +export const useMapRoute = (handlers) => { + const all = new Map(); + for (let i = 0; i < handlers.length; i++) { + console.log(handlers[i]); + const handler = new handlers[i](); + const prototype = Object.getPrototypeOf(handler); + // 取出路径 + const handlerPathMeta = Reflect.getMetadata(PATH_METADATA, prototype.constructor); + const methods = Object.getOwnPropertyNames(prototype).filter(item => { + // 构造函数,暂时不处理 + if (item === 'constructor') { + return false; + } + return typeof Reflect.get(prototype, item) === 'function'; + }); + methods.forEach(methodName => { + const method = Reflect.get(prototype, methodName); + const methodPath = Reflect.getMetadata(METHOD_METADATA, method); + if (!methodPath) { + return; + } + const path = handlerPathMeta + '/' + methodPath; + all.set(path, { + method: method.bind(handler), + validate: Reflect.getMetadata(PARAM_VALIDATE_METADATA, method), + doc: Reflect.getMetadata(METHOD_DOC_METADATA, method), + }); + }); + } + return all; +}; +/** + * 异常抛出基类 + */ +export class ResponseError extends Error { + code; + constructor(msg, code = 500) { + super(msg); + this.code = code; + } +} +const runHandler = async (handler, ctx) => { + if (handler.validate) { + const errors = await validate(plainToInstance(handler.validate, ctx.request.data)); + if (errors.length > 0) { + console.error(errors); + ctx.response.data = { + code: 500, + msg: Object.values(errors[0].constraints)[0] + }; + } + return; + } + try { + const res = await handler.method(ctx.request.data, ctx.socket); + if (res) { + ctx.response.data = { + data: res + }; + } + } + catch (e) { + if (e instanceof ResponseError) { + ctx.response.data = { + code: e.code, + msg: e.message + }; + } + else { + console.error(e); + } + } +}; +/** + * 自动导入应用文件 + * @param baseDir 应用文件夹 + * @param rule 导入路径规则 + * @returns + */ +export const include = async (baseDir, rule = '**/*.handler.ts') => { + // const dirs = await readdir(path); + // const files = await findUp(path + '/' + rule); + // console.log(files); + console.log(path.resolve(baseDir, rule)); + const handlerPaths = await glob(path.resolve(baseDir, rule)); + const handlers = []; + for (let i = 0; i < handlerPaths.length; i++) { + const handler = await import(handlerPaths[i]); + if (handler.default) { + handlers.push(handler.default); + } + } + const mapRoute = useMapRoute(handlers); + return async (ctx, next) => { + const handler = mapRoute.get(ctx.request.url); + if (handler) { + await runHandler(handler, ctx); + } + next(); + }; +};