commit 82191217de7a58eef23ff7a5ce89d3133f84bc7d Author: expressgy Date: Sat Dec 2 00:52:48 2023 +0800 first commit diff --git a/.eslintrc.cjs b/.eslintrc.cjs new file mode 100644 index 0000000..ce0bb13 --- /dev/null +++ b/.eslintrc.cjs @@ -0,0 +1,65 @@ +module.exports = { + "env": { + "browser": true, + "es2021": true, + "es2022": true, + "es2023": true, + }, + "extends": ["eslint:recommended"], + "overrides": [ + { + "env": { + "node": true + }, + "files": [ + ".eslintrc.{js,cjs}" + ], + "parserOptions": { + "sourceType": "script" + } + } + ], + "parserOptions": { + "ecmaVersion": "latest", + "sourceType": "module" + }, + "rules": { + indent: ['error', 4, { "SwitchCase": 1 }], // 用于指定代码缩进的方式,这里配置为使用四个空格进行缩进。 + // 'linebreak-style': [0, 'error', 'windows'], // 用于指定换行符的风格,这里配置为使用 Windows 风格的换行符(\r\n)。 + quotes: ['error', 'single'], // 用于指定字符串的引号风格,这里配置为使用单引号作为字符串的引号。 + semi: ['error', 'always'], //用于指定是否需要在语句末尾添加分号,这里配置为必须始终添加分号。 + "no-console": 2,//禁止使用console + "no-const-assign": 2,//禁止修改const声明的变量 + "no-empty": 2,//块语句中的内容不能为空 + "no-extra-parens": 2,//禁止非必要的括号 + "no-extra-semi": 2,//禁止多余的冒号 + "no-fallthrough": 1,//禁止switch穿透 + "no-func-assign": 2,//禁止重复的函数声明 + "no-inline-comments": 2,//禁止行内备注 + "no-irregular-whitespace": 2,//不能有不规则的空格 + "no-mixed-spaces-and-tabs": [2, false],//禁止混用tab和空格 + "no-multi-spaces": 1,//不能用多余的空格 + "no-multiple-empty-lines": [1, {"max": 2}],//空行最多不能超过2行 + "no-nested-ternary": 0,//禁止使用嵌套的三目运算 + "no-redeclare": 2,//禁止重复声明变量 + "no-shadow": 2,//外部作用域中的变量不能与它所包含的作用域中的变量或参数同名 + "no-trailing-spaces": 2,//一行结束后面不要有空格 + "no-unexpected-multiline": 2,//避免多行表达式 + "no-unused-vars": [2, {"vars": "all", "args": "after-used"}],//不能有声明后未被使用的变量或参数 + "no-use-before-define": 2,//未定义前不能使用 + "no-var": 2,//禁用var,用let和const代替 + "arrow-parens": 0,//箭头函数用小括号括起来 + "array-bracket-spacing": [2, "never"],//是否允许非空数组里面有多余的空格 + "camelcase": 2,//强制驼峰法命名 + "comma-style": [2, "last"],//逗号风格,换行时在行首还是行尾 + "comma-spacing": ["error", {"before": false, "after": true}],//对象字面量中冒号的前后空格 + "key-spacing": ["error", { "beforeColon": false, "afterColon": true }],// 冒号后面有空格 + "lines-around-comment": 0,//行前/行后备注 + "array-bracket-spacing": ["error", "always"],// 检查数组字面量中的元素之间的空格。 + }, + "globals": { + global: true, + Buffer: true, + process: true + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..805bc40 --- /dev/null +++ b/.gitignore @@ -0,0 +1,135 @@ +# ---> Node +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +pnpm-debug.log* +.pnpm-debug.log* +# log +winston-logs/* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp +.cache + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..10b731c --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,5 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml +# 基于编辑器的 HTTP 客户端请求 +/httpRequests/ diff --git a/.idea/graphResource2.iml b/.idea/graphResource2.iml new file mode 100644 index 0000000..24643cc --- /dev/null +++ b/.idea/graphResource2.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..fdcb436 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/prettier.xml b/.idea/prettier.xml new file mode 100644 index 0000000..b0c1c68 --- /dev/null +++ b/.idea/prettier.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..f4f39af --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,5 @@ +{ + "singleQuote": true, + "trailingComma": "all", + "tabWidth": 4 +} diff --git a/OM系统资源结构实例.xmind b/OM系统资源结构实例.xmind new file mode 100644 index 0000000..0727090 Binary files /dev/null and b/OM系统资源结构实例.xmind differ diff --git a/bootstrap.js b/bootstrap.js new file mode 100644 index 0000000..f574971 --- /dev/null +++ b/bootstrap.js @@ -0,0 +1,106 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: initkoa +// | @文件描述: bootstrap.js - Koa项目启动文件 +// | @创建时间: 2023-11-25 21:17 +// | @更新时间: 2023-11-25 21:17 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ + + +import devConfig from '#root/development.env.js'; +import prodConfig from '#root/production.env.js'; +import startApp from '#home/app.js'; +import winston from "winston"; +import {logger, colorizer} from "#common/logger/index.js"; +import createDatabase from "#common/database/index.js"; +import {createCatch} from "#cache/index.js"; +// | 获取ENV +const ENV = process.env.NODE_ENV && process.env.NODE_ENV.toLowerCase().trim(); + +if (ENV === 'development' || ENV === undefined) { + global.config = devConfig; + logger.add(new winston.transports.Console({ + format:winston.format.combine( + winston.format.printf( + (i) => { + return colorizer.colorize( + i.level, + i.message + ); + }, + ), + ) + })) +} else if (ENV === 'production') { + global.config = prodConfig; + logger.exceptions.handle(new winston.transports.File({ filename: 'winston-logs/winston-exceptions.log' })); + logger.rejections.handle(new winston.transports.File({ filename: 'winston-logs/winston-rejections.log' })) +} else { + throw new Error(`未识别的环境变量${ENV}`); +} +global.logger = logger +global.ENV = ENV; + +// = 函数名: checkPort +// = 描述: 检测服务端口是否正常 +// = 参数: None +// = 返回值: undefined +// = 创建人: nie +// = 创建时间: 2023-11-25 21:49:22 - +function checkPort() { + if ( + typeof global.config.port !== 'number' || + global.config.port > 65536 || + global.config.port < 3000 + ) { + throw new Error(`服务监听端口不合法:${global.config.port}`); + } +} +checkPort(); + +// = 函数名: checkAppName +// = 描述: 检测服务名是否正常 +// = 参数: None +// = 返回值: undefined +// = 创建人: nie +// = 创建时间: 2023-11-25 21:51:03 - +function checkAppName() { + if (!global.config.appName) { + throw new Error(`服务名不存在:${global.config.appName}`); + } +} +checkAppName() +// process.stdout.write('\u001b[2J\u001b[0;0H'); +async function createApp(){ + const sequelize = createDatabase(logger); + + await sequelize.sync({alter: true}) + await sequelize.authenticate().catch(e => { + console.error(`数据库连接失败, ${e}`); + throw new Error(e) + }); + logger.info(`== 已成功与数据库建立连接。 ==`); + + createCatch(sequelize) + + + + const app = startApp(); + + sequelize.getQueryInterface().showAllTables().then(data => { + // console.log(data) + }).catch(e => { + console.error(e) + }) + + app.context.sequelize = sequelize + app.listen(config.port); + logger.info( `Web服务 ${global.config.appName} 启动成功,访问: http://127.0.0.1:${global.config.port}`) +} +createApp() + diff --git a/development.env.js b/development.env.js new file mode 100644 index 0000000..dca18da --- /dev/null +++ b/development.env.js @@ -0,0 +1,22 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: initkoa +// | @文件描述: development.env.js - +// | @创建时间: 2023-11-25 21:36 +// | @更新时间: 2023-11-25 21:36 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ + +import prodConfig from "#root/production.env.js"; + +const config = { + port: 3000, +} + +const devConfig = {...prodConfig, ...config} + +export default devConfig diff --git a/gen-Model/models/init-models.js b/gen-Model/models/init-models.js new file mode 100644 index 0000000..412134f --- /dev/null +++ b/gen-Model/models/init-models.js @@ -0,0 +1,38 @@ +var DataTypes = require("sequelize").DataTypes; +var _lauchuser = require("./lauchuser"); +var _lauchuserexpandfield = require("./lauchuserexpandfield"); +var _lauchuserexpandrecord = require("./lauchuserexpandrecord"); +var _lauchuserloginrecord = require("./lauchuserloginrecord"); +var _lauchuserpasswd = require("./lauchuserpasswd"); +var _lauchuserstructauthority = require("./lauchuserstructauthority"); +var _lauchuserstructorganization = require("./lauchuserstructorganization"); +var _lauchuserstructrelationorganizationaccent = require("./lauchuserstructrelationorganizationaccent"); +var _lauchuserstructrelationorganizationauthority = require("./lauchuserstructrelationorganizationauthority"); + +function initModels(sequelize) { + var lauchuser = _lauchuser(sequelize, DataTypes); + var lauchuserexpandfield = _lauchuserexpandfield(sequelize, DataTypes); + var lauchuserexpandrecord = _lauchuserexpandrecord(sequelize, DataTypes); + var lauchuserloginrecord = _lauchuserloginrecord(sequelize, DataTypes); + var lauchuserpasswd = _lauchuserpasswd(sequelize, DataTypes); + var lauchuserstructauthority = _lauchuserstructauthority(sequelize, DataTypes); + var lauchuserstructorganization = _lauchuserstructorganization(sequelize, DataTypes); + var lauchuserstructrelationorganizationaccent = _lauchuserstructrelationorganizationaccent(sequelize, DataTypes); + var lauchuserstructrelationorganizationauthority = _lauchuserstructrelationorganizationauthority(sequelize, DataTypes); + + + return { + lauchuser, + lauchuserexpandfield, + lauchuserexpandrecord, + lauchuserloginrecord, + lauchuserpasswd, + lauchuserstructauthority, + lauchuserstructorganization, + lauchuserstructrelationorganizationaccent, + lauchuserstructrelationorganizationauthority, + }; +} +module.exports = initModels; +module.exports.initModels = initModels; +module.exports.default = initModels; diff --git a/gen-Model/models/lauchuser.js b/gen-Model/models/lauchuser.js new file mode 100644 index 0000000..3fa6f0b --- /dev/null +++ b/gen-Model/models/lauchuser.js @@ -0,0 +1,58 @@ +const Sequelize = require('sequelize'); +module.exports = function (sequelize, DataTypes) { + return sequelize.define('lauchuser', { + uuid: { + type: DataTypes.UUID, + allowNull: false, + primaryKey: true, + comment: "用户唯一ID" + }, + username: { + type: DataTypes.STRING(255), + allowNull: false, + comment: "用户名" + }, + email: { + type: DataTypes.STRING(255), + allowNull: false + }, + createTime: { + type: DataTypes.DATE, + allowNull: false, + comment: "创建时间" + }, + status: { + type: DataTypes.INTEGER.UNSIGNED.ZEROFILL, + allowNull: false, + defaultValue: 0000000000, + comment: "0正常1注销2停用" + }, + selfSequence: { + type: DataTypes.INTEGER, + allowNull: false, + autoIncrement: true, + comment: "自增序列" + } + }, { + sequelize, + tableName: 'lauchuser', + timestamps: false, + indexes: [ + { + name: "PRIMARY", + unique: true, + using: "BTREE", + fields: [ + {name: "uuid"}, + ] + }, + { + name: "selfSequence", + using: "BTREE", + fields: [ + {name: "selfSequence"}, + ] + }, + ] + }); +}; diff --git a/gen-Model/models/lauchuserexpandfield.js b/gen-Model/models/lauchuserexpandfield.js new file mode 100644 index 0000000..18c9177 --- /dev/null +++ b/gen-Model/models/lauchuserexpandfield.js @@ -0,0 +1,82 @@ +const Sequelize = require('sequelize'); +module.exports = function(sequelize, DataTypes) { + return sequelize.define('lauchuserexpandfield', { + expandFieldId: { + autoIncrement: true, + type: DataTypes.INTEGER, + allowNull: false, + primaryKey: true, + comment: "拓展字段ID" + }, + fieldIdentify: { + type: DataTypes.STRING(255), + allowNull: false, + comment: "字段标识" + }, + displayName: { + type: DataTypes.STRING(255), + allowNull: false, + comment: "字段名" + }, + fieldDescribe: { + type: DataTypes.STRING(255), + allowNull: false, + comment: "字段描述" + }, + defaultValue: { + type: DataTypes.STRING(255), + allowNull: true, + comment: "默认值" + }, + storageType: { + type: DataTypes.STRING(255), + allowNull: false, + comment: "存储类型" + }, + storageLength: { + type: DataTypes.INTEGER, + allowNull: false, + comment: "存储长度" + }, + isRequired: { + type: DataTypes.BOOLEAN, + allowNull: true, + comment: "是否必填" + }, + isRepeat: { + type: DataTypes.BOOLEAN, + allowNull: true, + comment: "是否可以重复" + }, + isEnable: { + type: DataTypes.BOOLEAN, + allowNull: true, + comment: "是否启用" + }, + createTime: { + type: DataTypes.DATE, + allowNull: false, + comment: "创建时间" + }, + isDelete: { + type: DataTypes.STRING(64), + allowNull: false, + defaultValue: "", + comment: "删除时间" + } + }, { + sequelize, + tableName: 'lauchuserexpandfield', + timestamps: false, + indexes: [ + { + name: "PRIMARY", + unique: true, + using: "BTREE", + fields: [ + { name: "expandFieldId" }, + ] + }, + ] + }); +}; diff --git a/gen-Model/models/lauchuserexpandrecord.js b/gen-Model/models/lauchuserexpandrecord.js new file mode 100644 index 0000000..b19f526 --- /dev/null +++ b/gen-Model/models/lauchuserexpandrecord.js @@ -0,0 +1,52 @@ +const Sequelize = require('sequelize'); +module.exports = function(sequelize, DataTypes) { + return sequelize.define('lauchuserexpandrecord', { + expandRecordId: { + autoIncrement: true, + type: DataTypes.INTEGER, + allowNull: false, + primaryKey: true, + comment: "记录ID" + }, + uuid: { + type: DataTypes.INTEGER, + allowNull: false, + comment: "用户ID" + }, + expandField: { + type: DataTypes.STRING(255), + allowNull: false, + comment: "多占字段ID" + }, + expandFieldValue: { + type: DataTypes.STRING(255), + allowNull: false, + comment: "拓展字段值" + }, + createTime: { + type: DataTypes.DATE, + allowNull: false, + comment: "创建时间" + }, + isDelete: { + type: DataTypes.STRING(64), + allowNull: false, + defaultValue: "", + comment: "删除时间" + } + }, { + sequelize, + tableName: 'lauchuserexpandrecord', + timestamps: false, + indexes: [ + { + name: "PRIMARY", + unique: true, + using: "BTREE", + fields: [ + { name: "expandRecordId" }, + ] + }, + ] + }); +}; diff --git a/gen-Model/models/lauchuserloginrecord.js b/gen-Model/models/lauchuserloginrecord.js new file mode 100644 index 0000000..c1d1107 --- /dev/null +++ b/gen-Model/models/lauchuserloginrecord.js @@ -0,0 +1,37 @@ +const Sequelize = require('sequelize'); +module.exports = function(sequelize, DataTypes) { + return sequelize.define('lauchuserloginrecord', { + loginRecordId: { + autoIncrement: true, + type: DataTypes.INTEGER, + allowNull: false, + primaryKey: true + }, + uuid: { + type: DataTypes.UUID, + allowNull: false + }, + recoredJson: { + type: DataTypes.TEXT, + allowNull: false + }, + createTime: { + type: DataTypes.DATE, + allowNull: false + } + }, { + sequelize, + tableName: 'lauchuserloginrecord', + timestamps: false, + indexes: [ + { + name: "PRIMARY", + unique: true, + using: "BTREE", + fields: [ + { name: "loginRecordId" }, + ] + }, + ] + }); +}; diff --git a/gen-Model/models/lauchuserpasswd.js b/gen-Model/models/lauchuserpasswd.js new file mode 100644 index 0000000..ab60d82 --- /dev/null +++ b/gen-Model/models/lauchuserpasswd.js @@ -0,0 +1,41 @@ +const Sequelize = require('sequelize'); +module.exports = function(sequelize, DataTypes) { + return sequelize.define('lauchuserpasswd', { + passwdId: { + autoIncrement: true, + type: DataTypes.INTEGER, + allowNull: false, + primaryKey: true, + comment: "密码记录ID" + }, + uuid: { + type: DataTypes.UUID, + allowNull: false, + comment: "用户ID" + }, + passwd: { + type: DataTypes.STRING(255), + allowNull: false, + comment: "用户密码" + }, + createTime: { + type: DataTypes.DATE, + allowNull: false, + comment: "创建时间" + } + }, { + sequelize, + tableName: 'lauchuserpasswd', + timestamps: false, + indexes: [ + { + name: "PRIMARY", + unique: true, + using: "BTREE", + fields: [ + { name: "passwdId" }, + ] + }, + ] + }); +}; diff --git a/gen-Model/models/lauchuserstructauthority.js b/gen-Model/models/lauchuserstructauthority.js new file mode 100644 index 0000000..b18ded5 --- /dev/null +++ b/gen-Model/models/lauchuserstructauthority.js @@ -0,0 +1,64 @@ +const Sequelize = require('sequelize'); +module.exports = function(sequelize, DataTypes) { + return sequelize.define('lauchuserstructauthority', { + authorityStructId: { + autoIncrement: true, + type: DataTypes.INTEGER, + allowNull: false, + primaryKey: true + }, + authorityType: { + type: DataTypes.STRING(255), + allowNull: false, + comment: "按钮、页面、接口" + }, + authorityName: { + type: DataTypes.STRING(255), + allowNull: false + }, + authorityIdentify: { + type: DataTypes.STRING(255), + allowNull: false + }, + authorityDescribe: { + type: DataTypes.STRING(255), + allowNull: false + }, + father: { + type: DataTypes.INTEGER, + allowNull: false + }, + avatar: { + type: DataTypes.STRING(255), + allowNull: false + }, + status: { + type: DataTypes.STRING(255), + allowNull: false, + comment: "禁用启用" + }, + createTime: { + type: DataTypes.DATE, + allowNull: false + }, + isDelete: { + type: DataTypes.STRING(64), + allowNull: false, + defaultValue: "" + } + }, { + sequelize, + tableName: 'lauchuserstructauthority', + timestamps: false, + indexes: [ + { + name: "PRIMARY", + unique: true, + using: "BTREE", + fields: [ + { name: "authorityStructId" }, + ] + }, + ] + }); +}; diff --git a/gen-Model/models/lauchuserstructorganization.js b/gen-Model/models/lauchuserstructorganization.js new file mode 100644 index 0000000..0975916 --- /dev/null +++ b/gen-Model/models/lauchuserstructorganization.js @@ -0,0 +1,54 @@ +const Sequelize = require('sequelize'); +module.exports = function(sequelize, DataTypes) { + return sequelize.define('lauchuserstructorganization', { + organizationStructId: { + autoIncrement: true, + type: DataTypes.INTEGER, + allowNull: false, + primaryKey: true + }, + organizationType: { + type: DataTypes.STRING(255), + allowNull: false + }, + organizationName: { + type: DataTypes.STRING(255), + allowNull: false + }, + organizationDescribe: { + type: DataTypes.STRING(255), + allowNull: false + }, + father: { + type: DataTypes.INTEGER.UNSIGNED.ZEROFILL, + allowNull: false + }, + isDefault: { + type: DataTypes.STRING(255), + allowNull: false + }, + createTime: { + type: DataTypes.DATE, + allowNull: false + }, + isDelete: { + type: DataTypes.STRING(64), + allowNull: false, + defaultValue: "" + } + }, { + sequelize, + tableName: 'lauchuserstructorganization', + timestamps: false, + indexes: [ + { + name: "PRIMARY", + unique: true, + using: "BTREE", + fields: [ + { name: "organizationStructId" }, + ] + }, + ] + }); +}; diff --git a/gen-Model/models/lauchuserstructrelationorganizationaccent.js b/gen-Model/models/lauchuserstructrelationorganizationaccent.js new file mode 100644 index 0000000..97c33f9 --- /dev/null +++ b/gen-Model/models/lauchuserstructrelationorganizationaccent.js @@ -0,0 +1,42 @@ +const Sequelize = require('sequelize'); +module.exports = function(sequelize, DataTypes) { + return sequelize.define('lauchuserstructrelationorganizationaccent', { + organizationRelationAccentId: { + autoIncrement: true, + type: DataTypes.INTEGER, + allowNull: false, + primaryKey: true + }, + uuid: { + type: DataTypes.UUID, + allowNull: false + }, + organizationStruct: { + type: DataTypes.INTEGER, + allowNull: false + }, + createTime: { + type: DataTypes.DATE, + allowNull: false + }, + isDelete: { + type: DataTypes.STRING(64), + allowNull: false, + defaultValue: "" + } + }, { + sequelize, + tableName: 'lauchuserstructrelationorganizationaccent', + timestamps: false, + indexes: [ + { + name: "PRIMARY", + unique: true, + using: "BTREE", + fields: [ + { name: "organizationRelationAccentId" }, + ] + }, + ] + }); +}; diff --git a/gen-Model/models/lauchuserstructrelationorganizationauthority.js b/gen-Model/models/lauchuserstructrelationorganizationauthority.js new file mode 100644 index 0000000..6417ae4 --- /dev/null +++ b/gen-Model/models/lauchuserstructrelationorganizationauthority.js @@ -0,0 +1,42 @@ +const Sequelize = require('sequelize'); +module.exports = function(sequelize, DataTypes) { + return sequelize.define('lauchuserstructrelationorganizationauthority', { + organizationRelationAuthorityId: { + autoIncrement: true, + type: DataTypes.INTEGER, + allowNull: false, + primaryKey: true + }, + organizationStruct: { + type: DataTypes.INTEGER, + allowNull: false + }, + authorityStruct: { + type: DataTypes.INTEGER, + allowNull: false + }, + createTime: { + type: DataTypes.DATE, + allowNull: false + }, + isDelete: { + type: DataTypes.STRING(64), + allowNull: false, + defaultValue: "" + } + }, { + sequelize, + tableName: 'lauchuserstructrelationorganizationauthority', + timestamps: false, + indexes: [ + { + name: "PRIMARY", + unique: true, + using: "BTREE", + fields: [ + { name: "organizationRelationAuthorityId" }, + ] + }, + ] + }); +}; diff --git a/gen-Model/使用方式.md b/gen-Model/使用方式.md new file mode 100644 index 0000000..c6f1650 --- /dev/null +++ b/gen-Model/使用方式.md @@ -0,0 +1 @@ +sequelize-auto -h 数据库的IP地址 -d 数据库名 -u 用户名 -x 密码 -p 端口 -t 表名 diff --git a/graphResource2数据结构.xmind b/graphResource2数据结构.xmind new file mode 100644 index 0000000..e675fa4 Binary files /dev/null and b/graphResource2数据结构.xmind differ diff --git a/package.json b/package.json new file mode 100644 index 0000000..8c45987 --- /dev/null +++ b/package.json @@ -0,0 +1,56 @@ +{ + "name": "initkoa", + "version": "1.0.0", + "description": "", + "type": "module", + "main": "app.js", + "imports": { + "#root/*": "./*", + "#home/*": "./src/*", + "#routes/*": "./src/routes/*", + "#common/*": "./src/common/*", + "#dataModels/*": "./src/common/database/dataModels/*", + "#cache/*": "./src/cache/*", + "#config": "./config/config.js", + "#task/*": "./src/task/*", + "#workers/*": "./src/workers/*", + "#protocol/*": "./src/protocol/*", + "#processes/*": "./src/processes/*" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "format": "prettier --write \"src/**/*.js\"", + "start": "cross-env NODE_ENV=production node bootstrap.js", + "start:dev": "cross-env NODE_ENV=development nodemon --unhandled-rejections=throw bootstrap.js", + "test:dev": "cross-env NODE_ENV=development node bootstrap.js", + "genmodel": "cd gen-Model && sequelize-auto -h 127.0.0.1 -d lauch -u root -x root -p 3306" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "ajv": "^8.12.0", + "ajv-errors": "^3.0.0", + "koa": "^2.14.2", + "koa-body": "^6.0.1", + "koa-compress": "^5.1.1", + "koa-json-error": "^3.1.2", + "koa-logger": "^3.2.1", + "koa-ratelimit": "^5.0.1", + "koa-router": "^12.0.1", + "koa-useragent": "^4.1.0", + "mysql2": "^3.6.5", + "sequelize": "^6.35.1", + "winston": "^3.11.0", + "winston-daily-rotate-file": "^4.7.1" + }, + "devDependencies": { + "cross-env": "^7.0.3", + "eslint": "^8.52.0", + "eslint-config-prettier": "^9.0.0", + "eslint-plugin-prettier": "^5.0.0", + "nodemon": "^3.0.1", + "prettier": "^3.0.3", + "sequelize-auto": "^0.8.8" + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..da22fec --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,2376 @@ +lockfileVersion: '6.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +dependencies: + ajv: + specifier: ^8.12.0 + version: 8.12.0 + ajv-errors: + specifier: ^3.0.0 + version: 3.0.0(ajv@8.12.0) + koa: + specifier: ^2.14.2 + version: 2.14.2 + koa-body: + specifier: ^6.0.1 + version: 6.0.1 + koa-compress: + specifier: ^5.1.1 + version: 5.1.1 + koa-json-error: + specifier: ^3.1.2 + version: 3.1.2 + koa-logger: + specifier: ^3.2.1 + version: 3.2.1 + koa-ratelimit: + specifier: ^5.0.1 + version: 5.0.1 + koa-router: + specifier: ^12.0.1 + version: 12.0.1 + koa-useragent: + specifier: ^4.1.0 + version: 4.1.0 + mysql2: + specifier: ^3.6.5 + version: 3.6.5 + sequelize: + specifier: ^6.35.1 + version: 6.35.1(mysql2@3.6.5) + winston: + specifier: ^3.11.0 + version: 3.11.0 + winston-daily-rotate-file: + specifier: ^4.7.1 + version: 4.7.1(winston@3.11.0) + +devDependencies: + cross-env: + specifier: ^7.0.3 + version: 7.0.3 + eslint: + specifier: ^8.52.0 + version: 8.54.0 + eslint-config-prettier: + specifier: ^9.0.0 + version: 9.0.0(eslint@8.54.0) + eslint-plugin-prettier: + specifier: ^5.0.0 + version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.54.0)(prettier@3.1.0) + nodemon: + specifier: ^3.0.1 + version: 3.0.1 + prettier: + specifier: ^3.0.3 + version: 3.1.0 + sequelize-auto: + specifier: ^0.8.8 + version: 0.8.8(sequelize@6.35.1) + +packages: + + /@aashutoshrathi/word-wrap@1.2.6: + resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==} + engines: {node: '>=0.10.0'} + dev: true + + /@colors/colors@1.6.0: + resolution: {integrity: sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==} + engines: {node: '>=0.1.90'} + dev: false + + /@dabh/diagnostics@2.0.3: + resolution: {integrity: sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==} + dependencies: + colorspace: 1.1.4 + enabled: 2.0.0 + kuler: 2.0.0 + dev: false + + /@eslint-community/eslint-utils@4.4.0(eslint@8.54.0): + resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + dependencies: + eslint: 8.54.0 + eslint-visitor-keys: 3.4.3 + dev: true + + /@eslint-community/regexpp@4.10.0: + resolution: {integrity: sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + dev: true + + /@eslint/eslintrc@2.1.3: + resolution: {integrity: sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + ajv: 6.12.6 + debug: 4.3.4 + espree: 9.6.1 + globals: 13.23.0 + ignore: 5.3.0 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@eslint/js@8.54.0: + resolution: {integrity: sha512-ut5V+D+fOoWPgGGNj83GGjnntO39xDy6DWxO0wb7Jp3DcMX0TfIqdzHF85VTQkerdyGmuuMD9AKAo5KiNlf/AQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + /@humanwhocodes/config-array@0.11.13: + resolution: {integrity: sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==} + engines: {node: '>=10.10.0'} + dependencies: + '@humanwhocodes/object-schema': 2.0.1 + debug: 4.3.4 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@humanwhocodes/module-importer@1.0.1: + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + dev: true + + /@humanwhocodes/object-schema@2.0.1: + resolution: {integrity: sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==} + dev: true + + /@nodelib/fs.scandir@2.1.5: + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + dev: true + + /@nodelib/fs.stat@2.0.5: + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + dev: true + + /@nodelib/fs.walk@1.2.8: + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.15.0 + dev: true + + /@pkgr/utils@2.4.2: + resolution: {integrity: sha512-POgTXhjrTfbTV63DiFXav4lBHiICLKKwDeaKn9Nphwj7WH6m0hMMCaJkMyRWjgtPFyRKRVoMXXjczsTQRDEhYw==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + dependencies: + cross-spawn: 7.0.3 + fast-glob: 3.3.2 + is-glob: 4.0.3 + open: 9.1.0 + picocolors: 1.0.0 + tslib: 2.6.2 + dev: true + + /@types/accepts@1.3.7: + resolution: {integrity: sha512-Pay9fq2lM2wXPWbteBsRAGiWH2hig4ZE2asK+mm7kUzlxRTfL961rj89I6zV/E3PcIkDqyuBEcMxFT7rccugeQ==} + dependencies: + '@types/node': 20.10.0 + dev: false + + /@types/body-parser@1.19.5: + resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==} + dependencies: + '@types/connect': 3.4.38 + '@types/node': 20.10.0 + dev: false + + /@types/co-body@6.1.3: + resolution: {integrity: sha512-UhuhrQ5hclX6UJctv5m4Rfp52AfG9o9+d9/HwjxhVB5NjXxr5t9oKgJxN8xRHgr35oo8meUEHUPFWiKg6y71aA==} + dependencies: + '@types/node': 20.10.0 + '@types/qs': 6.9.10 + dev: false + + /@types/connect@3.4.38: + resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} + dependencies: + '@types/node': 20.10.0 + dev: false + + /@types/content-disposition@0.5.8: + resolution: {integrity: sha512-QVSSvno3dE0MgO76pJhmv4Qyi/j0Yk9pBp0Y7TJ2Tlj+KCgJWY6qX7nnxCOLkZ3VYRSIk1WTxCvwUSdx6CCLdg==} + dev: false + + /@types/cookies@0.7.10: + resolution: {integrity: sha512-hmUCjAk2fwZVPPkkPBcI7jGLIR5mg4OVoNMBwU6aVsMm/iNPY7z9/R+x2fSwLt/ZXoGua6C5Zy2k5xOo9jUyhQ==} + dependencies: + '@types/connect': 3.4.38 + '@types/express': 4.17.21 + '@types/keygrip': 1.0.6 + '@types/node': 20.10.0 + dev: false + + /@types/debug@4.1.12: + resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} + dependencies: + '@types/ms': 0.7.34 + + /@types/express-serve-static-core@4.17.41: + resolution: {integrity: sha512-OaJ7XLaelTgrvlZD8/aa0vvvxZdUmlCn6MtWeB7TkiKW70BQLc9XEPpDLPdbo52ZhXUCrznlWdCHWxJWtdyajA==} + dependencies: + '@types/node': 20.10.0 + '@types/qs': 6.9.10 + '@types/range-parser': 1.2.7 + '@types/send': 0.17.4 + dev: false + + /@types/express@4.17.21: + resolution: {integrity: sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==} + dependencies: + '@types/body-parser': 1.19.5 + '@types/express-serve-static-core': 4.17.41 + '@types/qs': 6.9.10 + '@types/serve-static': 1.15.5 + dev: false + + /@types/formidable@2.0.6: + resolution: {integrity: sha512-L4HcrA05IgQyNYJj6kItuIkXrInJvsXTPC5B1i64FggWKKqSL+4hgt7asiSNva75AoLQjq29oPxFfU4GAQ6Z2w==} + dependencies: + '@types/node': 20.10.0 + dev: false + + /@types/http-assert@1.5.5: + resolution: {integrity: sha512-4+tE/lwdAahgZT1g30Jkdm9PzFRde0xwxBNUyRsCitRvCQB90iuA2uJYdUnhnANRcqGXaWOGY4FEoxeElNAK2g==} + dev: false + + /@types/http-errors@2.0.4: + resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==} + dev: false + + /@types/keygrip@1.0.6: + resolution: {integrity: sha512-lZuNAY9xeJt7Bx4t4dx0rYCDqGPW8RXhQZK1td7d4H6E9zYbLoOtjBvfwdTKpsyxQI/2jv+armjX/RW+ZNpXOQ==} + dev: false + + /@types/koa-compose@3.2.8: + resolution: {integrity: sha512-4Olc63RY+MKvxMwVknCUDhRQX1pFQoBZ/lXcRLP69PQkEpze/0cr8LNqJQe5NFb/b19DWi2a5bTi2VAlQzhJuA==} + dependencies: + '@types/koa': 2.13.12 + dev: false + + /@types/koa@2.13.12: + resolution: {integrity: sha512-vAo1KuDSYWFDB4Cs80CHvfmzSQWeUb909aQib0C0aFx4sw0K9UZFz2m5jaEP+b3X1+yr904iQiruS0hXi31jbw==} + dependencies: + '@types/accepts': 1.3.7 + '@types/content-disposition': 0.5.8 + '@types/cookies': 0.7.10 + '@types/http-assert': 1.5.5 + '@types/http-errors': 2.0.4 + '@types/keygrip': 1.0.6 + '@types/koa-compose': 3.2.8 + '@types/node': 20.10.0 + dev: false + + /@types/mime@1.3.5: + resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==} + dev: false + + /@types/mime@3.0.4: + resolution: {integrity: sha512-iJt33IQnVRkqeqC7PzBHPTC6fDlRNRW8vjrgqtScAhrmMwe8c4Eo7+fUGTa+XdWrpEgpyKWMYmi2dIwMAYRzPw==} + dev: false + + /@types/ms@0.7.34: + resolution: {integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==} + + /@types/node@20.10.0: + resolution: {integrity: sha512-D0WfRmU9TQ8I9PFx9Yc+EBHw+vSpIub4IDvQivcp26PtPrdMGAq5SDcpXEo/epqa/DXotVpekHiLNTg3iaKXBQ==} + dependencies: + undici-types: 5.26.5 + + /@types/qs@6.9.10: + resolution: {integrity: sha512-3Gnx08Ns1sEoCrWssEgTSJs/rsT2vhGP+Ja9cnnk9k4ALxinORlQneLXFeFKOTJMOeZUFD1s7w+w2AphTpvzZw==} + dev: false + + /@types/range-parser@1.2.7: + resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} + dev: false + + /@types/send@0.17.4: + resolution: {integrity: sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==} + dependencies: + '@types/mime': 1.3.5 + '@types/node': 20.10.0 + dev: false + + /@types/serve-static@1.15.5: + resolution: {integrity: sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==} + dependencies: + '@types/http-errors': 2.0.4 + '@types/mime': 3.0.4 + '@types/node': 20.10.0 + dev: false + + /@types/triple-beam@1.3.5: + resolution: {integrity: sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==} + dev: false + + /@types/validator@13.11.7: + resolution: {integrity: sha512-q0JomTsJ2I5Mv7dhHhQLGjMvX0JJm5dyZ1DXQySIUzU1UlwzB8bt+R6+LODUbz0UDIOvEzGc28tk27gBJw2N8Q==} + + /@ungap/structured-clone@1.2.0: + resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} + dev: true + + /abbrev@1.1.1: + resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} + dev: true + + /accepts@1.3.8: + resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} + engines: {node: '>= 0.6'} + dependencies: + mime-types: 2.1.35 + negotiator: 0.6.3 + dev: false + + /acorn-jsx@5.3.2(acorn@8.11.2): + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + acorn: 8.11.2 + dev: true + + /acorn@8.11.2: + resolution: {integrity: sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==} + engines: {node: '>=0.4.0'} + hasBin: true + dev: true + + /ajv-errors@3.0.0(ajv@8.12.0): + resolution: {integrity: sha512-V3wD15YHfHz6y0KdhYFjyy9vWtEVALT9UrxfN3zqlI6dMioHnJrqOYfyPKol3oqrnCM9uwkcdCwkJ0WUcbLMTQ==} + peerDependencies: + ajv: ^8.0.1 + dependencies: + ajv: 8.12.0 + dev: false + + /ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + dev: true + + /ajv@8.12.0: + resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} + dependencies: + fast-deep-equal: 3.1.3 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + uri-js: 4.4.1 + dev: false + + /ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + dev: true + + /ansi-styles@3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} + engines: {node: '>=4'} + dependencies: + color-convert: 1.9.3 + dev: false + + /ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + dependencies: + color-convert: 2.0.1 + dev: true + + /anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + dev: true + + /argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + dev: true + + /asap@2.0.6: + resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} + dev: false + + /async-ratelimiter@1.3.12: + resolution: {integrity: sha512-W7WWxWMjJ+XEZCyQhEWGrskqDgz3k2UWM/aUlatSl3ejFLwpM/G90AYSgkHHXeY2S53fiP204GITnmIxrJMsSQ==} + engines: {node: '>= 8'} + dev: false + + /async@3.2.5: + resolution: {integrity: sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==} + dev: false + + /balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + dev: true + + /big-integer@1.6.52: + resolution: {integrity: sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==} + engines: {node: '>=0.6'} + dev: true + + /binary-extensions@2.2.0: + resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} + engines: {node: '>=8'} + dev: true + + /bplist-parser@0.2.0: + resolution: {integrity: sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==} + engines: {node: '>= 5.10.0'} + dependencies: + big-integer: 1.6.52 + dev: true + + /brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + dev: true + + /braces@3.0.2: + resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} + engines: {node: '>=8'} + dependencies: + fill-range: 7.0.1 + dev: true + + /bundle-name@3.0.0: + resolution: {integrity: sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==} + engines: {node: '>=12'} + dependencies: + run-applescript: 5.0.0 + dev: true + + /bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} + dev: false + + /cache-content-type@1.0.1: + resolution: {integrity: sha512-IKufZ1o4Ut42YUrZSo8+qnMTrFuKkvyoLXUywKz9GJ5BrhOFGhLdkx9sG4KAnVvbY6kEcSFjLQul+DVmBm2bgA==} + engines: {node: '>= 6.0.0'} + dependencies: + mime-types: 2.1.35 + ylru: 1.3.2 + dev: false + + /call-bind@1.0.5: + resolution: {integrity: sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==} + dependencies: + function-bind: 1.1.2 + get-intrinsic: 1.2.2 + set-function-length: 1.1.1 + dev: false + + /callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + dev: true + + /chalk@2.4.2: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} + engines: {node: '>=4'} + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + dev: false + + /chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + dev: true + + /chokidar@3.5.3: + resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} + engines: {node: '>= 8.10.0'} + dependencies: + anymatch: 3.1.3 + braces: 3.0.2 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + dev: true + + /cliui@7.0.4: + resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + dev: true + + /co-body@6.1.0: + resolution: {integrity: sha512-m7pOT6CdLN7FuXUcpuz/8lfQ/L77x8SchHCF4G0RBTJO20Wzmhn5Sp4/5WsKy8OSpifBSUrmg83qEqaDHdyFuQ==} + dependencies: + inflation: 2.1.0 + qs: 6.11.2 + raw-body: 2.5.2 + type-is: 1.6.18 + dev: false + + /co@4.6.0: + resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} + engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} + dev: false + + /color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + dependencies: + color-name: 1.1.3 + dev: false + + /color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + dependencies: + color-name: 1.1.4 + dev: true + + /color-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + dev: false + + /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==} + dependencies: + color-name: 1.1.4 + simple-swizzle: 0.2.2 + dev: false + + /color@3.2.1: + resolution: {integrity: sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==} + dependencies: + color-convert: 1.9.3 + color-string: 1.9.1 + dev: false + + /colorspace@1.1.4: + resolution: {integrity: sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==} + dependencies: + color: 3.2.1 + text-hex: 1.0.0 + dev: false + + /compressible@2.0.18: + resolution: {integrity: sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==} + engines: {node: '>= 0.6'} + dependencies: + mime-db: 1.52.0 + dev: false + + /concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + dev: true + + /content-disposition@0.5.4: + resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} + engines: {node: '>= 0.6'} + dependencies: + safe-buffer: 5.2.1 + dev: false + + /content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + dev: false + + /cookies@0.8.0: + resolution: {integrity: sha512-8aPsApQfebXnuI+537McwYsDtjVxGm8gTIzQI3FDW6t5t/DAhERxtnbEPN/8RX+uZthoz4eCOgloXaE5cYyNow==} + engines: {node: '>= 0.8'} + dependencies: + depd: 2.0.0 + keygrip: 1.1.0 + dev: false + + /cross-env@7.0.3: + resolution: {integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==} + engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'} + hasBin: true + dependencies: + cross-spawn: 7.0.3 + dev: true + + /cross-spawn@7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + engines: {node: '>= 8'} + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + dev: true + + /debug@3.2.7(supports-color@5.5.0): + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.2 + supports-color: 5.5.0 + dev: true + + /debug@4.3.4: + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.2 + + /deep-equal@1.0.1: + resolution: {integrity: sha512-bHtC0iYvWhyaTzvV3CZgPeZQqCOBGyGsVV7v4eevpdkLHfiSrXUdBG+qAuSz4RI70sszvjQ1QSZ98An1yNwpSw==} + dev: false + + /deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + dev: true + + /default-browser-id@3.0.0: + resolution: {integrity: sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==} + engines: {node: '>=12'} + dependencies: + bplist-parser: 0.2.0 + untildify: 4.0.0 + dev: true + + /default-browser@4.0.0: + resolution: {integrity: sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==} + engines: {node: '>=14.16'} + dependencies: + bundle-name: 3.0.0 + default-browser-id: 3.0.0 + execa: 7.2.0 + titleize: 3.0.0 + dev: true + + /define-data-property@1.1.1: + resolution: {integrity: sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.2 + gopd: 1.0.1 + has-property-descriptors: 1.0.1 + dev: false + + /define-lazy-prop@3.0.0: + resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} + engines: {node: '>=12'} + dev: true + + /delegates@1.0.0: + resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==} + dev: false + + /denque@2.1.0: + resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} + engines: {node: '>=0.10'} + + /depd@1.1.2: + resolution: {integrity: sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==} + engines: {node: '>= 0.6'} + dev: false + + /depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + dev: false + + /destroy@1.2.0: + resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + dev: false + + /dezalgo@1.0.4: + resolution: {integrity: sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==} + dependencies: + asap: 2.0.6 + wrappy: 1.0.2 + dev: false + + /doctrine@3.0.0: + resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} + engines: {node: '>=6.0.0'} + dependencies: + esutils: 2.0.3 + dev: true + + /dottie@2.0.6: + resolution: {integrity: sha512-iGCHkfUc5kFekGiqhe8B/mdaurD+lakO9txNnTvKtA6PISrw86LgqHvRzWYPyoE2Ph5aMIrCw9/uko6XHTKCwA==} + + /ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + dev: false + + /emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + dev: true + + /enabled@2.0.0: + resolution: {integrity: sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==} + dev: false + + /encodeurl@1.0.2: + resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} + engines: {node: '>= 0.8'} + dev: false + + /escalade@3.1.1: + resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} + engines: {node: '>=6'} + dev: true + + /escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + dev: false + + /escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + dev: false + + /escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + dev: true + + /eslint-config-prettier@9.0.0(eslint@8.54.0): + resolution: {integrity: sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw==} + hasBin: true + peerDependencies: + eslint: '>=7.0.0' + dependencies: + eslint: 8.54.0 + dev: true + + /eslint-plugin-prettier@5.0.1(eslint-config-prettier@9.0.0)(eslint@8.54.0)(prettier@3.1.0): + resolution: {integrity: sha512-m3u5RnR56asrwV/lDC4GHorlW75DsFfmUcjfCYylTUs85dBRnB7VM6xG8eCMJdeDRnppzmxZVf1GEPJvl1JmNg==} + 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 + dependencies: + eslint: 8.54.0 + eslint-config-prettier: 9.0.0(eslint@8.54.0) + prettier: 3.1.0 + prettier-linter-helpers: 1.0.0 + synckit: 0.8.5 + dev: true + + /eslint-scope@7.2.2: + resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + dev: true + + /eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + /eslint@8.54.0: + resolution: {integrity: sha512-NY0DfAkM8BIZDVl6PgSa1ttZbx3xHgJzSNJKYcQglem6CppHyMhRIQkBVSSMaSRnLhig3jsDbEzOjwCVt4AmmA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + hasBin: true + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.54.0) + '@eslint-community/regexpp': 4.10.0 + '@eslint/eslintrc': 2.1.3 + '@eslint/js': 8.54.0 + '@humanwhocodes/config-array': 0.11.13 + '@humanwhocodes/module-importer': 1.0.1 + '@nodelib/fs.walk': 1.2.8 + '@ungap/structured-clone': 1.2.0 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.3 + debug: 4.3.4 + doctrine: 3.0.0 + escape-string-regexp: 4.0.0 + eslint-scope: 7.2.2 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 + esquery: 1.5.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 6.0.1 + find-up: 5.0.0 + glob-parent: 6.0.2 + globals: 13.23.0 + graphemer: 1.4.0 + ignore: 5.3.0 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + is-path-inside: 3.0.3 + js-yaml: 4.1.0 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.3 + strip-ansi: 6.0.1 + text-table: 0.2.0 + transitivePeerDependencies: + - supports-color + dev: true + + /espree@9.6.1: + resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + acorn: 8.11.2 + acorn-jsx: 5.3.2(acorn@8.11.2) + eslint-visitor-keys: 3.4.3 + dev: true + + /esquery@1.5.0: + resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} + engines: {node: '>=0.10'} + dependencies: + estraverse: 5.3.0 + dev: true + + /esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + dependencies: + estraverse: 5.3.0 + dev: true + + /estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + dev: true + + /esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + dev: true + + /execa@5.1.1: + resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} + engines: {node: '>=10'} + dependencies: + cross-spawn: 7.0.3 + get-stream: 6.0.1 + human-signals: 2.1.0 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + dev: true + + /execa@7.2.0: + resolution: {integrity: sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==} + engines: {node: ^14.18.0 || ^16.14.0 || >=18.0.0} + dependencies: + cross-spawn: 7.0.3 + get-stream: 6.0.1 + human-signals: 4.3.1 + is-stream: 3.0.0 + merge-stream: 2.0.0 + npm-run-path: 5.1.0 + onetime: 6.0.0 + signal-exit: 3.0.7 + strip-final-newline: 3.0.0 + dev: true + + /express-useragent@1.0.15: + resolution: {integrity: sha512-eq5xMiYCYwFPoekffMjvEIk+NWdlQY9Y38OsTyl13IvA728vKT+q/CSERYWzcw93HGBJcIqMIsZC5CZGARPVdg==} + engines: {node: '>=4.5'} + dev: false + + /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==} + dev: true + + /fast-glob@3.3.2: + resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} + engines: {node: '>=8.6.0'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.5 + dev: true + + /fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + dev: true + + /fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + dev: true + + /fastq@1.15.0: + resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} + dependencies: + reusify: 1.0.4 + dev: true + + /fecha@4.2.3: + resolution: {integrity: sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==} + dev: false + + /file-entry-cache@6.0.1: + resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} + engines: {node: ^10.12.0 || >=12.0.0} + dependencies: + flat-cache: 3.2.0 + dev: true + + /file-stream-rotator@0.6.1: + resolution: {integrity: sha512-u+dBid4PvZw17PmDeRcNOtCP9CCK/9lRN2w+r1xIS7yOL9JFrIBKTvrYsxT4P0pGtThYTn++QS5ChHaUov3+zQ==} + dependencies: + moment: 2.29.4 + dev: false + + /fill-range@7.0.1: + resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} + engines: {node: '>=8'} + dependencies: + to-regex-range: 5.0.1 + dev: true + + /find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + dev: true + + /flat-cache@3.2.0: + resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} + engines: {node: ^10.12.0 || >=12.0.0} + dependencies: + flatted: 3.2.9 + keyv: 4.5.4 + rimraf: 3.0.2 + dev: true + + /flatted@3.2.9: + resolution: {integrity: sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==} + dev: true + + /fn.name@1.1.0: + resolution: {integrity: sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==} + dev: false + + /formidable@2.1.2: + resolution: {integrity: sha512-CM3GuJ57US06mlpQ47YcunuUZ9jpm8Vx+P2CGt2j7HpgkKZO/DJYQ0Bobim8G6PFQmK5lOqOOdUXboU+h73A4g==} + dependencies: + dezalgo: 1.0.4 + hexoid: 1.0.0 + once: 1.4.0 + qs: 6.11.2 + dev: false + + /fresh@0.5.2: + resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} + engines: {node: '>= 0.6'} + dev: false + + /fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + dev: true + + /fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + dev: false + + /generate-function@2.3.1: + resolution: {integrity: sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==} + dependencies: + is-property: 1.0.2 + + /get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + dev: true + + /get-intrinsic@1.2.2: + resolution: {integrity: sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==} + dependencies: + function-bind: 1.1.2 + has-proto: 1.0.1 + has-symbols: 1.0.3 + hasown: 2.0.0 + dev: false + + /get-stream@6.0.1: + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} + dev: true + + /glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + dependencies: + is-glob: 4.0.3 + dev: true + + /glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + dependencies: + is-glob: 4.0.3 + dev: true + + /glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + dev: true + + /globals@13.23.0: + resolution: {integrity: sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==} + engines: {node: '>=8'} + dependencies: + type-fest: 0.20.2 + dev: true + + /gopd@1.0.1: + resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + dependencies: + get-intrinsic: 1.2.2 + dev: false + + /graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + dev: true + + /has-flag@3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} + + /has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + dev: true + + /has-property-descriptors@1.0.1: + resolution: {integrity: sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==} + dependencies: + get-intrinsic: 1.2.2 + dev: false + + /has-proto@1.0.1: + resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} + engines: {node: '>= 0.4'} + dev: false + + /has-symbols@1.0.3: + resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} + engines: {node: '>= 0.4'} + dev: false + + /has-tostringtag@1.0.0: + resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==} + engines: {node: '>= 0.4'} + dependencies: + has-symbols: 1.0.3 + dev: false + + /hasown@2.0.0: + resolution: {integrity: sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==} + engines: {node: '>= 0.4'} + dependencies: + function-bind: 1.1.2 + dev: false + + /hexoid@1.0.0: + resolution: {integrity: sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==} + engines: {node: '>=8'} + dev: false + + /http-assert@1.5.0: + resolution: {integrity: sha512-uPpH7OKX4H25hBmU6G1jWNaqJGpTXxey+YOUizJUAgu0AjLUeC8D73hTrhvDS5D+GJN1DN1+hhc/eF/wpxtp0w==} + engines: {node: '>= 0.8'} + dependencies: + deep-equal: 1.0.1 + http-errors: 1.8.1 + dev: false + + /http-errors@1.8.1: + resolution: {integrity: sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==} + engines: {node: '>= 0.6'} + dependencies: + depd: 1.1.2 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 1.5.0 + toidentifier: 1.0.1 + dev: false + + /http-errors@2.0.0: + resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} + engines: {node: '>= 0.8'} + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.1 + toidentifier: 1.0.1 + dev: false + + /human-signals@2.1.0: + resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} + engines: {node: '>=10.17.0'} + dev: true + + /human-signals@4.3.1: + resolution: {integrity: sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==} + engines: {node: '>=14.18.0'} + dev: true + + /humanize-number@0.0.2: + resolution: {integrity: sha512-un3ZAcNQGI7RzaWGZzQDH47HETM4Wrj6z6E4TId8Yeq9w5ZKUVB1nrT2jwFheTUjEmqcgTjXDc959jum+ai1kQ==} + dev: false + + /iconv-lite@0.4.24: + resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} + engines: {node: '>=0.10.0'} + dependencies: + safer-buffer: 2.1.2 + dev: false + + /iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + dependencies: + safer-buffer: 2.1.2 + + /ignore-by-default@1.0.1: + resolution: {integrity: sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==} + dev: true + + /ignore@5.3.0: + resolution: {integrity: sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==} + engines: {node: '>= 4'} + dev: true + + /import-fresh@3.3.0: + resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + engines: {node: '>=6'} + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + dev: true + + /imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + dev: true + + /inflation@2.1.0: + resolution: {integrity: sha512-t54PPJHG1Pp7VQvxyVCJ9mBbjG3Hqryges9bXoOO6GExCPa+//i/d5GSuFtpx3ALLd7lgIAur6zrIlBQyJuMlQ==} + engines: {node: '>= 0.8.0'} + dev: false + + /inflection@1.13.4: + resolution: {integrity: sha512-6I/HUDeYFfuNCVS3td055BaXBwKYuzw7K3ExVMStBowKo9oOAMJIXIHvdyR3iboTCp1b+1i5DSkIZTcwIktuDw==} + engines: {'0': node >= 0.4.0} + + /inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + dev: true + + /inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + /is-arrayish@0.3.2: + resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} + dev: false + + /is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + dependencies: + binary-extensions: 2.2.0 + dev: true + + /is-docker@2.2.1: + resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} + engines: {node: '>=8'} + hasBin: true + dev: true + + /is-docker@3.0.0: + resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + hasBin: true + dev: true + + /is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + dev: true + + /is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + dev: true + + /is-generator-function@1.0.10: + resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.0 + dev: false + + /is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + dependencies: + is-extglob: 2.1.1 + dev: true + + /is-inside-container@1.0.0: + resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} + engines: {node: '>=14.16'} + hasBin: true + dependencies: + is-docker: 3.0.0 + dev: true + + /is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + dev: true + + /is-path-inside@3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + dev: true + + /is-property@1.0.2: + resolution: {integrity: sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==} + + /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} + dev: true + + /is-wsl@2.2.0: + resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} + engines: {node: '>=8'} + dependencies: + is-docker: 2.2.1 + dev: true + + /isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + dev: true + + /js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + dependencies: + argparse: 2.0.1 + dev: true + + /json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + dev: true + + /json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + dev: true + + /json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + dev: false + + /json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + dev: true + + /keygrip@1.1.0: + resolution: {integrity: sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==} + engines: {node: '>= 0.6'} + dependencies: + tsscmp: 1.0.6 + dev: false + + /keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + dependencies: + json-buffer: 3.0.1 + dev: true + + /koa-body@6.0.1: + resolution: {integrity: sha512-M8ZvMD8r+kPHy28aWP9VxL7kY8oPWA+C7ZgCljrCMeaU7uX6wsIQgDHskyrAr9sw+jqnIXyv4Mlxri5R4InIJg==} + dependencies: + '@types/co-body': 6.1.3 + '@types/formidable': 2.0.6 + '@types/koa': 2.13.12 + co-body: 6.1.0 + formidable: 2.1.2 + zod: 3.22.4 + dev: false + + /koa-compose@4.1.0: + resolution: {integrity: sha512-8ODW8TrDuMYvXRwra/Kh7/rJo9BtOfPc6qO8eAfC80CnCvSjSl0bkRM24X6/XBBEyj0v1nRUQ1LyOy3dbqOWXw==} + dev: false + + /koa-compress@5.1.1: + resolution: {integrity: sha512-UgMIN7ZoEP2DuoSQmD6CYvFSLt0NReGlc2qSY4bO4Oq0L56OiD9pDG41Kj/zFmVY/A3Wvmn4BqKcfq5H30LGIg==} + engines: {node: '>= 12'} + dependencies: + bytes: 3.1.2 + compressible: 2.0.18 + http-errors: 1.8.1 + koa-is-json: 1.0.0 + dev: false + + /koa-convert@2.0.0: + resolution: {integrity: sha512-asOvN6bFlSnxewce2e/DK3p4tltyfC4VM7ZwuTuepI7dEQVcvpyFuBcEARu1+Hxg8DIwytce2n7jrZtRlPrARA==} + engines: {node: '>= 10'} + dependencies: + co: 4.6.0 + koa-compose: 4.1.0 + dev: false + + /koa-is-json@1.0.0: + resolution: {integrity: sha512-+97CtHAlWDx0ndt0J8y3P12EWLwTLMXIfMnYDev3wOTwH/RpBGMlfn4bDXlMEg1u73K6XRE9BbUp+5ZAYoRYWw==} + dev: false + + /koa-json-error@3.1.2: + resolution: {integrity: sha512-nqfNwD4W+hYaJijFl+6qNSQJHbTS4vp+gXTdXl5U8YK2PVNzCF0HnLZwyKHaMeBebhanAgmfheQv96wLDjLRxg==} + engines: {node: '>=6.0.0'} + dependencies: + lodash.compact: 3.0.1 + lodash.curry: 4.1.1 + dev: false + + /koa-logger@3.2.1: + resolution: {integrity: sha512-MjlznhLLKy9+kG8nAXKJLM0/ClsQp/Or2vI3a5rbSQmgl8IJBQO0KI5FA70BvW+hqjtxjp49SpH2E7okS6NmHg==} + engines: {node: '>= 7.6.0'} + dependencies: + bytes: 3.1.2 + chalk: 2.4.2 + humanize-number: 0.0.2 + passthrough-counter: 1.0.0 + dev: false + + /koa-ratelimit@5.0.1: + resolution: {integrity: sha512-H7IEkNS/b18Uwtm3RIvAK3orJE8ew8wEBsnezlQWz7GTWqEnDtbTNfTedVXjj07gyh8gWTkEdODEXRquGCBqmg==} + engines: {node: '>= 10'} + dependencies: + async-ratelimiter: 1.3.12 + debug: 4.3.4 + ms: 2.1.2 + transitivePeerDependencies: + - supports-color + dev: false + + /koa-router@12.0.1: + resolution: {integrity: sha512-gaDdj3GtzoLoeosacd50kBBTnnh3B9AYxDThQUo4sfUyXdOhY6ku1qyZKW88tQCRgc3Sw6ChXYXWZwwgjOxE0w==} + engines: {node: '>= 12'} + dependencies: + debug: 4.3.4 + http-errors: 2.0.0 + koa-compose: 4.1.0 + methods: 1.1.2 + path-to-regexp: 6.2.1 + transitivePeerDependencies: + - supports-color + dev: false + + /koa-useragent@4.1.0: + resolution: {integrity: sha512-x/HUDZ1zAmNNh5hA9hHbPm9p3UVg2prlpHzxCXQCzbibrNS0kmj7MkCResCbAbG7ZT6FVxNSMjR94ZGamdMwxA==} + engines: {node: '>=7.6.0'} + dependencies: + express-useragent: 1.0.15 + dev: false + + /koa@2.14.2: + resolution: {integrity: sha512-VFI2bpJaodz6P7x2uyLiX6RLYpZmOJqNmoCst/Yyd7hQlszyPwG/I9CQJ63nOtKSxpt5M7NH67V6nJL2BwCl7g==} + engines: {node: ^4.8.4 || ^6.10.1 || ^7.10.1 || >= 8.1.4} + dependencies: + accepts: 1.3.8 + cache-content-type: 1.0.1 + content-disposition: 0.5.4 + content-type: 1.0.5 + cookies: 0.8.0 + debug: 4.3.4 + delegates: 1.0.0 + depd: 2.0.0 + destroy: 1.2.0 + encodeurl: 1.0.2 + escape-html: 1.0.3 + fresh: 0.5.2 + http-assert: 1.5.0 + http-errors: 1.8.1 + is-generator-function: 1.0.10 + koa-compose: 4.1.0 + koa-convert: 2.0.0 + on-finished: 2.4.1 + only: 0.0.2 + parseurl: 1.3.3 + statuses: 1.5.0 + type-is: 1.6.18 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + dev: false + + /kuler@2.0.0: + resolution: {integrity: sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==} + dev: false + + /levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + dev: true + + /locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + dependencies: + p-locate: 5.0.0 + dev: true + + /lodash.compact@3.0.1: + resolution: {integrity: sha512-2ozeiPi+5eBXW1CLtzjk8XQFhQOEMwwfxblqeq6EGyTxZJ1bPATqilY0e6g2SLQpP4KuMeuioBhEnWz5Pr7ICQ==} + dev: false + + /lodash.curry@4.1.1: + resolution: {integrity: sha512-/u14pXGviLaweY5JI0IUzgzF2J6Ne8INyzAZjImcryjgkZ+ebruBxy2/JaOOkTqScddcYtakjhSaeemV8lR0tA==} + dev: false + + /lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + dev: true + + /lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + + /logform@2.6.0: + resolution: {integrity: sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ==} + engines: {node: '>= 12.0.0'} + dependencies: + '@colors/colors': 1.6.0 + '@types/triple-beam': 1.3.5 + fecha: 4.2.3 + ms: 2.1.2 + safe-stable-stringify: 2.4.3 + triple-beam: 1.4.1 + dev: false + + /long@5.2.3: + resolution: {integrity: sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==} + + /lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + dependencies: + yallist: 4.0.0 + + /lru-cache@7.18.3: + resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} + engines: {node: '>=12'} + + /lru-cache@8.0.5: + resolution: {integrity: sha512-MhWWlVnuab1RG5/zMRRcVGXZLCXrZTgfwMikgzCegsPnG62yDQo5JnqKkrK4jO5iKqDAZGItAqN5CtKBCBWRUA==} + engines: {node: '>=16.14'} + + /media-typer@0.3.0: + resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} + engines: {node: '>= 0.6'} + dev: false + + /merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + dev: true + + /merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + dev: true + + /methods@1.1.2: + resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} + engines: {node: '>= 0.6'} + dev: false + + /micromatch@4.0.5: + resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} + engines: {node: '>=8.6'} + dependencies: + braces: 3.0.2 + picomatch: 2.3.1 + dev: true + + /mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + dev: false + + /mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + dependencies: + mime-db: 1.52.0 + dev: false + + /mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + dev: true + + /mimic-fn@4.0.0: + resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} + engines: {node: '>=12'} + dev: true + + /minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + dependencies: + brace-expansion: 1.1.11 + dev: true + + /mkdirp@1.0.4: + resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} + engines: {node: '>=10'} + hasBin: true + dev: true + + /moment-timezone@0.5.43: + resolution: {integrity: sha512-72j3aNyuIsDxdF1i7CEgV2FfxM1r6aaqJyLB2vwb33mXYyoyLly+F1zbWqhA3/bVIoJ4szlUoMbUnVdid32NUQ==} + dependencies: + moment: 2.29.4 + + /moment@2.29.4: + resolution: {integrity: sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==} + + /ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + + /mysql2@3.6.5: + resolution: {integrity: sha512-pS/KqIb0xlXmtmqEuTvBXTmLoQ5LmAz5NW/r8UyQ1ldvnprNEj3P9GbmuQQ2J0A4LO+ynotGi6TbscPa8OUb+w==} + engines: {node: '>= 8.0'} + dependencies: + denque: 2.1.0 + generate-function: 2.3.1 + iconv-lite: 0.6.3 + long: 5.2.3 + lru-cache: 8.0.5 + named-placeholders: 1.1.3 + seq-queue: 0.0.5 + sqlstring: 2.3.3 + + /named-placeholders@1.1.3: + resolution: {integrity: sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==} + engines: {node: '>=12.0.0'} + dependencies: + lru-cache: 7.18.3 + + /natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + dev: true + + /negotiator@0.6.3: + resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} + engines: {node: '>= 0.6'} + dev: false + + /nodemon@3.0.1: + resolution: {integrity: sha512-g9AZ7HmkhQkqXkRc20w+ZfQ73cHLbE8hnPbtaFbFtCumZsjyMhKk9LajQ07U5Ux28lvFjZ5X7HvWR1xzU8jHVw==} + engines: {node: '>=10'} + hasBin: true + dependencies: + chokidar: 3.5.3 + debug: 3.2.7(supports-color@5.5.0) + ignore-by-default: 1.0.1 + minimatch: 3.1.2 + pstree.remy: 1.1.8 + semver: 7.5.4 + simple-update-notifier: 2.0.0 + supports-color: 5.5.0 + touch: 3.1.0 + undefsafe: 2.0.5 + dev: true + + /nopt@1.0.10: + resolution: {integrity: sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==} + hasBin: true + dependencies: + abbrev: 1.1.1 + dev: true + + /normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + dev: true + + /npm-run-path@4.0.1: + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} + engines: {node: '>=8'} + dependencies: + path-key: 3.1.1 + dev: true + + /npm-run-path@5.1.0: + resolution: {integrity: sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + path-key: 4.0.0 + dev: true + + /object-hash@2.2.0: + resolution: {integrity: sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==} + engines: {node: '>= 6'} + dev: false + + /object-inspect@1.13.1: + resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} + dev: false + + /on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + dependencies: + ee-first: 1.1.1 + dev: false + + /once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + dependencies: + wrappy: 1.0.2 + + /one-time@1.0.0: + resolution: {integrity: sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==} + dependencies: + fn.name: 1.1.0 + dev: false + + /onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + dependencies: + mimic-fn: 2.1.0 + dev: true + + /onetime@6.0.0: + resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} + engines: {node: '>=12'} + dependencies: + mimic-fn: 4.0.0 + dev: true + + /only@0.0.2: + resolution: {integrity: sha512-Fvw+Jemq5fjjyWz6CpKx6w9s7xxqo3+JCyM0WXWeCSOboZ8ABkyvP8ID4CZuChA/wxSx+XSJmdOm8rGVyJ1hdQ==} + dev: false + + /open@9.1.0: + resolution: {integrity: sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg==} + engines: {node: '>=14.16'} + dependencies: + default-browser: 4.0.0 + define-lazy-prop: 3.0.0 + is-inside-container: 1.0.0 + is-wsl: 2.2.0 + dev: true + + /optionator@0.9.3: + resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} + engines: {node: '>= 0.8.0'} + dependencies: + '@aashutoshrathi/word-wrap': 1.2.6 + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + dev: true + + /p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + dependencies: + yocto-queue: 0.1.0 + dev: true + + /p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + dependencies: + p-limit: 3.1.0 + dev: true + + /parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + dependencies: + callsites: 3.1.0 + dev: true + + /parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + dev: false + + /passthrough-counter@1.0.0: + resolution: {integrity: sha512-Wy8PXTLqPAN0oEgBrlnsXPMww3SYJ44tQ8aVrGAI4h4JZYCS0oYqsPqtPR8OhJpv6qFbpbB7XAn0liKV7EXubA==} + dev: false + + /path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + dev: true + + /path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + dev: true + + /path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + dev: true + + /path-key@4.0.0: + resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} + engines: {node: '>=12'} + dev: true + + /path-to-regexp@6.2.1: + resolution: {integrity: sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==} + dev: false + + /pg-connection-string@2.6.2: + resolution: {integrity: sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==} + + /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'} + dev: true + + /prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + dev: true + + /prettier-linter-helpers@1.0.0: + resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} + engines: {node: '>=6.0.0'} + dependencies: + fast-diff: 1.3.0 + dev: true + + /prettier@3.1.0: + resolution: {integrity: sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw==} + engines: {node: '>=14'} + hasBin: true + dev: true + + /pstree.remy@1.1.8: + resolution: {integrity: sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==} + dev: true + + /punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + /qs@6.11.2: + resolution: {integrity: sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==} + engines: {node: '>=0.6'} + dependencies: + side-channel: 1.0.4 + dev: false + + /queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + dev: true + + /raw-body@2.5.2: + resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} + engines: {node: '>= 0.8'} + dependencies: + bytes: 3.1.2 + http-errors: 2.0.0 + iconv-lite: 0.4.24 + unpipe: 1.0.0 + dev: false + + /readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + dev: false + + /readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + dependencies: + picomatch: 2.3.1 + dev: true + + /require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + dev: true + + /require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + dev: false + + /reserved-words@0.1.2: + resolution: {integrity: sha512-0S5SrIUJ9LfpbVl4Yzij6VipUdafHrOTzvmfazSw/jeZrZtQK303OPZW+obtkaw7jQlTQppy0UvZWm9872PbRw==} + dev: true + + /resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + dev: true + + /retry-as-promised@7.0.4: + resolution: {integrity: sha512-XgmCoxKWkDofwH8WddD0w85ZfqYz+ZHlr5yo+3YUCfycWawU56T5ckWXsScsj5B8tqUcIG67DxXByo3VUgiAdA==} + + /reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + dev: true + + /rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + hasBin: true + dependencies: + glob: 7.2.3 + dev: true + + /run-applescript@5.0.0: + resolution: {integrity: sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==} + engines: {node: '>=12'} + dependencies: + execa: 5.1.1 + dev: true + + /run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + dependencies: + queue-microtask: 1.2.3 + dev: true + + /safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + dev: false + + /safe-stable-stringify@2.4.3: + resolution: {integrity: sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==} + engines: {node: '>=10'} + dev: false + + /safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + /semver@7.5.4: + resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} + engines: {node: '>=10'} + hasBin: true + dependencies: + lru-cache: 6.0.0 + + /seq-queue@0.0.5: + resolution: {integrity: sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==} + + /sequelize-auto@0.8.8(sequelize@6.35.1): + resolution: {integrity: sha512-9o0qi2yMA86oFqcA5Nh14PnQSHP0E9WPEB4hP/NgxqdFE44Nq2u8Di5O3xmvWwXMIV6W+Q0YI/2VTLvlMJAjnQ==} + engines: {node: '>= 10'} + hasBin: true + peerDependencies: + sequelize: '>3.30.0' + dependencies: + lodash: 4.17.21 + mkdirp: 1.0.4 + reserved-words: 0.1.2 + sequelize: 6.35.1(mysql2@3.6.5) + yargs: 16.2.0 + dev: true + + /sequelize-pool@7.1.0: + resolution: {integrity: sha512-G9c0qlIWQSK29pR/5U2JF5dDQeqqHRragoyahj/Nx4KOOQ3CPPfzxnfqFPCSB7x5UgjOgnZ61nSxz+fjDpRlJg==} + engines: {node: '>= 10.0.0'} + + /sequelize@6.35.1(mysql2@3.6.5): + resolution: {integrity: sha512-UlP5k33nJsN11wCDLaWZXw9bB8w4ESKc5QmG6D04qMimwBwKVNeqRJiaaBlEJdtg8cRK+OJh95dliP+uEi+g9Q==} + engines: {node: '>=10.0.0'} + peerDependencies: + ibm_db: '*' + mariadb: '*' + mysql2: '*' + oracledb: '*' + pg: '*' + pg-hstore: '*' + snowflake-sdk: '*' + sqlite3: '*' + tedious: '*' + peerDependenciesMeta: + ibm_db: + optional: true + mariadb: + optional: true + mysql2: + optional: true + oracledb: + optional: true + pg: + optional: true + pg-hstore: + optional: true + snowflake-sdk: + optional: true + sqlite3: + optional: true + tedious: + optional: true + dependencies: + '@types/debug': 4.1.12 + '@types/validator': 13.11.7 + debug: 4.3.4 + dottie: 2.0.6 + inflection: 1.13.4 + lodash: 4.17.21 + moment: 2.29.4 + moment-timezone: 0.5.43 + mysql2: 3.6.5 + pg-connection-string: 2.6.2 + retry-as-promised: 7.0.4 + semver: 7.5.4 + sequelize-pool: 7.1.0 + toposort-class: 1.0.1 + uuid: 8.3.2 + validator: 13.11.0 + wkx: 0.5.0 + transitivePeerDependencies: + - supports-color + + /set-function-length@1.1.1: + resolution: {integrity: sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.1 + get-intrinsic: 1.2.2 + gopd: 1.0.1 + has-property-descriptors: 1.0.1 + dev: false + + /setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + dev: false + + /shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + dependencies: + shebang-regex: 3.0.0 + dev: true + + /shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + dev: true + + /side-channel@1.0.4: + resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} + dependencies: + call-bind: 1.0.5 + get-intrinsic: 1.2.2 + object-inspect: 1.13.1 + dev: false + + /signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + dev: true + + /simple-swizzle@0.2.2: + resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} + dependencies: + is-arrayish: 0.3.2 + dev: false + + /simple-update-notifier@2.0.0: + resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==} + engines: {node: '>=10'} + dependencies: + semver: 7.5.4 + dev: true + + /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==} + dev: false + + /statuses@1.5.0: + resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==} + engines: {node: '>= 0.6'} + dev: false + + /statuses@2.0.1: + resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} + engines: {node: '>= 0.8'} + dev: false + + /string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + dev: true + + /string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + dependencies: + safe-buffer: 5.2.1 + dev: false + + /strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + dependencies: + ansi-regex: 5.0.1 + dev: true + + /strip-final-newline@2.0.0: + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} + engines: {node: '>=6'} + dev: true + + /strip-final-newline@3.0.0: + resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} + engines: {node: '>=12'} + dev: true + + /strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + dev: true + + /supports-color@5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + dependencies: + has-flag: 3.0.0 + + /supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + dependencies: + has-flag: 4.0.0 + dev: true + + /synckit@0.8.5: + resolution: {integrity: sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==} + engines: {node: ^14.18.0 || >=16.0.0} + dependencies: + '@pkgr/utils': 2.4.2 + tslib: 2.6.2 + dev: true + + /text-hex@1.0.0: + resolution: {integrity: sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==} + dev: false + + /text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + dev: true + + /titleize@3.0.0: + resolution: {integrity: sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==} + engines: {node: '>=12'} + dev: true + + /to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + dependencies: + is-number: 7.0.0 + dev: true + + /toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + dev: false + + /toposort-class@1.0.1: + resolution: {integrity: sha512-OsLcGGbYF3rMjPUf8oKktyvCiUxSbqMMS39m33MAjLTC1DVIH6x3WSt63/M77ihI09+Sdfk1AXvfhCEeUmC7mg==} + + /touch@3.1.0: + resolution: {integrity: sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==} + hasBin: true + dependencies: + nopt: 1.0.10 + dev: true + + /triple-beam@1.4.1: + resolution: {integrity: sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==} + engines: {node: '>= 14.0.0'} + dev: false + + /tslib@2.6.2: + resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} + dev: true + + /tsscmp@1.0.6: + resolution: {integrity: sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==} + engines: {node: '>=0.6.x'} + dev: false + + /type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + dependencies: + prelude-ls: 1.2.1 + dev: true + + /type-fest@0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} + dev: true + + /type-is@1.6.18: + resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} + engines: {node: '>= 0.6'} + dependencies: + media-typer: 0.3.0 + mime-types: 2.1.35 + dev: false + + /undefsafe@2.0.5: + resolution: {integrity: sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==} + dev: true + + /undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + + /unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + dev: false + + /untildify@4.0.0: + resolution: {integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==} + engines: {node: '>=8'} + dev: true + + /uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + dependencies: + punycode: 2.3.1 + + /util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + dev: false + + /uuid@8.3.2: + resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} + hasBin: true + + /validator@13.11.0: + resolution: {integrity: sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ==} + engines: {node: '>= 0.10'} + + /vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + dev: false + + /which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + dependencies: + isexe: 2.0.0 + dev: true + + /winston-daily-rotate-file@4.7.1(winston@3.11.0): + resolution: {integrity: sha512-7LGPiYGBPNyGHLn9z33i96zx/bd71pjBn9tqQzO3I4Tayv94WPmBNwKC7CO1wPHdP9uvu+Md/1nr6VSH9h0iaA==} + engines: {node: '>=8'} + peerDependencies: + winston: ^3 + dependencies: + file-stream-rotator: 0.6.1 + object-hash: 2.2.0 + triple-beam: 1.4.1 + winston: 3.11.0 + winston-transport: 4.6.0 + dev: false + + /winston-transport@4.6.0: + resolution: {integrity: sha512-wbBA9PbPAHxKiygo7ub7BYRiKxms0tpfU2ljtWzb3SjRjv5yl6Ozuy/TkXf00HTAt+Uylo3gSkNwzc4ME0wiIg==} + engines: {node: '>= 12.0.0'} + dependencies: + logform: 2.6.0 + readable-stream: 3.6.2 + triple-beam: 1.4.1 + dev: false + + /winston@3.11.0: + resolution: {integrity: sha512-L3yR6/MzZAOl0DsysUXHVjOwv8mKZ71TrA/41EIduGpOOV5LQVodqN+QdQ6BS6PJ/RdIshZhq84P/fStEZkk7g==} + engines: {node: '>= 12.0.0'} + dependencies: + '@colors/colors': 1.6.0 + '@dabh/diagnostics': 2.0.3 + async: 3.2.5 + is-stream: 2.0.1 + logform: 2.6.0 + one-time: 1.0.0 + readable-stream: 3.6.2 + safe-stable-stringify: 2.4.3 + stack-trace: 0.0.10 + triple-beam: 1.4.1 + winston-transport: 4.6.0 + dev: false + + /wkx@0.5.0: + resolution: {integrity: sha512-Xng/d4Ichh8uN4l0FToV/258EjMGU9MGcA0HV2d9B/ZpZB3lqQm7nkOdZdm5GhKtLLhAE7PiVQwN4eN+2YJJUg==} + dependencies: + '@types/node': 20.10.0 + + /wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + dev: true + + /wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + /y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + dev: true + + /yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + + /yargs-parser@20.2.9: + resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} + engines: {node: '>=10'} + dev: true + + /yargs@16.2.0: + resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} + engines: {node: '>=10'} + dependencies: + cliui: 7.0.4 + escalade: 3.1.1 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 20.2.9 + dev: true + + /ylru@1.3.2: + resolution: {integrity: sha512-RXRJzMiK6U2ye0BlGGZnmpwJDPgakn6aNQ0A7gHRbD4I0uvK4TW6UqkK1V0pp9jskjJBAXd3dRrbzWkqJ+6cxA==} + engines: {node: '>= 4.0.0'} + dev: false + + /yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + dev: true + + /zod@3.22.4: + resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==} + dev: false diff --git a/production.env.js b/production.env.js new file mode 100644 index 0000000..a3aad51 --- /dev/null +++ b/production.env.js @@ -0,0 +1,43 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: initkoa +// | @文件描述: production.env.js - +// | @创建时间: 2023-11-25 21:36 +// | @更新时间: 2023-11-25 21:36 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ + + +const prodConfig = { + appName: 'graphResource2', + port: 3000, + zip: true, + upfile:{ + maxFileSize: 200 * 1024 * 1024, + hashAlgorithm: false, // md5 sha1 sha256 sha512 + }, + request:{ + maxFieldsSize: 2 * 1024 * 1024,// 请求体大小 + }, + ratelimit:{ + // 同设备(IP)限制登陆次数 + status: true, + duration: 60 * 1000, + max: 3, + }, + database:{ + mysql:{ + host: '127.0.0.1', + port: 3306, + username: 'root', + password: 'root', + database: 'graph_resource2' + } + } +} + +export default prodConfig diff --git a/src/app.js b/src/app.js new file mode 100644 index 0000000..872b513 --- /dev/null +++ b/src/app.js @@ -0,0 +1,125 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: initkoa +// | @文件描述: app.js - Koa项目的入口文件 +// | @创建时间: 2023-11-25 20:58 +// | @更新时间: 2023-11-25 20:58 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ + +import Koa from 'koa'; +import koaLogger from 'koa-logger'; +import compress from 'koa-compress'; +import ratelimit from 'koa-ratelimit'; +import handleError from 'koa-json-error'; +import { koaBody } from 'koa-body'; +import { userAgent } from 'koa-useragent'; + +import rootRouter from '#routes/index.js'; + +export default function startApp() { + const app = new Koa(); + if (global.ENV === 'development') { + // | 开启自带日志 + app.use(koaLogger()); + } + + if (config.ratelimit.status) { + // | 限制同一用户的频繁请求 + app.use( + ratelimit({ + driver: 'memory', // 存储限流数据的驱动,这里使用内存驱动 + db: new Map(), // 存储被限制的客户端信息的数据结构 + duration: config.ratelimit.duration, // 时间窗口,单位毫秒 + max: config.ratelimit.max, // 时间窗口内允许的最大请求数量 + id: (ctx) => ctx.ip, // 提取每个请求的唯一标识符,默认使用请求的 IP 地址 + }), + ); + } + + app.use( + handleError({ + format: (err) => { + // 返回错误的格式 + switch (err.status) { + case 400: { + return { + code: err.status, + message: err.e, + }; + break; + } + default: { + return { + code: err.status, + message: err.message, + result: ENV === 'development' && err.stack, + }; + } + } + }, + postFormat: (err, obj) => { + //根据不同环境,返回不同格式的错误信息 + const { result, ...rest } = obj; + return process.env.NODE_ENV == 'production' ? rest : obj; + }, + }), + ); + + // 响应封装中间件 + async function responseHandler(ctx, next) { + // 执行后续中间件 + await next(); + // 如果有响应且没有错误状态码 + if (ctx.response.is('json') && ![404, 204].includes(ctx.status)) { + // 封装响应体为标准格式 + ctx.body = { + code: ctx.status, + success: true, + data: ctx.body, + }; + } + } + + // 在路由之前加载响应封装中间件 + app.use(responseHandler); + + if (global.zip === true) { + // | koa-compress 是一个 Koa 中间件,用于压缩 HTTP 响应。使用该中间件可减少 HTTP 响应的大小,从而提升应用程序的性能。 + app.use(compress()); + } + app.use(userAgent); + + app.use( + koaBody({ + multipart: true, // 支持文件上传 + detectJSON: true, + gzip: true, + // encoding: 'gzip', + formidable: { + // uploadDir:path.join(__dirname,'public/upload/'), // 设置文件上传目录 + keepExtensions: true, // 保持文件的后缀 + maxFileSize: config.upfile.maxFileSize, // 文件上传大小 + maxFieldsSize: config.request.maxFieldsSize, // 除文件外的数据大小 + onFileBegin: (name, file) => { + // 文件上传前的设置 + }, + hashAlgorithm: config.upfile.hashAlgorithm, + }, + }), + ); + + app.use(rootRouter.routes()); + app.use(rootRouter.allowedMethods()); + + // console.log(rootRouter) + + const routes = rootRouter.stack.map((route) => route.path); + // console.log(routes); + + return app; +} diff --git a/src/cache/index.js b/src/cache/index.js new file mode 100644 index 0000000..5972a5e --- /dev/null +++ b/src/cache/index.js @@ -0,0 +1,43 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: graphResource2 +// | @文件描述: index.js - +// | @创建时间: 2023-12-01 21:38 +// | @更新时间: 2023-12-01 21:38 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ +import {Op} from "sequelize"; + +export async function createCatch(sequelize){ + global.resourceCache = {} + // atomModelCache + const atomModelPoolStartTime = performance.now() + const atomModelPool = await makeAtomModelCache(sequelize) + global.resourceCache.atomModelPool = atomModelPool + const atomModelPoolEndTime = performance.now() + logger.fatal(`元分类/模型缓存加载完毕: atomModelPool - ${atomModelPoolEndTime - atomModelPoolStartTime} ms`) +} + +async function makeAtomModelCache(sequelize){ + const atomModelList = await sequelize.models.AtomModel.findAll({ + attributes:['*'], + where: { + isDelete:{ + [Op.is]: null, + } + }, + raw: true, // 原始数据 + mapToModel: true, // 将下划线变成驼峰 + }); + const atomModelPool = { + length: atomModelList.length, + createtime: new Date().getTime(), + updatetime: new Date().getTime(), + data: atomModelList + } + return atomModelPool +} diff --git a/src/common/database/dataModels/atomModel.dataModel.js b/src/common/database/dataModels/atomModel.dataModel.js new file mode 100644 index 0000000..0ac150e --- /dev/null +++ b/src/common/database/dataModels/atomModel.dataModel.js @@ -0,0 +1,61 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: graphResource2 +// | @文件描述: atomModel.dataModel.js - +// | @创建时间: 2023-12-01 13:45 +// | @更新时间: 2023-12-01 13:45 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ + +import {Model} from 'sequelize'; + +export function mountAtomModel(sequelize, DataTypes) { + class AtomModel extends Model { + } + + AtomModel.init({ + // 在这里定义模型属性 + atomModelId: { + type: DataTypes.INTEGER, + autoIncrement: true, + primaryKey: true, + allowNull: false, + comment: '元分类/模型ID' + }, + atomModelName: { + type: DataTypes.STRING, + allowNull: false, + comment: '元分类/模型名称' + }, + atomModelDescribe: { + type: DataTypes.STRING(2048), + allowNull: false, + comment: '元分类/模型描述' + }, + creator:{ + type: DataTypes.STRING, + comment: "创建人" + }, + isDelete:{ + type: DataTypes.STRING(64), + comment: "删除时间" + } + }, { + // 这是其他模型参数 + sequelize, // 我们需要传递连接实例 + modelName: 'AtomModel', // 我们需要选择模型名称 + // tableName: 'atom_model', + comment: "元分类/模型表", + timestamps: true, // 不要忘记启用时间戳! + createdAt: 'createTimestamp', // 不想要 createdAt + // 想要 updatedAt 但是希望名称叫做 updateTimestamp + updatedAt: 'updateTimestamp', + underscored: true, // 改成下划线格式 + }); + + return AtomModel +} diff --git a/src/common/database/dataModels/baseDict.dataModel.js b/src/common/database/dataModels/baseDict.dataModel.js new file mode 100644 index 0000000..bd346ce --- /dev/null +++ b/src/common/database/dataModels/baseDict.dataModel.js @@ -0,0 +1,83 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: graphResource2 +// | @文件描述: baseDict.dataModel.js - +// | @创建时间: 2023-12-01 14:37 +// | @更新时间: 2023-12-01 14:37 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ + +import {Model} from 'sequelize'; + +export function mountBaseDict(sequelize, DataTypes) { + class BaseDict extends Model { + } + + BaseDict.init({ + // 在这里定义模型属性 + baseDictId: { + type: DataTypes.INTEGER, + autoIncrement: true, + primaryKey: true, + allowNull: false, + comment: '基础字典Id' + }, + atomModel: { + type: DataTypes.INTEGER, + allowNull: true, + comment: '元分类/模型Id' + }, + baseDictIsBase: { + type: DataTypes.INTEGER, + allowNull: false, + comment: '是否为基础字典(0是自定义,1是基础)', + defaultValue: 0, + }, + baseDictOriginType: { + type: DataTypes.INTEGER, + allowNull: false, + comment: '模型数据来源(0是系统内,1是系统外)', + defaultValue: 0, + }, + baseDictName:{ + type: DataTypes.STRING, + allowNull: false, + comment: "字典项名称" + }, + baseDictDescribe:{ + type: DataTypes.STRING(2048), + comment: "字典项名描述" + }, + baseDictFather:{ + type: DataTypes.INTEGER, + allowNull: false, + comment: "字典项父级", + defaultValue: 0, + }, + creator:{ + type: DataTypes.STRING, + comment: "创建人" + }, + isDelete:{ + type: DataTypes.STRING(64), + comment: "删除时间" + } + }, { + // 这是其他模型参数 + sequelize, // 我们需要传递连接实例 + modelName: 'BaseDict', // 我们需要选择模型名称 + // tableName: 'baseDict', + comment: "基础字典表", + timestamps: true, // 不要忘记启用时间戳! + createdAt: 'createTimestamp', // 不想要 createdAt + // 想要 updatedAt 但是希望名称叫做 updateTimestamp + updatedAt: 'updateTimestamp', + underscored: true, // 改成下划线格式 + }); + + return BaseDict +} diff --git a/src/common/database/dataModels/resourceClassBase.dataModel.js b/src/common/database/dataModels/resourceClassBase.dataModel.js new file mode 100644 index 0000000..fb58daa --- /dev/null +++ b/src/common/database/dataModels/resourceClassBase.dataModel.js @@ -0,0 +1,103 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: graphResource2 +// | @文件描述: resourceClassBase.dataModel.js - +// | @创建时间: 2023-12-01 14:56 +// | @更新时间: 2023-12-01 14:56 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ + +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: graphResource2 +// | @文件描述: atomModel.dataModel.js - +// | @创建时间: 2023-12-01 13:45 +// | @更新时间: 2023-12-01 13:45 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ + +import { Model } from 'sequelize'; + +export function mountResourceClassBase(sequelize, DataTypes) { + class ResourceClassBase extends Model {} + + ResourceClassBase.init( + { + // 在这里定义模型属性 + resourceClassBaseId: { + type: DataTypes.INTEGER, + autoIncrement: true, + primaryKey: true, + allowNull: false, + comment: '资源类ID', + }, + atomModel: { + type: DataTypes.INTEGER, + allowNull: false, + comment: '元分类/模型Id', + }, + resourceClassBaseDefine:{ + type: DataTypes.INTEGER, + comment: "对资源类的定义,方便建立资源结构,来源于基础字典。" + }, + resourceClassBaseIdentify:{ + type: DataTypes.STRING(8), + allowNull: false, + comment: '资源类标识', + }, + resourceClassBaseName:{ + type: DataTypes.STRING, + allowNull: false, + comment: '资源类名', + }, + resourceClassBaseDescribe: { + type: DataTypes.STRING(2048), + comment: '资源类描述', + }, + resourceClassBaseType:{ + type: DataTypes.INTEGER, + allowNull: false, + comment: "对资源类的分类,0实体、1虚拟、2管理。", + defaultValue: 0, + }, + resourceClassBaseColor:{ + type: DataTypes.STRING, + comment: '资源类名', + }, + resourceClassBaseAvatar:{ + type: DataTypes.STRING, + comment: '资源类图标', + }, + creator: { + type: DataTypes.STRING, + comment: '创建人', + }, + isDelete: { + type: DataTypes.STRING(64), + comment: '删除时间', + }, + }, + { + // 这是其他模型参数 + sequelize, // 我们需要传递连接实例 + modelName: 'ResourceClassBase', // 我们需要选择模型名称 + // tableName: 'ResourceClassBase', + comment: '资源类基础表', + timestamps: true, // 不要忘记启用时间戳! + createdAt: 'createTimestamp', // 不想要 createdAt + // 想要 updatedAt 但是希望名称叫做 updateTimestamp + updatedAt: 'updateTimestamp', + underscored: true, // 改成下划线格式 + }, + ); + + return ResourceClassBase; +} diff --git a/src/common/database/dataModels/resourceClassExpandField.dataModel.js b/src/common/database/dataModels/resourceClassExpandField.dataModel.js new file mode 100644 index 0000000..c7aaf36 --- /dev/null +++ b/src/common/database/dataModels/resourceClassExpandField.dataModel.js @@ -0,0 +1,83 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: graphResource2 +// | @文件描述: resourceClassExpandField.dataModel.js - +// | @创建时间: 2023-12-01 15:12 +// | @更新时间: 2023-12-01 15:12 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ + +import { Model } from 'sequelize'; + +export function mountResourceClassExpandField(sequelize, DataTypes) { + class ResourceClassExpandField extends Model {} + + ResourceClassExpandField.init( + { + // 在这里定义模型属性 + resourceClassExpandFieldId: { + type: DataTypes.INTEGER, + autoIncrement: true, + primaryKey: true, + allowNull: false, + comment: '资源类拓展字段ID', + }, + resourceClassBase: { + type: DataTypes.INTEGER, + allowNull: false, + comment: '资源类ID', + }, + resourceClassExpandFieldName: { + type: DataTypes.STRING, + allowNull: false, + comment: '资源类拓展字段名', + }, + resourceClassExpandFieldIdentify: { + type: DataTypes.STRING(64), + allowNull: false, + comment: '资源类拓展字段标识', + }, + resourceClassExpandFieldDisplayType: { + type: DataTypes.INTEGER, + allowNull: false, + comment: '显示类型,后期在字典添加', + defaultValue:0 + }, + resourceClassExpandFieldRelationType: { + type: DataTypes.INTEGER, + comment: '拓展字段关联类型,0字典,1资源类', + }, + resourceClassExpandFieldValue: { + type: DataTypes.STRING, + allowNull: false, + comment: '资源类拓展字段值', + }, + creator: { + type: DataTypes.STRING, + comment: '创建人', + }, + isDelete: { + type: DataTypes.STRING(64), + comment: '删除时间', + }, + }, + { + // 这是其他模型参数 + sequelize, // 我们需要传递连接实例 + modelName: 'ResourceClassExpandField', // 我们需要选择模型名称 + // tableName: 'ResourceClassExpandField', + comment: '资源类拓展字段表', + timestamps: true, // 不要忘记启用时间戳! + createdAt: 'createTimestamp', // 不想要 createdAt + // 想要 updatedAt 但是希望名称叫做 updateTimestamp + updatedAt: 'updateTimestamp', + underscored: true, // 改成下划线格式 + }, + ); + + return ResourceClassExpandField; +} diff --git a/src/common/database/dataModels/resourceClassRelation.dataModel.js b/src/common/database/dataModels/resourceClassRelation.dataModel.js new file mode 100644 index 0000000..9bf13f6 --- /dev/null +++ b/src/common/database/dataModels/resourceClassRelation.dataModel.js @@ -0,0 +1,60 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: graphResource2 +// | @文件描述: resourceClassRelation.dataModel.js - +// | @创建时间: 2023-12-01 15:23 +// | @更新时间: 2023-12-01 15:23 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ +import {Model} from 'sequelize'; + +export function mountResourceClassRelation(sequelize, DataTypes) { + class ResourceClassRelation extends Model { + } + + ResourceClassRelation.init({ + // 在这里定义模型属性 + resourceClassRelationId: { + type: DataTypes.INTEGER, + autoIncrement: true, + primaryKey: true, + allowNull: false, + comment: '资源类关系ID' + }, + resourceClassRelationTarget: { + type: DataTypes.INTEGER, + allowNull: false, + comment: '目标资源类ID' + }, + resourceClassRelationFather: { + type: DataTypes.INTEGER, + allowNull: false, + comment: '父资源类ID' + }, + creator:{ + type: DataTypes.STRING, + comment: "创建人" + }, + isDelete:{ + type: DataTypes.STRING(64), + comment: "删除时间" + } + }, { + // 这是其他模型参数 + sequelize, // 我们需要传递连接实例 + modelName: 'ResourceClassRelation', // 我们需要选择模型名称 + // tableName: 'ResourceClassRelation', + comment: "资源类关系表", + timestamps: true, // 不要忘记启用时间戳! + createdAt: 'createTimestamp', // 不想要 createdAt + // 想要 updatedAt 但是希望名称叫做 updateTimestamp + updatedAt: 'updateTimestamp', + underscored: true, // 改成下划线格式 + }); + + return ResourceClassRelation +} diff --git a/src/common/database/dataModels/resourceEntityRelation.dataModel.js b/src/common/database/dataModels/resourceEntityRelation.dataModel.js new file mode 100644 index 0000000..ed615a2 --- /dev/null +++ b/src/common/database/dataModels/resourceEntityRelation.dataModel.js @@ -0,0 +1,60 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: graphResource2 +// | @文件描述: resourceEntityRelation.dataModel.js - +// | @创建时间: 2023-12-01 15:23 +// | @更新时间: 2023-12-01 15:23 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ +import {Model} from 'sequelize'; + +export function mountResourceEntityRelation(sequelize, DataTypes) { + class ResourceEntityRelation extends Model { + } + + ResourceEntityRelation.init({ + // 在这里定义模型属性 + resourceEntityRelationId: { + type: DataTypes.INTEGER, + autoIncrement: true, + primaryKey: true, + allowNull: false, + comment: '资源关系ID' + }, + resourceEntityRelationTarget: { + type: DataTypes.INTEGER, + allowNull: false, + comment: '目标资源ID' + }, + resourceEntityRelationFather: { + type: DataTypes.INTEGER, + allowNull: false, + comment: '父资源ID' + }, + creator:{ + type: DataTypes.STRING, + comment: "创建人" + }, + isDelete:{ + type: DataTypes.STRING(64), + comment: "删除时间" + } + }, { + // 这是其他模型参数 + sequelize, // 我们需要传递连接实例 + modelName: 'ResourceEntityRelation', // 我们需要选择模型名称 + // tableName: 'ResourceEntityRelation', + comment: "资源实体关系表", + timestamps: true, // 不要忘记启用时间戳! + createdAt: 'createTimestamp', // 不想要 createdAt + // 想要 updatedAt 但是希望名称叫做 updateTimestamp + updatedAt: 'updateTimestamp', + underscored: true, // 改成下划线格式 + }); + + return ResourceEntityRelation +} diff --git a/src/common/database/dataModels/resourceEntityStruct.dataModel.js b/src/common/database/dataModels/resourceEntityStruct.dataModel.js new file mode 100644 index 0000000..c2695db --- /dev/null +++ b/src/common/database/dataModels/resourceEntityStruct.dataModel.js @@ -0,0 +1,130 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: graphResource2 +// | @文件描述: resourceEntityStruct.dataModel.js - +// | @创建时间: 2023-12-01 15:38 +// | @更新时间: 2023-12-01 15:38 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ +import {Model} from 'sequelize'; + +export function mountResourceEntityStruct(sequelize, DataTypes) { + class ResourceEntityStruct extends Model { + } + + ResourceEntityStruct.init({ + // 在这里定义模型属性 + resourceEntityStructId: { + type: DataTypes.INTEGER, + // type: DataTypes.STRING, + autoIncrement: true, + primaryKey: true, + allowNull: false, + comment: '元分类/模型ID' + }, + resourceClassBase: { + type: DataTypes.INTEGER, + allowNull: false, + comment: '资源类ID', + }, + resourceEntityStructName:{ + type: DataTypes.STRING, + allowNull: false, + comment: '资源实体字段名', + }, + resourceEntityStructIdentify:{ + type: DataTypes.STRING(64), + allowNull: false, + comment: '资源实体字段标识', + }, + resourceEntityStructNickname:{ + type: DataTypes.STRING, + comment: '资源实体字段别名', + }, + resourceEntityStructDescribe:{ + type: DataTypes.STRING(2048), + comment: '资源实体字段描述', + }, + resourceEntityStructRank:{ + type: DataTypes.INTEGER, + comment: '资源实体字段排序', + default:0, + }, + resourceEntityStructStorageType:{ + type: DataTypes.INTEGER, + allowNull: false, + comment: '资源实体字段在数据库中存储的类型', + }, + resourceEntityStructStorageLength:{ + type: DataTypes.INTEGER, + allowNull: false, + comment: '资源实体字段在数据库中存储的长度', + defaultValue: 20, + }, + resourceEntityStructDisplayType:{ + type: DataTypes.INTEGER, + allowNull: false, + comment: '资源实体字段显示类型', + defaultValue: 0, + }, + resourceEntityStructIsGather:{ + type: DataTypes.BOOLEAN, + allowNull: false, + comment: '资源实体字段是否采集(0是采集、1是不采集)', + defaultValue: 0, + }, + resourceEntityStructAppIsShow:{ + type: DataTypes.BOOLEAN, + allowNull: false, + comment: '资源实体字段是否显示在APP上(0是显示、1是不显示)', + defaultValue: 0, + }, + resourceEntityStructWebIsShow:{ + type: DataTypes.BOOLEAN, + allowNull: false, + comment: '资源实体字段是否显示在Web上(0是显示、1是不显示)', + defaultValue: 0, + }, + resourceEntityStructAppNickname:{ + type: DataTypes.STRING, + comment: '资源实体字段APP别名', + }, + resourceEntityStructWebNickname:{ + type: DataTypes.STRING, + comment: '资源实体字段Web别名', + }, + resourceEntityStructRelationType:{ + type: DataTypes.INTEGER, + comment: '资源实体字段关联类型', + }, + resourceEntityStructRelationValue:{ + type: DataTypes.INTEGER, + comment: '资源实体字段关联值', + }, + creator:{ + type: DataTypes.STRING, + comment: "创建人" + }, + isDelete:{ + type: DataTypes.STRING(64), + comment: "删除时间" + } + }, { + // 这是其他模型参数 + sequelize, // 我们需要传递连接实例 + modelName: 'ResourceEntityStruct', // 我们需要选择模型名称 + // tableName: 'ResourceEntityStruct', + comment: "资源实体字段结构表", + timestamps: true, // 不要忘记启用时间戳! + createdAt: 'createTimestamp', // 不想要 createdAt + // 想要 updatedAt 但是希望名称叫做 updateTimestamp + updatedAt: 'updateTimestamp', + underscored: true, // 改成下划线格式 + }); + + return ResourceEntityStruct +} diff --git a/src/common/database/index.js b/src/common/database/index.js new file mode 100644 index 0000000..45b97f9 --- /dev/null +++ b/src/common/database/index.js @@ -0,0 +1,60 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: expressgy-web-lauch +// | @文件描述: index.js - +// | @创建时间: 2023-11-28 22:27 +// | @更新时间: 2023-11-28 22:27 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ + +import { Sequelize, DataTypes } from 'sequelize'; + +import { mountAtomModel } from '#dataModels/atomModel.dataModel.js'; +import { mountBaseDict } from '#dataModels/baseDict.dataModel.js'; +import { mountResourceClassBase } from '#dataModels/resourceClassBase.dataModel.js'; +import { mountResourceClassExpandField } from '#dataModels/resourceClassExpandField.dataModel.js'; +import {mountResourceClassRelation} from "#dataModels/resourceClassRelation.dataModel.js"; +import {mountResourceEntityStruct} from "#dataModels/resourceEntityStruct.dataModel.js"; +import {mountResourceEntityRelation} from "#dataModels/resourceEntityRelation.dataModel.js"; + +// import prodConfig from "#root/production.env.js"; +// +// global.config = prodConfig + +export default function createDatabase(logger) { + const { database, username, password, host, port } = + global.config.database.mysql; + console.log(database, username, password, host, port); + const sequelize = new Sequelize(database, username, password, { + host, + dialect: 'mysql', // 根据你的数据库类型修改 + underscored: true, + timezone: '+08:00', // 时区设置为东八区 + dialectOptions: { + dateStrings: true, // 将所有日期字段值转换成字符串格式 + typeCast: true, // 允许将字符串类型的日期字段值自动转换为 Date 类型 + }, + // 以下为一些额外配置选项 + // pool: { + // max: 5, + // min: 0, + // acquire: 30000, + // idle: 10000 + // }, + logging: logger.debug.bind(logger), + }); + + mountAtomModel(sequelize, DataTypes); + mountBaseDict(sequelize, DataTypes); + mountResourceClassBase(sequelize, DataTypes); + mountResourceClassExpandField(sequelize, DataTypes); + mountResourceClassRelation(sequelize, DataTypes) + mountResourceEntityStruct(sequelize,DataTypes) + mountResourceEntityRelation(sequelize,DataTypes) + return sequelize; +} +// createDatabase() diff --git a/src/common/dto/index.js b/src/common/dto/index.js new file mode 100644 index 0000000..001ed61 --- /dev/null +++ b/src/common/dto/index.js @@ -0,0 +1,36 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: initkoa +// | @文件描述: index.js - +// | @创建时间: 2023-11-26 15:41 +// | @更新时间: 2023-11-26 15:41 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ +import Ajv from 'ajv'; +import addAjvErrors from 'ajv-errors'; + +export default function makeDTO(data, schema) { + const ajv = new Ajv({ + allErrors: true, //多错误消息 + // jsonPointers: true, // 消息写在内部吗?? JSON 指针是一个字符串表示法,用于在 JSON 文档中指定特定的路径。它采用一种类似于文件路径的结构,通过使用斜杠 / 来分隔层级,例如 /path/to/property + coerceTypes: true, // 类型转换 + useDefaults: true + }); + + addAjvErrors(ajv); + const validate = ajv.compile(schema); + const valid = validate(data); + const message = { + status: true, + error: null, + }; + if (!valid) { + message.status = false; + message.error = validate.errors; + } + return message; +} diff --git a/src/common/logger/index.js b/src/common/logger/index.js new file mode 100644 index 0000000..55579ce --- /dev/null +++ b/src/common/logger/index.js @@ -0,0 +1,91 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: initkoa +// | @文件描述: index.js - +// | @创建时间: 2023-11-26 14:51 +// | @更新时间: 2023-11-26 14:51 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ + +import winston from "winston"; +import "winston-daily-rotate-file" + + +// 自定义日志等级和颜色 +const myCustomLevels = { + levels:{ + fatal: 0, + error: 1, + warn: 2, + info: 3, + debug: 4, + trace: 5 + }, +// 字体样式:bold, dim,italic, underline, inverse, hidden, strikethrough +// 字体背景颜色:black, red, green, yellow, blue, magenta紫色, cyan青色, white, gray, grey +// 背景颜色:blackBG, redBG, greenBG, yellowBG, blueBG, magentaBG, cyanBG, whiteBG + levelsColor:{ + fatal: 'bold red cyanBG italic underline', + error: 'bold magenta', + warn: 'yellow', + info: 'green', + debug: 'cyan', + trace: 'white' + } +} +// 创建颜色方法 +export const colorizer = winston.format.colorize(); +colorizer.addColors(myCustomLevels.levelsColor) + +export const logger = winston.createLogger({ + level: 'trace', // 日志打印等级 + levels: myCustomLevels.levels,// 日志等级列表 + exitOnError: false,// 如果为false,处理异常不会导致process.exit + silent: false, // 如果为true,所有日志被抑制 + format: winston.format.combine( + winston.format.errors({ stack: true }), + winston.format.json(), + winston.format.timestamp({ format: "YYYY-MM-DD HH:mm:ss:SSS" }), + // winston.format.printf( + // (i) => { + // // const splatList = Array.from(Object.getOwnPropertySymbols(i)) + // // const splat = splatList && splatList.filter(item => item.toString() === 'Symbol(splat)') + // // const splatName = splat.length == 1 ? splat[0] : null + // // const data = splatName ? JSON.stringify([i.message, ...i[splatName]]) : JSON.stringify({message:i.message}) + // return `${i.timestamp} [${i.level.padEnd(5, ' ').toUpperCase()}] ${i.message}` + // }, + // ), + ), + transports: [ + new winston.transports.DailyRotateFile({ + filename: "winston-logs/%DATE%-INFO--winston.log", + level: "info", + datePattern: "YYYY-MM-DD", + zippedArchive: true,// 启用压缩 + maxSize: "10m",// 单文件大小 + maxFiles: "30d",// 存储时间 + }), + new winston.transports.DailyRotateFile({ + filename: "winston-logs/%DATE%-ERROR-winston.log", + level: "error", + datePattern: "YYYY-MM-DD", + zippedArchive: true, + maxSize: "10m", + maxFiles: "365d", + }), + ], + // winston可以捕获和记录异常 + // exceptionHandlers: [ + // new winston.transports.File({ filename: 'winston-logs/winston-exceptions.log' }) + // ], + // 捕获uncaughtRejection事件 + // rejectionHandlers: [ + // new winston.transports.File({ filename: 'winston-logs/rejections.log' }) + // ] +}); +// 后续加入记录器,这里可以加入环境变量的判断,当为生产模式时,取消控制台的打印操作。 + diff --git a/src/common/tools/getArrayPage.js b/src/common/tools/getArrayPage.js new file mode 100644 index 0000000..7f801d1 --- /dev/null +++ b/src/common/tools/getArrayPage.js @@ -0,0 +1,20 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: graphResource2 +// | @文件描述: getArrayPage.js - +// | @创建时间: 2023-12-01 22:48 +// | @更新时间: 2023-12-01 22:48 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ + +export default function getPage(array, pageSize, pageNumber){ + const startIndex = (pageNumber - 1) * pageSize; + + // 使用 slice() 方法获取分页内容 + const pageContent = array.slice(startIndex, startIndex + pageSize); + return pageContent +} diff --git a/src/common/tools/getNoSpacesStr.js b/src/common/tools/getNoSpacesStr.js new file mode 100644 index 0000000..139a779 --- /dev/null +++ b/src/common/tools/getNoSpacesStr.js @@ -0,0 +1,16 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: graphResource2 +// | @文件描述: getNoSpacesStr.js - +// | @创建时间: 2023-12-01 22:54 +// | @更新时间: 2023-12-01 22:54 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ + +export default function getNoSpacesStr(str){ + return str.replace(/\s/g, ''); +} diff --git a/src/routes/graphResource2/atomModel/index.dto.js b/src/routes/graphResource2/atomModel/index.dto.js new file mode 100644 index 0000000..bf2d915 --- /dev/null +++ b/src/routes/graphResource2/atomModel/index.dto.js @@ -0,0 +1,180 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: graphResource2 +// | @文件描述: index.dto.js - +// | @创建时间: 2023-12-01 18:13 +// | @更新时间: 2023-12-01 18:13 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ + +import makeDTO from '#common/dto/index.js'; + +export function CreateAtomModelItemDTO(data) { + const schema = { + type: 'object', + properties: { + atomModelName: { + type: 'string', + minLength: 1, + maxLength: 255, + pattern: "^[a-zA-Z\\s]+$", + errorMessage: { + type: '元分类/模型名称必须是一个字符串', + maxLength: '元分类/模型名称长度超出限制255', + minLength: '元分类/模型名称长度过短', + pattern: '元分类/模型名称必须为纯英文' + }, + }, + atomModelDescribe: { + type: 'string', + minLength: 1, + maxLength: 2048, + errorMessage: { + type: '元分类/模型描述必须是一个字符串', + maxLength: '元分类/模型描述长度超出限制2048', + minLength: '元分类/模型描述长度过短', + }, + }, + }, + required: ['atomModelName', 'atomModelDescribe'], + errorMessage: { + required: { + atomModelName: '元分类/模型名称为必填项', + atomModelDescribe: '元分类/模型描述为必填项', + }, + }, + }; + return makeDTO(data, schema); +} + +export function DeleteAtomModelItemDTO(data) { + const schema = { + type: 'object', + properties: { + atomModelId: { + type: 'integer', + errorMessage: { + type: '元分类/模型id必须是整数', + }, + }, + }, + required: ['atomModelId'], + errorMessage: { + required: { + atomModelId: '元分类/模型ID为为必填项', + }, + }, + }; + return makeDTO(data, schema); +} + +export function EditAtomModelItemDTO(data) { + const schema = { + type: 'object', + properties: { + atomModelId: { + type: 'integer', + errorMessage: { + type: '元分类/模型id必须是整数', + }, + }, + atomModelName: { + type: 'string', + minLength: 1, + maxLength: 255, + errorMessage: { + type: '元分类/模型名称必须是一个字符串', + maxLength: '元分类/模型名称长度超出限制255', + minLength: '元分类/模型名称长度过短', + }, + }, + atomModelDescribe: { + type: 'string', + minLength: 1, + maxLength: 2048, + errorMessage: { + type: '元分类/模型描述必须是一个字符串', + maxLength: '元分类/模型描述长度超出限制2048', + minLength: '元分类/模型描述长度过短', + }, + }, + }, + required: ['atomModelName', 'atomModelDescribe', 'atomModelId'], + errorMessage: { + required: { + atomModelName: '元分类/模型名称为必填项', + atomModelDescribe: '元分类/模型描述为必填项', + atomModelId: '元分类/模型ID为为必填项', + }, + }, + }; + return makeDTO(data, schema); +} + +export function CheckAtomModelItemNameDTO(data) { + const schema = { + type: 'object', + properties: { + atomModelName: { + type: 'string', + minLength: 1, + maxLength: 255, + pattern: "^[a-zA-Z\\s]+$", + errorMessage: { + type: '元分类/模型名称必须是一个字符串', + maxLength: '元分类/模型名称长度超出限制255', + minLength: '元分类/模型名称长度过短', + pattern: '元分类/模型名称必须为纯英文' + }, + }, + }, + required: ['atomModelName'], + errorMessage: { + required: { + atomModelName: '元分类/模型名称为必填项', + }, + }, + }; + return makeDTO(data, schema); +} + +export function GetAtomModelPageDTO(data) { + const schema = { + type: 'object', + properties: { + pageSize: { + type: 'integer', + minimum: 1, + maximum: 200, + default:10, + errorMessage: { + type: '每页数量必须是一个数字', + minimum: '每页数量最少是1', + maximum: '每页数量最多是200', + }, + }, + pageNum: { + type: 'integer', + minimum:1, + default: 1, + errorMessage: { + type: '页码必须是数字类型', + minimum: '页码最小是1', + }, + }, + searchData: { + type: 'string', + maxLength: 255, + errorMessage: { + type: '查询内容必须是一个字符串', + maxLength: '查询内容长度超出限制255', + }, + }, + }, + }; + return makeDTO(data, schema); +} diff --git a/src/routes/graphResource2/atomModel/index.js b/src/routes/graphResource2/atomModel/index.js new file mode 100644 index 0000000..7f2d805 --- /dev/null +++ b/src/routes/graphResource2/atomModel/index.js @@ -0,0 +1,180 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: graphResource2 +// | @文件描述: index.js - +// | @创建时间: 2023-12-01 17:50 +// | @更新时间: 2023-12-01 17:50 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ + +import Router from 'koa-router'; + +import { + CheckAtomModelItemNameDTO, + CreateAtomModelItemDTO, + DeleteAtomModelItemDTO, + EditAtomModelItemDTO, + GetAtomModelPageDTO, +} from '#routes/graphResource2/atomModel/index.dto.js'; +import getPage from '#common/tools/getArrayPage.js'; +import getNoSpacesStr from '#common/tools/getNoSpacesStr.js'; + +const atomModel = new Router(); + +// @ 获取元分类模型页 +atomModel.get('/getAtomModelPage', async (ctx, next) => { + const verif = GetAtomModelPageDTO(ctx.query); + if (!verif.status) { + ctx.throw(400, { e: verif.error.map((i) => i.message) }); + return; + } + let list = resourceCache.atomModelPool.data; + if (ctx.query.searchData) { + const searchData = ctx.query.searchData; + list = list.filter((i) => { + return (i.atomModelName + i.atomModelDescribe).includes(searchData); + }); + } + const total = list.length; + list = getPage(list, ctx.query.pageSize, ctx.query.pageNum); + ctx.body = { + total, + data: list, + }; +}); + +// @ 获取元分类列表 +atomModel.get('/getAtomModelList', async (ctx, next) => { + ctx.body = resourceCache.atomModelPool.data.map((i) => ({ + atomModelId: i.atomModelId, + atomModelName: i.atomModelName, + })); +}); + +// @ 新建元分类 +atomModel.post('/createAtomModelItem', async (ctx, next) => { + const verif = CreateAtomModelItemDTO(ctx.request.body); + if (!verif.status) { + ctx.throw(400, { e: verif.error.map((i) => i.message) }); + return; + } + let { atomModelName, atomModelDescribe } = ctx.request.body; + atomModelName = getNoSpacesStr(atomModelName).toUpperCase(); + if (checkName(atomModelName) == -1) { + const newAtomModel = await ctx.sequelize.models.AtomModel.create({ + atomModelName, + atomModelDescribe, + }); + resourceCache.atomModelPool.data.push(newAtomModel.dataValues); + resourceCache.atomModelPool.length++; + resourceCache.atomModelPool.updatetime = new Date().getTime(); + ctx.body = { + message: '新建元分类成功。', + data: newAtomModel.dataValues, + }; + } else { + ctx.throw(400, { e: `元分类/模型重名: ${atomModelName}` }); + } +}); + +// @ 编辑元分类 +atomModel.post('/editAtomModelItem', async (ctx, next) => { + const verif = EditAtomModelItemDTO(ctx.request.body); + if (!verif.status) { + ctx.throw(400, { e: verif.error.map((i) => i.message) }); + return; + } + let { atomModelName, atomModelDescribe, atomModelId } = ctx.request.body; + console.log(atomModelName) + atomModelName = getNoSpacesStr(atomModelName).toUpperCase() + const index= checkName(atomModelName) + if([-1, atomModelId].includes(resourceCache.atomModelPool.data[index].atomModelId)){ + if(resourceCache.atomModelPool.data[index].atomModelDescribe == atomModelDescribe && resourceCache.atomModelPool.data[index].atomModelName == atomModelName){ + ctx.body = { + message: '编辑元分类/模型成功', + }; + return + } + resourceCache.atomModelPool.data[index].atomModelDescribe = atomModelDescribe; + resourceCache.atomModelPool.data[index].atomModelName = atomModelName + resourceCache.atomModelPool.updatetime = new Date().getTime(); + ctx.body = { + message: '编辑元分类/模型成功', + }; + await next(); + await ctx.sequelize.models.AtomModel.update( + { atomModelName, atomModelDescribe, }, + { where: { atomModelId } }, + ); + }else{ + ctx.throw(400, {e: '元分类/模型名称重复'}) + } + +}); + +// @ 查重元分类名称 +atomModel.get('/checkAtomModelItemName', async (ctx, next) => { + const verif = CheckAtomModelItemNameDTO(ctx.query); + if (!verif.status) { + ctx.throw(400, { e: verif.error.map((i) => i.message) }); + return; + } + let { atomModelName } = ctx.query; + atomModelName = getNoSpacesStr(atomModelName).toUpperCase(); + if (checkName(atomModelName) == -1) { + ctx.body = { message: '元分类/模型名称可用' }; + } else { + ctx.throw(400, { e: '元分类/模型名称重复' }); + } +}); + +// @ 删除元分类 +atomModel.delete('/deleteAtomModelItem', async (ctx, next) => { + const verif = DeleteAtomModelItemDTO(ctx.query); + if (!verif.status) { + ctx.throw(400, { e: verif.error.map((i) => i.message) }); + return; + } + const { atomModelId } = ctx.query; + let index = -1; + for (let i in resourceCache.atomModelPool.data) { + if (resourceCache.atomModelPool.data[i].atomModelId == atomModelId) { + index = i; + break; + } + } + if (index == -1) { + ctx.throw(400, { e: '不存在此元分类/模型记录。' }); + return; + } + resourceCache.atomModelPool.data.splice(index, 1); + resourceCache.atomModelPool.length--; + resourceCache.atomModelPool.updatetime = new Date().getTime(); + ctx.body = { message: '删除元分类/模型成功。' }; + await next(); + await ctx.sequelize.models.AtomModel.update( + { isDelete: new Date().toISOString() }, + { where: { atomModelId } }, + ); +}); + +export default atomModel; + +// = 函数名: checkName +// = 描述: 查重模型名称 +// = 参数: None +// = 返回值: undefined +// = 创建人: expressgy +// = 创建时间: 2023-12-01 22:56:12 - +function checkName(name) { + for (let i in resourceCache.atomModelPool.data) { + if (name == resourceCache.atomModelPool.data[i].atomModelName) { + return i; + } + } + return -1; +} diff --git a/src/routes/graphResource2/baseDict/index.dto.js b/src/routes/graphResource2/baseDict/index.dto.js new file mode 100644 index 0000000..aae3d25 --- /dev/null +++ b/src/routes/graphResource2/baseDict/index.dto.js @@ -0,0 +1,206 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: graphResource2 +// | @文件描述: index.dto.js - +// | @创建时间: 2023-12-02 00:21 +// | @更新时间: 2023-12-02 00:21 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ + +import makeDTO from '#common/dto/index.js'; + +export function GetBaseDictTreeDTO(data) { + const schema = { + type: 'object', + properties: { + atomModelId: { + type: ['integer', 'null'], + minimum: 0, + errorMessage: { + type: '元分类/模型ID必须是整数', + minimum: '元分类/模型ID是一个正整数', + }, + }, + }, + }; + return makeDTO(data, schema); +} + +export function GetBaseDictListDTO(data) { + const schema = { + type: 'object', + properties: { + atomModelId: { + type: ['integer', 'null'], + minimum: 0, + errorMessage: { + type: '元分类/模型ID必须是整数', + minimum: '元分类/模型ID是一个正整数', + }, + }, + searchData: { + type: 'string', + maxLength: 255, + errorMessage: { + type: '查询内容必须是一个字符串', + maxLength: '查询内容长度超出限制255', + }, + }, + }, + }; + return makeDTO(data, schema); +} + + +export function GetBaseDictStructForBaseDictIdDTO(data) { + const schema = { + type: 'object', + properties: { + baseDictId: { + type: 'integer', + minimum: 0, + errorMessage: { + type: '字典ID必须是整数', + minimum: '字典ID是一个正整数', + }, + }, + }, + required: ['baseDictId'], + errorMessage: { + required: { + baseDictId: '字典ID为必填项', + }, + }, + }; + return makeDTO(data, schema); +} + + + +export function DeleteBaseDictItemDTO(data) { + const schema = { + type: 'object', + properties: { + baseDictId: { + type: 'integer', + minimum: 0, + errorMessage: { + type: '字典ID必须是整数', + minimum: '字典ID是一个正整数', + }, + }, + }, + required: ['baseDictId'], + errorMessage: { + required: { + baseDictId: '字典ID为必填项', + }, + }, + }; + return makeDTO(data, schema); +} + + + + +export function CreateBaseDictItemDTO(data) { + const schema = { + type: 'object', + properties: { + atomModelId: { + type: ['integer', 'null'], + minimum: 0, + errorMessage: { + type: '元分类/模型ID必须是整数', + minimum: '元分类/模型ID是一个正整数', + }, + }, + baseDictName:{ + type: 'string', + minLength: 1, + maxLength: 255, + errorMessage: { + type: '字典项名称必须是一个字符串', + maxLength: '字典项名称长度超出限制255', + minLength: '字典项名称长度过短', + }, + }, + baseDictFather:{ + type: ['integer', 'null'], + minimum: 0, + default: 0, + errorMessage: { + type: '字典项父ID必须是整数', + minimum: '字典项父ID是一个正整数', + }, + }, + baseDictDescribe:{ + type: 'string', + minLength: 1, + maxLength: 2048, + errorMessage: { + type: '字典项名称必须是一个字符串', + maxLength: '字典项名称长度超出限制2048', + minLength: '字典项名称长度过短', + }, + } + }, + required: ['baseDictName', 'baseDictDescribe'], + errorMessage: { + required: { + baseDictName: '字典项名称为必填项', + baseDictDescribe: '字典项描述为必填项' + }, + }, + }; + return makeDTO(data, schema); +} + +export function EditBaseDictItemDTO(data) { + const schema = { + type: 'object', + properties: { + baseDictId: { + type: 'integer', + minimum: 0, + errorMessage: { + type: '字典ID必须是整数', + minimum: '字典ID是一个正整数', + }, + }, + baseDictName:{ + type: 'string', + minLength: 1, + maxLength: 255, + errorMessage: { + type: '字典项名称必须是一个字符串', + maxLength: '字典项名称长度超出限制255', + minLength: '字典项名称长度过短', + }, + }, + baseDictDescribe:{ + type: 'string', + minLength: 1, + maxLength: 2048, + errorMessage: { + type: '字典项名称必须是一个字符串', + maxLength: '字典项名称长度超出限制2048', + minLength: '字典项名称长度过短', + }, + } + }, + required: ['baseDictName', 'baseDictDescribe', 'baseDictId'], + errorMessage: { + required: { + baseDictName: '字典项名称为必填项', + baseDictDescribe: '字典项描述为必填项', + baseDictId: '字典ID为必填项', + }, + }, + }; + return makeDTO(data, schema); +} diff --git a/src/routes/graphResource2/baseDict/index.js b/src/routes/graphResource2/baseDict/index.js new file mode 100644 index 0000000..ead3518 --- /dev/null +++ b/src/routes/graphResource2/baseDict/index.js @@ -0,0 +1,93 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: graphResource2 +// | @文件描述: index.js - +// | @创建时间: 2023-12-02 00:15 +// | @更新时间: 2023-12-02 00:15 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ + +import Router from 'koa-router'; +import { + CreateBaseDictItemDTO, + DeleteBaseDictItemDTO, EditBaseDictItemDTO, + GetBaseDictListDTO, + GetBaseDictStructForBaseDictIdDTO, + GetBaseDictTreeDTO +} from '#routes/graphResource2/baseDict/index.dto.js'; +import {DeleteAtomModelItemDTO} from "#routes/graphResource2/atomModel/index.dto.js"; + +const baseDict = new Router(); + +// @ 获取字典树 +baseDict.get('/getBaseDictTree', async (ctx, next) => { + const data = ctx.query; + const verif = GetBaseDictTreeDTO(data); + if (!verif.status) { + ctx.throw(400, { e: verif.error.map((i) => i.message) }); + return; + } + ctx.body = 1 +}); + +// @ 获取字典名列表 +baseDict.get('/getBaseDictList', async (ctx, next) => { + const data = ctx.query; + console.log(data) + const verif = GetBaseDictListDTO(data); + if (!verif.status) { + ctx.throw(400, { e: verif.error.map((i) => i.message) }); + return; + } + ctx.body = 2 +}); + +// @ 通过字典ID获取完整字典结构 +baseDict.get('/getBaseDictStructForBaseDictId', async (ctx, next) => { + const data = ctx.query; + const verif = GetBaseDictStructForBaseDictIdDTO(data); + if (!verif.status) { + ctx.throw(400, { e: verif.error.map((i) => i.message) }); + return; + } + ctx.body = 3 +}); + +// @ 删除字典项 +baseDict.delete('/deleteBaseDictItem', async (ctx, next) => { + const data = ctx.query; + const verif = DeleteBaseDictItemDTO(data); + if (!verif.status) { + ctx.throw(400, { e: verif.error.map((i) => i.message) }); + return; + } + ctx.body = 4 +}); + +// @ 新建字典项 +baseDict.post('/createBaseDictItem', async (ctx, next) => { + const data = ctx.request.body; + const verif = CreateBaseDictItemDTO(data); + if (!verif.status) { + ctx.throw(400, { e: verif.error.map((i) => i.message) }); + return; + } + ctx.body = 5 +}); + +// @ 编辑字典项 +baseDict.post('/editBaseDictItem', async (ctx, next) => { + const data = ctx.request.body; + const verif = EditBaseDictItemDTO(data); + if (!verif.status) { + ctx.throw(400, { e: verif.error.map((i) => i.message) }); + return; + } + ctx.body = 6 +}); + +export default baseDict; diff --git a/src/routes/graphResource2/index.js b/src/routes/graphResource2/index.js new file mode 100644 index 0000000..d09b785 --- /dev/null +++ b/src/routes/graphResource2/index.js @@ -0,0 +1,63 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: graphResource2 +// | @文件描述: index.js - +// | @创建时间: 2023-12-01 17:48 +// | @更新时间: 2023-12-01 17:48 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ + +import Router from 'koa-router'; +import atomModel from "#routes/graphResource2/atomModel/index.js"; +import testDTO from "#routes/index.dto.js"; +import rootRouter from "#routes/index.js"; +import baseDict from "#routes/graphResource2/baseDict/index.js"; + +const graphResource2 = new Router(); + +graphResource2.get('/', async (ctx) => { + const data = testDTO({ + name: 'hexi', + age: 32, + email: 'expressgy', + }); + console.log(data); + ctx.body = 'Hello graphResource2!'; +}); +graphResource2.use('/atomModel', atomModel.routes()); +graphResource2.use('/baseDict', baseDict.routes()); + + +// graphResource2.use(async (ctx, next) => { +// +// console.log(1) +// await next() +// console.log(2) +// }) +// +// graphResource2.get('/', async ctx => { +// ctx.body = 'USER' +// }) +// +// +// graphResource2.get('/:id', async ctx => { +// console.log(ctx.params) +// console.log(ctx.query) +// ctx.body = 'USER' +// }) +// +// graphResource2.post('/:id/create', async ctx => { +// console.log(ctx.params) +// console.log(ctx.query) +// console.log(ctx.request.body) +// ctx.body = 'USER' +// }) + + + + +export default graphResource2 diff --git a/src/routes/index.dto.js b/src/routes/index.dto.js new file mode 100644 index 0000000..7cc85b9 --- /dev/null +++ b/src/routes/index.dto.js @@ -0,0 +1,28 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: initkoa +// | @文件描述: index.dto.js - +// | @创建时间: 2023-11-26 15:10 +// | @更新时间: 2023-11-26 15:10 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ + +import makeDTO from "#common/dto/index.js"; + +export default function testDTO(data){ + const schema = { + "type": "object", + "properties": { + "name": { "type": "string" }, + "age": { "type": "number" }, + "email": { "type": "string", + "pattern": "^\\S+@\\S+\\.\\S+$" } + }, + "required": ["name", "age"] + } + return makeDTO(data, schema) +} diff --git a/src/routes/index.js b/src/routes/index.js new file mode 100644 index 0000000..6c015a2 --- /dev/null +++ b/src/routes/index.js @@ -0,0 +1,41 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: initkoa +// | @文件描述: index.js - +// | @创建时间: 2023-11-26 01:34 +// | @更新时间: 2023-11-26 01:34 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ + +import Router from 'koa-router'; + +import graphResource2 from "#routes/graphResource2/index.js"; +import testDTO from '#routes/index.dto.js'; + +// const rootRouter = new Router({ +// prefix: '/api', // 添加前缀 +// }); + +// const apiRouter = new Router(); +// apiRouter.get('/', async (ctx) => { +// ctx.body = 'Hello /API!'; +// }); +// apiRouter.use('/user', userRouter.routes()); + +const rootRouter = new Router(); +rootRouter.get('/', async (ctx) => { + const data = testDTO({ + name: 'hexi', + age: 32, + email: 'expressgy', + }); + console.log(data); + ctx.body = 'Hello World!'; +}); +rootRouter.use('/graphResource2', graphResource2.routes()); + +export default rootRouter; diff --git a/test/ajvTest.js b/test/ajvTest.js new file mode 100644 index 0000000..ebcc887 --- /dev/null +++ b/test/ajvTest.js @@ -0,0 +1,82 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: initkoa +// | @文件描述: ajvTest.js - +// | @创建时间: 2023-11-25 21:59 +// | @更新时间: 2023-11-25 21:59 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ +const Ajv = require('ajv'); +const ajv = new Ajv({ allErrors: true }); + +const schema = { + type: 'object', + properties: { + name: { type: 'string' }, + age: { type: 'integer', minimum: 18 }, + }, + required: ['name', 'age'], + errorMessage: { + type: '数据应该是一个对象', // 整体 schema 错误消息 + required: '对象缺少必要属性', // 缺少必要属性错误消息 + properties: { + name: '姓名应该是一个字符串', + age: '年龄应该是一个大于或等于 18 的整数', + }, + }, +}; + +const validate = ajv.compile(schema); + +const data = { + name: 123, + age: 17, +}; + +validate(data); +if (validate.errors) { + console.log(validate.errors); // 输出自定义错误消息 +} + +// ================================ + +const Ajv = require('ajv'); +const ajv = new Ajv({ allErrors: true }); + +// 添加自定义关键字 +ajv.addKeyword('isOldEnough', { + validate: function (schema, data) { + ajv.errors = [ + { + keyword: 'isOldEnough', + message: '年龄必须大于18岁', + params: { keyword: 'isOldEnough' }, + }, + ]; + return data >= 18; + }, + errors: true, // 使用自定义的错误列表 +}); + +const schema = { + type: 'object', + properties: { + age: { type: 'integer', isOldEnough: true }, + }, + required: ['age'], +}; + +const validate = ajv.compile(schema); + +const data = { + age: 17, +}; + +validate(data); +if (validate.errors) { + console.log(validate.errors); // 输出自定义错误消息 +} diff --git a/test/koa-body使用.md b/test/koa-body使用.md new file mode 100644 index 0000000..ce2162f --- /dev/null +++ b/test/koa-body使用.md @@ -0,0 +1,286 @@ +`koa-body` 是一个流行的 Koa 请求体解析中间件,支持解析常见的请求体数据类型,包括 JSON 数据、表单数据,以及文件上传。下面是 `koa-body` 的详细配置和使用方式: + +## 安装 + +使用 npm 安装 `koa-body` 中间件: + +``` +npm install koa-body --save +``` + +## 使用 + +要使用 `koa-body` 中间件,只需要在 Koa 应用程序中使用 `app.use` 方法将其注册,然后可以在请求处理程序和中间件中使用 `ctx.request.body` 来访问已解析的请求体数据。 + +以下是一个使用 `koa-body` 中间件的示例: + +```javascript +const Koa = require('koa'); +const koaBody = require('koa-body'); + +const app = new Koa(); + +// 将 koaBody 中间件注册到应用程序中 +app.use( + koaBody({ + multipart: true, + formidable: { + maxFileSize: 100 * 1024 * 1024, + }, + }) +); + +// 处理请求 +app.use((ctx) => { + // 访问已解析的请求体数据 + console.log(ctx.request.body); + ctx.body = 'Hello Koa'; +}); + +// 启动应用程序 +app.listen(3000, () => { + console.log('Server started on http://localhost:3000'); +}); +``` + +在上面的示例中,我们将 `koa-body` 中间件注册到应用程序中,并通过参数对象配置解析器。其中,`multipart` 选项是用于启用文件上传支持的选项,`formidable` 对象包括有关文件上传的配置选项,例如 `maxFileSize`,用于限制文件的大小。 + +在请求处理程序中,我们可以使用 `ctx.request.body` 访问已解析的请求体数据。 + +## 配置选项 + +下面是 `koa-body` 可用的配置选项及其默认值: + +- `form`:是否解析 `application/x-www-form-urlencoded` 格式的请求体数据,默认为 `true` +- `json`:是否解析 `application/json` 格式的请求体数据,默认为 `true` +- `text`:是否解析 `text/*` 格式的请求体数据,默认为 `true` +- `encoding`:请求体的编码方式,默认为 `'utf-8'` +- `xml`:是否解析 `application/xml` 和 `text/xml` 格式的请求体数据,默认为 `false` +- `jsonLimit`:限制解析 `application/json` 格式请求体数据的大小(以字节为单位),默认为 `1mb` +- `formLimit`:限制解析 `application/x-www-form-urlencoded` 格式的请求体数据大小(以字节为单位),默认为 `56kb` +- `textLimit`:限制解析 `text/*` 格式的请求体数据大小(以字节为单位),默认为 `56kb` +- `xmlLimit`:限制解析 `application/xml` 和 `text/xml` 格式的请求体数据大小(以字节为单位),默认为 `1mb` +- `multipart`:是否解析 `multipart/*` 格式的请求体数据(用于文件上传),默认为 `false` +- `multiples`:是否解析多个文件上传,默认为 `false` +- `onError`:错误处理程序,用于处理请求体解析错误,默认为 `ctx.throw` +- `includeUnparsed`:是否将未解析的请求体数据存储在 `ctx.request.body` 中,默认为 `false` +- `textLimit`:限制解析 `text/*` 格式的请求体数据大小(以字节为单位),默认为 `56kb` + +## 示例 + +### 解析表单数据和 JSON 数据 + +以下示例演示如何将 `koa-body` 中间件配置为仅解析表单数据和 JSON 数据: + +```javascript +const Koa = require('koa'); +const koaBody = require('koa-body'); + +const app = new Koa(); + +// 仅解析表单数据和 JSON 数据 +app.use(koaBody({ form: true, json: true })); + +app.use((ctx) => { + console.log(ctx.request.body); + ctx.body = 'Hello Koa'; +}); + +app.listen(3000, () => { + console.log('Server started on http://localhost:3000'); +}); +``` + +在上面的示例中,我们将 `koa-body` 中间件配置为仅解析表单数据和 JSON 数据。我们可以在请求处理程序中使用 `ctx.request.body` 访问已解析的请求体数据。 + +### 解析文件上传 + +以下示例演示如何使用 `koa-body` 中间件解析文件上传: + +```javascript +const Koa = require('koa'); +const koaBody = require('koa-body'); + +const app = new Koa(); + +// 启用文件上传支持 +app.use( + koaBody({ + multipart: true, + formidable: { + maxFileSize: 100 * 1024 * 1024, + }, + }) +); + +app.use((ctx) => { + // 文件上传信息存储在 ctx.request.files 中 + console.log(ctx.request.files); + ctx.body = 'Hello Koa'; +}); + +app.listen(3000, () => { + console.log('Server started on http://localhost:3000'); +}); +``` + +在上面的示例中,我们将 `koa-body` 中间件配置为启用文件上传支持,并使用 `formidable` 对象配置文件上传选项。在请求处理程序中,我们可以使用 `ctx.request.files` 访问文件上传信息。 + +### 错误处理 + +`koa-body` 中间件的默认错误处理程序是 `ctx.throw`,它会抛出一个 HTTP 400 错误响应。你可以自定义一个错误处理程序来处理请求体解析错误。 + +以下示例演示如何自定义错误处理程序: + +```javascript +const Koa = require('koa'); +const koaBody = require('koa-body'); + +const app = new Koa(); + +app.use( + koaBody({ + onError: (err, ctx) => { + ctx.throw('Body parse error', 422); + }, + }) +); + +app.use((ctx) => { + console.log(ctx.request.body); + ctx.body = 'Hello Koa'; +}); + +app.listen(3000, () => { + console.log('Server started on http://localhost:3000'); +}); +``` + +在上面的示例中,我们自定义了一个错误处理程序,当发生请求体解析错误时,它会抛出一个 HTTP 422 错误响应。 + +## 总结 + +`koa-body` 是一个流行的 Koa 请求体解析中间件,它支持解析常见的请求体数据类型,包括 JSON 数据、表单数据,以及文件上传。你可以通过配置选项来自定义解析器的行为,并使用 `ctx.request.body` 和 `ctx.request.files` 在请求处理程序中访问已解析的请求体数据和上传的文件信息。同时,你也可以自定义错误处理程序来处理请求体解析错误。 + + + + + + + + + + + + + + +一、需求 +之前使用 koa2 的时候,处理 post 请求使用的是 koa-bodyparser,同时如果是图片上传使用的是 koa-multer。 + +这两者的组合没什么问题,不过 koa-multer 和 koa-route(注意不是 koa-router) 存在不兼容的问题。 + +这个问题已经在这篇文章中说明了: + +使用koa-multer实现文件上传并自定义文件名和目录 +关于 koa-bodyparser 的使用,见下面文章: + +手动实现koa2 body-parser中间件及koa-boayparser的使用 +但是这两者可以通过 koa-body 代替,并且只是用 koa-body 即可。 + +koa-body 主要是下面两个依赖: + +"co-body": "^5.1.1", +"formidable": "^1.1.1" +具体的实现可以在 github 上查看 : https://github.com/dlau/koa-body + +二、koa-body 的基本使用 +在 koa2 中使用 koa-body,我使用的是全局引入,而不是路由级别的引入,因为考虑到很多地方都有 post 请求或者是文件上传请求,没必要只在路由级别引入。 + +1、安装依赖 +yarn add koa-body +## npm i koa-body -S +2、app.js +省略了 koa 的一些基本代码 + +const koaBody = require('koa-body'); +const app = new koa(); +app.use(koaBody({ +multipart:true, // 支持文件上传 +encoding:'gzip', +formidable:{ +uploadDir:path.join(__dirname,'public/upload/'), // 设置文件上传目录 +keepExtensions: true, // 保持文件的后缀 +maxFieldsSize:2 * 1024 * 1024, // 文件上传大小 +onFileBegin:(name,file) => { // 文件上传前的设置 +// console.log(`name: ${name}`); +// console.log(file); +}, +} +})); +3、有用的参数 +1)koa-body 的基本参数 + +参数名 描述 类型 默认值 +patchNode 将请求体打到原生 node.js 的ctx.req中 Boolean false +patchKoa 将请求体打到 koa 的 ctx.request 中 Boolean true +jsonLimit JSON 数据体的大小限制 String / Integer 1mb +formLimit 限制表单请求体的大小 String / Integer 56kb +textLimit 限制 text body 的大小 String / Integer 56kb +encoding 表单的默认编码 String utf-8 +multipart 是否支持 multipart-formdate 的表单 Boolean false +urlencoded 是否支持 urlencoded 的表单 Boolean true +text 是否解析 text/plain 的表单 Boolean true +json 是否解析 json 请求体 Boolean true +jsonStrict 是否使用 json 严格模式,true 会只处理数组和对象 Boolean true +formidable 配置更多的关于 multipart 的选项 Object {} +onError 错误处理 Function function(){} +stict 严格模式,启用后不会解析 GET, HEAD, DELETE 请求 Boolean true +2)formidable 的相关配置参数 + +参数名 描述 类型 默认值 +maxFields 限制字段的数量 Integer 1000 +maxFieldsSize 限制字段的最大大小 Integer 2 * 1024 * 1024 +uploadDir 文件上传的文件夹 String os.tmpDir() +keepExtensions 保留原来的文件后缀 Boolean false +hash 如果要计算文件的 hash,则可以选择 md5/sha1 String false +multipart 是否支持多文件上传 Boolean true +onFileBegin 文件上传前的一些设置操作 Function function(name,file){} +关于 onFileBegin 的更多信息可以查看: + +https://github.com/felixge/node-formidable#filebegin +4、获取文件上传后的信息 +这些代码是在路由中体现的 + +需要注意的是,如果是获取上传后文件的信息,则需要在 ctx.request.files 中获取。 + +如果是获取其他的表单字段,则需要在 ctx.request.body 中获取,这是由 co-body 决定的(默认情况)。 + +router.get('/', async (ctx) => { +await ctx.render('index'); +}); + +router.post('/',async (ctx)=>{ +console.log(ctx.request.files); +console.log(ctx.request.body); +ctx.body = JSON.stringify(ctx.request.files); +}); +三、结果 + + +因为默认开启多个文件上传,因此 ctx.request.files 是一个对象, + +而且是通过表单的 name=photo 属性作为对象的 key,值便是一个 File 对象,有用的字段如下: + +字段名 描述 +size 文件大小 +path 文件上传后的目录 +name 文件的原始名称 +type 文件类型 +lastModifiedDate 上次更新的时间 + + +http://www.ptbird.cn/koa-body.html +———————————————— +版权声明:本文为CSDN博主「after you」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 +原文链接:https://blog.csdn.net/gwdgwd123/article/details/103561817 diff --git a/test/koa-compress说明.md b/test/koa-compress说明.md new file mode 100644 index 0000000..4e23269 --- /dev/null +++ b/test/koa-compress说明.md @@ -0,0 +1,104 @@ + + +koa-compress 是一个 Koa 中间件,用于压缩 HTTP 响应。使用该中间件可减少 HTTP 响应的大小,从而提升应用程序的性能。 + +下面是使用 koa-compress 的简单示例: + +```javascript +const Koa = require('koa'); +const compress = require('koa-compress'); + +const app = new Koa(); + +// 注册中间件 +app.use(compress()); + +// 定义路由 +app.use(async (ctx) => { + ctx.body = 'Hello, world!'; +}); + +app.listen(3000, () => { + console.log('Server started on 3000'); +}); +``` + +在上面的示例中,我们首先通过 `require` 引入了 Koa 和 koa-compress,然后创建了一个 Koa 应用程序实例。 + +在注册中间件时,我们使用了 `compress()` 函数来创建 koa-compress 中间件的实例,并将其添加到应用程序中间件栈中。 + +最后,我们定义了一个非常简单的路由,在该路由中,我们设置了响应的正文内容为 "Hello, world!"。由于我们已经注册了 koa-compress 中间件,因此响应的内容将被压缩后返回给客户端。 + +需要注意的是,koa-compress 的默认配置已经适用于大多数情况。如果需要对其进行个性化配置,请参阅 koa-compress 的文档。 + + +虽然 koa-compress 是一个非常有用的中间件,但它也有一些缺点,包括: + +1. CPU 开销:压缩和解压缩数据需要消耗一定的 CPU 资源。对于大量并发请求的应用程序,尤其是在处理大型响应时,这可能会占用大量的 CPU 时间,并可能成为性能瓶颈。 + +2. 内存消耗:压缩和解压缩数据可能会占用一定的内存。对于包含大量压缩数据的响应,这可能会导致应用程序的内存占用增加。 + +3. 配置复杂性:虽然 koa-compress 的默认配置适用于大多数情况,但某些情况下可能需要进行个性化的配置。配置复杂性可能会增加,特别是在需要针对不同的响应类型或路径进行不同的压缩设置时。 + +4. 不适用于动态内容:由于压缩是在响应生成后进行的,因此对于动态内容(如实时数据或流式响应)无法实时压缩。这可能会导致传输过程中的数据量较大,影响网络传输速度。 + +总体来说,koa-compress 是一个功能强大的中间件,可以提高应用程序的性能和网络传输效率。然而,在使用它时,需要权衡使用压缩所带来的性能消耗和配置复杂性,以确保最佳的应用程序性能和用户体验。 + +koa-compress 提供了一系列的配置选项,可以根据需要进行个性化的配置。下面是常用的一些选项: + +- `filter`:指定哪些 HTTP 响应需要被压缩。可以是一个布尔值、字符串、正则表达式或一个自定义函数。默认为压缩所有响应。 + +- `threshold`:指定响应正文的大小下限,只有当响应正文大小超过指定值时才会进行压缩。默认为 `1024` 字节。 + +- `gzip`:指定是否启用 Gzip 压缩。默认为 `true`。 + +- `deflate`:指定是否启用 Deflate 压缩。默认为 `true`。 + +- `br`:指定是否启用 Brotli 压缩。默认为 `false`。 + +- `chunkSize`:指定压缩块的大小。默认为 `16 * 1024` 字节。 + +- `mimeTypes`:指定要压缩的 MIME 类型。默认为 `['text/*']`。 + +- `enableTypes`:指定要启用压缩的 MIME 类型。默认为所有 MIME 类型。 + +- `skip`:指定一个自定义函数,以跳过指定的请求或响应。默认为 `null`。 + +下面是一个配置示例: + +```javascript +const Koa = require('koa'); +const compress = require('koa-compress'); + +const app = new Koa(); + +// 注册中间件并进行个性化配置 +app.use(compress({ + filter (content_type) { + return /text/i.test(content_type) + }, + threshold: 1024, + gzip: true, + deflate: false, + br: false, + chunkSize: 16 * 1024, + mimeTypes: ['text/plain', 'application/json'], + enableTypes: ['text/plain', 'application/json'], + skip (ctx) { + return ctx.path === '/healthcheck'; + } +})); + +// 定义路由 +app.use(async (ctx) => { + ctx.body = 'Hello, world!'; +}); + +app.listen(3000, () => { + console.log('Server started on 3000'); +}); +``` + +在上面的示例中,我们使用了一些常见的配置选项。我们指定了只对文本类型的响应进行压缩,并且启用了 Gzip 压缩。我们还指定了要启用的 MIME 类型和要跳过的路径,以及其他一些选项。 + +需要注意的是,配置选项可以根据需要进行个性化的调整。可以根据实际情况进行选择。在使用 koa-compress 时,确保在经过测试和评估后再进行个性化的配置。 diff --git a/test/koa-ratelimit限制批量请求工具的应用.md b/test/koa-ratelimit限制批量请求工具的应用.md new file mode 100644 index 0000000..8f682ce --- /dev/null +++ b/test/koa-ratelimit限制批量请求工具的应用.md @@ -0,0 +1,33 @@ +要限制同一个客户端的请求数量,可以使用 `koa-ratelimit` 插件。该插件可以按照一定的速率限制客户端的请求数量。以下是使用 `koa-ratelimit` 的示例代码: + +```javascript +const Koa = require('koa'); +const ratelimit = require('koa-ratelimit'); + +const app = new Koa(); + +app.use(ratelimit({ + driver: 'memory', // 存储限流数据的驱动,这里使用内存驱动 + db: new Map(), // 存储被限制的客户端信息的数据结构 + duration: 60000, // 时间窗口,单位毫秒 + max: 10, // 时间窗口内允许的最大请求数量 + id: ctx => ctx.ip, // 提取每个请求的唯一标识符,默认使用请求的 IP 地址 +})); + +// 添加其他中间件和路由 + +app.listen(3000, () => { + console.log('Server started on http://localhost:3000'); +}); +``` + +在上述代码中,我们使用 `koa-ratelimit` 插件来限制同一个客户端的请求数量。插件配置中的关键参数如下: +- `driver`:存储限流数据的驱动,可以选择内存 (`memory`)、Redis (`redis`)、MongoDB (`mongodb`) 等。在示例中我们使用内存驱动。 +- `db`:存储被限制的客户端信息的数据结构,这里我们使用 `Map`。 +- `duration`:时间窗口的持续时间,单位为毫秒。 +- `max`:时间窗口内允许的最大请求数量。 +- `id`:提取每个请求的唯一标识符,默认使用请求的 IP 地址。 + +当某个客户端超过设定的最大请求数量时,该插件会返回 HTTP 状态码 429 Too Many Requests,并且设置 `Retry-After` 头部,表示重新尝试请求的时间。 + +通过使用 `koa-ratelimit` 插件,可以有效地限制同一个客户端的请求数量,从而保护服务器免受过多的请求负载。同时,你也可以根据实际需求调整时间窗口和最大请求数量的配置。 diff --git a/test/koa-send方法.md b/test/koa-send方法.md new file mode 100644 index 0000000..29bca8d --- /dev/null +++ b/test/koa-send方法.md @@ -0,0 +1,46 @@ +`koa-send` 是一个 Koa 中间件,用于发送文件或目录响应给客户端。它提供了一种简单的方式来处理静态文件的发送。下面是一个使用示例: + +```javascript +const Koa = require('koa'); +const send = require('koa-send'); +const app = new Koa(); + +app.use(async (ctx, next) => { + // 使用 koa-send 发送文件 + await send(ctx, 'path/to/file.txt'); +}); + +app.listen(3000, () => { + console.log('Server started on 3000'); +}); +``` + +在上面的示例中,`koa-send` 中间件用于处理所有的请求,并将文件 `path/to/file.txt` 发送给客户端。 + +除了发送单个文件外,你还可以发送整个目录: + +```javascript +app.use(async (ctx, next) => { + // 使用 koa-send 发送目录 + await send(ctx, 'path/to/directory'); +}); +``` + +这将发送指定目录下的文件,可以在请求的 URL 中指定特定的文件。 + +`koa-send` 还提供了一些选项,用于设置发送文件时的行为。例如,你可以指定根目录、设置缓存控制头、设置内容类型等。以下是一个使用选项的示例: + +```javascript +app.use(async (ctx, next) => { + await send(ctx, 'path/to/file.txt', { + root: 'public', // 设置根目录 + maxage: 1 * 24 * 60 * 60 * 1000, // 设置缓存时间 + immutable: true, // 设置不可变性(immutable) + contentType: 'text/plain' // 设置内容类型 + }); +}); +``` + +在上面的示例中,我们将根目录设置为 `public`,将缓存时间设置为 1 天,启用不可变性,并设置内容类型为 `text/plain`。 + +通过这些选项,你可以对发送的文件进行更细致的控制。更多的选项和详细的使用方式可以查看 `koa-send` 的文档。 diff --git a/test/koa修改code.md b/test/koa修改code.md new file mode 100644 index 0000000..9257db2 --- /dev/null +++ b/test/koa修改code.md @@ -0,0 +1,39 @@ +要在 Koa 中修改 HTTP 响应的状态码(code),可以简单地通过 ctx.status 属性进行修改。例如,将响应状态码修改为 404: + +```js +app.use(async (ctx, next) => { + ctx.status = 404; + // 继续执行后续中间件,并在之后对响应进行修改 + await next(); +}); +``` + +在上述代码中,我们将响应状态码设置为 404,并在之后继续执行后续中间件。这意味着你可以在后续中间件中进一步修改响应内容,比如设置响应体、设置 headers 等。 + +如果你想要在响应发送之前中止中间件的执行,可以通过 ctx.throw 方法或在抛出一个 Error 对象,同时设置其 status 或者 statusCode 属性: + +```js +app.use(async (ctx, next) => { + if (someCondition) { + ctx.throw(400, 'Bad Request'); + } else { + await next(); + } +}); +``` + +或者: + +```js +app.use(async (ctx, next) => { + if (someCondition) { + const err = new Error('Bad Request'); + err.status = 400; + throw err; + } else { + await next(); + } +}); +``` + +在上述代码中,当 someCondition 符合时,我们通过 ctx.throw 或抛出 Error 对象来中止中间件执行,并将响应状态码设置为 400。