diff --git a/.gitignore b/.gitignore index aa4b2f5..52962c2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,143 +1,58 @@ -# ---> Node # Logs logs *.log npm-debug.log* -yarn-debug.log* -yarn-error.log* -lerna-debug.log* -.pnpm-debug.log* - -# 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 intermediate storage (http://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) +# Compiled binary addons (http://nodejs.org/api/addons.html) build/Release # Dependency directories -node_modules/ -jspm_packages/ - -# Snowpack dependency directory (https://snowpack.dev/) -web_modules/ - -# TypeScript cache -*.tsbuildinfo +node_modules +jspm_packages # 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 +# 0x +profile-* -# yarn v2 -.yarn/cache -.yarn/unplugged -.yarn/build-state.yml -.yarn/install-state.gz -.pnp.* +# mac files +.DS_Store -# ---> Vue -# gitignore template for Vue.js projects -# -# Recommended template: Node.gitignore +# vim swap files +*.swp -# TODO: where does this rule come from? -docs/_book +# webstorm +.idea -# TODO: where does this rule come from? -test/ +# vscode +.vscode +*code-workspace +# clinic +profile* +*clinic* +*flamegraph* diff --git a/app.js b/app.js new file mode 100644 index 0000000..2164841 --- /dev/null +++ b/app.js @@ -0,0 +1,135 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: hutao +// | @文件描述: app.js - +// | @创建时间: 2024-03-15 11:38 +// | @更新时间: 2024-03-15 11:38 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ + +import config from "config"; +import Fastify from "fastify"; +import {isLowerCase, isTrim} from "#plugins/ajv/index.js"; +import ajvErrors from "ajv-errors"; +import chalk from "chalk"; +import {destr} from 'destr' + +global.tostr = JSON.stringify +global.destr = destr + +const fastify = Fastify({ + ajv: { + customOptions: { + removeAdditional: true, + useDefaults: true, + coerceTypes: true, + allErrors: true, + // 允许使用联合模式 严格模式下 + allowUnionTypes: true + }, + plugins: [ + ajvErrors, + // 这种方式完美解决,开心, 实际上这是一个函数,会传进去ajv实例对象 + isLowerCase, + isTrim, + ] + + } +}) +fastify.decorate('color', chalk) +fastify.decorate('config', config) +fastify.decorate('authenticate', async function (request, reply) { + try { + // 校验token,并生成request的user参数 + await request.jwtVerify(); + } catch (err) { + // token校验未通过,记录错误 + fastify.log.debug({reqId: request.id, Auth: err.message}); + reply.code(err.statusCode).send({ + statusCode: err.statusCode, + message: err.message, + error: err.name + }); + } +}); +// | 插件 +// @ 注册日志记录 +await fastify.register(import("#common/logger/index.js")) +// @ 注册数据库 +await fastify.register(import("#plugins/sequelize/index.js")) +// @ 注册redis +await fastify.register(import('@fastify/redis'), { + // 配置文件基础redis配置 host,port,password + host: '172.16.1.10', + port: 6379, + password: 'Hxl1314521', + // fastify调用的名称空间 + namespace: 'db1', + // 指向的redis数据库0-15 + db: 1, + // 4 (IPv4) or 6 (IPv6) + family: 4, + // redis连接中的名字 + connectionName: 'global.conf.projectName' +}); +// @ 注册防止恶意请求封ip +await fastify.register(import('@fastify/rate-limit'), { + // 限制每个 IP 地址在时间窗口内最多可以发出的请求数 + max: 500, + // '1 second' = '1000':1 秒 | '1 minute' 1 分钟 | '1 hour' 1 小时 | '1 day' 1 天 | '1 week' 1 周 + timeWindow: '1 day' +}); +// @ 注册错误处理工具 +await fastify.register(import('@fastify/sensible')); +// @ 注册jwt +await fastify.register(import('@fastify/jwt'), { + // token的加密值 + secret: 'xadvdgfhga21xabhgnumo;opilkujya8axa21', + sign: { + // token过期时间 + expiresIn: '20m' + } +}); +// @ 注册路由 +await fastify.register(import('#routes/index.js'), {prefix: '/api'}) + +// @ 发送消息拦截 +fastify.addHook('onSend', async (request, reply, payload) => { + // fastify.log.info(reply.getHeader('content-type')); + if (reply.statusCode === 200 && !request.url.includes('/api/file')) { + if(['{', '"'].indexOf(payload.trim().slice(0, 1)[0]) > -1){ + return `{"statusCode": 200, "status": "success", "data": ${payload}}`; + }else{ + reply.header('Content-Type', 'application/json'); + return `{"statusCode": 200, "status": "success", "data": "${payload}"}`; + } + } + return payload; +}); +// @ 错误拦截 +fastify.setErrorHandler(async (error, request, reply) => { + // 自定义错误处理逻辑 + fastify.log.error(error); + reply + .code(error.statusCode) + .send({ + statusCode: error.statusCode, + message: error.message, + error: error.name + }); +}); + +fastify.logger.info(await fastify.redis.db1.set('name', 'xsx', 'EX', 60)); + +// console.log(fastify.data) + + +fastify.listen({ + port: config.get('port') +}).then(resd => { + console.log(`http://127.0.0.1:${config.get('port')}`) +}) diff --git a/config/default.json b/config/default.json new file mode 100644 index 0000000..e99b647 --- /dev/null +++ b/config/default.json @@ -0,0 +1,13 @@ +{ + "ProjectName": "HuTao", + "timestamp": "20240315", + "host": "0.0.0.0", + "port": "48826", + "db": { + "username": "nie", + "password": "Hxl1314521", + "database": "hutao", + "host": "172.16.1.10", + "port": "3306" + } +} diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml new file mode 100644 index 0000000..ba7a837 --- /dev/null +++ b/docker/docker-compose.yml @@ -0,0 +1,35 @@ +version: '3.8' + +services: + mysql: + image: mysql:8 + restart: always + environment: + MYSQL_ROOT_PASSWORD: Hxl1314521 + MYSQL_DATABASE: hutao + MYSQL_USER: nie + MYSQL_PASSWORD: Hxl1314521 + ports: + - "3306:3306" + volumes: + - mysql8:/var/lib/mysql + + redis: + image: redis:latest + restart: always + ports: + - "6379:6379" + volumes: + - ./redis.conf:/usr/local/etc/redis/redis.conf + - redis_data:/data + - redis_log:/var/log/redis + + redisinsight: + image: redislabs/redisinsight:latest + ports: + - "8001:8001" + +volumes: + mysql8: + redis_data: + redis_log: diff --git a/docs/ProCatch5微服务部署流程.md b/docs/ProCatch5微服务部署流程.md new file mode 100644 index 0000000..b6b339d --- /dev/null +++ b/docs/ProCatch5微服务部署流程.md @@ -0,0 +1,351 @@ +# 一、后端打包 + +## 服务 +- 基础服务 + - 网关服务procatch-gateway + - 文件服务procatch-modules-file + - 认证服务procatch-auth +- 核心服务 + - 用户服务procatch-modules-system + - 资源服务procatch-resource +- 业务服务 + - 运维服务procatch-work-om + +### 后端打包错误整理 + +- 2023-03-30 + - 建项目的时候工程目录包结构顺序错误,导致打包找不到启动类。解决办法:把顺序调对。以后建项目要仔细。 + - 通过端口可以访问服务,但通过网关不行,检查nacos网关配置,修改子系统路径前缀 + +## 数据 + +## 权限文件 + + +# 二、前端打包 + +```bash +npm run build +``` + +# 三、服务器环境 + +## 1. 系统Debian11 + +- 换源 + +```bash +echo "deb http://mirrors.aliyun.com/debian/ bullseye main non-free contrib +deb-src http://mirrors.aliyun.com/debian/ bullseye main non-free contrib +deb http://mirrors.aliyun.com/debian-security/ bullseye-security main +deb-src http://mirrors.aliyun.com/debian-security/ bullseye-security main +deb http://mirrors.aliyun.com/debian/ bullseye-updates main non-free contrib +deb-src http://mirrors.aliyun.com/debian/ bullseye-updates main non-free contrib +deb http://mirrors.aliyun.com/debian/ bullseye-backports main non-free contrib +deb-src http://mirrors.aliyun.com/debian/ bullseye-backports main non-free contrib" > sources.list + +apt-get update +``` + +## 2. Docker +```bash +sudo apt-get install docker-compose + +#查看Docker可用用户 +sudo cat /etc/group |grep docker +# docker:x:998:表示存在 +sudo groupadd docker +sudo usermod -aG docker $USER +newgrp docker # 激活组更改,无效的话尝试重连ssh,退出登录,重启计算机等 +``` + +## 3.Java8 + +```bash +# windows +# 上传java文件到服务器 +scp jdk-8u361-linux-x64.tar.gz snow@192.168.1.200:~/. +# Linux +sudo mv jdk-8u361-linux-x64.tar.gz /opt/. +# 解压 +cd /opt/ tar zxvf jdk-8u361-linux-x64.tar.gz +# 配置环境变量 +echo "export JAVA_HOME=/opt/jdk1.8.0_361 +export PATH=$JAVA_HOME/bin:$PATH" >> /etc/profile +# 即时生效配置 +source /etc/profile +``` + +## 4. MySQL5.7 +```bash +# 创建Docker文件存储点 +cd ~ +mkdir DockerData +cd DockerData +mdkir mysql5.7 +cd mysql5.7 +mkdir log +mkdir data +mkdir conf +nowpath=$(pwd) +# 运行docker +docker run -d --name mysql5.7 \ + --restart=always \ + -v $nowpath/data:/var/lib/mysql \ + -v $nowpath/conf:/etc/mysql/conf.d \ + -v $nowpath/log:/logs \ + -e MYSQL_ROOT_PASSWORD=root \ + -p 3306:3306 \ + mysql:5.7 +# 设置开机自启动 +docker update --restart=always mysql5.7 +docker cp /usr/share/zoneinfo/Asia/Shanghai mysql5.7:etc/localtime +docker restart +``` + +## 5. Nacos +```bash +#docker版 +cd ~/DockerData +mdkir nacos +cd nacos +mkdir log +mkdir data +mkdir conf +nowpath=$(pwd) +# 写入配置文件 +touch conf/application.properties +echo " +server.servlet.contextPath=/nacos +server.error.include-message=ON_PARAM +server.port=8848 + +db.pool.config.connectionTimeout=30000 +db.pool.config.validationTimeout=10000 +db.pool.config.maximumPoolSize=20 +db.pool.config.minimumIdle=2 + +nacos.naming.empty-service.auto-clean=true +nacos.naming.empty-service.clean.initial-delay-ms=50000 +nacos.naming.empty-service.clean.period-time-ms=30000 + +management.endpoints.web.exposure.include=* + +management.metrics.export.elastic.enabled=false +management.metrics.export.influx.enabled=false + +server.tomcat.accesslog.enabled=true + +server.tomcat.accesslog.pattern=%h %l %u %t "%r" %s %b %D %{User-Agent}i %{Request-Source}i + +server.tomcat.basedir=file:. + +nacos.security.ignore.urls=/,/error,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-ui/public/**,/v1/auth/**,/v1/console/health/**,/actuator/**,/v1/console/server/** + +nacos.core.auth.system.type=nacos + +nacos.core.auth.enabled=false +nacos.core.auth.caching.enabled=true +nacos.core.auth.enable.userAgentAuthWhite=false + +nacos.core.auth.server.identity.key=serverIdentity +nacos.core.auth.server.identity.value=security + +nacos.core.auth.plugin.nacos.token.expire.seconds=18000 +nacos.core.auth.plugin.nacos.token.secret.key=SecretKey012345678901234567890123456789012345678901234567890123456789 + +nacos.istio.mcp.server.enabled=false + +spring.datasource.platform=mysql +db.num=1 +db.url.0=jdbc:mysql://192.168.1.201:3306/procatch-config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC +db.user=root +db.password=root" > conf/application.properties +# 运行docker +docker run \ +--name nacos -d \ +-p 8848:8848 \ +-p 9848:9848 \ +--privileged=true \ +--restart=always \ +-e JVM_XMS=256m \ +-e JVM_XMX=256m \ +-e MODE=standalone \ +-e PREFER_HOST_MODE=10.10.10.20 \ +-v $nowpath/log:/home/nacos/logs \ +-v $nowpath/conf/application.properties:/home/nacos/conf/application.properties \ +-v $nowpath/data:/home/nacos/data \ +nacos/nacos-server +# 设置开机自启动 +docker update --restart=always nacos +``` + +## 6. redis +```bash +mkdir redis +cd redis/ +mkdir log +mkdir data +mkdir conf +echo "# Redis配置文件 + +# Redis默认不是以守护进程的方式运行,可以通过该配置项修改,使用yes启用守护进程 +daemonize no + +# 指定Redis监听端口,默认端口为6379 +port 6379 + +# 绑定的主机地址,不要绑定容器的本地127.0.0.1地址,因为这样就无法在容器外部访问 +bind 0.0.0.0 + +#需要密码则打开 +# requirepass mima +# 持久化 +# appendonly yes" > conf/redis.conf +nowpath=$(pwd) +docker run -d -p 6379:6379 \ +--name redis \ +-v $nowpath/conf/redis.conf:/etc/redis/redis.conf \ +-v $nowpath/data:/data \ +redis \ +redis-server /etc/redis/redis.conf +docker update --restart=always redis +``` + +## 7. Nginx + +```bash +sudo apt-get install nginx +sudo systemctl enable nginx +sudo systemctl start nginx +# 配置文件在/etc/nginx/nginxconf +``` + +# 四、部署和运行 + +1. 将各模块包上传至服务器 + +- 后端jar包放在latest文件夹下 +- 前端文件直接放在项目根目录下 + +```bash +# 创建项目文件夹 +mkdir ProCatch5_Test +cd ProCatch5_Test +mkdir latest +mkdir log +mkdir PID.d +``` + +目录结构为 + +```bash +├── latest +├── log +├── PID.d +└── start.sh +``` + +- start.sh为最初后台服务启动文件 + +```bash +#! start.sh + +echo "等待网管启动 ==>" +nohup java -jar -Xms512m -Xmx512m ./latest/procatch-gateway.jar > ./log/procatch-gateway.log 2>&1 & echo $! > ./PID.d/procatch-gateway.pid & +sleep 15 +echo "procatch-auth ==>" +nohup java -jar -Xms512m -Xmx512m ./latest/procatch-auth.jar > ./log/procatch-auth.log 2>&1 & echo $! > ./PID.d/procatch-auth.pid & +sleep 5 +echo "procatch-modules-file ==>" +nohup java -jar -Xms512m -Xmx512m ./latest/procatch-modules-file.jar > ./log/procatch-modules-file.log 2>&1 & echo $! > ./PID.d/procatch-modules-file.pid & +sleep 5 +echo "procatch-modules-system ==>" +nohup java -jar -Xms512m -Xmx512m ./latest/procatch-modules-system.jar > ./log/procatch-modules-system.log 2>&1 & echo $! > ./PID.d/procatch-modules-system.pid & +sleep 5 +echo "procatch-resource ==>" +nohup java -jar -Xms512m -Xmx512m ./latest/procatch-resource.jar > ./log/procatch-procatch-resource.log 2>&1 & echo $! > ./PID.d/procatch-resource.pid & +sleep 5 +echo "procatch-work-om ==>" +nohup java -jar -Xms512m -Xmx512m ./latest/procatch-work-om.jar > ./log/procatch-work-om.log 2>&1 & echo $! > ./PID.d/procatch-work-om.pid & +sleep 5 +``` + +dist.zip为前端包文件 + +- 解压 + +```bash +unzip dist.zip +#生成 dist文件夹 +``` + +2. 启动服务 + +```bash +chmod +x start.sh +./start.sh +``` +- 生成的一些日志文件 + +```bash +. +├── dist # 前端文件夹 +│   ├── assets +├── dist.zip # 前端文件包 +├── latest # 后端包存放文件夹 +│   ├── procatch-auth.jar +│   ├── procatch-gateway.jar +│   ├── procatch-modules-file.jar +│   ├── procatch-modules-system.jar +│   ├── procatch-resource.jar +│   └── procatch-work-om.jar +├── log # 启动时日志 +│   ├── procatch-auth.log +│   ├── procatch-gateway.log +│   ├── procatch-modules-file.log +│   ├── procatch-modules-system.log +│   ├── procatch-procatch-resource.log +│   ├── procatch-work-om-3.6.1.log +│   └── procatch-work-om.log +├── logs # 运行时日志 +│   ├── procatch-auth +│   │   ├── error.2023-03-29.log +│   │   ├── error.log +│   │   └── info.log +│   ├── procatch-file +│   │   ├── error.log +│   │   └── info.log +│   ├── procatch-gateway +│   │   ├── error.2023-03-29.log +│   │   ├── error.log +│   │   ├── info.2023-03-29.log +│   │   └── info.log +│   ├── procatch-source +│   │   ├── error.2023-03-29.log +│   │   ├── error.log +│   │   └── info.log +│   ├── procatch-system +│   │   ├── error.2023-03-29.log +│   │   ├── error.log +│   │   └── info.log +│   └── procatch-work-om +│   ├── error.2023-03-29.log +│   ├── error.log +│   ├── info.2023-03-29.log +│   ├── info.log +│   ├── warn.2023-03-29.log +│   └── warn.log +├── PID.d # 进程号文件夹 +│   ├── procatch-auth.pid +│   ├── procatch-gateway.pid +│   ├── procatch-modules-file.pid +│   ├── procatch-modules-system.pid +│   ├── procatch-resource.pid +│   └── procatch-work-om.pid +└── start.sh +``` + +# 四、系统配置 + +- 需要在naos各个服务配置上进行改动,主要为更改数据库地址、密码,redis地址以及各个子系统的路径前缀和端口调整 \ No newline at end of file diff --git a/docs/book/hooks.md b/docs/book/hooks.md new file mode 100644 index 0000000..9f9cf7d --- /dev/null +++ b/docs/book/hooks.md @@ -0,0 +1,213 @@ +Fastify 提供了多种钩子(hooks),允许您在不同的生命周期阶段介入服务器的行为。它们在处理请求和响应时非常有用,例如验证请求、日志记录、执行清理或统计任务等。 + +下面是 Fastify 所有的生命周期钩子列表,按照它们在请求生命周期中的执行顺序排列: + +### 应用层面的钩子 + +1. `onRequest(req, reply, done)` + - 在路由解析之前执行(但在请求被解析之后,例如 HTTP 方法、URL 和头部)。 + - 可以用来执行验证、解密等任务。 + +2. `preParsing(req, reply, payload, done)` + - 在解析 HTTP 请求之前执行(例如,解析请求体之前)。 + - 允许您操作原始请求对象和有效载荷。 + +3. `preValidation(req, reply, done)` + - 在执行路由处理程序之前、请求校验之前执行。 + - 适合执行权限校验等任务。 + +4. `preHandler(req, reply, done)` + - 在执行路由处理程序之前执行。 + - 可用于修改请求或回复,或在实际处理程序运行前做准备工作。 + +### 路由层面的钩子 + +在路由声明时,可以指定以下钩子,它们仅在应用于该路由的请求中执行: + +1. `preValidation(req, reply, done)` + - 类似于应用层面的 preValidation 钩子,但只作用于特定路由。 + +2. `preHandler(req, reply, done)` + - 类似于应用层面的 preHandler 钩子,但只作用于特定路由。 + +### 异常处理钩子 + +1. `onError(req, reply, error, done)` + - 当处理程序或钩子抛出异常时执行。 + - 用于自定义错误处理逻辑。 + +### 回复生命周期钩子 + +1. `onSend(req, reply, payload, done)` + - 在将回复发送给客户端之前执行。 + - 可以用来修改回复的有效载荷。 + +2. `onResponse(req, reply, done)` + - 当响应完全发送给客户端后执行。 + - 适用于清理资源或记录日志。 + +### 关闭钩子 + +1. `onClose(instance, done)` + - 在服务器关闭时执行。 + - 通常用于关闭数据库连接、清理资源等。 + +这些钩子都遵循 `fastify` 的 "错误优先回调" 约定,即 `done` 回调函数的第一个参数是一个错误对象,如果有错误的话。如果一切正常,您只需调用 `done()`,没有任何参数或者传入 `null`。 + +要使用这些钩子,通常您会将它们注册为 Fastify 插件,或者直接应用在 Fastify 实例上。例如: + +```javascript +// 注册一个 onRequest 钩子 +fastify.addHook('onRequest', (req, reply, done) => { + // 钩子逻辑 + done(); +}); +``` + +对于路由特定的钩子,您将它们添加到路由声明中,如下所示: + +```javascript +fastify.route({ + method: 'GET', + url: '/', + preHandler: (req, reply, done) => { + // 路由特定的钩子逻辑 + done(); + }, + handler: (req, reply) => { + // 路由处理程序 + reply.send({ hello: 'world' }); + } +}); +``` + +钩子可以是非常强大的工具,它们提供了对 Fastify 应用程序的细粒度控制,允许您优雅地集成自定义逻辑和中间件。 + + + + + + +在 Fastify 中,您可以通过在路由声明中直接添加钩子来将它们作用于特定的路由。当您声明路由时,Fastify 允许您指定 `preValidation`、`preHandler`、`preSerialization`、`onError`、`onSend` 和 `onResponse` 这些生命周期钩子。 + +这里有一个例子,展示了如何给特定路由添加钩子: + +```javascript +fastify.route({ + method: 'GET', + url: '/special', + preHandler: (request, reply, done) => { + // ... 在这个特定路由之前执行一些逻辑 + done(); + }, + handler: (request, reply) => { + // ... 处理路由请求 + reply.send({ hello: 'world' }); + }, + onSend: (request, reply, payload, done) => { + // ... 在回复发送到客户端之前修改回复内容 + done(); + } +}); +``` + +在这个例子中,`preHandler` 钩子函数在处理 GET 请求到 `/special` 路由之前运行,而 `onSend` 钩子在响应发送之前运行,可以用于修改响应 payload。 + +每个钩子函数都会接受不同的参数,根据所执行的任务,这些参数提供了对请求 (`request`)、回复 (`reply`)、有效载载荷 (`payload`) 等的访问权。钩子函数最后需要调用 `done` 函数来通知 Fastify 钩子已完成执行,如果出现错误,可以将错误作为 `done` 函数的第一个参数传递。如果一切顺利,那么只需调用 `done()` 或 `done(null)` 即可。 + +如果您需要在一个特定的路由上应用多个同类型的钩子,您可以传递一个钩子函数的数组: + +```javascript +fastify.route({ + method: 'GET', + url: '/special', + preHandler: [ + (request, reply, done) => { + // 第一个 preHandler 钩子 + done(); + }, + (request, reply, done) => { + // 第二个 preHandler 钩子 + done(); + } + ], + handler: (request, reply) => { + // ...处理路由请求 + reply.send({ hello: 'world' }); + } +}); +``` + +在这个例子中,当请求 `/special` 路由时,将按照数组中的顺序执行两个 `preHandler` 钩子函数。 + +通过将钩子绑定到特定路由上,您可以为每个路由精细地控制流程,并按需集成权限检查、请求数据修改、响应的自定义处理等逻辑。 + + + + + + + + +在 Fastify 中,如果多个路由有部分共同的路径,并且你想对这些具有共同路径的路由应用特定的钩子,你可以使用两种主要方法: + +1. **通过插件和前缀注册钩子**:你可以创建一个插件,为这个插件设置一个路径前缀(路由的共同部分),然后在这个插件内注册全局钩子(这将仅应用于插件范围内的路由)。 + + 以下是使用插件来注册一个钩子的示例: + + ```javascript + const fastify = require('fastify')({ logger: true }); + + // 插件定义 + fastify.register(function (instance, options, done) { + // 这里的钩子将仅作用于 '/api' 前缀路径下的路由 + instance.addHook('preHandler', async (request, reply) => { + // ... 在该插件下所有路由的处理器之前执行逻辑 + }); + + instance.get('/feature1', async (request, reply) => { + // ... 处理该路由的请求 + return { feature: '1' }; + }); + + instance.get('/feature2', async (request, reply) => { + // ... 处理该路由的请求 + return { feature: '2' }; + }); + + done(); + }, { prefix: '/api' }); + + // 启动服务器 + fastify.listen(3000, err => { + if (err) throw err; + console.log(`Server listening on ${fastify.server.address().port}`); + }); + ``` + + 在这个例子中,所有前缀为 `/api` 的路由都将执行在 `addHook` 中定义的 `preHandler` 钩子。 + +2. **条件性地在钩子中检查路由路径**:你还可以在一个全局钩子中检查请求的路径,根据请求的路由路径来做出条件性的反应,这种方法没有上面那种结构化,但在某些情况下可能有用。 + + 以下是使用条件性钩子的示例: + + ```javascript + // 全局钩子 + fastify.addHook('preHandler', async (request, reply) => { + // 查看请求路径是否匹配特定模式 + if (request.raw.url.startsWith('/api')) { + // ... 在所有 '/api' 路径下的路由之前执行逻辑 + } + }); + + // 非`/api`前缀的路由 + fastify.get('/other', async (request, reply) => { + // 这个路由不会受到上述全局钩子影响 + // 除非在上面的条件检查中同时包括此路径 + return { hello: 'world' }; + }); + ``` + + 在这个例子中,全局 `preHandler` 钩子对所有路由生效,但是它内部检查请求的 URL 是不是以 `/api` 开头,仅对符合该条件的路径执行额外的逻辑。 + +通常,对于维护性和可读性而言,使用插件和前缀注册钩子的方法更为推荐,因为它将相关的路由和钩子逻辑组织在一起,并避免了全局状态的潜在冲突。 diff --git a/docs/book/register.md b/docs/book/register.md new file mode 100644 index 0000000..3642b12 --- /dev/null +++ b/docs/book/register.md @@ -0,0 +1,51 @@ +在 Fastify 中, `register` 函数用于注册插件。插件可以是一组封装的路由、服务、插件或者是装饰器等。使用 `register` 可以为应用添加新的功能或改变其默认行为。`register` 函数接受两个参数:插件本身及一个可选的选项对象。 + +### 1. 插件 (Plugin) + +第一个参数是插件本身,它可以是一个异步函数,该函数接受三个参数: +- `fastify` 实例:当前服务器实例的引用。 +- `options`:传递给插件的选项对象。 +- `done`:一个回调函数,用于声明插件的注册完成。 + +### 2. 选项 (Options) + +第二个参数是一个可选的选项对象,用于提供给插件额外的配置。 + +一个 `register` 调用的基本结构如下: + +```javascript +fastify.register( + plugin, // 插件函数 + options // 可选的配置对象 +); +``` + +`options` 对象可以含有以下属性: + +- `prefix`:一个字符串值,为插件内所有路由添加前缀,很有用当你需要版本化 API 或者有多个相似的路由集合。 +- 其他自定义属性:这些属性将传递给插件函数内的 `options` 参数,可以根据插件的需求来设定。不同的插件可能需要不同的选项。 + +### 示例: + +```javascript +fastify.register( + require('fastify-plugin'), + { prefix: '/api/v1' } // 为这个插件下的所有路由设置前缀 +); + +// 或者使用 async/await 语法 +fastify.register(async (instance, opts) => { + instance.get('/route', async (request, reply) => { + return { hello: 'world' }; + }); +}, { prefix: '/api/v1' }); +``` + +在第二个例子中,我们定义了一个匿名插件函数并将其注册到 Fastify 实例中,并通过 `options` 对象设置了一个 `prefix`。这意味着,插件内部定义的所有路由都将自动添加 `/api/v1` 作为路径前缀。 + +### 注意: + +- `fastify-plugin`:这是一个可以保证插件注册的声明周期钩子和装饰器在父作用域中也同样可见的工具,通常用于那些需要全局可访问的插件。 +- 插件隔离:Fastify 实例是通过原型链继承创建的,这表示每个插件拥有自己的封装作用域。插件内的装饰器、钩子等,不会影响到其他插件或主应用,除非使用了 `fastify-plugin`。 + +参考 [Fastify 插件文档](https://www.fastify.io/docs/latest/Reference/Plugins/) 可以提供更详细的信息和高级配置选项。 diff --git a/docs/book/router.md b/docs/book/router.md new file mode 100644 index 0000000..9c3be1c --- /dev/null +++ b/docs/book/router.md @@ -0,0 +1,238 @@ +在Fastify中,可以通过路由拆分来组织和维护大型应用的代码。路由拆分通常意味着你将相关的路由处理函数放到单独的文件或模块中,并在应用中相应地注册它们。下面是如何做到路由拆分的一般步骤: + +1. 创建一个路由文件或模块。 +2. 在该文件中定义路由。 +3. 导出这些路由。 +4. 在你的主应用文件中注册这些路由。 + +### 例子:创建和使用路由模块 + +以下给出一个非常基础的例子来演示如何拆分路由。 + +#### user-routes.js +```javascript +// user-routes.js +async function routes(fastify, options) { + fastify.get('/users', async (request, reply) => { + // 处理获取用户的逻辑... + return { users: [] }; + }); + + fastify.get('/users/:id', async (request, reply) => { + // 处理获取单个用户的逻辑... + const { id } = request.params; + return { user: id }; + }); +} + +module.exports = routes; +``` + +#### item-routes.js +```javascript +// item-routes.js +async function routes(fastify, options) { + fastify.get('/items', async (request, reply) => { + // 处理获取物品的逻辑... + return { items: [] }; + }); + + fastify.get('/items/:id', async (request, reply) => { + // 处理获取单个物品的逻辑... + const { id } = request.params; + return { item: id }; + }); +} + +module.exports = routes; +``` + +#### 主应用文件(比如app.js或server.js) +```javascript +// app.js +const fastify = require('fastify')({ logger: true }); + +// 注册路由模块 +fastify.register(require('./user-routes')); +fastify.register(require('./item-routes')); + +// 启动服务器 +fastify.listen({ port: 3000, host: '0.0.0.0' }, (err, address) => { + if (err) { + fastify.log.error(err); + process.exit(1); + } + console.log(`Server listening on ${address}`); +}); +``` + +在这个例子中,我们有两个路由模块(`user-routes.js` 和 `item-routes.js`),它们被导入到主应用文件 `app.js` 中,使用 `fastify.register` 方法来注册。每个路由文件处理特定路径的请求,并有自己的路由处理函数。这种方式使得代码结构更清晰,并且容易维护,特别是当应用程序规模变大时。 + +为了更好的代码组织,你甚至可以进一步把路由处理函数分离到独立的控制器文件中。但以上示例提供了一个如何开始拆分路由的基础结构。 + + + + +*** + + +如果你想进一步组织你的代码,尤其是对于大型应用程序,以下是一些可以考虑的额外步骤: + +### 1. 分离控制器 + +可以创建一个控制器目录,用于存放处理路由逻辑的函数。这能让你的路由定义更加简洁,因为控制器将包含大部分业务逻辑。 + +**controllers/userController.js** +```javascript +async function getUsers(request, reply) { + // 处理逻辑... + return { users: [] }; +} + +async function getUserById(request, reply) { + const { id } = request.params; + // 处理逻辑... + return { user: id }; +} + +module.exports = { + getUsers, + getUserById, +}; +``` + +然后,在路由文件中,你可以导入并使用这些控制器函数: + +**routes/user-routes.js** +```javascript +const userController = require('../controllers/userController'); + +async function routes(fastify, options) { + fastify.get('/users', userController.getUsers); + fastify.get('/users/:id', userController.getUserById); +} + +module.exports = routes; +``` + +### 2. 路由前缀 + +当注册路由时,可以为一组路由指定一个公共前缀。Fastify 允许你在注册插件时提供一个 `prefix` 选项,该选项会应用于该插件中定义的所有路由。 + +```javascript +fastify.register(require('./user-routes'), { prefix: '/users' }); +fastify.register(require('./item-routes'), { prefix: '/items' }); +``` + +这将相应地更改 `user-routes.js` 和 `item-routes.js` 中的路径定义,因为你不再需要在每个路由路径中包含 `/users` 或 `/items`。 + +### 3. 插件化 + +为了进一步的模块化,可以将某些功能片段封装为插件。Fastify 天然支持插件架构,以便于封装和共享代码。例如,可以创建一个为特定资源服务的插件,将路由处理和相关功能封装在内。 + +**plugins/users.js** +```javascript +const userRoutes = require('../routes/user-routes'); + +async function usersPlugin(fastify, options) { + fastify.decorate('someUtility', () => {/* ... */}); + fastify.register(userRoutes); +} + +module.exports = usersPlugin; +``` + +注册插件: + +**app.js** +```javascript +fastify.register(require('./plugins/users'), { prefix: '/users' }); +``` + +### 4. 结构化错误处理和验证 + +Fastify 提供了丰富的钩子(hooks)和插件来处理错误和验证请求。你可以创建共享的钩子和模式,在你的应用中使用它们,以保持代码的一致性和减少重复。 + +### 5. 使用 `fastify-cli` 工具 + +Fastify 社区还提供了 `fastify-cli` 命令行工具,用于快速地搭建和管理 Fastify 项目。它可以自动为你生成项目结构,包括路由、插件和其他配置,从而让你更容易地按照最佳实践组织代码。 + +通过使用上述步骤,你将能够创建一个更加模块化、易于维护和可扩展的 Fastify 应用程序。 + + +*** + + +在 Fastify 中,可以使用钩子(Hooks)来执行拦截和验证操作。钩子可以在请求的生命周期的不同阶段被触发,例如在请求被路由之前(`onRequest`)、在执行路由处理函数之前(`preValidation`、`preHandler`)、在发送响应之前(`onSend`)等等。 + +若要针对不同的路由模块执行不同的拦截验证,你可以在每个路由模块中分别声明这些钩子。这样,只有当请求达到特定模块的路由时,相应的钩子才会被触发。以下是如何为不同的路由模块添加特定逻辑的示例: + +### 创建一个带有 onRequest 钩子的路由模块 + +```javascript +// routes/user-routes.js +module.exports = async function (fastify, options) { + // 在 '/users' 路径及其子路径上应用 onRequest 钩子 + fastify.addHook('onRequest', async (request, reply) => { + // 添加一些用户身份验证逻辑 + if (!request.headers['auth-token']) { + throw new Error('Missing auth token!'); + } + // 检查 auth-token 是否有效... + }); + + // 用户路由 + fastify.get('/users', async (request, reply) => { + // 返回用户列表 + }); + + fastify.get('/users/:id', async (request, reply) => { + // 返回单个用户 + }); +}; +``` + +### 创建另一个带有 preHandler 钩子的路由模块 + +```javascript +// routes/item-routes.js +module.exports = async function (fastify, options) { + // 在 '/items' 路径及其子路径上应用 preHandler 钩子 + fastify.addHook('preHandler', async (request, reply) => { + // 添加一些权限检查逻辑 + const userRole = request.user.role; // 假设我们已经在earlier hook中设置了用户 + if (userRole !== 'admin') { + throw new Error('Unauthorized!'); + } + // 执行其它必要的权限检查... + }); + + // 物品路由 + fastify.get('/items', async (request, reply) => { + // 返回物品列表 + }); + + fastify.get('/items/:id', async (request, reply) => { + // 返回单个物品详情 + }); +}; +``` + +在主应用文件中,你需要注册上述路由模块: + +```javascript +// app.js +const fastify = require('fastify')(); + +// 注册用户路由模块,'onRequest' 钩子将适用于此路由及其子路由 +fastify.register(require('./routes/user-routes'), { prefix: '/users' }); + +// 注册物品路由模块,'preHandler' 钩子将适用于此路由及其子路由 +fastify.register(require('./routes/item-routes'), { prefix: '/items' }); + +// 运行服务器... +``` + +在这个例子中,用户相关的路由会检查请求头中是否包含 `auth-token`,而物品相关的路由则会在路由处理之前检查用户的角色。这种方式能够让你按模块进行细粒度的拦截和验证控制,同时保持代码的整洁和模块化。 + +值得注意的是,钩子内部抛出的错误将被 Fastify 捕获,并作为 HTTP 错误被发送给客户端。这样,你可以根据需要定制错误响应。此外,Fastify 还允许你通过 `fastify.decorateRequest` 和 `fastify.decorateReply` 方法给 `request` 和 `reply` 对象添加自定义属性和方法,进一步增强拦截和验证的能力。 diff --git a/docs/docker.md b/docs/docker.md new file mode 100644 index 0000000..aff2476 --- /dev/null +++ b/docs/docker.md @@ -0,0 +1,181 @@ +## 安装Docker + +```bash +sudo apt-get install docker docker-compose + +#查看Docker可用用户 +sudo cat /etc/group |grep docker +# docker:x:998:表示存在 +sudo groupadd docker +sudo usermod -aG docker $USER +newgrp docker # 激活组更改,无效的话尝试重连ssh,退出登录,重启计算机等 + +# 查看版本 +docker version +``` +## docker-compose操作 + +```bash +# 启动当前目录下的docker-compose的yaml文件 +docker-compose up +# 后台运行 +docker-compose up -d +# 启动文件中的指定服务 +docker-compose up -d 服务名称 + +# 停止所有服务 这个命令会停止并移除所有容器,网络,但不包括数据卷 +docker-compose down +# 仅停止服务不移除容器 +docker-compose stop +# 停止特定服务 +docker-compose stop 服务名称 +# 重新启动服务 +docker-compose restart +``` + +## docker卷操作 + +```bash +# 创建卷 +# docker volume create [OPTIONS] [VOLUME] +# 这个命令用于创建一个新的卷。你可以指定卷的名称,如果不指定,Docker 会为你生成一个随机名称。此外,还可以通过选项设置卷的各种属性。 +docker volume create my_volume + + +# 列出所有现有的卷 +docker volume ls + +# 检查卷 +# docker volume inspect [VOLUME_NAME] +# 显示某个卷的详细信息,包括其名称、驱动、挂载点等 +docker volume inspect my_volume + +# 删除卷 +# docker volume rm [VOLUME_NAME] +# 此命令用于删除指定的卷。如果某个卷当前被一个或多个容器使用,那么这个卷不能被删除,除非使用 -f 或 --force 选项 +docker volume rm my_volume + +# 清理未使用的卷 +# 此命令会删除所有未被任何容器使用的卷。执行此命令前,Docker 通常会请求确认 +docker volume prune +``` + +## 文件示例 +```yaml +version: '3.8' + +services: + mysql: + image: mysql:8 + restart: always + environment: + MYSQL_ROOT_PASSWORD: Hxl1314521 + MYSQL_DATABASE: hutao + MYSQL_USER: nie + MYSQL_PASSWORD: Hxl1314521 + ports: + - "3306:3306" + volumes: + - mysql8:/var/lib/mysql + + redis: + image: redis:latest + restart: always + ports: + - "6379:6379" + volumes: + - ./redis.conf:/usr/local/etc/redis/redis.conf + - redis_data:/data + - redis_log:/var/log/redis + + redisinsight: + image: redislabs/redisinsight:latest + ports: + - "8001:8001" + +volumes: + mysql8: + redis_data: + redis_log: +``` + + +## redis配置 +```editorconfig +# Redis持久化选项 +# 使用RDB持久化 +# +# save 900 1 +# save 300 10 +# save 60 10000 + +# AOF持久化开关 +#appendonly yes +# AOF文件写入方式 +#appendfsync everysec +# AOF重写时,是否减少写操作的阻塞 +#no-appendfsync-on-rewrite no + +# Redis安全设置 +# 设置密码(这里设置的密码为yourpassword,请替换为你自己的密码) +requirepass Hxl1314521 + +# 网络设置 +# 绑定的IP,如果需要远程连接,请注释掉这行 +# bind 127.0.0.1 +# 监听的端口,默认为6379 +#port 6379 + +# 日志文件位置 +logfile "/var/log/redis/redis-server.log" + +# 最大内存使用量,超出则根据淘汰策略删除键,示例为无限制 +# maxmemory +# 内存淘汰策略 +# maxmemory-policy noeviction +``` + + +## Docker 安装 + +```bash +# 更新软件包索引 +sudo apt-get update +# 安装所需的包 +sudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common +# 添加Docker的官方GPG密钥 +curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg +# 设置稳定版仓库 +echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null +# 再次更新软件包索引(此时包括Docker仓库) +sudo apt-get update +# 安装Docker Engine +sudo apt-get install -y docker-ce docker-ce-cli containerd.io +# 验证Docker是否安装成功 +sudo docker version +# Docker作为非root用户 +sudo usermod -aG docker $USER +newgrp docker +# 开启远程访问 +sudo systemctl edit docker.service +#[Service] +#ExecStart= +#ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2375 +sudo systemctl daemon-reload +sudo systemctl restart docker.service +sudo netstat -lntp | grep dockerd +docker -H tcp://127.0.0.1:2375 version +``` + +## 卸载docker + +```bash +# 删除软件包及其配置文件 +sudo apt-get purge docker-ce docker-ce-cli containerd.io docker-compose +# 删除资源 +sudo rm -rf /var/lib/docker +sudo rm -rf /var/lib/containerd +# 删除Docker的GPG密钥和源列表文件 +sudo rm /usr/share/keyrings/docker-archive-keyring.gpg +sudo rm /etc/apt/sources.list.d/docker.list +``` diff --git a/docs/select.md b/docs/select.md new file mode 100644 index 0000000..f3667f6 --- /dev/null +++ b/docs/select.md @@ -0,0 +1,185 @@ +# 数据库查询 + +## 一、基础查询 + +### 1.1SELECT + +#### 查全部 + +```sql +SELECT * FROM table; +``` + +#### 查指定字段 + +```sql +SELECT name,age FROM table; +``` + +#### 字段别名 + +```sql +SELECT name as newName,age as '年龄' FROM table; +``` + +#### 过滤字段重复 + +```sql +# 过滤掉目标所有字段都重复的行 +SELECT DISTINCT name, age FROM table; +``` +### 1.2聚合函数 + +```sql +SELECT COUNT(id) AS '数量', SUM(id) AS '总和', AVG(id) AS '平均数', MAX(id) AS '最大数', MIN(id) AS '最小数' FROM table; +``` + +### 1.3WHERE + +```sql +SELECT * FROM table WHERE id = 1; +/* SELECT * FROM user_info_structs WHERE user_info_struct_sequence= '3' OR field_name = '头像'; */ +/* SELECT * FROM user_info_structs WHERE user_info_struct_sequence= '1' AND field_name = '头像'; */ +``` + +### 1.4模糊查询 LIKE + +```sql +/* +任意字符 % +单一字符 _ +*/ +SELECT name WHERE name LIKE '何%'; +/* +何% 何(任意个字符) +何_ 何X +何__ 何XX +*/ +``` + +### 1.5排序 ORDER BY + +```sql +/* +默认 ASC 从小到大 升序 +DESC 从大到小 降序 +*/ +SELECT * FROM table ORDER BY id DESC; +SELECT * FROM user_info_structs WHERE field_name LIKE '手机%' ORDER BY user_info_struct_sequence ASC; +/* ORDER BY 要写在 WHERE后面*/ + +/*多顺序*/ +SELECT * FROM table ORDER BY id DESC, name ASC; +``` + +### 1.6分组 GROUP BY + +```sql +/* +分组只会出现分组数量的列 +最好用分组目标作为一个列明区分,然后用count之类的几何函数 +ORDER BY放在WHERE后面 +HAVING 相当于条件中的条件 放在ORDER BY后面 + +*/ +SELECT field_name,COUNT(user_info_struct_sequence) AS 'num' FROM user_info_structs WHERE user_info_struct_sequence >= 1 GROUP BY field_name HAVING field_name != '手机'; +``` +### 1.7分页LIMIT + +```sql +/*LIMIT要放在后面,在ORDER BY之后*/ + +SELECT * FROM table WHERE id >= 3 ORDER BY age DESC LIMIT 0,10; +SELECT * FROM user_info_structs WHERE user_info_struct_sequence >= 1 ORDER BY field_display_type DESC LIMIT 0,3; +/*想要先切片在排序,需要写子查询*/ +SELECT column1, column2 +FROM ( + SELECT column1, column2 + FROM table_name + LIMIT 10 + ) AS subquery +ORDER BY column1; +``` +## 二、比较逻辑运算 + +### 2.1 AND + +```sql +SELECT * FROM table WHERE age > 13 AND age < 20; +``` + +### 2.2 BETWEEN < > +```sql +SELECT * FROM table WHERE age > 13 AND age < 20; +/*相当于*/ +SELECT * FROM table WHERE BETWEEN 13 AND 20; +``` +### 2.3 OR + +```sql +SELECT * FROM table WHERE age >= 13 OR sex = 1; +``` +### 2.4 NULL和'' + +```sql +SELECT * FROM table WHERE sex = ''; +SELECT * FROM table WHERE sex IS NULL; +SELECT * FROM table WHERE sex IS NOT NULL; +``` +### 2.5 !=,<>,NOT + +```sql +SELECT * FROM table WHERE sex != ''; +/*相当与*/ +SELECT * FROM table WHERE sex <> ''; +``` + +## 三、多表连接 + +### 3.1 内连接 + +```sql +/*student是学生表,dept是专业表,差学生所有信息,并获取学生的所在专业ID的名称*/ +SELECT s.*, d.name FROM student s INNER JOIN dept d ON s.did = d.did; +SELECT s.*, d.name FROM student s JOIN dept d ON s.did = d.did; +/*不推荐写法*/ +SELECT s.*, d.name FROM student s , dept d WHERE s.did = d.did; +``` +### 3.2 左外连接/右外连接 + +```sql +/*以A表为基准, 查出来的数据A表是满的,*/ +-- 左连接 +SELECT a.*,b.* FROM ATABLE a LEFT JOIN BTABLE b ON a.bid = b.id; +-- 左外连接 +SELECT a.*,b.* FROM ATABLE a LEFT OUTER JOIN BTABLE b ON a.bid = b.id; +-- 以b表为基准 +SELECT a.*,b.* FROM BTABLE b LEFT JOIN ATABLE a ON a.bid = b.id; +``` +## 四、子查询 + +### 4.1 = +```sql +-- 查询和id等于2的列名一样的数据 +SELECT * +FROM user_info_structs +WHERE field_name = ( + SELECT field_name + FROM user_info_structs + WHERE user_info_struct_sequence = 2 + ); +``` + +### 4.2 IN +```sql +-- 查列名为生日的id的数据 +SELECT * +FROM user_info_structs +WHERE user_info_struct_sequence IN ( + SELECT user_info_struct_sequence + FROM user_info_structs + WHERE field_name = "生日" + ); +-- 可以使用NOT IN +-- IN查询一般效率比较低,建议使用多表连接 +``` diff --git a/package.json b/package.json new file mode 100644 index 0000000..010d734 --- /dev/null +++ b/package.json @@ -0,0 +1,42 @@ +{ + "name": "hutao", + "version": "1.0.0", + "description": "", + "main": "app.js", + "type": "module", + "scripts": { + "test": "node -v", + "start": "node app.js", + "dev": "nodemon app.js" + }, + "imports": { + "#/*": "./*", + "#common/*": "./src/common/*", + "#plugins/*": "./src/plugins/*", + "#databaseModel/*": "./src/databaseModel/*", + "#routes/*": "./src/routes/*" + }, + "keywords": [], + "author": "", + "license": "ISC", + "devDependencies": { + "nodemon": "^3.1.0" + }, + "dependencies": { + "@fastify/jwt": "^8.0.0", + "@fastify/rate-limit": "^9.1.0", + "@fastify/redis": "^6.1.1", + "@fastify/sensible": "^5.5.0", + "ajv": "^8.12.0", + "ajv-errors": "^3.0.0", + "chalk": "^5.3.0", + "config": "^3.3.11", + "destr": "^2.0.3", + "fastify": "^4.26.2", + "fastify-plugin": "^4.5.1", + "mysql2": "^3.9.2", + "sequelize": "^6.37.1", + "winston": "^3.12.0", + "winston-daily-rotate-file": "^5.0.0" + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..9b782ef --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,1297 @@ +lockfileVersion: '6.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +dependencies: + '@fastify/jwt': + specifier: ^8.0.0 + version: 8.0.0 + '@fastify/rate-limit': + specifier: ^9.1.0 + version: 9.1.0 + '@fastify/redis': + specifier: ^6.1.1 + version: 6.1.1 + '@fastify/sensible': + specifier: ^5.5.0 + version: 5.5.0 + ajv: + specifier: ^8.12.0 + version: 8.12.0 + ajv-errors: + specifier: ^3.0.0 + version: 3.0.0(ajv@8.12.0) + chalk: + specifier: ^5.3.0 + version: 5.3.0 + config: + specifier: ^3.3.11 + version: 3.3.11 + destr: + specifier: ^2.0.3 + version: 2.0.3 + fastify: + specifier: ^4.26.2 + version: 4.26.2 + fastify-plugin: + specifier: ^4.5.1 + version: 4.5.1 + mysql2: + specifier: ^3.9.2 + version: 3.9.2 + sequelize: + specifier: ^6.37.1 + version: 6.37.1(mysql2@3.9.2) + winston: + specifier: ^3.12.0 + version: 3.12.0 + winston-daily-rotate-file: + specifier: ^5.0.0 + version: 5.0.0(winston@3.12.0) + +devDependencies: + nodemon: + specifier: ^3.1.0 + version: 3.1.0 + +packages: + + /@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 + + /@fastify/ajv-compiler@3.5.0: + resolution: {integrity: sha512-ebbEtlI7dxXF5ziNdr05mOY8NnDiPB1XvAlLHctRt/Rc+C3LCOVW5imUVX+mhvUhnNzmPBHewUkOFgGlCxgdAA==} + dependencies: + ajv: 8.12.0 + ajv-formats: 2.1.1(ajv@8.12.0) + fast-uri: 2.3.0 + dev: false + + /@fastify/error@3.4.1: + resolution: {integrity: sha512-wWSvph+29GR783IhmvdwWnN4bUxTD01Vm5Xad4i7i1VuAOItLvbPAb69sb0IQ2N57yprvhNIwAP5B6xfKTmjmQ==} + dev: false + + /@fastify/fast-json-stringify-compiler@4.3.0: + resolution: {integrity: sha512-aZAXGYo6m22Fk1zZzEUKBvut/CIIQe/BapEORnxiD5Qr0kPHqqI69NtEMCme74h+at72sPhbkb4ZrLd1W3KRLA==} + dependencies: + fast-json-stringify: 5.13.0 + dev: false + + /@fastify/jwt@8.0.0: + resolution: {integrity: sha512-pJHjmZaokteZFMbsVVt7pbyJpbDogTnpl/aD7eR3vLOPgfktp4k4gUM6cd7RtjL/Ol1qDwL5mup+vdNlZI3K0Q==} + dependencies: + '@fastify/error': 3.4.1 + '@lukeed/ms': 2.0.2 + fast-jwt: 3.3.3 + fastify-plugin: 4.5.1 + steed: 1.1.3 + dev: false + + /@fastify/merge-json-schemas@0.1.1: + resolution: {integrity: sha512-fERDVz7topgNjtXsJTTW1JKLy0rhuLRcquYqNR9rF7OcVpCa2OVW49ZPDIhaRRCaUuvVxI+N416xUoF76HNSXA==} + dependencies: + fast-deep-equal: 3.1.3 + dev: false + + /@fastify/rate-limit@9.1.0: + resolution: {integrity: sha512-h5dZWCkuZXN0PxwqaFQLxeln8/LNwQwH9popywmDCFdKfgpi4b/HoMH1lluy6P+30CG9yzzpSpwTCIPNB9T1JA==} + dependencies: + '@lukeed/ms': 2.0.2 + fastify-plugin: 4.5.1 + toad-cache: 3.7.0 + dev: false + + /@fastify/redis@6.1.1: + resolution: {integrity: sha512-NZpHK+d3uJJ+w1iHx5n1woFvrHhhG52XjM9byWvU81KSsQpO0N/OikgQvz83frLV7UD4UQtTUgPvVbLxW0X81w==} + dependencies: + fastify-plugin: 4.5.1 + ioredis: 5.3.2 + transitivePeerDependencies: + - supports-color + dev: false + + /@fastify/sensible@5.5.0: + resolution: {integrity: sha512-D0zpl+nocsRXLceSbc4gasQaO3ZNQR4dy9Uu8Ym0mh8VUdrjpZ4g8Ca9O3pGXbBVOnPIGHUJNTV7Yf9dg/OYdg==} + dependencies: + '@lukeed/ms': 2.0.2 + fast-deep-equal: 3.1.3 + fastify-plugin: 4.5.1 + forwarded: 0.2.0 + http-errors: 2.0.0 + type-is: 1.6.18 + vary: 1.1.2 + dev: false + + /@ioredis/commands@1.2.0: + resolution: {integrity: sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==} + dev: false + + /@lukeed/ms@2.0.2: + resolution: {integrity: sha512-9I2Zn6+NJLfaGoz9jN3lpwDgAYvfGeNYdbAIjJOqzs4Tpc+VU3Jqq4IofSUBKajiDS8k9fZIg18/z13mpk1bsA==} + engines: {node: '>=8'} + dev: false + + /@types/debug@4.1.12: + resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} + dependencies: + '@types/ms': 0.7.34 + dev: false + + /@types/ms@0.7.34: + resolution: {integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==} + dev: false + + /@types/node@20.11.28: + resolution: {integrity: sha512-M/GPWVS2wLkSkNHVeLkrF2fD5Lx5UC4PxA0uZcKc6QqbIQUJyW1jVjueJYi1z8n0I5PxYrtpnPnWglE+y9A0KA==} + dependencies: + undici-types: 5.26.5 + dev: false + + /@types/triple-beam@1.3.5: + resolution: {integrity: sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==} + dev: false + + /@types/validator@13.11.9: + resolution: {integrity: sha512-FCTsikRozryfayPuiI46QzH3fnrOoctTjvOYZkho9BTFLCOZ2rgZJHMOVgCOfttjPJcgOx52EpkY0CMfy87MIw==} + dev: false + + /abbrev@1.1.1: + resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} + dev: true + + /abort-controller@3.0.0: + resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} + engines: {node: '>=6.5'} + dependencies: + event-target-shim: 5.0.1 + dev: false + + /abstract-logging@2.0.1: + resolution: {integrity: sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==} + dev: false + + /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-formats@2.1.1(ajv@8.12.0): + resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + dependencies: + ajv: 8.12.0 + dev: false + + /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 + + /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 + + /archy@1.0.0: + resolution: {integrity: sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==} + dev: false + + /asn1.js@5.4.1: + resolution: {integrity: sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==} + dependencies: + bn.js: 4.12.0 + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + safer-buffer: 2.1.2 + dev: false + + /async@3.2.5: + resolution: {integrity: sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==} + dev: false + + /atomic-sleep@1.0.0: + resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} + engines: {node: '>=8.0.0'} + dev: false + + /avvio@8.3.0: + resolution: {integrity: sha512-VBVH0jubFr9LdFASy/vNtm5giTrnbVquWBhT0fyizuNK2rQ7e7ONU2plZQWUNqtE1EmxFEb+kbSkFRkstiaS9Q==} + dependencies: + '@fastify/error': 3.4.1 + archy: 1.0.0 + debug: 4.3.4(supports-color@5.5.0) + fastq: 1.17.1 + transitivePeerDependencies: + - supports-color + dev: false + + /balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + dev: true + + /base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + dev: false + + /binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + dev: true + + /bn.js@4.12.0: + resolution: {integrity: sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==} + dev: false + + /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 + + /buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + dev: false + + /chalk@5.3.0: + resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + dev: false + + /chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + 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 + + /cluster-key-slot@1.1.2: + resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==} + engines: {node: '>=0.10.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-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + dev: false + + /color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + dev: false + + /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 + + /concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + dev: true + + /config@3.3.11: + resolution: {integrity: sha512-Dhn63ZoWCW5EMg4P0Sl/XNsj/7RLiUIA1x1npCy+m2cRwRHzLnt3UtYtxRDMZW/6oOMdWhCzaGYkOcajGgrAOA==} + engines: {node: '>= 10.0.0'} + dependencies: + json5: 2.2.3 + dev: false + + /cookie@0.6.0: + resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} + engines: {node: '>= 0.6'} + dev: false + + /debug@4.3.4(supports-color@5.5.0): + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.2 + supports-color: 5.5.0 + + /denque@2.1.0: + resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} + engines: {node: '>=0.10'} + dev: false + + /depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + dev: false + + /destr@2.0.3: + resolution: {integrity: sha512-2N3BOUU4gYMpTP24s5rF5iP7BDr7uNTCs4ozw3kf/eKfvWSIu93GEBi5m427YoyJoeOzQ5smuu4nNAPGb8idSQ==} + dev: false + + /dottie@2.0.6: + resolution: {integrity: sha512-iGCHkfUc5kFekGiqhe8B/mdaurD+lakO9txNnTvKtA6PISrw86LgqHvRzWYPyoE2Ph5aMIrCw9/uko6XHTKCwA==} + dev: false + + /ecdsa-sig-formatter@1.0.11: + resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} + dependencies: + safe-buffer: 5.2.1 + dev: false + + /enabled@2.0.0: + resolution: {integrity: sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==} + dev: false + + /event-target-shim@5.0.1: + resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} + engines: {node: '>=6'} + dev: false + + /events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + dev: false + + /fast-content-type-parse@1.1.0: + resolution: {integrity: sha512-fBHHqSTFLVnR61C+gltJuE5GkVQMV0S2nqUO8TJ+5Z3qAKG8vAx4FKai1s5jq/inV1+sREynIWSuQ6HgoSXpDQ==} + dev: false + + /fast-decode-uri-component@1.0.1: + resolution: {integrity: sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==} + dev: false + + /fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + dev: false + + /fast-json-stringify@5.13.0: + resolution: {integrity: sha512-XjTDWKHP3GoMQUOfnjYUbqeHeEt+PvYgvBdG2fRSmYaORILbSr8xTJvZX+w1YSAP5pw2NwKrGRmQleYueZEoxw==} + dependencies: + '@fastify/merge-json-schemas': 0.1.1 + ajv: 8.12.0 + ajv-formats: 2.1.1(ajv@8.12.0) + fast-deep-equal: 3.1.3 + fast-uri: 2.3.0 + json-schema-ref-resolver: 1.0.1 + rfdc: 1.3.1 + dev: false + + /fast-jwt@3.3.3: + resolution: {integrity: sha512-oS3P8bRI24oPLJUePt2OgF64FBQib5TlgHLFQxYNoHYEEZe0gU3cKjJAVqpB5XKV/zjxmq4Hzbk3fgfW/wRz8Q==} + engines: {node: '>=16 <22'} + dependencies: + '@lukeed/ms': 2.0.2 + asn1.js: 5.4.1 + ecdsa-sig-formatter: 1.0.11 + mnemonist: 0.39.8 + dev: false + + /fast-querystring@1.1.2: + resolution: {integrity: sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==} + dependencies: + fast-decode-uri-component: 1.0.1 + dev: false + + /fast-redact@3.4.0: + resolution: {integrity: sha512-2gwPvyna0zwBdxKnng1suu/dTL5s8XEy2ZqH8mwDUwJdDkV8w5kp+JV26mupdK68HmPMbm6yjW9m7/Ys/BHEHg==} + engines: {node: '>=6'} + dev: false + + /fast-uri@2.3.0: + resolution: {integrity: sha512-eel5UKGn369gGEWOqBShmFJWfq/xSJvsgDzgLYC845GneayWvXBf0lJCBn5qTABfewy1ZDPoaR5OZCP+kssfuw==} + dev: false + + /fastfall@1.5.1: + resolution: {integrity: sha512-KH6p+Z8AKPXnmA7+Iz2Lh8ARCMr+8WNPVludm1LGkZoD2MjY6LVnRMtTKhkdzI+jr0RzQWXKzKyBJm1zoHEL4Q==} + engines: {node: '>=0.10.0'} + dependencies: + reusify: 1.0.4 + dev: false + + /fastify-plugin@4.5.1: + resolution: {integrity: sha512-stRHYGeuqpEZTL1Ef0Ovr2ltazUT9g844X5z/zEBFLG8RYlpDiOCIG+ATvYEp+/zmc7sN29mcIMp8gvYplYPIQ==} + dev: false + + /fastify@4.26.2: + resolution: {integrity: sha512-90pjTuPGrfVKtdpLeLzND5nyC4woXZN5VadiNQCicj/iJU4viNHKhsAnb7jmv1vu2IzkLXyBiCzdWuzeXgQ5Ug==} + dependencies: + '@fastify/ajv-compiler': 3.5.0 + '@fastify/error': 3.4.1 + '@fastify/fast-json-stringify-compiler': 4.3.0 + abstract-logging: 2.0.1 + avvio: 8.3.0 + fast-content-type-parse: 1.1.0 + fast-json-stringify: 5.13.0 + find-my-way: 8.1.0 + light-my-request: 5.12.0 + pino: 8.19.0 + process-warning: 3.0.0 + proxy-addr: 2.0.7 + rfdc: 1.3.1 + secure-json-parse: 2.7.0 + semver: 7.6.0 + toad-cache: 3.7.0 + transitivePeerDependencies: + - supports-color + dev: false + + /fastparallel@2.4.1: + resolution: {integrity: sha512-qUmhxPgNHmvRjZKBFUNI0oZuuH9OlSIOXmJ98lhKPxMZZ7zS/Fi0wRHOihDSz0R1YiIOjxzOY4bq65YTcdBi2Q==} + dependencies: + reusify: 1.0.4 + xtend: 4.0.2 + dev: false + + /fastq@1.17.1: + resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} + dependencies: + reusify: 1.0.4 + dev: false + + /fastseries@1.7.2: + resolution: {integrity: sha512-dTPFrPGS8SNSzAt7u/CbMKCJ3s01N04s4JFbORHcmyvVfVKmbhMD1VtRbh5enGHxkaQDqWyLefiKOGGmohGDDQ==} + dependencies: + reusify: 1.0.4 + xtend: 4.0.2 + dev: false + + /fecha@4.2.3: + resolution: {integrity: sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==} + dev: false + + /file-stream-rotator@0.6.1: + resolution: {integrity: sha512-u+dBid4PvZw17PmDeRcNOtCP9CCK/9lRN2w+r1xIS7yOL9JFrIBKTvrYsxT4P0pGtThYTn++QS5ChHaUov3+zQ==} + dependencies: + moment: 2.30.1 + 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-my-way@8.1.0: + resolution: {integrity: sha512-41QwjCGcVTODUmLLqTMeoHeiozbMXYMAE1CKFiDyi9zVZ2Vjh0yz3MF0WQZoIb+cmzP/XlbFjlF2NtJmvZHznA==} + engines: {node: '>=14'} + dependencies: + fast-deep-equal: 3.1.3 + fast-querystring: 1.1.2 + safe-regex2: 2.0.0 + dev: false + + /fn.name@1.1.0: + resolution: {integrity: sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==} + dev: false + + /forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} + dev: false + + /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 + + /generate-function@2.3.1: + resolution: {integrity: sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==} + dependencies: + is-property: 1.0.2 + dev: false + + /glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + dependencies: + is-glob: 4.0.3 + dev: true + + /has-flag@3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} + + /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 + + /iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + dependencies: + safer-buffer: 2.1.2 + dev: false + + /ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + dev: false + + /ignore-by-default@1.0.1: + resolution: {integrity: sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==} + dev: true + + /inflection@1.13.4: + resolution: {integrity: sha512-6I/HUDeYFfuNCVS3td055BaXBwKYuzw7K3ExVMStBowKo9oOAMJIXIHvdyR3iboTCp1b+1i5DSkIZTcwIktuDw==} + engines: {'0': node >= 0.4.0} + dev: false + + /inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + dev: false + + /ioredis@5.3.2: + resolution: {integrity: sha512-1DKMMzlIHM02eBBVOFQ1+AolGjs6+xEcM4PDL7NqOS6szq7H9jSaEkIUH6/a5Hl241LzW6JLSiAbNvTQjUupUA==} + engines: {node: '>=12.22.0'} + dependencies: + '@ioredis/commands': 1.2.0 + cluster-key-slot: 1.1.2 + debug: 4.3.4(supports-color@5.5.0) + denque: 2.1.0 + lodash.defaults: 4.2.0 + lodash.isarguments: 3.1.0 + redis-errors: 1.2.0 + redis-parser: 3.0.0 + standard-as-callback: 2.1.0 + transitivePeerDependencies: + - supports-color + dev: false + + /ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + dev: false + + /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.3.0 + dev: true + + /is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + dev: true + + /is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + dependencies: + is-extglob: 2.1.1 + dev: true + + /is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + dev: true + + /is-property@1.0.2: + resolution: {integrity: sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==} + dev: false + + /is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + dev: false + + /json-schema-ref-resolver@1.0.1: + resolution: {integrity: sha512-EJAj1pgHc1hxF6vo2Z3s69fMjO1INq6eGHXZ8Z6wCQeldCuwxGK9Sxf4/cScGn3FZubCVUehfWtcDM/PLteCQw==} + dependencies: + fast-deep-equal: 3.1.3 + dev: false + + /json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + dev: false + + /json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + dev: false + + /kuler@2.0.0: + resolution: {integrity: sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==} + dev: false + + /light-my-request@5.12.0: + resolution: {integrity: sha512-P526OX6E7aeCIfw/9UyJNsAISfcFETghysaWHQAlQYayynShT08MOj4c6fBCvTWBrHXSvqBAKDp3amUPSCQI4w==} + dependencies: + cookie: 0.6.0 + process-warning: 3.0.0 + set-cookie-parser: 2.6.0 + dev: false + + /lodash.defaults@4.2.0: + resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==} + dev: false + + /lodash.isarguments@3.1.0: + resolution: {integrity: sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==} + dev: false + + /lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + dev: false + + /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==} + dev: false + + /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'} + dev: false + + /lru-cache@8.0.5: + resolution: {integrity: sha512-MhWWlVnuab1RG5/zMRRcVGXZLCXrZTgfwMikgzCegsPnG62yDQo5JnqKkrK4jO5iKqDAZGItAqN5CtKBCBWRUA==} + engines: {node: '>=16.14'} + dev: false + + /media-typer@0.3.0: + resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} + engines: {node: '>= 0.6'} + dev: false + + /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 + + /minimalistic-assert@1.0.1: + resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} + dev: false + + /minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + dependencies: + brace-expansion: 1.1.11 + dev: true + + /mnemonist@0.39.8: + resolution: {integrity: sha512-vyWo2K3fjrUw8YeeZ1zF0fy6Mu59RHokURlld8ymdUPjMlD9EC9ov1/YPqTgqRvUN9nTr3Gqfz29LYAmu0PHPQ==} + dependencies: + obliterator: 2.0.4 + dev: false + + /moment-timezone@0.5.45: + resolution: {integrity: sha512-HIWmqA86KcmCAhnMAN0wuDOARV/525R2+lOLotuGFzn4HO+FH+/645z2wx0Dt3iDv6/p61SIvKnDstISainhLQ==} + dependencies: + moment: 2.30.1 + dev: false + + /moment@2.30.1: + resolution: {integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==} + dev: false + + /ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + + /mysql2@3.9.2: + resolution: {integrity: sha512-3Cwg/UuRkAv/wm6RhtPE5L7JlPB877vwSF6gfLAS68H+zhH+u5oa3AieqEd0D0/kC3W7qIhYbH419f7O9i/5nw==} + 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 + dev: false + + /named-placeholders@1.1.3: + resolution: {integrity: sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==} + engines: {node: '>=12.0.0'} + dependencies: + lru-cache: 7.18.3 + dev: false + + /nodemon@3.1.0: + resolution: {integrity: sha512-xqlktYlDMCepBJd43ZQhjWwMw2obW/JRvkrLxq5RCNcuDDX1DbcPT+qT1IlIIdf+DhnWs90JpTMe+Y5KxOchvA==} + engines: {node: '>=10'} + hasBin: true + dependencies: + chokidar: 3.6.0 + debug: 4.3.4(supports-color@5.5.0) + ignore-by-default: 1.0.1 + minimatch: 3.1.2 + pstree.remy: 1.1.8 + semver: 7.6.0 + 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 + + /object-hash@3.0.0: + resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} + engines: {node: '>= 6'} + dev: false + + /obliterator@2.0.4: + resolution: {integrity: sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ==} + dev: false + + /on-exit-leak-free@2.1.2: + resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==} + engines: {node: '>=14.0.0'} + dev: false + + /one-time@1.0.0: + resolution: {integrity: sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==} + dependencies: + fn.name: 1.1.0 + dev: false + + /pg-connection-string@2.6.2: + resolution: {integrity: sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==} + dev: false + + /picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + dev: true + + /pino-abstract-transport@1.1.0: + resolution: {integrity: sha512-lsleG3/2a/JIWUtf9Q5gUNErBqwIu1tUKTT3dUzaf5DySw9ra1wcqKjJjLX1VTY64Wk1eEOYsVGSaGfCK85ekA==} + dependencies: + readable-stream: 4.5.2 + split2: 4.2.0 + dev: false + + /pino-std-serializers@6.2.2: + resolution: {integrity: sha512-cHjPPsE+vhj/tnhCy/wiMh3M3z3h/j15zHQX+S9GkTBgqJuTuJzYJ4gUyACLhDaJ7kk9ba9iRDmbH2tJU03OiA==} + dev: false + + /pino@8.19.0: + resolution: {integrity: sha512-oswmokxkav9bADfJ2ifrvfHUwad6MLp73Uat0IkQWY3iAw5xTRoznXbXksZs8oaOUMpmhVWD+PZogNzllWpJaA==} + hasBin: true + dependencies: + atomic-sleep: 1.0.0 + fast-redact: 3.4.0 + on-exit-leak-free: 2.1.2 + pino-abstract-transport: 1.1.0 + pino-std-serializers: 6.2.2 + process-warning: 3.0.0 + quick-format-unescaped: 4.0.4 + real-require: 0.2.0 + safe-stable-stringify: 2.4.3 + sonic-boom: 3.8.0 + thread-stream: 2.4.1 + dev: false + + /process-warning@3.0.0: + resolution: {integrity: sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==} + dev: false + + /process@0.11.10: + resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} + engines: {node: '>= 0.6.0'} + dev: false + + /proxy-addr@2.0.7: + resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} + engines: {node: '>= 0.10'} + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + dev: false + + /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'} + dev: false + + /quick-format-unescaped@4.0.4: + resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} + 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 + + /readable-stream@4.5.2: + resolution: {integrity: sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + abort-controller: 3.0.0 + buffer: 6.0.3 + events: 3.3.0 + process: 0.11.10 + string_decoder: 1.3.0 + dev: false + + /readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + dependencies: + picomatch: 2.3.1 + dev: true + + /real-require@0.2.0: + resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} + engines: {node: '>= 12.13.0'} + dev: false + + /redis-errors@1.2.0: + resolution: {integrity: sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==} + engines: {node: '>=4'} + dev: false + + /redis-parser@3.0.0: + resolution: {integrity: sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==} + engines: {node: '>=4'} + dependencies: + redis-errors: 1.2.0 + dev: false + + /require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + dev: false + + /ret@0.2.2: + resolution: {integrity: sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ==} + engines: {node: '>=4'} + dev: false + + /retry-as-promised@7.0.4: + resolution: {integrity: sha512-XgmCoxKWkDofwH8WddD0w85ZfqYz+ZHlr5yo+3YUCfycWawU56T5ckWXsScsj5B8tqUcIG67DxXByo3VUgiAdA==} + dev: false + + /reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + dev: false + + /rfdc@1.3.1: + resolution: {integrity: sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==} + dev: false + + /safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + dev: false + + /safe-regex2@2.0.0: + resolution: {integrity: sha512-PaUSFsUaNNuKwkBijoAPHAK6/eM6VirvyPWlZ7BAQy4D+hCvh4B6lIG+nPdhbFfIbP+gTGBcrdsOaUs0F+ZBOQ==} + dependencies: + ret: 0.2.2 + 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==} + dev: false + + /secure-json-parse@2.7.0: + resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} + dev: false + + /semver@7.6.0: + resolution: {integrity: sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==} + engines: {node: '>=10'} + hasBin: true + dependencies: + lru-cache: 6.0.0 + + /seq-queue@0.0.5: + resolution: {integrity: sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==} + dev: false + + /sequelize-pool@7.1.0: + resolution: {integrity: sha512-G9c0qlIWQSK29pR/5U2JF5dDQeqqHRragoyahj/Nx4KOOQ3CPPfzxnfqFPCSB7x5UgjOgnZ61nSxz+fjDpRlJg==} + engines: {node: '>= 10.0.0'} + dev: false + + /sequelize@6.37.1(mysql2@3.9.2): + resolution: {integrity: sha512-vIKKzQ9dGp2aBOxQRD1FmUYViuQiKXSJ8yah8TsaBx4U3BokJt+Y2A0qz2C4pj08uX59qpWxRqSLEfRmVOEgQw==} + 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.9 + debug: 4.3.4(supports-color@5.5.0) + dottie: 2.0.6 + inflection: 1.13.4 + lodash: 4.17.21 + moment: 2.30.1 + moment-timezone: 0.5.45 + mysql2: 3.9.2 + pg-connection-string: 2.6.2 + retry-as-promised: 7.0.4 + semver: 7.6.0 + 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 + dev: false + + /set-cookie-parser@2.6.0: + resolution: {integrity: sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==} + dev: false + + /setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + dev: false + + /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.6.0 + dev: true + + /sonic-boom@3.8.0: + resolution: {integrity: sha512-ybz6OYOUjoQQCQ/i4LU8kaToD8ACtYP+Cj5qd2AO36bwbdewxWJ3ArmJ2cr6AvxlL2o0PqnCcPGUgkILbfkaCA==} + dependencies: + atomic-sleep: 1.0.0 + dev: false + + /split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + dev: false + + /sqlstring@2.3.3: + resolution: {integrity: sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==} + engines: {node: '>= 0.6'} + dev: false + + /stack-trace@0.0.10: + resolution: {integrity: sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==} + dev: false + + /standard-as-callback@2.1.0: + resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==} + dev: false + + /statuses@2.0.1: + resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} + engines: {node: '>= 0.8'} + dev: false + + /steed@1.1.3: + resolution: {integrity: sha512-EUkci0FAUiE4IvGTSKcDJIQ/eRUP2JJb56+fvZ4sdnguLTqIdKjSxUe138poW8mkvKWXW2sFPrgTsxqoISnmoA==} + dependencies: + fastfall: 1.5.1 + fastparallel: 2.4.1 + fastq: 1.17.1 + fastseries: 1.7.2 + reusify: 1.0.4 + dev: false + + /string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + dependencies: + safe-buffer: 5.2.1 + dev: false + + /supports-color@5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + dependencies: + has-flag: 3.0.0 + + /text-hex@1.0.0: + resolution: {integrity: sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==} + dev: false + + /thread-stream@2.4.1: + resolution: {integrity: sha512-d/Ex2iWd1whipbT681JmTINKw0ZwOUBZm7+Gjs64DHuX34mmw8vJL2bFAaNacaW72zYiTJxSHi5abUuOi5nsfg==} + dependencies: + real-require: 0.2.0 + dev: false + + /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 + + /toad-cache@3.7.0: + resolution: {integrity: sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==} + engines: {node: '>=12'} + dev: false + + /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==} + dev: false + + /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 + + /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==} + dev: false + + /uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + dependencies: + punycode: 2.3.1 + dev: false + + /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 + dev: false + + /validator@13.11.0: + resolution: {integrity: sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ==} + engines: {node: '>= 0.10'} + dev: false + + /vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + dev: false + + /winston-daily-rotate-file@5.0.0(winston@3.12.0): + resolution: {integrity: sha512-JDjiXXkM5qvwY06733vf09I2wnMXpZEhxEVOSPenZMii+g7pcDcTBt2MRugnoi8BwVSuCT2jfRXBUy+n1Zz/Yw==} + engines: {node: '>=8'} + peerDependencies: + winston: ^3 + dependencies: + file-stream-rotator: 0.6.1 + object-hash: 3.0.0 + triple-beam: 1.4.1 + winston: 3.12.0 + winston-transport: 4.7.0 + dev: false + + /winston-transport@4.7.0: + resolution: {integrity: sha512-ajBj65K5I7denzer2IYW6+2bNIVqLGDHqDw3Ow8Ohh+vdW+rv4MZ6eiDvHoKhfJFZ2auyN8byXieDDJ96ViONg==} + engines: {node: '>= 12.0.0'} + dependencies: + logform: 2.6.0 + readable-stream: 3.6.2 + triple-beam: 1.4.1 + dev: false + + /winston@3.12.0: + resolution: {integrity: sha512-OwbxKaOlESDi01mC9rkM0dQqQt2I8DAUMRLZ/HpbwvDXm85IryEHgoogy5fziQy38PntgZsLlhAYHz//UPHZ5w==} + 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.7.0 + dev: false + + /wkx@0.5.0: + resolution: {integrity: sha512-Xng/d4Ichh8uN4l0FToV/258EjMGU9MGcA0HV2d9B/ZpZB3lqQm7nkOdZdm5GhKtLLhAE7PiVQwN4eN+2YJJUg==} + dependencies: + '@types/node': 20.11.28 + dev: false + + /xtend@4.0.2: + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} + engines: {node: '>=0.4'} + dev: false + + /yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} diff --git a/reference/P01CentralControl/.eslintrc.cjs b/reference/P01CentralControl/.eslintrc.cjs new file mode 100644 index 0000000..ce0bb13 --- /dev/null +++ b/reference/P01CentralControl/.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/reference/P01CentralControl/.prettierrc.json b/reference/P01CentralControl/.prettierrc.json new file mode 100644 index 0000000..f4f39af --- /dev/null +++ b/reference/P01CentralControl/.prettierrc.json @@ -0,0 +1,5 @@ +{ + "singleQuote": true, + "trailingComma": "all", + "tabWidth": 4 +} diff --git a/reference/P01CentralControl/PlanA.md b/reference/P01CentralControl/PlanA.md new file mode 100644 index 0000000..edd695e --- /dev/null +++ b/reference/P01CentralControl/PlanA.md @@ -0,0 +1,89 @@ +> 如此美妙的音乐 + +# Plan Title + +1. [中央控制器-Central Control](#P01 中央控制器) + - 简易宿主系统控制 + - 日志控制 + - 子系统状态控制 + - Docker操作 +2. 笔记 +3. todo +4. 账本 +5. 文件 +6. 书籍管理 +7. 树洞 + 1. 自己缺点的集合,把自己的问题都记录下来 + 2. 可以针对每一个缺点标签开启记录 + 3. 去年今日 + 4. 曾经的自己 + + +--- + +# P01 中央控制器 + +## 第一部分 概述 + +  此模块旨在建立一个易于操作的底层操作系统(Linux|Debian)和应用子系统的统一管理控制面板,它能够对宿主系统进行一定程度的管理,如:宿主系统资源监控,还能对应用系统进行管理,如:环境布置(包括Docker)、应用系统启停、应用系统日志查看、负载均衡、应用系统部署、应用系统版本控制等操作。 + +  此模块的目的是将在Linux系统上的操作指令**简化**成图形化的按钮操作,同时对应用系统的开发模板进行一定的**约束/规范**,这里的约束是指应用系统需要一个中央控制器的配置文件,中央控制器会根据配置文件得知应用系统具有的一些功能和操作。 + +## 第二部分 思维采集,脑洞补完计划 + +### 2024/01/13 20:20 +1. 进入控制器的入口很隐蔽,需要特殊的端口,特殊的域名,特殊的标记或操作 +2. 具有网关的作用,可以一键主宰应用子系统的生命周期及请求周期 +3. 以地图和ip列表的方式,主动防御,阻止请求 +4. 能够统计子系统的访问记录 +5. 能够记录对子系统的所有操作和响应 +6. 中央控制器自身拥有可升级操作 +7. 在安装子系统配置环境时,可以选择npm源 + +## 第三部分 项目准备 + +### 技术选型 + +- 后端: + - 语言: JavaScript + - 框架: Fastify +- 前端: + - React + - 原生 +- 开发环境: + - 操作系统: Windows11 + - 编辑器: WebStorm + +### 开发计划 + +- 预计开始时间: 2024/01/13 +- 开发人员: expressgy +- 预计开发周期: 2024/01/13 - 2024/01/28 [星期日] + +### 实际开发日志 + +- 2024/01/13 + - 1. 项目开始前准备 + - 2. 环境探测(了解Fastify和内部存储) +- 2024/01/14 + - 1. 登陆界面 + +- 2024/01/15 + - 1. - [x] 登陆验证 + 1. - [x] 自定义参数验证AJV,我真强 +- 2024/01/16 + - 1. - [x] 引入redis + - 2. - [x] 了解双token + - 3. - [x] 听说了PostgreSQL + +- 2024/01/17 + - 1. - [ ] 写一点获取系统信息的东西 + + + +## 开发设计 + +### 登录模块 + + +### diff --git a/reference/P01CentralControl/app.js b/reference/P01CentralControl/app.js new file mode 100644 index 0000000..2396499 --- /dev/null +++ b/reference/P01CentralControl/app.js @@ -0,0 +1,184 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: 2160 +// | @文件描述: app.js - +// | @创建时间: 2024-01-13 21:05 +// | @更新时间: 2024-01-13 21:05 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ + +// 加载时间工具 +import '#tools/dateFormate.js'; + +// ! 读取ENV +const ENV = process.argv[2]?.trim().toLowerCase() || 'production'; +// ! 是否为开发环境 +const isDev = ENV == 'development' || ENV == 'dev' || ENV == 'develop'; +// ! 导入环境标识 +global.isDev = isDev; +// ! 加载配置文件 +import {devConf, proConf} from '#config'; +// ! 导入配置文件 +global.conf = global.isDev ? devConf : proConf; +// * 加载核心框架 +import Fastify from 'fastify'; +// ! 加载路由 +import routes from '#routes/index.js'; +// ! 获取当前设备IP +import getLocalIPv4 from '#tools/getLocalIp.js'; +// * ejs模板 +import ejs from 'ejs'; +// * ajv错误模板 +import ajvErrors from 'ajv-errors'; +// ! 自定义Ajv参数验证插件 +import { isLowerCase, isTrim } from '#plugins/ajv/index.js'; + + +async function start(){ + // | 创建fastify实例 + const fastify = new Fastify({ + logger: { + level: 'debug', + serializers: { + req(request) { + // 不返回任何东西,实际上就是屏蔽了自动的请求日志 + return {}; + }, + res(reply) { + // 同理,不返回任何东西以屏蔽响应日志 + return {}; + } + }, + transport: { + target: 'pino-pretty', + options: { + level: 'error', + // 这个选项确保输出带颜色 + colorize: true, + translateTime: 'yyyy-mm-dd HH:MM:ss', + // 对象信息打印在一行 + singleLine: true + } + } + }, + ajv: { + customOptions: { + removeAdditional: true, + useDefaults: true, + coerceTypes: true, + allErrors: true, + // 允许使用联合模式 严格模式下 + allowUnionTypes: true + }, + + plugins: [ + ajvErrors, + // 这种方式完美解决,开心, 实际上这是一个函数,会传进去ajv实例对象 + isLowerCase, + isTrim, + ] + + } + }); + // | 装饰器示例 + // @ 配置文件 + fastify.decorate('conf', global.conf); + + fastify.decorate('authenticate', async function(request, reply) { + try { + // 校验token,并生成request的user参数 + await request.jwtVerify(); + } catch (err) { + // token校验未通过,记录错误 + fastify.log.debug({ reqId: request.id, Auth: err.message }); + reply.code(err.statusCode).send({ + statusCode: err.statusCode, + message: err.message, + error: err.name + }); + } + }); + + // | 生命周期 + // @ 请求拦截 + fastify.addHook('onRequest', async function (request, reply) { + return; + }); + + // @ 响应拦截 + fastify.addHook('onResponse', async function (request, reply){ + return; + }); + + // @ 发送消息拦截 + fastify.addHook('onSend', async (request, reply, payload) => { + // fastify.log.info(reply.getHeader('content-type')); + if(reply.statusCode === 200 && !request.url.includes('/api/file') ){ + return `{"statusCode": 200, "status": "success", "data": ${payload}}`; + } + return payload; + }); + // @ 错误拦截 + fastify.setErrorHandler(async (error, request, reply) => { + // 自定义错误处理逻辑 + fastify.log.error(error); + reply + .code(error.statusCode) + .send({ + statusCode: error.statusCode, + message: error.message, + error: error.name + }); + }); + + // | 插件 + // @ 注册防止恶意请求封ip + await fastify.register(import('@fastify/rate-limit'), global.conf.rateLimit); + + // @ 注册html模板 + fastify.register(import('@fastify/view'), { + engine: {ejs}, + includeViewExtension: true, + root: 'views' + }); + + // @ 错误处理工具 + fastify.register(import('@fastify/sensible')); + + // @ 注册redis + await fastify.register(import('@fastify/redis'), { + // 配置文件基础redis配置 host,port,password + ...global.conf.redis, + // fastify调用的名称空间 + namespace: 'db1', + // 指向的redis数据库0-15 + db: 1, + // 4 (IPv4) or 6 (IPv6) + family: 4, + // redis连接中的名字 + connectionName: global.conf.projectName + }); + // fastify.log.info(await fastify.redis.db1.set('name', 'xsx', 'EX', 60)); + + // @ 注册jwt + fastify.register(import('@fastify/jwt'), global.conf.jwt); + + // @ 注册路由 + await fastify.register(routes); + + // | 监听指定端口 + await fastify.listen(global.conf.listen); + // | 输出监听地址和端口 + getLocalIPv4().map(i => isDev && fastify.log.info(`http://${i}:${fastify.conf.listen.port}`)); + + + // console.log(fastify.printPlugins()) + // console.log(fastify.printRoutes({ commonPrefix: false })); + // console.log(fastify.printRoutes({ method: 'GET' })); +} + +start(); diff --git a/reference/P01CentralControl/config/dev.conf.js b/reference/P01CentralControl/config/dev.conf.js new file mode 100644 index 0000000..0b74eb6 --- /dev/null +++ b/reference/P01CentralControl/config/dev.conf.js @@ -0,0 +1,23 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: P01CentralControl +// | @文件描述: dev.conf.js - +// | @创建时间: 2024-01-13 21:15 +// | @更新时间: 2024-01-13 21:15 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ +import proConf from '#root/config/pro.conf.js'; +const config = { + devUser: 'expressgy' +}; +Object.keys(proConf).forEach(item => { + if(!config[item]){ + config[item] = proConf[item]; + } +}); + +export default config; diff --git a/reference/P01CentralControl/config/index.js b/reference/P01CentralControl/config/index.js new file mode 100644 index 0000000..09298f3 --- /dev/null +++ b/reference/P01CentralControl/config/index.js @@ -0,0 +1,18 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: P01CentralControl +// | @文件描述: index.js - +// | @创建时间: 2024-01-13 21:14 +// | @更新时间: 2024-01-13 21:14 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ + +import devConfig from './dev.conf.js'; +import proConfig from './pro.conf.js'; + +export const devConf = devConfig; +export const proConf = proConfig; diff --git a/reference/P01CentralControl/config/pro.conf.js b/reference/P01CentralControl/config/pro.conf.js new file mode 100644 index 0000000..4fbb9ef --- /dev/null +++ b/reference/P01CentralControl/config/pro.conf.js @@ -0,0 +1,55 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: P01CentralControl +// | @文件描述: pro.conf.js - +// | @创建时间: 2024-01-13 21:15 +// | @更新时间: 2024-01-13 21:15 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ + + +const config = { + // @ 项目名 + projectName: 'Plan2160-P01 Central Control', + // 服务启动监听 + listen: { + // @ 监听地址 + host: '0.0.0.0', + // @ 监听端口 + port: 21601, + }, + // @ 中央控制器账户密码 + administrator: { + username: 'expressgy', + userpass: '**Hxl@1314521' + }, + // @ redis + redis: { + host: '172.16.1.10', + port: 6379, + password: 'redispassword' + }, + // jwt + jwt: { + // token的加密值 + secret: 'xadvdgfhga21xabhgnumo;opilkujya8axa21', + sign: { + // token过期时间 + expiresIn: '20m' + } + }, + // 防止恶意访问 + rateLimit: { + // 限制每个 IP 地址在时间窗口内最多可以发出的请求数 + max: 500, + // '1 second' = '1000':1 秒 | '1 minute' 1 分钟 | '1 hour' 1 小时 | '1 day' 1 天 | '1 week' 1 周 + timeWindow: '1 day' + } +}; + + +export default config; diff --git a/reference/P01CentralControl/docs/backdrop-filter.md b/reference/P01CentralControl/docs/backdrop-filter.md new file mode 100644 index 0000000..d4a3866 --- /dev/null +++ b/reference/P01CentralControl/docs/backdrop-filter.md @@ -0,0 +1,21 @@ +`backdrop-filter` 是 CSS 的一个属性,用于在元素的背景和元素之间创建一个视觉效果的过滤器。它可以应用多种效果,如模糊、色彩调整和亮度调整等。以下是一些常见的 `backdrop-filter` 属性及其作用与单位: + +1. `blur()`: 模糊元素的背景,可以通过指定一个模糊半径来调整模糊程度。单位为像素(px)。 + +2. `brightness()`: 调整元素的背景亮度,可以通过指定一个百分比或小数值来控制亮度增减。单位为百分比(%)或小数。 + +3. `contrast()`: 调整元素的背景对比度,可以通过指定一个百分比或小数值来增加或减小对比度。单位为百分比(%)或小数。 + +4. `grayscale()`: 将元素的背景转为灰度图像,可以通过指定一个百分比或小数值来控制转换程度。单位为百分比(%)或小数。 + +5. `hue-rotate()`: 调整元素的背景颜色的色调,可以通过指定一个角度值来旋转颜色。单位为角度(deg)。 + +6. `invert()`: 反转元素的背景颜色,即颜色取反。无单位。 + +7. `opacity()`: 调整元素的背景透明度,可以通过指定一个百分比或小数值来控制透明度。单位为百分比(%)或小数。 + +8. `saturate()`: 调整元素的背景饱和度,可以通过指定一个百分比或小数值来增加或减小饱和度。单位为百分比(%)或小数。 + +9. `sepia()`: 将元素的背景转为深褐色调,可以通过指定一个百分比或小数值来控制转换程度。单位为百分比(%)或小数。 + +这些 `backdrop-filter` 属性可以结合使用,以创建具有复合效果的背景过滤器。请注意,`backdrop-filter` 属性需要一些现代 Web 浏览器的支持,且可能不支持所有旧版浏览器。在使用时,请确保检查浏览器的兼容性。 diff --git a/reference/P01CentralControl/docs/fastify的request和reply.md b/reference/P01CentralControl/docs/fastify的request和reply.md new file mode 100644 index 0000000..1a067bd --- /dev/null +++ b/reference/P01CentralControl/docs/fastify的request和reply.md @@ -0,0 +1,24 @@ +在 Fastify 框架中,`request` 和 `reply` 是对 HTTP 请求和响应的封装,并传递给每个路由处理函数。它们分别提供了丰富的 API 来处理传入的请求和构造回去的响应。 + +1. **request**: 表示一个传入的 HTTP 请求。它具有多个属性和方法,用来访问请求的内容,例如: + + - `request.body`: 包含了 POST、PATCH 或 PUT 请求中的 payload。 + - `request.query`: 包含了 URL 查询字符串的键值对。 + - `request.params`: 包含了路由参数。 + - `request.headers`: 包含了请求头的键值对。 + - `request.raw`: Fastify 为了性能考虑并不会对 Node.js 原生的 `request` 对象进行重量级的包装,所以 `request.raw` 就是原始的 Node.js HTTP 请求对象。 + - `request.log`: 用于记录日志的 logger 实例。 + + 此外,还有很多其他的属性和方法,你可以用来操作和获取有关请求的其他细节。 + +2. **reply**: 表示对于客户端请求的响应。它封装了多个定义和发送 HTTP 响应的方法,例如: + + - `reply.code(statusCode)`: 设置 HTTP 响应的状态代码。 + - `reply.header(name, value)`: 设置 HTTP 响应头。 + - `reply.send(payload)`: 发送响应数据到客户端,这里的 payload 可以是一个字符串、Buffer、对象等。 + - `reply.type(contentType)`: 简便方法设置 `Content-Type` 响应头。 + - `reply.raw`: 和 `request.raw` 类似,`reply.raw` 就是原始的 Node.js HTTP 响应对象。 + + 就像 `request` 一样,`reply` 提供了其他的方法和属性来处理 HTTP 响应。 + +这些封装提供了快捷的方法操作请求和响应,而不必深入了解底层的 Node.js HTTP API。Fastify 的设计也为高性能优化,避免不必要的封装和抽象。 diff --git a/reference/P01CentralControl/docs/schema的一些知识.md b/reference/P01CentralControl/docs/schema的一些知识.md new file mode 100644 index 0000000..b6d6c15 --- /dev/null +++ b/reference/P01CentralControl/docs/schema的一些知识.md @@ -0,0 +1,191 @@ +在使用 JSON Schema(如在 Fastify 或其他支持 JSON Schema 验证的系统中)时,`type` 关键字定义了数据类型。以下是一般支持的数据类型列表: + +1. **string**:表示字符串。还可以配合 `format` 代表特定格式的字符串,如 `date-time`, `email`, `hostname`, `ipv4`, `ipv6`, `uri`, 等。 + +2. **number**:表示任意数值,包括浮点数。 + +3. **integer**:表示整数。 + +4. **boolean**:表示布尔值 true 或 false。 + +5. **object**:表示关键字和值的集合,关键字必须为字符串。可以进一步描述对象的属性、所需的属性、属性的依赖性等。 + +6. **array**:表示一组有序的元素(项),项可以是任何类型。可以进一步定义项类型、数组长度等。 + +7. **null**:表示 null 值。 + +JSON Schema 还支持复合类型,例如: + +- 使用 **enums** 定义一组固定的值。 +- 使用 `oneOf`, `anyOf`, `allOf`, 和 `not` 关键字定义更复杂的逻辑组合。 + +例如,如果你希望属性接受字符串或 null 两种类型,可以使用 `type` 关键字的数组形式: + +```json +{ + "type": ["string", "null"] +} +``` + +需要注意的是,除了上述的基本数据类型,JSON Schema 还支持定义更细致的限制条件,比如: + +- 对于字符串:`minLength`, `maxLength`, 和正则表达式 `pattern` +- 对于数值:`minimum`, `maximum`, `exclusiveMinimum`, `exclusiveMaximum`, `multipleOf` +- 对于对象:`properties`, `additionalProperties`, `required`, `patternProperties`, `minProperties`, `maxProperties` +- 对于数组:`items`, `additionalItems`, `minItems`, `maxItems`, `uniqueItems`, `contains` + +还可以通过 `default`, `examples`, 和 `const` 等关键字提供更多信息。 + +上述列表涵盖了 JSON Schema Draft-07 和之后版本中的常见数据类型和功能。根据具体实施和使用的 JSON Schema 草案版本(Draft),可能会有细微差别。确保查看你使用的 JSON Schema 草案版本文档以获取完整信息。 + + + +--- + +`oneOf`,`anyOf`,`allOf` 和 `not` 是 JSON Schema 中用于组合其他规则的关键字。它们允许您对多个条件进行逻辑运算,以更精细地定义数据的结构。 + +- `oneOf`: 表示只有一个架构应匹配数据。如果多个架构都匹配数据,验证将失败。这类似于 "XOR" 的逻辑关系。 + + 示例: + ```json + { + "oneOf": [ + { "type": "string" }, + { "maxLength": 5 } + ] + } + ``` + 这个示例声明了数据可以是一个字符串,或者长度最大为 5 的字符串。如果数据不是字符串,或者长度超过 5,验证将失败。 + +- `anyOf`: 表示至少有一个架构应匹配数据。只有当至少一个架构满足条件时,验证才会通过。 + + 示例: + ```json + { + "anyOf": [ + { "type": "string" }, + { "maxLength": 5 } + ] + } + ``` + 这个示例声明了数据可以是一个字符串,或者长度最大为 5 的字符串。只要满足其中一个条件,即可通过验证。 + +- `allOf`: 表示所有架构都必须匹配数据。只有当所有架构条件都满足时,验证才会通过。 + + 示例: + ```json + { + "allOf": [ + { "type": "string" }, + { "minLength": 2 }, + { "maxLength": 5 } + ] + } + ``` + 这个示例要求数据必须是一个长度介于 2 和 5 之间的字符串,同时满足三个条件。 + +- `not`: 表示数据不能匹配给定的架构。如果数据满足 `not` 中描述的架构,则验证将失败。 + + 示例: + ```json + { + "not": { + "type": "null" + } + } + ``` + 这个示例要求数据不能是 `null`。如果数据是 `null`,则验证将失败。 + +这些组合关键字能够根据特定的需求对数据施加更复杂的约束和规则。您可以根据您的条件使用适当的组合关键字来定义数据的结构和验证规则。 + + +--- + +在 JSON Schema 中,当你在定义数组类型的时候,有几个关键字可以用来更精确地描述数组的结构和约束: + +- `items`: 用来指定数组中每个元素的架构。它可以是单个架构,适用于数组中的所有元素,或者是一个架构数组,适用于数组中每个位置的元素。 + + 示例(所有元素相同架构): + ```json + { + "type": "array", + "items": { "type": "string" } + } + ``` + 在这个例子中,数组中的所有元素都必须是字符串。 + + 示例(特定位置架构): + ```json + { + "type": "array", + "items": [ + { "type": "number" }, + { "type": "string" } + ] + } + ``` + 在这个例子中,数组的第一个元素必须是数字,第二个元素必须是字符串。 + +- `additionalItems`: 当使用架构数组定义 `items` 时,`additionalItems` 关键字规定了数组中额外元素的架构(即超出 `items`数组定义的元素的架构)。 + + 示例: + ```json + { + "type": "array", + "items": [ + { "type": "number" }, + { "type": "string" } + ], + "additionalItems": { "type": "string" } + } + ``` + 在这个例子中,第三个及以后的元素都必须是字符串。 + +- `minItems`: 指定数组的最小长度。 + + 示例: + ```json + { + "type": "array", + "minItems": 2 + } + ``` + 数组至少要有两个元素。 + +- `maxItems`: 指定数组的最大长度。 + + 示例: + ```json + { + "type": "array", + "maxItems": 5 + } + ``` + 数组最多可以有五个元素。 + +- `uniqueItems`: 要求数组中的所有元素都是唯一的。如果设置为 `true`,则不允许有重复的元素。 + + 示例: + ```json + { + "type": "array", + "uniqueItems": true + } + ``` + 所有的元素应该都是独一无二的。 + +- `contains`: 确保数组至少包含一个符合提供的架构的元素。 + + 示例: + ```json + { + "type": "array", + "contains": { + "type": "string", + "pattern": "^a" + } + } + ``` + 这个架构要求数组至少包含一个以字母“a”开头的字符串。 + +这些关键字可以单独使用,也可以组合使用,以便根据具体的需要为数组数据结构定义详细的限制和规则。 diff --git a/reference/P01CentralControl/package.json b/reference/P01CentralControl/package.json new file mode 100644 index 0000000..ac32c1b --- /dev/null +++ b/reference/P01CentralControl/package.json @@ -0,0 +1,48 @@ +{ + "name": "p01centralcontrol", + "version": "1.0.0", + "description": "", + "main": "app.js", + "type": "module", + "directories": { + "test": "test" + }, + "imports": { + "#root/*": "./*", + "#config": "./config/index.js", + "#tools/*": "./tools/*", + "#routes/*": "./routes/*", + "#plugins/*": "./plugins/*", + "#task/*": "./src/task/*", + "#workers/*": "./src/workers/*", + "#protocol/*": "./src/protocol/*", + "#processes/*": "./src/processes/*" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start": "node app.js production", + "dev": "nodemon app.js dev" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "@fastify/jwt": "^8.0.0", + "@fastify/rate-limit": "^9.1.0", + "@fastify/redis": "^6.1.1", + "@fastify/sensible": "^5.5.0", + "@fastify/view": "^8.2.0", + "ajv": "^8.12.0", + "ajv-errors": "^3.0.0", + "ejs": "^3.1.9", + "fastify": "^4.25.2" + }, + "devDependencies": { + "eslint": "^8.52.0", + "eslint-config-prettier": "^9.0.0", + "eslint-plugin-prettier": "^5.0.0", + "nodemon": "^3.0.2", + "pino-pretty": "^10.3.1", + "prettier": "^3.0.3" + } +} diff --git a/reference/P01CentralControl/plugins/ajv/index.js b/reference/P01CentralControl/plugins/ajv/index.js new file mode 100644 index 0000000..5ebc668 --- /dev/null +++ b/reference/P01CentralControl/plugins/ajv/index.js @@ -0,0 +1,82 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: P01CentralControl +// | @文件描述: index.js - +// | @创建时间: 2024-01-15 10:49 +// | @更新时间: 2024-01-15 10:49 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ +import Ajv from 'ajv'; +// ajv错误消息回应 +import ajvErrors from 'ajv-errors'; + + + +// 将字符串转化为全小写 +export function isLowerCase(ajv){ + ajv.addKeyword({ + keyword: 'isLowerCase', + // 开启错误收集 + errors: true, + modifying: true, + validate: function validateIsEven(schema, data, parentSchema, dataCxt) { + if(typeof data == 'string'){ + dataCxt.parentData[dataCxt.parentDataProperty] = dataCxt.parentData[dataCxt.parentDataProperty].trim().toLowerCase(); + return true; + }else{ + validateIsEven.errors = [ { + message: '错误的数据' + } ]; + return false; + } + } + }); +} + +// 去除两端空格 +export function isTrim(ajv){ + ajv.addKeyword({ + keyword: 'isTrim', + type: 'string', + // 开启错误收集 + errors: true, + modifying: true, + validate: function validateIsEven(schema, data, parentSchema, dataCxt) { + if(typeof data == 'string'){ + dataCxt.parentData[dataCxt.parentDataProperty] = dataCxt.parentData[dataCxt.parentDataProperty].trim(); + return true; + }else{ + validateIsEven.errors = [ { + message: 'is note String' + } ]; + return false; + } + } + }); +} + + + +// 给fastify添加自定义的参数校验规则 +function customAjv(fastify, options){ + // 创建一个新的 AJV 实例 + // 创建一个新的 AJV 实例 + const ajv = new Ajv({ + removeAdditional: true, + useDefaults: true, + coerceTypes: true, + // jsonPointers: true, + allErrors: true + }); + ajvErrors(ajv); + isLowerCase(ajv); + // 使用自定义的 AJV 实例为 Fastify 设置验证器编译器 + fastify.setValidatorCompiler(({ schema, method, url, httpPart }) => { + return ajv.compile(schema); + }); +} + diff --git a/reference/P01CentralControl/pnpm-lock.yaml b/reference/P01CentralControl/pnpm-lock.yaml new file mode 100644 index 0000000..0d3acee --- /dev/null +++ b/reference/P01CentralControl/pnpm-lock.yaml @@ -0,0 +1,1613 @@ +lockfileVersion: '6.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +dependencies: + '@fastify/jwt': + specifier: ^8.0.0 + version: 8.0.0 + '@fastify/rate-limit': + specifier: ^9.1.0 + version: 9.1.0 + '@fastify/redis': + specifier: ^6.1.1 + version: 6.1.1 + '@fastify/sensible': + specifier: ^5.5.0 + version: 5.5.0 + '@fastify/view': + specifier: ^8.2.0 + version: 8.2.0 + ajv: + specifier: ^8.12.0 + version: 8.12.0 + ajv-errors: + specifier: ^3.0.0 + version: 3.0.0(ajv@8.12.0) + ejs: + specifier: ^3.1.9 + version: 3.1.9 + fastify: + specifier: ^4.25.2 + version: 4.25.2 + +devDependencies: + eslint: + specifier: ^8.52.0 + version: 8.56.0 + eslint-config-prettier: + specifier: ^9.0.0 + version: 9.1.0(eslint@8.56.0) + eslint-plugin-prettier: + specifier: ^5.0.0 + version: 5.1.3(eslint-config-prettier@9.1.0)(eslint@8.56.0)(prettier@3.2.1) + nodemon: + specifier: ^3.0.2 + version: 3.0.2 + pino-pretty: + specifier: ^10.3.1 + version: 10.3.1 + prettier: + specifier: ^3.0.3 + version: 3.2.1 + +packages: + + /@aashutoshrathi/word-wrap@1.2.6: + resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==} + engines: {node: '>=0.10.0'} + dev: true + + /@eslint-community/eslint-utils@4.4.0(eslint@8.56.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.56.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.4: + resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + ajv: 6.12.6 + debug: 4.3.4(supports-color@5.5.0) + espree: 9.6.1 + globals: 13.24.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.56.0: + resolution: {integrity: sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + /@fastify/ajv-compiler@3.5.0: + resolution: {integrity: sha512-ebbEtlI7dxXF5ziNdr05mOY8NnDiPB1XvAlLHctRt/Rc+C3LCOVW5imUVX+mhvUhnNzmPBHewUkOFgGlCxgdAA==} + dependencies: + ajv: 8.12.0 + ajv-formats: 2.1.1(ajv@8.12.0) + fast-uri: 2.3.0 + dev: false + + /@fastify/deepmerge@1.3.0: + resolution: {integrity: sha512-J8TOSBq3SoZbDhM9+R/u77hP93gz/rajSA+K2kGyijPpORPWUXHUpTaleoj+92As0S9uPRP7Oi8IqMf0u+ro6A==} + dev: false + + /@fastify/error@3.4.1: + resolution: {integrity: sha512-wWSvph+29GR783IhmvdwWnN4bUxTD01Vm5Xad4i7i1VuAOItLvbPAb69sb0IQ2N57yprvhNIwAP5B6xfKTmjmQ==} + dev: false + + /@fastify/fast-json-stringify-compiler@4.3.0: + resolution: {integrity: sha512-aZAXGYo6m22Fk1zZzEUKBvut/CIIQe/BapEORnxiD5Qr0kPHqqI69NtEMCme74h+at72sPhbkb4ZrLd1W3KRLA==} + dependencies: + fast-json-stringify: 5.10.0 + dev: false + + /@fastify/jwt@8.0.0: + resolution: {integrity: sha512-pJHjmZaokteZFMbsVVt7pbyJpbDogTnpl/aD7eR3vLOPgfktp4k4gUM6cd7RtjL/Ol1qDwL5mup+vdNlZI3K0Q==} + dependencies: + '@fastify/error': 3.4.1 + '@lukeed/ms': 2.0.2 + fast-jwt: 3.3.2 + fastify-plugin: 4.5.1 + steed: 1.1.3 + dev: false + + /@fastify/rate-limit@9.1.0: + resolution: {integrity: sha512-h5dZWCkuZXN0PxwqaFQLxeln8/LNwQwH9popywmDCFdKfgpi4b/HoMH1lluy6P+30CG9yzzpSpwTCIPNB9T1JA==} + dependencies: + '@lukeed/ms': 2.0.2 + fastify-plugin: 4.5.1 + toad-cache: 3.7.0 + dev: false + + /@fastify/redis@6.1.1: + resolution: {integrity: sha512-NZpHK+d3uJJ+w1iHx5n1woFvrHhhG52XjM9byWvU81KSsQpO0N/OikgQvz83frLV7UD4UQtTUgPvVbLxW0X81w==} + dependencies: + fastify-plugin: 4.5.1 + ioredis: 5.3.2 + transitivePeerDependencies: + - supports-color + dev: false + + /@fastify/sensible@5.5.0: + resolution: {integrity: sha512-D0zpl+nocsRXLceSbc4gasQaO3ZNQR4dy9Uu8Ym0mh8VUdrjpZ4g8Ca9O3pGXbBVOnPIGHUJNTV7Yf9dg/OYdg==} + dependencies: + '@lukeed/ms': 2.0.2 + fast-deep-equal: 3.1.3 + fastify-plugin: 4.5.1 + forwarded: 0.2.0 + http-errors: 2.0.0 + type-is: 1.6.18 + vary: 1.1.2 + dev: false + + /@fastify/view@8.2.0: + resolution: {integrity: sha512-hBSiBofCnJNlPHEMZWpO1SL84eqOaqujJ1hR3jntFyZZCkweH5jMs12DKYyGesjVll7SJFRRxPUBB8kmUmneRQ==} + dependencies: + fastify-plugin: 4.5.1 + hashlru: 2.3.0 + dev: false + + /@humanwhocodes/config-array@0.11.14: + resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} + engines: {node: '>=10.10.0'} + dependencies: + '@humanwhocodes/object-schema': 2.0.2 + debug: 4.3.4(supports-color@5.5.0) + 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.2: + resolution: {integrity: sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==} + dev: true + + /@ioredis/commands@1.2.0: + resolution: {integrity: sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==} + dev: false + + /@lukeed/ms@2.0.2: + resolution: {integrity: sha512-9I2Zn6+NJLfaGoz9jN3lpwDgAYvfGeNYdbAIjJOqzs4Tpc+VU3Jqq4IofSUBKajiDS8k9fZIg18/z13mpk1bsA==} + engines: {node: '>=8'} + dev: false + + /@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.16.0 + dev: true + + /@pkgr/core@0.1.0: + resolution: {integrity: sha512-Zwq5OCzuwJC2jwqmpEQt7Ds1DTi6BWSwoGkbb1n9pO3hzb35BoJELx7c0T23iDkBGkh2e7tvOtjF3tr3OaQHDQ==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + dev: true + + /@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 + + /abort-controller@3.0.0: + resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} + engines: {node: '>=6.5'} + dependencies: + event-target-shim: 5.0.1 + + /abstract-logging@2.0.1: + resolution: {integrity: sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==} + dev: false + + /acorn-jsx@5.3.2(acorn@8.11.3): + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + acorn: 8.11.3 + dev: true + + /acorn@8.11.3: + resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} + 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-formats@2.1.1(ajv@8.12.0): + resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + 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@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + dependencies: + color-convert: 2.0.1 + + /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 + + /archy@1.0.0: + resolution: {integrity: sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==} + dev: false + + /argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + dev: true + + /asn1.js@5.4.1: + resolution: {integrity: sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==} + dependencies: + bn.js: 4.12.0 + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + safer-buffer: 2.1.2 + dev: false + + /async@3.2.5: + resolution: {integrity: sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==} + dev: false + + /atomic-sleep@1.0.0: + resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} + engines: {node: '>=8.0.0'} + + /avvio@8.2.1: + resolution: {integrity: sha512-TAlMYvOuwGyLK3PfBb5WKBXZmXz2fVCgv23d6zZFdle/q3gPjmxBaeuC0pY0Dzs5PWMSgfqqEZkrye19GlDTgw==} + dependencies: + archy: 1.0.0 + debug: 4.3.4(supports-color@5.5.0) + fastq: 1.16.0 + transitivePeerDependencies: + - supports-color + dev: false + + /balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + /base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + /binary-extensions@2.2.0: + resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} + engines: {node: '>=8'} + dev: true + + /bn.js@4.12.0: + resolution: {integrity: sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==} + dev: false + + /brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + /brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + dependencies: + balanced-match: 1.0.2 + dev: false + + /braces@3.0.2: + resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} + engines: {node: '>=8'} + dependencies: + fill-range: 7.0.1 + dev: true + + /buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + + /callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + dev: true + + /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 + + /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 + + /cluster-key-slot@1.1.2: + resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==} + engines: {node: '>=0.10.0'} + 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 + + /color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + /colorette@2.0.20: + resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + dev: true + + /concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + /cookie@0.5.0: + resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==} + engines: {node: '>= 0.6'} + dev: false + + /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 + + /dateformat@4.6.3: + resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==} + dev: true + + /debug@4.3.4(supports-color@5.5.0): + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.2 + supports-color: 5.5.0 + + /deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + dev: true + + /denque@2.1.0: + resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} + engines: {node: '>=0.10'} + dev: false + + /depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + dev: false + + /doctrine@3.0.0: + resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} + engines: {node: '>=6.0.0'} + dependencies: + esutils: 2.0.3 + dev: true + + /ecdsa-sig-formatter@1.0.11: + resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} + dependencies: + safe-buffer: 5.2.1 + dev: false + + /ejs@3.1.9: + resolution: {integrity: sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==} + engines: {node: '>=0.10.0'} + hasBin: true + dependencies: + jake: 10.8.7 + dev: false + + /end-of-stream@1.4.4: + resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} + dependencies: + once: 1.4.0 + dev: true + + /escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + dev: true + + /eslint-config-prettier@9.1.0(eslint@8.56.0): + resolution: {integrity: sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==} + hasBin: true + peerDependencies: + eslint: '>=7.0.0' + dependencies: + eslint: 8.56.0 + dev: true + + /eslint-plugin-prettier@5.1.3(eslint-config-prettier@9.1.0)(eslint@8.56.0)(prettier@3.2.1): + resolution: {integrity: sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==} + 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.56.0 + eslint-config-prettier: 9.1.0(eslint@8.56.0) + prettier: 3.2.1 + prettier-linter-helpers: 1.0.0 + synckit: 0.8.8 + 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.56.0: + resolution: {integrity: sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + hasBin: true + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.56.0) + '@eslint-community/regexpp': 4.10.0 + '@eslint/eslintrc': 2.1.4 + '@eslint/js': 8.56.0 + '@humanwhocodes/config-array': 0.11.14 + '@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(supports-color@5.5.0) + 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.24.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.3 + acorn-jsx: 5.3.2(acorn@8.11.3) + 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 + + /event-target-shim@5.0.1: + resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} + engines: {node: '>=6'} + + /events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + + /fast-content-type-parse@1.1.0: + resolution: {integrity: sha512-fBHHqSTFLVnR61C+gltJuE5GkVQMV0S2nqUO8TJ+5Z3qAKG8vAx4FKai1s5jq/inV1+sREynIWSuQ6HgoSXpDQ==} + dev: false + + /fast-copy@3.0.1: + resolution: {integrity: sha512-Knr7NOtK3HWRYGtHoJrjkaWepqT8thIVGAwt0p0aUs1zqkAzXZV4vo9fFNwyb5fcqK1GKYFYxldQdIDVKhUAfA==} + dev: true + + /fast-decode-uri-component@1.0.1: + resolution: {integrity: sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==} + 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-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + dev: true + + /fast-json-stringify@5.10.0: + resolution: {integrity: sha512-fu1BhzPzgOdvK+sVhSPFzm06DQl0Dwbo+NQxWm21k03ili2wsJExXbGZ9qsD4Lsn7zFGltF8h9I1fuhk4JPnrQ==} + dependencies: + '@fastify/deepmerge': 1.3.0 + ajv: 8.12.0 + ajv-formats: 2.1.1(ajv@8.12.0) + fast-deep-equal: 3.1.3 + fast-uri: 2.3.0 + json-schema-ref-resolver: 1.0.1 + rfdc: 1.3.0 + dev: false + + /fast-jwt@3.3.2: + resolution: {integrity: sha512-H+JYxaFy2LepiC1AQWM/2hzKlQOWaWUkEnu/yebhYu4+ameb3qG77WiRZ1Ct6YBk6d/ESsNguBfTT5+q0XMtKg==} + engines: {node: '>=16 <22'} + dependencies: + '@lukeed/ms': 2.0.2 + asn1.js: 5.4.1 + ecdsa-sig-formatter: 1.0.11 + mnemonist: 0.39.7 + dev: false + + /fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + dev: true + + /fast-querystring@1.1.2: + resolution: {integrity: sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==} + dependencies: + fast-decode-uri-component: 1.0.1 + dev: false + + /fast-redact@3.3.0: + resolution: {integrity: sha512-6T5V1QK1u4oF+ATxs1lWUmlEk6P2T9HqJG3e2DnHOdVgZy2rFJBoEnrIedcTXlkAHU/zKC+7KETJ+KGGKwxgMQ==} + engines: {node: '>=6'} + dev: false + + /fast-safe-stringify@2.1.1: + resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} + dev: true + + /fast-uri@2.3.0: + resolution: {integrity: sha512-eel5UKGn369gGEWOqBShmFJWfq/xSJvsgDzgLYC845GneayWvXBf0lJCBn5qTABfewy1ZDPoaR5OZCP+kssfuw==} + dev: false + + /fastfall@1.5.1: + resolution: {integrity: sha512-KH6p+Z8AKPXnmA7+Iz2Lh8ARCMr+8WNPVludm1LGkZoD2MjY6LVnRMtTKhkdzI+jr0RzQWXKzKyBJm1zoHEL4Q==} + engines: {node: '>=0.10.0'} + dependencies: + reusify: 1.0.4 + dev: false + + /fastify-plugin@4.5.1: + resolution: {integrity: sha512-stRHYGeuqpEZTL1Ef0Ovr2ltazUT9g844X5z/zEBFLG8RYlpDiOCIG+ATvYEp+/zmc7sN29mcIMp8gvYplYPIQ==} + dev: false + + /fastify@4.25.2: + resolution: {integrity: sha512-SywRouGleDHvRh054onj+lEZnbC1sBCLkR0UY3oyJwjD4BdZJUrxBqfkfCaqn74pVCwBaRHGuL3nEWeHbHzAfw==} + dependencies: + '@fastify/ajv-compiler': 3.5.0 + '@fastify/error': 3.4.1 + '@fastify/fast-json-stringify-compiler': 4.3.0 + abstract-logging: 2.0.1 + avvio: 8.2.1 + fast-content-type-parse: 1.1.0 + fast-json-stringify: 5.10.0 + find-my-way: 7.7.0 + light-my-request: 5.11.0 + pino: 8.17.2 + process-warning: 3.0.0 + proxy-addr: 2.0.7 + rfdc: 1.3.0 + secure-json-parse: 2.7.0 + semver: 7.5.4 + toad-cache: 3.7.0 + transitivePeerDependencies: + - supports-color + dev: false + + /fastparallel@2.4.1: + resolution: {integrity: sha512-qUmhxPgNHmvRjZKBFUNI0oZuuH9OlSIOXmJ98lhKPxMZZ7zS/Fi0wRHOihDSz0R1YiIOjxzOY4bq65YTcdBi2Q==} + dependencies: + reusify: 1.0.4 + xtend: 4.0.2 + dev: false + + /fastq@1.16.0: + resolution: {integrity: sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==} + dependencies: + reusify: 1.0.4 + + /fastseries@1.7.2: + resolution: {integrity: sha512-dTPFrPGS8SNSzAt7u/CbMKCJ3s01N04s4JFbORHcmyvVfVKmbhMD1VtRbh5enGHxkaQDqWyLefiKOGGmohGDDQ==} + dependencies: + reusify: 1.0.4 + xtend: 4.0.2 + 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 + + /filelist@1.0.4: + resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} + dependencies: + minimatch: 5.1.6 + 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-my-way@7.7.0: + resolution: {integrity: sha512-+SrHpvQ52Q6W9f3wJoJBbAQULJuNEEQwBvlvYwACDhBTLOTMiQ0HYWh4+vC3OivGP2ENcTI1oKlFA2OepJNjhQ==} + engines: {node: '>=14'} + dependencies: + fast-deep-equal: 3.1.3 + fast-querystring: 1.1.2 + safe-regex2: 2.0.0 + dev: false + + /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 + + /forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + 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 + + /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.24.0: + resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} + engines: {node: '>=8'} + dependencies: + type-fest: 0.20.2 + dev: true + + /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'} + + /hashlru@2.3.0: + resolution: {integrity: sha512-0cMsjjIC8I+D3M44pOQdsy0OHXGLVz6Z0beRuufhKa0KfaD2wGwAev6jILzXsd3/vpnNQJmWyZtIILqM1N+n5A==} + dev: false + + /help-me@5.0.0: + resolution: {integrity: sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==} + dev: true + + /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 + + /ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + + /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 + + /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==} + + /ioredis@5.3.2: + resolution: {integrity: sha512-1DKMMzlIHM02eBBVOFQ1+AolGjs6+xEcM4PDL7NqOS6szq7H9jSaEkIUH6/a5Hl241LzW6JLSiAbNvTQjUupUA==} + engines: {node: '>=12.22.0'} + dependencies: + '@ioredis/commands': 1.2.0 + cluster-key-slot: 1.1.2 + debug: 4.3.4(supports-color@5.5.0) + denque: 2.1.0 + lodash.defaults: 4.2.0 + lodash.isarguments: 3.1.0 + redis-errors: 1.2.0 + redis-parser: 3.0.0 + standard-as-callback: 2.1.0 + transitivePeerDependencies: + - supports-color + dev: false + + /ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + 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-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + dev: true + + /is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + dependencies: + is-extglob: 2.1.1 + 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 + + /isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + dev: true + + /jake@10.8.7: + resolution: {integrity: sha512-ZDi3aP+fG/LchyBzUM804VjddnwfSfsdeYkwt8NcbKRvo4rFkjhs456iLFn3k2ZUWvNe4i48WACDbza8fhq2+w==} + engines: {node: '>=10'} + hasBin: true + dependencies: + async: 3.2.5 + chalk: 4.1.2 + filelist: 1.0.4 + minimatch: 3.1.2 + dev: false + + /joycon@3.1.1: + resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} + engines: {node: '>=10'} + 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-ref-resolver@1.0.1: + resolution: {integrity: sha512-EJAj1pgHc1hxF6vo2Z3s69fMjO1INq6eGHXZ8Z6wCQeldCuwxGK9Sxf4/cScGn3FZubCVUehfWtcDM/PLteCQw==} + dependencies: + fast-deep-equal: 3.1.3 + dev: false + + /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 + + /keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + dependencies: + json-buffer: 3.0.1 + dev: true + + /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 + + /light-my-request@5.11.0: + resolution: {integrity: sha512-qkFCeloXCOMpmEdZ/MV91P8AT4fjwFXWaAFz3lUeStM8RcoM1ks4J/F8r1b3r6y/H4u3ACEJ1T+Gv5bopj7oDA==} + dependencies: + cookie: 0.5.0 + process-warning: 2.3.2 + set-cookie-parser: 2.6.0 + dev: false + + /locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + dependencies: + p-locate: 5.0.0 + dev: true + + /lodash.defaults@4.2.0: + resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==} + dev: false + + /lodash.isarguments@3.1.0: + resolution: {integrity: sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==} + dev: false + + /lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + dev: true + + /lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + dependencies: + yallist: 4.0.0 + + /media-typer@0.3.0: + resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} + engines: {node: '>= 0.6'} + dev: false + + /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 + + /minimalistic-assert@1.0.1: + resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} + dev: false + + /minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + dependencies: + brace-expansion: 1.1.11 + + /minimatch@5.1.6: + resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + engines: {node: '>=10'} + dependencies: + brace-expansion: 2.0.1 + dev: false + + /minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + dev: true + + /mnemonist@0.39.7: + resolution: {integrity: sha512-ix3FwHWZgdXUt0dHM8bCrI4r1KMeYx8bCunPCYmvKXq4tn6gbNsqrsb4q0kDbDqbpIOvEaW5Sn+dmDwGydfrwA==} + dependencies: + obliterator: 2.0.4 + dev: false + + /ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + + /natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + dev: true + + /nodemon@3.0.2: + resolution: {integrity: sha512-9qIN2LNTrEzpOPBaWHTm4Asy1LxXLSickZStAQ4IZe7zsoIpD/A7LWxhZV3t4Zu352uBcqVnRsDXSMR2Sc3lTA==} + engines: {node: '>=10'} + hasBin: true + dependencies: + chokidar: 3.5.3 + debug: 4.3.4(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 + + /obliterator@2.0.4: + resolution: {integrity: sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ==} + dev: false + + /on-exit-leak-free@2.1.2: + resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==} + engines: {node: '>=14.0.0'} + + /once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + dependencies: + wrappy: 1.0.2 + 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 + + /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 + + /picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + dev: true + + /pino-abstract-transport@1.1.0: + resolution: {integrity: sha512-lsleG3/2a/JIWUtf9Q5gUNErBqwIu1tUKTT3dUzaf5DySw9ra1wcqKjJjLX1VTY64Wk1eEOYsVGSaGfCK85ekA==} + dependencies: + readable-stream: 4.5.2 + split2: 4.2.0 + + /pino-pretty@10.3.1: + resolution: {integrity: sha512-az8JbIYeN/1iLj2t0jR9DV48/LQ3RC6hZPpapKPkb84Q+yTidMCpgWxIT3N0flnBDilyBQ1luWNpOeJptjdp/g==} + hasBin: true + dependencies: + colorette: 2.0.20 + dateformat: 4.6.3 + fast-copy: 3.0.1 + fast-safe-stringify: 2.1.1 + help-me: 5.0.0 + joycon: 3.1.1 + minimist: 1.2.8 + on-exit-leak-free: 2.1.2 + pino-abstract-transport: 1.1.0 + pump: 3.0.0 + readable-stream: 4.5.2 + secure-json-parse: 2.7.0 + sonic-boom: 3.8.0 + strip-json-comments: 3.1.1 + dev: true + + /pino-std-serializers@6.2.2: + resolution: {integrity: sha512-cHjPPsE+vhj/tnhCy/wiMh3M3z3h/j15zHQX+S9GkTBgqJuTuJzYJ4gUyACLhDaJ7kk9ba9iRDmbH2tJU03OiA==} + dev: false + + /pino@8.17.2: + resolution: {integrity: sha512-LA6qKgeDMLr2ux2y/YiUt47EfgQ+S9LznBWOJdN3q1dx2sv0ziDLUBeVpyVv17TEcGCBuWf0zNtg3M5m1NhhWQ==} + hasBin: true + dependencies: + atomic-sleep: 1.0.0 + fast-redact: 3.3.0 + on-exit-leak-free: 2.1.2 + pino-abstract-transport: 1.1.0 + pino-std-serializers: 6.2.2 + process-warning: 3.0.0 + quick-format-unescaped: 4.0.4 + real-require: 0.2.0 + safe-stable-stringify: 2.4.3 + sonic-boom: 3.8.0 + thread-stream: 2.4.1 + dev: false + + /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.2.1: + resolution: {integrity: sha512-qSUWshj1IobVbKc226Gw2pync27t0Kf0EdufZa9j7uBSJay1CC+B3K5lAAZoqgX3ASiKuWsk6OmzKRetXNObWg==} + engines: {node: '>=14'} + hasBin: true + dev: true + + /process-warning@2.3.2: + resolution: {integrity: sha512-n9wh8tvBe5sFmsqlg+XQhaQLumwpqoAUruLwjCopgTmUBjJ/fjtBsJzKleCaIGBOMXYEhp1YfKl4d7rJ5ZKJGA==} + dev: false + + /process-warning@3.0.0: + resolution: {integrity: sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==} + dev: false + + /process@0.11.10: + resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} + engines: {node: '>= 0.6.0'} + + /proxy-addr@2.0.7: + resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} + engines: {node: '>= 0.10'} + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + dev: false + + /pstree.remy@1.1.8: + resolution: {integrity: sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==} + dev: true + + /pump@3.0.0: + resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} + dependencies: + end-of-stream: 1.4.4 + once: 1.4.0 + dev: true + + /punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + /queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + dev: true + + /quick-format-unescaped@4.0.4: + resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} + dev: false + + /readable-stream@4.5.2: + resolution: {integrity: sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + abort-controller: 3.0.0 + buffer: 6.0.3 + events: 3.3.0 + process: 0.11.10 + string_decoder: 1.3.0 + + /readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + dependencies: + picomatch: 2.3.1 + dev: true + + /real-require@0.2.0: + resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} + engines: {node: '>= 12.13.0'} + dev: false + + /redis-errors@1.2.0: + resolution: {integrity: sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==} + engines: {node: '>=4'} + dev: false + + /redis-parser@3.0.0: + resolution: {integrity: sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==} + engines: {node: '>=4'} + dependencies: + redis-errors: 1.2.0 + dev: false + + /require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + dev: false + + /resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + dev: true + + /ret@0.2.2: + resolution: {integrity: sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ==} + engines: {node: '>=4'} + dev: false + + /reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + /rfdc@1.3.0: + resolution: {integrity: sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==} + dev: false + + /rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + hasBin: true + dependencies: + glob: 7.2.3 + 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==} + + /safe-regex2@2.0.0: + resolution: {integrity: sha512-PaUSFsUaNNuKwkBijoAPHAK6/eM6VirvyPWlZ7BAQy4D+hCvh4B6lIG+nPdhbFfIbP+gTGBcrdsOaUs0F+ZBOQ==} + dependencies: + ret: 0.2.2 + 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==} + dev: false + + /secure-json-parse@2.7.0: + resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} + + /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 + + /set-cookie-parser@2.6.0: + resolution: {integrity: sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==} + 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 + + /simple-update-notifier@2.0.0: + resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==} + engines: {node: '>=10'} + dependencies: + semver: 7.5.4 + dev: true + + /sonic-boom@3.8.0: + resolution: {integrity: sha512-ybz6OYOUjoQQCQ/i4LU8kaToD8ACtYP+Cj5qd2AO36bwbdewxWJ3ArmJ2cr6AvxlL2o0PqnCcPGUgkILbfkaCA==} + dependencies: + atomic-sleep: 1.0.0 + + /split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + + /standard-as-callback@2.1.0: + resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==} + dev: false + + /statuses@2.0.1: + resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} + engines: {node: '>= 0.8'} + dev: false + + /steed@1.1.3: + resolution: {integrity: sha512-EUkci0FAUiE4IvGTSKcDJIQ/eRUP2JJb56+fvZ4sdnguLTqIdKjSxUe138poW8mkvKWXW2sFPrgTsxqoISnmoA==} + dependencies: + fastfall: 1.5.1 + fastparallel: 2.4.1 + fastq: 1.16.0 + fastseries: 1.7.2 + reusify: 1.0.4 + dev: false + + /string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + dependencies: + safe-buffer: 5.2.1 + + /strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + dependencies: + ansi-regex: 5.0.1 + 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 + + /synckit@0.8.8: + resolution: {integrity: sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==} + engines: {node: ^14.18.0 || >=16.0.0} + dependencies: + '@pkgr/core': 0.1.0 + tslib: 2.6.2 + dev: true + + /text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + dev: true + + /thread-stream@2.4.1: + resolution: {integrity: sha512-d/Ex2iWd1whipbT681JmTINKw0ZwOUBZm7+Gjs64DHuX34mmw8vJL2bFAaNacaW72zYiTJxSHi5abUuOi5nsfg==} + dependencies: + real-require: 0.2.0 + dev: false + + /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 + + /toad-cache@3.7.0: + resolution: {integrity: sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==} + engines: {node: '>=12'} + dev: false + + /toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + dev: false + + /touch@3.1.0: + resolution: {integrity: sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==} + hasBin: true + dependencies: + nopt: 1.0.10 + dev: true + + /tslib@2.6.2: + resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} + dev: true + + /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 + + /uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + dependencies: + punycode: 2.3.1 + + /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 + + /wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + dev: true + + /xtend@4.0.2: + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} + engines: {node: '>=0.4'} + dev: false + + /yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + + /yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + dev: true diff --git a/reference/P01CentralControl/routes/index.js b/reference/P01CentralControl/routes/index.js new file mode 100644 index 0000000..4e77835 --- /dev/null +++ b/reference/P01CentralControl/routes/index.js @@ -0,0 +1,183 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: fastify-template +// | @文件描述: index.js - +// | @创建时间: 2023-12-16 22:41 +// | @更新时间: 2023-12-16 22:41 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ + +import user from './user/index.js'; +import system from './system/index.js'; +function rootRoute(fastify, options, done){ + fastify.decorate('projectName', fastify.conf.projectName); + fastify.get('/', async function (request, reply){ + return { + path: request.url, + timestamp: new Date().getZH() + }; + }); + const mySchema = { + type: 'object', + properties: { + name: { + type: 'string' + }, + age: { + type: 'integer' + }, + love: { + type: 'string' + } + }, + required: [ 'name', 'age' ] + }; + const mySchema2 = { + body: { + type: 'object', + additionalProperties: false, // 不允许读取 + required: [ 'string' ], // 必填 + minProperties: 1, // 最小属性数量 + maxProperties: 25, // 最大属性数量 + properties: { + array: { + type: 'array', + minItems: 2, + maxItems: 2, + uniqueItems: true, // 元素唯一 + items: [ + { type: 'number' }, + { type: 'string' } + ], // 数组的第一个元素必须是数字,第二个元素必须是字符串。 + // items: { + // anyOf: [ + // { type: 'number' }, + // { type: 'string' } + // ] + // }, // 数组任意位置都可以是number和string + // additionalItems: { + // anyOf: [ + // { type: 'number' }, + // { type: 'string' } + // ] + // }, // items定义之外的元素,必须定义items + errorMessage: { + minItems: '数组长度不能小于2', + maxItems: '数组长度不能大于5' + } + }, + string: { + type: 'string', + maxLength: 200, + minLength: 1, + // pattern: '', // 支持正则表达式 + errorMessage: { + type: 'string必须为字符串', + maxLength: '字符长度不能大于20', + minLength: '字符长度不能小于10' + } + }, + number: { + type: 'number', + maximum: 2000, + minimum: 1, + // multipleOf: 3, // 必须是3的倍数 + errorMessage: { + type: 'string必须为数字', + maximum: '数字大小最大为20', + minimum: '数字大小最小为10' + } + }, + integer: { + type: 'integer', + exclusiveMaximum: 20, + exclusiveMinimum: 2, + errorMessage: { + type: 'string必须为数字', + exclusiveMaximum: '数字大小最大为19', + exclusiveMinimum: '数字大小最小为11' + } + }, + enum1: { + type: 'number', + enum: [ 1, 2, 3 ] + }, + enum2: { + type: [ 'number', 'string' ], + enum: [ 1, 2, 'xs' ], + errorMessage: { + enum: '不在枚举范围内', + } + }, + enum3: { + oneOf: [ + { 'type': 'string', 'enum': [ 'temp' ] }, + { 'type': 'number', 'enum': [ 25 ] }, + { 'type': 'boolean', 'enum': [ true, false ] } + ], + errorMessage: { + enum: '不在枚举范围内', + } + }, + boolean: { + type: 'boolean' + }, + // xsx: 'number', + studentList: { + type: 'array', + items: mySchema + } + } + }, + response: { + 200: { + type: 'object', + properties: { + hello: { type: 'string' } + } + } + } + }; + fastify.route({ + url: '/testSchema', + method: 'POST', + schema: mySchema2, + handler: async function(request, reply){ + console.log(request.body); + return 'A'; + } + }); + fastify.post('/testSchema2', {schema: mySchema2}, async function(response, reply){ + return 'A'; + }); + + fastify.register(user, { + prefix: 'user' + }); + + fastify.register(system, { + prefix: 'system' + }); + + done(); +} + +export default function routes(fastify, option, done){ + fastify.get('/', async function(request, reply){ + + return reply.view('/index.pug', { title: this.conf.projectName }); + // return { + // project: fastify.conf.projectName, + // framework: 'Fastify ' + fastify.version, + // timestamp: new Date().getZH() + // }; + }); + fastify.register(rootRoute, { + prefix: '/api' + }); + done(); +} diff --git a/reference/P01CentralControl/routes/system/index.js b/reference/P01CentralControl/routes/system/index.js new file mode 100644 index 0000000..40648a4 --- /dev/null +++ b/reference/P01CentralControl/routes/system/index.js @@ -0,0 +1,24 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: P01CentralControl +// | @文件描述: index.js - +// | @创建时间: 2024-01-16 15:23 +// | @更新时间: 2024-01-16 15:23 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ +export default function (fastify, options, done){ + // @ 获取系统信息 + fastify.get('/getInfo', { + preValidation: [ fastify.authenticate ] + }, async function(request, reply){ + this.log.error(request); + this.log.warn(request.user); + return 'ok'; + }); + done(); +} + diff --git a/reference/P01CentralControl/routes/user/index.js b/reference/P01CentralControl/routes/user/index.js new file mode 100644 index 0000000..61d302f --- /dev/null +++ b/reference/P01CentralControl/routes/user/index.js @@ -0,0 +1,55 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: fastify-template +// | @文件描述: index.js - +// | @创建时间: 2023-12-16 22:52 +// | @更新时间: 2023-12-16 22:52 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ +export default function (fastify, options, done){ + // @ 登录 + fastify.post('/signin', { + schema: { + body: { + type: 'object', + required: [ 'username', 'userpass' ], + properties: { + username: { + type: 'string', + isLowerCase: true, + errorMessage: { + type: 'username必须为字符串', + // isEven: 'isEven' + }, + }, + userpass: { + type: 'string', + isTrim: true, + }, + code: { + type: 'integer' + } + }, + errorMessage: { + required: { + username: 'username为必填项' + } + } + + } + }, + }, async function(request, reply){ + const {username, userpass} = request.body; + if(username != this.conf.administrator.username || userpass != this.conf.administrator.userpass){ + return fastify.httpErrors.conflict('用户名或密码错误!'); + } + // 生成token + const token = fastify.jwt.sign({ payload: {username: 'expressgy'}, timestamp: new Date().getZH() }); + return { token }; + }); + done(); +} diff --git a/reference/P01CentralControl/test/background.html b/reference/P01CentralControl/test/background.html new file mode 100644 index 0000000..f364281 --- /dev/null +++ b/reference/P01CentralControl/test/background.html @@ -0,0 +1,52 @@ + + + + + Title + + + +
+
+ + + +
+
老当益壮 宁移白首之心 穷且益坚 不坠青云之志
+
明日复明日 明日何其多 我生待明日 万事成蹉跎
+
严肃认真 周到细致 稳妥可靠 万无一失
+
天与弗取 反受其咎 时至不行 反受其殃
+
吾之所向 一往无前 愈挫愈奋 再接再厉
+
待到秋来九月八 我花开后百花杀
+
酌贪泉而觉爽 处涸辙以犹欢
+
知不可乎骤得 托遗响于悲风
+
实迷途其未远 觉今是而昨非
+
+
滕王高阁临江渚 佩玉鸣鸾罢歌舞
+
画栋朝飞南浦云 珠帘暮卷西山雨
+
闲云潭影日悠悠 物换星移几度秋
+
阁中帝子今何在 槛外长江空自流
+
+
己所不欲 勿施于人
+
+ + diff --git a/reference/P01CentralControl/test/homePage.js b/reference/P01CentralControl/test/homePage.js new file mode 100644 index 0000000..eef67ed --- /dev/null +++ b/reference/P01CentralControl/test/homePage.js @@ -0,0 +1,163 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: 2160 +// | @文件描述: homePage.js - +// | @创建时间: 2024-01-13 20:57 +// | @更新时间: 2024-01-13 20:57 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ +window.onload = () => { + const body = document.body; + let username, password + + // 开局提示 + const welcomeElement = document.createElement('div'); + body.append(welcomeElement); + const welcomeText = `Welcome To XY.\nYou Are About To Enter The Top Management Interface.`; + renderText(welcomeText, welcomeElement, () => { + // 询问是否继续 + const askElement = document.createElement('div'); + body.append(askElement); + const askText = 'Can Verify Your Identity Now? (Yes / No):' + renderText(askText, askElement, () => { + // 确认输入 + const answerElement = document.createElement('div'); + body.append(answerElement); + inputText(answerElement, text => { + const answer = text.toLowerCase() + if(answer == 'y' || answer == 'yes'){ + // 用户名提示 + const userText = 'USERNAME: ' + const usernameElement = document.createElement('div'); + const userHeaderElement = document.createElement('span'); + const userBodyElement = document.createElement('span'); + body.append(usernameElement) + usernameElement.append(userHeaderElement) + usernameElement.append(userBodyElement) + renderText(userText, userHeaderElement, () => { + inputText(userBodyElement, usernameText => { + username = usernameText + // 密码提示 + const passwdText = 'PASSWORD: ' + const passwdElement = document.createElement('div'); + const passwdHeaderElement = document.createElement('span'); + const passwdBodyElement = document.createElement('span'); + body.append(passwdElement) + passwdElement.append(passwdHeaderElement) + passwdElement.append(passwdBodyElement) + renderText(passwdText, passwdHeaderElement, () => { + inputText(passwdBodyElement, passwdText => { + password = passwdText + Entry() + }, null, true) + }, 0, 0) + }, null) + }, 0, 0) + }else{ + setTimeout(() => { + window.close() + }, 3000) + console.log('Window On Close in 3000ms!') + return; + } + }, true) + }, 0, 0) + }) +} + +function renderText(text, element, callback, startWait = 2000, endWait= 1000){ + const textElement = document.createElement('span'); + const cursorElement = document.createElement('span'); + cursorElement.classList.add('welecomeTextCursor'); + cursorElement.innerHTML = ' ' + + element.append(textElement, cursorElement) + const max = text.length + let nowLetter = 1 + setTimeout(() => { + const setTextInterval = setInterval(() => { + const spanElement = document.createElement('span'); + const nowText = text[nowLetter - 1] + if(nowText == ' '){ + spanElement.innerHTML = ' ' + }else{ + spanElement.innerText = nowText + } + + spanElement.classList.add('welecomeText'); + textElement.append(spanElement) + if(nowLetter == max){ + clearInterval(setTextInterval) + setTimeout(() => { + cursorElement.remove() + callback() + }, endWait) + }else{ + nowLetter++ + } + }, 30) + }, startWait) + +} + +function inputText(element, callback, letter, passwd){ + const textElement = document.createElement('span'); + const cursorElement = document.createElement('span'); + cursorElement.classList.add('inputTextCursor'); + cursorElement.innerHTML = ' '; + + element.append(textElement, cursorElement) + + const store = { + key: '', + string: '' + } + + document.body.addEventListener('keyup', getKeyWord) + if(!letter){ + letter = 'QWERTYUIOPASDFGHJKLZXCVBNM1234567890*@#&' + 'QWERTYUIOPASDFGHJKLZXCVBNM'.toLowerCase().split('') + }else{ + letter = ['Y','y','E','e','S','s','N','n','O','o'] + } + function getKeyWord(){ + if(letter && letter.includes(event.key)){ + store.key = event.key; + store.string = store.string + event.key + } + if(event.key == 'Backspace'){ + store.string = store.string.slice(0, store.string.length - 1) + } + if(event.key == 'Enter'){ + if(store.string.length==0){ + + }else{ + cursorElement.remove() + callback(store.string) + document.body.removeEventListener('keyup', getKeyWord) + } + } + if(passwd){ + textElement.innerText = new Array(store.string.length).fill('*').join('') + }else{ + textElement.innerText = store.string + } + } +} + + +function Entry(){ + if(true){ + const entryMessageElement = document.createElement('div') + document.body.append(entryMessageElement) + renderText('About To Enter The System!', entryMessageElement, () => { + const loadingElement = document.createElement('div') + loadingElement.classList.add('loading') + document.body.append(loadingElement) + }, 0, 0) + + } +} diff --git a/reference/P01CentralControl/tools/dateFormate.js b/reference/P01CentralControl/tools/dateFormate.js new file mode 100644 index 0000000..6bb6c90 --- /dev/null +++ b/reference/P01CentralControl/tools/dateFormate.js @@ -0,0 +1,41 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: P01CentralControl +// | @文件描述: dateFormate.js - +// | @创建时间: 2024-01-13 21:48 +// | @更新时间: 2024-01-13 21:48 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ + +function formateDate(){ + Date.prototype.format = function (format) { + let args = { + 'M+': this.getMonth() + 1, + 'd+': this.getDate(), + 'h+': this.getHours(), + 'm+': this.getMinutes(), + 's+': this.getSeconds(), + 'q+': Math.floor((this.getMonth() + 3) / 3), //quarter + 'S': this.getMilliseconds() + }; + if (/(y+)/.test(format)) + format = format.replace(RegExp.$1, (this.getFullYear() + '').substr(4 - RegExp.$1.length)); + for (let i in args) { + let n = args[i]; + if (new RegExp('(' + i + ')').test(format)) + format = format.replace(RegExp.$1, RegExp.$1.length == 1 ? n : ('00' + n).substr(('' + n).length)); + } + return format; + }; + Date.prototype.getZH = function(){ + return `${this.getFullYear()}-${this.getMonth()}-${this.getDate()} ${this.getHours()}:${this.getMinutes()}:${this.getSeconds()}`; + }; + Date.prototype.getZHS = function(){ + return `${this.getFullYear()}-${this.getMonth()}-${this.getDate()} ${this.getHours()}:${this.getMinutes()}:${this.getSeconds()}:${this.getMilliseconds()}`; + }; +} +formateDate(); diff --git a/reference/P01CentralControl/tools/getLocalIp.js b/reference/P01CentralControl/tools/getLocalIp.js new file mode 100644 index 0000000..0ce983b --- /dev/null +++ b/reference/P01CentralControl/tools/getLocalIp.js @@ -0,0 +1,26 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: P01CentralControl +// | @文件描述: getLocalIp.js - +// | @创建时间: 2024-01-14 01:07 +// | @更新时间: 2024-01-14 01:07 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ +import os from 'os'; +export default function getLocalIPv4() { + const networkInterfaces = os.networkInterfaces(); + const ipList = []; + for (const interfaceKey of Object.keys(networkInterfaces)) { + const addresses = networkInterfaces[interfaceKey]; + for (const address of addresses) { + if (address.family === 'IPv4' && !address.internal) { + ipList.push(address.address); + } + } + } + return ipList; +} diff --git a/reference/P01CentralControl/views/index.ejs b/reference/P01CentralControl/views/index.ejs new file mode 100644 index 0000000..a5653a6 --- /dev/null +++ b/reference/P01CentralControl/views/index.ejs @@ -0,0 +1,268 @@ + + + + + <%= title %> + + + + + + + diff --git a/reference/P01CentralControl/vision/.eslintrc.cjs b/reference/P01CentralControl/vision/.eslintrc.cjs new file mode 100644 index 0000000..c26b102 --- /dev/null +++ b/reference/P01CentralControl/vision/.eslintrc.cjs @@ -0,0 +1,21 @@ +module.exports = { + root: true, + env: { browser: true, es2020: true }, + extends: [ + 'eslint:recommended', + 'plugin:react/recommended', + 'plugin:react/jsx-runtime', + 'plugin:react-hooks/recommended', + ], + ignorePatterns: ['dist', '.eslintrc.cjs'], + parserOptions: { ecmaVersion: 'latest', sourceType: 'module' }, + settings: { react: { version: '18.2' } }, + plugins: ['react-refresh'], + rules: { + 'react-refresh/only-export-components': [ + 'warn', + { allowConstantExport: true }, + ], + indent: [2, 4, { SwitchCase: 1 }], + }, +} diff --git a/reference/P01CentralControl/vision/.gitignore b/reference/P01CentralControl/vision/.gitignore new file mode 100644 index 0000000..a547bf3 --- /dev/null +++ b/reference/P01CentralControl/vision/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/reference/P01CentralControl/vision/README.md b/reference/P01CentralControl/vision/README.md new file mode 100644 index 0000000..f768e33 --- /dev/null +++ b/reference/P01CentralControl/vision/README.md @@ -0,0 +1,8 @@ +# React + Vite + +This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. + +Currently, two official plugins are available: + +- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh +- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh diff --git a/reference/P01CentralControl/vision/index.html b/reference/P01CentralControl/vision/index.html new file mode 100644 index 0000000..cfaee7d --- /dev/null +++ b/reference/P01CentralControl/vision/index.html @@ -0,0 +1,24 @@ + + + + + + + + + + Vite + React + + +
+
+
+
+
waiting
+
+
+ + + diff --git a/reference/P01CentralControl/vision/package.json b/reference/P01CentralControl/vision/package.json new file mode 100644 index 0000000..a2f5ff4 --- /dev/null +++ b/reference/P01CentralControl/vision/package.json @@ -0,0 +1,30 @@ +{ + "name": "react-template", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0", + "preview": "vite preview" + }, + "dependencies": { + "@reduxjs/toolkit": "^1.9.7", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-router-dom": "^6.20.0", + "redux": "^4.2.1", + "sass": "^1.69.5" + }, + "devDependencies": { + "@types/react": "^18.2.37", + "@types/react-dom": "^18.2.15", + "@vitejs/plugin-react": "^4.2.0", + "eslint": "^8.53.0", + "eslint-plugin-react": "^7.33.2", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-react-refresh": "^0.4.4", + "vite": "^5.0.0" + } +} diff --git a/reference/P01CentralControl/vision/pnpm-lock.yaml b/reference/P01CentralControl/vision/pnpm-lock.yaml new file mode 100644 index 0000000..546f4f8 --- /dev/null +++ b/reference/P01CentralControl/vision/pnpm-lock.yaml @@ -0,0 +1,2543 @@ +lockfileVersion: '6.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +dependencies: + '@reduxjs/toolkit': + specifier: ^1.9.7 + version: 1.9.7(react@18.2.0) + react: + specifier: ^18.2.0 + version: 18.2.0 + react-dom: + specifier: ^18.2.0 + version: 18.2.0(react@18.2.0) + react-router-dom: + specifier: ^6.20.0 + version: 6.20.0(react-dom@18.2.0)(react@18.2.0) + redux: + specifier: ^4.2.1 + version: 4.2.1 + sass: + specifier: ^1.69.5 + version: 1.69.5 + +devDependencies: + '@types/react': + specifier: ^18.2.37 + version: 18.2.38 + '@types/react-dom': + specifier: ^18.2.15 + version: 18.2.17 + '@vitejs/plugin-react': + specifier: ^4.2.0 + version: 4.2.0(vite@5.0.2) + eslint: + specifier: ^8.53.0 + version: 8.54.0 + eslint-plugin-react: + specifier: ^7.33.2 + version: 7.33.2(eslint@8.54.0) + eslint-plugin-react-hooks: + specifier: ^4.6.0 + version: 4.6.0(eslint@8.54.0) + eslint-plugin-react-refresh: + specifier: ^0.4.4 + version: 0.4.4(eslint@8.54.0) + vite: + specifier: ^5.0.0 + version: 5.0.2(sass@1.69.5) + +packages: + + /@aashutoshrathi/word-wrap@1.2.6: + resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==} + engines: {node: '>=0.10.0'} + dev: true + + /@ampproject/remapping@2.2.1: + resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==} + engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/gen-mapping': 0.3.3 + '@jridgewell/trace-mapping': 0.3.20 + dev: true + + /@babel/code-frame@7.23.4: + resolution: {integrity: sha512-r1IONyb6Ia+jYR2vvIDhdWdlTGhqbBoFqLTQidzZ4kepUFH15ejXvFHxCVbtl7BOXIudsIubf4E81xeA3h3IXA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/highlight': 7.23.4 + chalk: 2.4.2 + dev: true + + /@babel/compat-data@7.23.3: + resolution: {integrity: sha512-BmR4bWbDIoFJmJ9z2cZ8Gmm2MXgEDgjdWgpKmKWUt54UGFJdlj31ECtbaDvCG/qVdG3AQ1SfpZEs01lUFbzLOQ==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/core@7.23.3: + resolution: {integrity: sha512-Jg+msLuNuCJDyBvFv5+OKOUjWMZgd85bKjbICd3zWrKAo+bJ49HJufi7CQE0q0uR8NGyO6xkCACScNqyjHSZew==} + engines: {node: '>=6.9.0'} + dependencies: + '@ampproject/remapping': 2.2.1 + '@babel/code-frame': 7.23.4 + '@babel/generator': 7.23.4 + '@babel/helper-compilation-targets': 7.22.15 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.3) + '@babel/helpers': 7.23.4 + '@babel/parser': 7.23.4 + '@babel/template': 7.22.15 + '@babel/traverse': 7.23.4 + '@babel/types': 7.23.4 + convert-source-map: 2.0.0 + debug: 4.3.4 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/generator@7.23.4: + resolution: {integrity: sha512-esuS49Cga3HcThFNebGhlgsrVLkvhqvYDTzgjfFFlHJcIfLe5jFmRRfCQ1KuBfc4Jrtn3ndLgKWAKjBE+IraYQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.4 + '@jridgewell/gen-mapping': 0.3.3 + '@jridgewell/trace-mapping': 0.3.20 + jsesc: 2.5.2 + dev: true + + /@babel/helper-compilation-targets@7.22.15: + resolution: {integrity: sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/compat-data': 7.23.3 + '@babel/helper-validator-option': 7.22.15 + browserslist: 4.22.1 + lru-cache: 5.1.1 + semver: 6.3.1 + dev: true + + /@babel/helper-environment-visitor@7.22.20: + resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-function-name@7.23.0: + resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.22.15 + '@babel/types': 7.23.4 + dev: true + + /@babel/helper-hoist-variables@7.22.5: + resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.4 + dev: true + + /@babel/helper-module-imports@7.22.15: + resolution: {integrity: sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.4 + dev: true + + /@babel/helper-module-transforms@7.23.3(@babel/core@7.23.3): + resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.23.3 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-module-imports': 7.22.15 + '@babel/helper-simple-access': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/helper-validator-identifier': 7.22.20 + dev: true + + /@babel/helper-plugin-utils@7.22.5: + resolution: {integrity: sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-simple-access@7.22.5: + resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.4 + dev: true + + /@babel/helper-split-export-declaration@7.22.6: + resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.4 + dev: true + + /@babel/helper-string-parser@7.23.4: + resolution: {integrity: sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-validator-identifier@7.22.20: + resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-validator-option@7.22.15: + resolution: {integrity: sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helpers@7.23.4: + resolution: {integrity: sha512-HfcMizYz10cr3h29VqyfGL6ZWIjTwWfvYBMsBVGwpcbhNGe3wQ1ZXZRPzZoAHhd9OqHadHqjQ89iVKINXnbzuw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.22.15 + '@babel/traverse': 7.23.4 + '@babel/types': 7.23.4 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/highlight@7.23.4: + resolution: {integrity: sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': 7.22.20 + chalk: 2.4.2 + js-tokens: 4.0.0 + dev: true + + /@babel/parser@7.23.4: + resolution: {integrity: sha512-vf3Xna6UEprW+7t6EtOmFpHNAuxw3xqPZghy+brsnusscJRW5BMUzzHZc5ICjULee81WeUV2jjakG09MDglJXQ==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.23.4 + dev: true + + /@babel/plugin-transform-react-jsx-self@7.23.3(@babel/core@7.23.3): + resolution: {integrity: sha512-qXRvbeKDSfwnlJnanVRp0SfuWE5DQhwQr5xtLBzp56Wabyo+4CMosF6Kfp+eOD/4FYpql64XVJ2W0pVLlJZxOQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.3 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-transform-react-jsx-source@7.23.3(@babel/core@7.23.3): + resolution: {integrity: sha512-91RS0MDnAWDNvGC6Wio5XYkyWI39FMFO+JK9+4AlgaTH+yWwVTsw7/sn6LK0lH7c5F+TFkpv/3LfCJ1Ydwof/g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.3 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/runtime@7.23.4: + resolution: {integrity: sha512-2Yv65nlWnWlSpe3fXEyX5i7fx5kIKo4Qbcj+hMO0odwaneFjfXw5fdum+4yL20O0QiaHpia0cYQ9xpNMqrBwHg==} + engines: {node: '>=6.9.0'} + dependencies: + regenerator-runtime: 0.14.0 + dev: false + + /@babel/template@7.22.15: + resolution: {integrity: sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.23.4 + '@babel/parser': 7.23.4 + '@babel/types': 7.23.4 + dev: true + + /@babel/traverse@7.23.4: + resolution: {integrity: sha512-IYM8wSUwunWTB6tFC2dkKZhxbIjHoWemdK+3f8/wq8aKhbUscxD5MX72ubd90fxvFknaLPeGw5ycU84V1obHJg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.23.4 + '@babel/generator': 7.23.4 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-hoist-variables': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/parser': 7.23.4 + '@babel/types': 7.23.4 + debug: 4.3.4 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/types@7.23.4: + resolution: {integrity: sha512-7uIFwVYpoplT5jp/kVv6EF93VaJ8H+Yn5IczYiaAi98ajzjfoZfslet/e0sLh+wVBjb2qqIut1b0S26VSafsSQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': 7.23.4 + '@babel/helper-validator-identifier': 7.22.20 + to-fast-properties: 2.0.0 + dev: true + + /@esbuild/android-arm64@0.19.7: + resolution: {integrity: sha512-YEDcw5IT7hW3sFKZBkCAQaOCJQLONVcD4bOyTXMZz5fr66pTHnAet46XAtbXAkJRfIn2YVhdC6R9g4xa27jQ1w==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm@0.19.7: + resolution: {integrity: sha512-YGSPnndkcLo4PmVl2tKatEn+0mlVMr3yEpOOT0BeMria87PhvoJb5dg5f5Ft9fbCVgtAz4pWMzZVgSEGpDAlww==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-x64@0.19.7: + resolution: {integrity: sha512-jhINx8DEjz68cChFvM72YzrqfwJuFbfvSxZAk4bebpngGfNNRm+zRl4rtT9oAX6N9b6gBcFaJHFew5Blf6CvUw==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-arm64@0.19.7: + resolution: {integrity: sha512-dr81gbmWN//3ZnBIm6YNCl4p3pjnabg1/ZVOgz2fJoUO1a3mq9WQ/1iuEluMs7mCL+Zwv7AY5e3g1hjXqQZ9Iw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-x64@0.19.7: + resolution: {integrity: sha512-Lc0q5HouGlzQEwLkgEKnWcSazqr9l9OdV2HhVasWJzLKeOt0PLhHaUHuzb8s/UIya38DJDoUm74GToZ6Wc7NGQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-arm64@0.19.7: + resolution: {integrity: sha512-+y2YsUr0CxDFF7GWiegWjGtTUF6gac2zFasfFkRJPkMAuMy9O7+2EH550VlqVdpEEchWMynkdhC9ZjtnMiHImQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-x64@0.19.7: + resolution: {integrity: sha512-CdXOxIbIzPJmJhrpmJTLx+o35NoiKBIgOvmvT+jeSadYiWJn0vFKsl+0bSG/5lwjNHoIDEyMYc/GAPR9jxusTA==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm64@0.19.7: + resolution: {integrity: sha512-inHqdOVCkUhHNvuQPT1oCB7cWz9qQ/Cz46xmVe0b7UXcuIJU3166aqSunsqkgSGMtUCWOZw3+KMwI6otINuC9g==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm@0.19.7: + resolution: {integrity: sha512-Y+SCmWxsJOdQtjcBxoacn/pGW9HDZpwsoof0ttL+2vGcHokFlfqV666JpfLCSP2xLxFpF1lj7T3Ox3sr95YXww==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ia32@0.19.7: + resolution: {integrity: sha512-2BbiL7nLS5ZO96bxTQkdO0euGZIUQEUXMTrqLxKUmk/Y5pmrWU84f+CMJpM8+EHaBPfFSPnomEaQiG/+Gmh61g==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-loong64@0.19.7: + resolution: {integrity: sha512-BVFQla72KXv3yyTFCQXF7MORvpTo4uTA8FVFgmwVrqbB/4DsBFWilUm1i2Oq6zN36DOZKSVUTb16jbjedhfSHw==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-mips64el@0.19.7: + resolution: {integrity: sha512-DzAYckIaK+pS31Q/rGpvUKu7M+5/t+jI+cdleDgUwbU7KdG2eC3SUbZHlo6Q4P1CfVKZ1lUERRFP8+q0ob9i2w==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ppc64@0.19.7: + resolution: {integrity: sha512-JQ1p0SmUteNdUaaiRtyS59GkkfTW0Edo+e0O2sihnY4FoZLz5glpWUQEKMSzMhA430ctkylkS7+vn8ziuhUugQ==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-riscv64@0.19.7: + resolution: {integrity: sha512-xGwVJ7eGhkprY/nB7L7MXysHduqjpzUl40+XoYDGC4UPLbnG+gsyS1wQPJ9lFPcxYAaDXbdRXd1ACs9AE9lxuw==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-s390x@0.19.7: + resolution: {integrity: sha512-U8Rhki5PVU0L0nvk+E8FjkV8r4Lh4hVEb9duR6Zl21eIEYEwXz8RScj4LZWA2i3V70V4UHVgiqMpszXvG0Yqhg==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-x64@0.19.7: + resolution: {integrity: sha512-ZYZopyLhm4mcoZXjFt25itRlocKlcazDVkB4AhioiL9hOWhDldU9n38g62fhOI4Pth6vp+Mrd5rFKxD0/S+7aQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/netbsd-x64@0.19.7: + resolution: {integrity: sha512-/yfjlsYmT1O3cum3J6cmGG16Fd5tqKMcg5D+sBYLaOQExheAJhqr8xOAEIuLo8JYkevmjM5zFD9rVs3VBcsjtQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/openbsd-x64@0.19.7: + resolution: {integrity: sha512-MYDFyV0EW1cTP46IgUJ38OnEY5TaXxjoDmwiTXPjezahQgZd+j3T55Ht8/Q9YXBM0+T9HJygrSRGV5QNF/YVDQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/sunos-x64@0.19.7: + resolution: {integrity: sha512-JcPvgzf2NN/y6X3UUSqP6jSS06V0DZAV/8q0PjsZyGSXsIGcG110XsdmuWiHM+pno7/mJF6fjH5/vhUz/vA9fw==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-arm64@0.19.7: + resolution: {integrity: sha512-ZA0KSYti5w5toax5FpmfcAgu3ZNJxYSRm0AW/Dao5up0YV1hDVof1NvwLomjEN+3/GMtaWDI+CIyJOMTRSTdMw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-ia32@0.19.7: + resolution: {integrity: sha512-CTOnijBKc5Jpk6/W9hQMMvJnsSYRYgveN6O75DTACCY18RA2nqka8dTZR+x/JqXCRiKk84+5+bRKXUSbbwsS0A==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-x64@0.19.7: + resolution: {integrity: sha512-gRaP2sk6hc98N734luX4VpF318l3w+ofrtTu9j5L8EQXF+FzQKV6alCOHMVoJJHvVK/mGbwBXfOL1HETQu9IGQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@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 + + /@jridgewell/gen-mapping@0.3.3: + resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} + engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/set-array': 1.1.2 + '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/trace-mapping': 0.3.20 + dev: true + + /@jridgewell/resolve-uri@3.1.1: + resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==} + engines: {node: '>=6.0.0'} + dev: true + + /@jridgewell/set-array@1.1.2: + resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} + engines: {node: '>=6.0.0'} + dev: true + + /@jridgewell/sourcemap-codec@1.4.15: + resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + dev: true + + /@jridgewell/trace-mapping@0.3.20: + resolution: {integrity: sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==} + dependencies: + '@jridgewell/resolve-uri': 3.1.1 + '@jridgewell/sourcemap-codec': 1.4.15 + 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 + + /@reduxjs/toolkit@1.9.7(react@18.2.0): + resolution: {integrity: sha512-t7v8ZPxhhKgOKtU+uyJT13lu4vL7az5aFi4IdoDs/eS548edn2M8Ik9h8fxgvMjGoAUVFSt6ZC1P5cWmQ014QQ==} + peerDependencies: + react: ^16.9.0 || ^17.0.0 || ^18 + react-redux: ^7.2.1 || ^8.0.2 + peerDependenciesMeta: + react: + optional: true + react-redux: + optional: true + dependencies: + immer: 9.0.21 + react: 18.2.0 + redux: 4.2.1 + redux-thunk: 2.4.2(redux@4.2.1) + reselect: 4.1.8 + dev: false + + /@remix-run/router@1.13.0: + resolution: {integrity: sha512-5dMOnVnefRsl4uRnAdoWjtVTdh8e6aZqgM4puy9nmEADH72ck+uXwzpJLEKE9Q6F8ZljNewLgmTfkxUrBdv4WA==} + engines: {node: '>=14.0.0'} + dev: false + + /@rollup/rollup-android-arm-eabi@4.5.2: + resolution: {integrity: sha512-ee7BudTwwrglFYSc3UnqInDDjCLWHKrFmGNi4aK7jlEyg4CyPa1DCMrZfsN1O13YT76UFEqXz2CoN7BCGpUlJw==} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-android-arm64@4.5.2: + resolution: {integrity: sha512-xOuhj9HHtn8128ir8veoQsBbAUBasDbHIBniYTEx02pAmu9EXL+ZjJqngnNEy6ZgZ4h1JwL33GMNu3yJL5Mzow==} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-darwin-arm64@4.5.2: + resolution: {integrity: sha512-NTGJWoL8bKyqyWFn9/RzSv4hQ4wTbaAv0lHHRwf4OnpiiP4P8W0jiXbm8Nc5BCXKmWAwuvJY82mcIU2TayC20g==} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-darwin-x64@4.5.2: + resolution: {integrity: sha512-hlKqj7bpPvU15sZo4za14u185lpMzdwWLMc9raMqPK4wywt0wR23y1CaVQ4oAFXat3b5/gmRntyfpwWTKl+vvA==} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm-gnueabihf@4.5.2: + resolution: {integrity: sha512-7ZIZx8c3u+pfI0ohQsft/GywrXez0uR6dUP0JhBuCK3sFO5TfdLn/YApnVkvPxuTv3+YKPIZend9Mt7Cz6sS3Q==} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm64-gnu@4.5.2: + resolution: {integrity: sha512-7Pk/5mO11JW/cH+a8lL/i0ZxmRGrbpYqN0VwO2DHhU+SJWWOH2zE1RAcPaj8KqiwC8DCDIJOSxjV9+9lLb6aeA==} + cpu: [arm64] + os: [linux] + libc: [glibc] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm64-musl@4.5.2: + resolution: {integrity: sha512-KrRnuG5phJx756e62wxvWH2e+TK84MP2IVuPwfge+GBvWqIUfVzFRn09TKruuQBXzZp52Vyma7FjMDkwlA9xpg==} + cpu: [arm64] + os: [linux] + libc: [musl] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-x64-gnu@4.5.2: + resolution: {integrity: sha512-My+53GasPa2D2tU5dXiyHYwrELAUouSfkNlZ3bUKpI7btaztO5vpALEs3mvFjM7aKTvEbc7GQckuXeXIDKQ0fg==} + cpu: [x64] + os: [linux] + libc: [glibc] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-x64-musl@4.5.2: + resolution: {integrity: sha512-/f0Q6Sc+Vw54Ws6N8fxaEe4R7at3b8pFyv+O/F2VaQ4hODUJcRUcCBJh6zuqtgQQt7w845VTkGLFgWZkP3tUoQ==} + cpu: [x64] + os: [linux] + libc: [musl] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-win32-arm64-msvc@4.5.2: + resolution: {integrity: sha512-NCKuuZWLht6zj7s6EIFef4BxCRX1GMr83S2W4HPCA0RnJ4iHE4FS1695q6Ewoa6A9nFjJe1//yUu0kgBU07Edw==} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-win32-ia32-msvc@4.5.2: + resolution: {integrity: sha512-J5zL3riR4AOyU/J3M/i4k/zZ8eP1yT+nTmAKztCXJtnI36jYH0eepvob22mAQ/kLwfsK2TB6dbyVY1F8c/0H5A==} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-win32-x64-msvc@4.5.2: + resolution: {integrity: sha512-pL0RXRHuuGLhvs7ayX/SAHph1hrDPXOM5anyYUQXWJEENxw3nfHkzv8FfVlEVcLyKPAEgDRkd6RKZq2SMqS/yg==} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@types/babel__core@7.20.5: + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + dependencies: + '@babel/parser': 7.23.4 + '@babel/types': 7.23.4 + '@types/babel__generator': 7.6.7 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.20.4 + dev: true + + /@types/babel__generator@7.6.7: + resolution: {integrity: sha512-6Sfsq+EaaLrw4RmdFWE9Onp63TOUue71AWb4Gpa6JxzgTYtimbM086WnYTy2U67AofR++QKCo08ZP6pwx8YFHQ==} + dependencies: + '@babel/types': 7.23.4 + dev: true + + /@types/babel__template@7.4.4: + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + dependencies: + '@babel/parser': 7.23.4 + '@babel/types': 7.23.4 + dev: true + + /@types/babel__traverse@7.20.4: + resolution: {integrity: sha512-mSM/iKUk5fDDrEV/e83qY+Cr3I1+Q3qqTuEn++HAWYjEa1+NxZr6CNrcJGf2ZTnq4HoFGC3zaTPZTobCzCFukA==} + dependencies: + '@babel/types': 7.23.4 + dev: true + + /@types/prop-types@15.7.11: + resolution: {integrity: sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==} + dev: true + + /@types/react-dom@18.2.17: + resolution: {integrity: sha512-rvrT/M7Df5eykWFxn6MYt5Pem/Dbyc1N8Y0S9Mrkw2WFCRiqUgw9P7ul2NpwsXCSM1DVdENzdG9J5SreqfAIWg==} + dependencies: + '@types/react': 18.2.38 + dev: true + + /@types/react@18.2.38: + resolution: {integrity: sha512-cBBXHzuPtQK6wNthuVMV6IjHAFkdl/FOPFIlkd81/Cd1+IqkHu/A+w4g43kaQQoYHik/ruaQBDL72HyCy1vuMw==} + dependencies: + '@types/prop-types': 15.7.11 + '@types/scheduler': 0.16.8 + csstype: 3.1.2 + dev: true + + /@types/scheduler@0.16.8: + resolution: {integrity: sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==} + dev: true + + /@ungap/structured-clone@1.2.0: + resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} + dev: true + + /@vitejs/plugin-react@4.2.0(vite@5.0.2): + resolution: {integrity: sha512-+MHTH/e6H12kRp5HUkzOGqPMksezRMmW+TNzlh/QXfI8rRf6l2Z2yH/v12no1UvTwhZgEDMuQ7g7rrfMseU6FQ==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + vite: ^4.2.0 || ^5.0.0 + dependencies: + '@babel/core': 7.23.3 + '@babel/plugin-transform-react-jsx-self': 7.23.3(@babel/core@7.23.3) + '@babel/plugin-transform-react-jsx-source': 7.23.3(@babel/core@7.23.3) + '@types/babel__core': 7.20.5 + react-refresh: 0.14.0 + vite: 5.0.2(sass@1.69.5) + transitivePeerDependencies: + - supports-color + dev: true + + /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@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 + + /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: true + + /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 + + /argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + dev: true + + /array-buffer-byte-length@1.0.0: + resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==} + dependencies: + call-bind: 1.0.5 + is-array-buffer: 3.0.2 + dev: true + + /array-includes@3.1.7: + resolution: {integrity: sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + get-intrinsic: 1.2.2 + is-string: 1.0.7 + dev: true + + /array.prototype.flat@1.3.2: + resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + es-shim-unscopables: 1.0.2 + dev: true + + /array.prototype.flatmap@1.3.2: + resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + es-shim-unscopables: 1.0.2 + dev: true + + /array.prototype.tosorted@1.1.2: + resolution: {integrity: sha512-HuQCHOlk1Weat5jzStICBCd83NxiIMwqDg/dHEsoefabn/hJRj5pVdWcPUSpRrwhwxZOsQassMpgN/xRYFBMIg==} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + es-shim-unscopables: 1.0.2 + get-intrinsic: 1.2.2 + dev: true + + /arraybuffer.prototype.slice@1.0.2: + resolution: {integrity: sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==} + engines: {node: '>= 0.4'} + dependencies: + array-buffer-byte-length: 1.0.0 + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + get-intrinsic: 1.2.2 + is-array-buffer: 3.0.2 + is-shared-array-buffer: 1.0.2 + dev: true + + /asynciterator.prototype@1.0.0: + resolution: {integrity: sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg==} + dependencies: + has-symbols: 1.0.3 + dev: true + + /available-typed-arrays@1.0.5: + resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==} + engines: {node: '>= 0.4'} + dev: true + + /balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + dev: true + + /binary-extensions@2.2.0: + resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} + engines: {node: '>=8'} + + /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 + + /browserslist@4.22.1: + resolution: {integrity: sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + dependencies: + caniuse-lite: 1.0.30001564 + electron-to-chromium: 1.4.594 + node-releases: 2.0.13 + update-browserslist-db: 1.0.13(browserslist@4.22.1) + dev: true + + /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: true + + /callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + dev: true + + /caniuse-lite@1.0.30001564: + resolution: {integrity: sha512-DqAOf+rhof+6GVx1y+xzbFPeOumfQnhYzVnZD6LAXijR77yPtm9mfOcqOnT3mpnJiZVT+kwLAFnRlZcIz+c6bg==} + 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: true + + /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 + + /color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + dependencies: + color-name: 1.1.3 + dev: true + + /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: true + + /color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + dev: true + + /concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + dev: true + + /convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + 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 + + /csstype@3.1.2: + resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==} + 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 + dev: true + + /deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + 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: true + + /define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.1 + has-property-descriptors: 1.0.1 + object-keys: 1.1.1 + dev: true + + /doctrine@2.1.0: + resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} + engines: {node: '>=0.10.0'} + dependencies: + esutils: 2.0.3 + dev: true + + /doctrine@3.0.0: + resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} + engines: {node: '>=6.0.0'} + dependencies: + esutils: 2.0.3 + dev: true + + /electron-to-chromium@1.4.594: + resolution: {integrity: sha512-xT1HVAu5xFn7bDfkjGQi9dNpMqGchUkebwf1GL7cZN32NSwwlHRPMSDJ1KN6HkS0bWUtndbSQZqvpQftKG2uFQ==} + dev: true + + /es-abstract@1.22.3: + resolution: {integrity: sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==} + engines: {node: '>= 0.4'} + dependencies: + array-buffer-byte-length: 1.0.0 + arraybuffer.prototype.slice: 1.0.2 + available-typed-arrays: 1.0.5 + call-bind: 1.0.5 + es-set-tostringtag: 2.0.2 + es-to-primitive: 1.2.1 + function.prototype.name: 1.1.6 + get-intrinsic: 1.2.2 + get-symbol-description: 1.0.0 + globalthis: 1.0.3 + gopd: 1.0.1 + has-property-descriptors: 1.0.1 + has-proto: 1.0.1 + has-symbols: 1.0.3 + hasown: 2.0.0 + internal-slot: 1.0.6 + is-array-buffer: 3.0.2 + is-callable: 1.2.7 + is-negative-zero: 2.0.2 + is-regex: 1.1.4 + is-shared-array-buffer: 1.0.2 + is-string: 1.0.7 + is-typed-array: 1.1.12 + is-weakref: 1.0.2 + object-inspect: 1.13.1 + object-keys: 1.1.1 + object.assign: 4.1.4 + regexp.prototype.flags: 1.5.1 + safe-array-concat: 1.0.1 + safe-regex-test: 1.0.0 + string.prototype.trim: 1.2.8 + string.prototype.trimend: 1.0.7 + string.prototype.trimstart: 1.0.7 + typed-array-buffer: 1.0.0 + typed-array-byte-length: 1.0.0 + typed-array-byte-offset: 1.0.0 + typed-array-length: 1.0.4 + unbox-primitive: 1.0.2 + which-typed-array: 1.1.13 + dev: true + + /es-iterator-helpers@1.0.15: + resolution: {integrity: sha512-GhoY8uYqd6iwUl2kgjTm4CZAf6oo5mHK7BPqx3rKgx893YSsy0LGHV6gfqqQvZt/8xM8xeOnfXBCfqclMKkJ5g==} + dependencies: + asynciterator.prototype: 1.0.0 + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + es-set-tostringtag: 2.0.2 + function-bind: 1.1.2 + get-intrinsic: 1.2.2 + globalthis: 1.0.3 + has-property-descriptors: 1.0.1 + has-proto: 1.0.1 + has-symbols: 1.0.3 + internal-slot: 1.0.6 + iterator.prototype: 1.1.2 + safe-array-concat: 1.0.1 + dev: true + + /es-set-tostringtag@2.0.2: + resolution: {integrity: sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.2 + has-tostringtag: 1.0.0 + hasown: 2.0.0 + dev: true + + /es-shim-unscopables@1.0.2: + resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==} + dependencies: + hasown: 2.0.0 + dev: true + + /es-to-primitive@1.2.1: + resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} + engines: {node: '>= 0.4'} + dependencies: + is-callable: 1.2.7 + is-date-object: 1.0.5 + is-symbol: 1.0.4 + dev: true + + /esbuild@0.19.7: + resolution: {integrity: sha512-6brbTZVqxhqgbpqBR5MzErImcpA0SQdoKOkcWK/U30HtQxnokIpG3TX2r0IJqbFUzqLjhU/zC1S5ndgakObVCQ==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/android-arm': 0.19.7 + '@esbuild/android-arm64': 0.19.7 + '@esbuild/android-x64': 0.19.7 + '@esbuild/darwin-arm64': 0.19.7 + '@esbuild/darwin-x64': 0.19.7 + '@esbuild/freebsd-arm64': 0.19.7 + '@esbuild/freebsd-x64': 0.19.7 + '@esbuild/linux-arm': 0.19.7 + '@esbuild/linux-arm64': 0.19.7 + '@esbuild/linux-ia32': 0.19.7 + '@esbuild/linux-loong64': 0.19.7 + '@esbuild/linux-mips64el': 0.19.7 + '@esbuild/linux-ppc64': 0.19.7 + '@esbuild/linux-riscv64': 0.19.7 + '@esbuild/linux-s390x': 0.19.7 + '@esbuild/linux-x64': 0.19.7 + '@esbuild/netbsd-x64': 0.19.7 + '@esbuild/openbsd-x64': 0.19.7 + '@esbuild/sunos-x64': 0.19.7 + '@esbuild/win32-arm64': 0.19.7 + '@esbuild/win32-ia32': 0.19.7 + '@esbuild/win32-x64': 0.19.7 + dev: true + + /escalade@3.1.1: + resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} + engines: {node: '>=6'} + dev: true + + /escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + dev: true + + /escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + dev: true + + /eslint-plugin-react-hooks@4.6.0(eslint@8.54.0): + resolution: {integrity: sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==} + engines: {node: '>=10'} + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 + dependencies: + eslint: 8.54.0 + dev: true + + /eslint-plugin-react-refresh@0.4.4(eslint@8.54.0): + resolution: {integrity: sha512-eD83+65e8YPVg6603Om2iCIwcQJf/y7++MWm4tACtEswFLYMwxwVWAfwN+e19f5Ad/FOyyNg9Dfi5lXhH3Y3rA==} + peerDependencies: + eslint: '>=7' + dependencies: + eslint: 8.54.0 + dev: true + + /eslint-plugin-react@7.33.2(eslint@8.54.0): + resolution: {integrity: sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==} + engines: {node: '>=4'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 + dependencies: + array-includes: 3.1.7 + array.prototype.flatmap: 1.3.2 + array.prototype.tosorted: 1.1.2 + doctrine: 2.1.0 + es-iterator-helpers: 1.0.15 + eslint: 8.54.0 + estraverse: 5.3.0 + jsx-ast-utils: 3.3.5 + minimatch: 3.1.2 + object.entries: 1.1.7 + object.fromentries: 2.0.7 + object.hasown: 1.1.3 + object.values: 1.1.7 + prop-types: 15.8.1 + resolve: 2.0.0-next.5 + semver: 6.3.1 + string.prototype.matchall: 4.0.10 + 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 + + /fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + 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 + + /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 + + /fill-range@7.0.1: + resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} + engines: {node: '>=8'} + dependencies: + to-regex-range: 5.0.1 + + /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 + + /for-each@0.3.3: + resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} + dependencies: + is-callable: 1.2.7 + dev: true + + /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 + optional: true + + /function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + dev: true + + /function.prototype.name@1.1.6: + resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + functions-have-names: 1.2.3 + dev: true + + /functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + dev: true + + /gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + 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: true + + /get-symbol-description@1.0.0: + resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + get-intrinsic: 1.2.2 + dev: true + + /glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + dependencies: + is-glob: 4.0.3 + + /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@11.12.0: + resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} + engines: {node: '>=4'} + dev: true + + /globals@13.23.0: + resolution: {integrity: sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==} + engines: {node: '>=8'} + dependencies: + type-fest: 0.20.2 + dev: true + + /globalthis@1.0.3: + resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} + engines: {node: '>= 0.4'} + dependencies: + define-properties: 1.2.1 + dev: true + + /gopd@1.0.1: + resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + dependencies: + get-intrinsic: 1.2.2 + dev: true + + /graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + dev: true + + /has-bigints@1.0.2: + resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} + dev: true + + /has-flag@3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} + dev: true + + /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: true + + /has-proto@1.0.1: + resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} + engines: {node: '>= 0.4'} + dev: true + + /has-symbols@1.0.3: + resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} + engines: {node: '>= 0.4'} + dev: true + + /has-tostringtag@1.0.0: + resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==} + engines: {node: '>= 0.4'} + dependencies: + has-symbols: 1.0.3 + dev: true + + /hasown@2.0.0: + resolution: {integrity: sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==} + engines: {node: '>= 0.4'} + dependencies: + function-bind: 1.1.2 + dev: true + + /ignore@5.3.0: + resolution: {integrity: sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==} + engines: {node: '>= 4'} + dev: true + + /immer@9.0.21: + resolution: {integrity: sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==} + dev: false + + /immutable@4.3.4: + resolution: {integrity: sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==} + + /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 + + /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==} + dev: true + + /internal-slot@1.0.6: + resolution: {integrity: sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.2 + hasown: 2.0.0 + side-channel: 1.0.4 + dev: true + + /is-array-buffer@3.0.2: + resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==} + dependencies: + call-bind: 1.0.5 + get-intrinsic: 1.2.2 + is-typed-array: 1.1.12 + dev: true + + /is-async-function@2.0.0: + resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.0 + dev: true + + /is-bigint@1.0.4: + resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} + dependencies: + has-bigints: 1.0.2 + dev: true + + /is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + dependencies: + binary-extensions: 2.2.0 + + /is-boolean-object@1.1.2: + resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + has-tostringtag: 1.0.0 + dev: true + + /is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + dev: true + + /is-core-module@2.13.1: + resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} + dependencies: + hasown: 2.0.0 + dev: true + + /is-date-object@1.0.5: + resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.0 + dev: true + + /is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + /is-finalizationregistry@1.0.2: + resolution: {integrity: sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==} + dependencies: + call-bind: 1.0.5 + 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: true + + /is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + dependencies: + is-extglob: 2.1.1 + + /is-map@2.0.2: + resolution: {integrity: sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==} + dev: true + + /is-negative-zero@2.0.2: + resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==} + engines: {node: '>= 0.4'} + dev: true + + /is-number-object@1.0.7: + resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.0 + dev: true + + /is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + /is-path-inside@3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + dev: true + + /is-regex@1.1.4: + resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + has-tostringtag: 1.0.0 + dev: true + + /is-set@2.0.2: + resolution: {integrity: sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==} + dev: true + + /is-shared-array-buffer@1.0.2: + resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==} + dependencies: + call-bind: 1.0.5 + dev: true + + /is-string@1.0.7: + resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.0 + dev: true + + /is-symbol@1.0.4: + resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} + engines: {node: '>= 0.4'} + dependencies: + has-symbols: 1.0.3 + dev: true + + /is-typed-array@1.1.12: + resolution: {integrity: sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==} + engines: {node: '>= 0.4'} + dependencies: + which-typed-array: 1.1.13 + dev: true + + /is-weakmap@2.0.1: + resolution: {integrity: sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==} + dev: true + + /is-weakref@1.0.2: + resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} + dependencies: + call-bind: 1.0.5 + dev: true + + /is-weakset@2.0.2: + resolution: {integrity: sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==} + dependencies: + call-bind: 1.0.5 + get-intrinsic: 1.2.2 + dev: true + + /isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + dev: true + + /isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + dev: true + + /iterator.prototype@1.1.2: + resolution: {integrity: sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==} + dependencies: + define-properties: 1.2.1 + get-intrinsic: 1.2.2 + has-symbols: 1.0.3 + reflect.getprototypeof: 1.0.4 + set-function-name: 2.0.1 + dev: true + + /js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + /js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + dependencies: + argparse: 2.0.1 + dev: true + + /jsesc@2.5.2: + resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} + engines: {node: '>=4'} + hasBin: true + 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-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + dev: true + + /json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + dev: true + + /jsx-ast-utils@3.3.5: + resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} + engines: {node: '>=4.0'} + dependencies: + array-includes: 3.1.7 + array.prototype.flat: 1.3.2 + object.assign: 4.1.4 + object.values: 1.1.7 + dev: true + + /keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + dependencies: + json-buffer: 3.0.1 + dev: true + + /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.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + dev: true + + /loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + dependencies: + js-tokens: 4.0.0 + + /lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + dependencies: + yallist: 3.1.1 + dev: true + + /minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + dependencies: + brace-expansion: 1.1.11 + dev: true + + /ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + dev: true + + /nanoid@3.3.7: + resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + dev: true + + /natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + dev: true + + /node-releases@2.0.13: + resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==} + dev: true + + /normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + /object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + dev: true + + /object-inspect@1.13.1: + resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} + dev: true + + /object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + dev: true + + /object.assign@4.1.4: + resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + has-symbols: 1.0.3 + object-keys: 1.1.1 + dev: true + + /object.entries@1.1.7: + resolution: {integrity: sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + dev: true + + /object.fromentries@2.0.7: + resolution: {integrity: sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + dev: true + + /object.hasown@1.1.3: + resolution: {integrity: sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA==} + dependencies: + define-properties: 1.2.1 + es-abstract: 1.22.3 + dev: true + + /object.values@1.1.7: + resolution: {integrity: sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + dev: true + + /once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + dependencies: + wrappy: 1.0.2 + 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 + + /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-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + dev: true + + /picocolors@1.0.0: + resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + dev: true + + /picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + /postcss@8.4.31: + resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.7 + picocolors: 1.0.0 + source-map-js: 1.0.2 + dev: true + + /prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + dev: true + + /prop-types@15.8.1: + resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + dependencies: + loose-envify: 1.4.0 + object-assign: 4.1.1 + react-is: 16.13.1 + dev: true + + /punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + dev: true + + /queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + dev: true + + /react-dom@18.2.0(react@18.2.0): + resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} + peerDependencies: + react: ^18.2.0 + dependencies: + loose-envify: 1.4.0 + react: 18.2.0 + scheduler: 0.23.0 + dev: false + + /react-is@16.13.1: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + dev: true + + /react-refresh@0.14.0: + resolution: {integrity: sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==} + engines: {node: '>=0.10.0'} + dev: true + + /react-router-dom@6.20.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-CbcKjEyiSVpA6UtCHOIYLUYn/UJfwzp55va4yEfpk7JBN3GPqWfHrdLkAvNCcpXr8QoihcDMuk0dzWZxtlB/mQ==} + engines: {node: '>=14.0.0'} + peerDependencies: + react: '>=16.8' + react-dom: '>=16.8' + dependencies: + '@remix-run/router': 1.13.0 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + react-router: 6.20.0(react@18.2.0) + dev: false + + /react-router@6.20.0(react@18.2.0): + resolution: {integrity: sha512-pVvzsSsgUxxtuNfTHC4IxjATs10UaAtvLGVSA1tbUE4GDaOSU1Esu2xF5nWLz7KPiMuW8BJWuPFdlGYJ7/rW0w==} + engines: {node: '>=14.0.0'} + peerDependencies: + react: '>=16.8' + dependencies: + '@remix-run/router': 1.13.0 + react: 18.2.0 + dev: false + + /react@18.2.0: + resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} + engines: {node: '>=0.10.0'} + dependencies: + loose-envify: 1.4.0 + dev: false + + /readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + dependencies: + picomatch: 2.3.1 + + /redux-thunk@2.4.2(redux@4.2.1): + resolution: {integrity: sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==} + peerDependencies: + redux: ^4 + dependencies: + redux: 4.2.1 + dev: false + + /redux@4.2.1: + resolution: {integrity: sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==} + dependencies: + '@babel/runtime': 7.23.4 + dev: false + + /reflect.getprototypeof@1.0.4: + resolution: {integrity: sha512-ECkTw8TmJwW60lOTR+ZkODISW6RQ8+2CL3COqtiJKLd6MmB45hN51HprHFziKLGkAuTGQhBb91V8cy+KHlaCjw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + get-intrinsic: 1.2.2 + globalthis: 1.0.3 + which-builtin-type: 1.1.3 + dev: true + + /regenerator-runtime@0.14.0: + resolution: {integrity: sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==} + dev: false + + /regexp.prototype.flags@1.5.1: + resolution: {integrity: sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + set-function-name: 2.0.1 + dev: true + + /reselect@4.1.8: + resolution: {integrity: sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ==} + dev: false + + /resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + dev: true + + /resolve@2.0.0-next.5: + resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} + hasBin: true + dependencies: + is-core-module: 2.13.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + dev: true + + /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 + + /rollup@4.5.2: + resolution: {integrity: sha512-CRK1uoROBfkcqrZKyaFcqCcZWNsvJ6yVYZkqTlRocZhO2s5yER6Z3f/QaYtO8RGyloPnmhwgzuPQpNGeK210xQ==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.5.2 + '@rollup/rollup-android-arm64': 4.5.2 + '@rollup/rollup-darwin-arm64': 4.5.2 + '@rollup/rollup-darwin-x64': 4.5.2 + '@rollup/rollup-linux-arm-gnueabihf': 4.5.2 + '@rollup/rollup-linux-arm64-gnu': 4.5.2 + '@rollup/rollup-linux-arm64-musl': 4.5.2 + '@rollup/rollup-linux-x64-gnu': 4.5.2 + '@rollup/rollup-linux-x64-musl': 4.5.2 + '@rollup/rollup-win32-arm64-msvc': 4.5.2 + '@rollup/rollup-win32-ia32-msvc': 4.5.2 + '@rollup/rollup-win32-x64-msvc': 4.5.2 + fsevents: 2.3.3 + dev: true + + /run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + dependencies: + queue-microtask: 1.2.3 + dev: true + + /safe-array-concat@1.0.1: + resolution: {integrity: sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==} + engines: {node: '>=0.4'} + dependencies: + call-bind: 1.0.5 + get-intrinsic: 1.2.2 + has-symbols: 1.0.3 + isarray: 2.0.5 + dev: true + + /safe-regex-test@1.0.0: + resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==} + dependencies: + call-bind: 1.0.5 + get-intrinsic: 1.2.2 + is-regex: 1.1.4 + dev: true + + /sass@1.69.5: + resolution: {integrity: sha512-qg2+UCJibLr2LCVOt3OlPhr/dqVHWOa9XtZf2OjbLs/T4VPSJ00udtgJxH3neXZm+QqX8B+3cU7RaLqp1iVfcQ==} + engines: {node: '>=14.0.0'} + hasBin: true + dependencies: + chokidar: 3.5.3 + immutable: 4.3.4 + source-map-js: 1.0.2 + + /scheduler@0.23.0: + resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==} + dependencies: + loose-envify: 1.4.0 + dev: false + + /semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + dev: true + + /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: true + + /set-function-name@2.0.1: + resolution: {integrity: sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.1 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.1 + dev: true + + /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: true + + /source-map-js@1.0.2: + resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} + engines: {node: '>=0.10.0'} + + /string.prototype.matchall@4.0.10: + resolution: {integrity: sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ==} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + get-intrinsic: 1.2.2 + has-symbols: 1.0.3 + internal-slot: 1.0.6 + regexp.prototype.flags: 1.5.1 + set-function-name: 2.0.1 + side-channel: 1.0.4 + dev: true + + /string.prototype.trim@1.2.8: + resolution: {integrity: sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + dev: true + + /string.prototype.trimend@1.0.7: + resolution: {integrity: sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + dev: true + + /string.prototype.trimstart@1.0.7: + resolution: {integrity: sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + dev: true + + /strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + dependencies: + ansi-regex: 5.0.1 + 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 + dev: true + + /supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + dependencies: + has-flag: 4.0.0 + dev: true + + /supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + dev: true + + /text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + dev: true + + /to-fast-properties@2.0.0: + resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} + engines: {node: '>=4'} + 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 + + /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 + + /typed-array-buffer@1.0.0: + resolution: {integrity: sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + get-intrinsic: 1.2.2 + is-typed-array: 1.1.12 + dev: true + + /typed-array-byte-length@1.0.0: + resolution: {integrity: sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + for-each: 0.3.3 + has-proto: 1.0.1 + is-typed-array: 1.1.12 + dev: true + + /typed-array-byte-offset@1.0.0: + resolution: {integrity: sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.5 + call-bind: 1.0.5 + for-each: 0.3.3 + has-proto: 1.0.1 + is-typed-array: 1.1.12 + dev: true + + /typed-array-length@1.0.4: + resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==} + dependencies: + call-bind: 1.0.5 + for-each: 0.3.3 + is-typed-array: 1.1.12 + dev: true + + /unbox-primitive@1.0.2: + resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} + dependencies: + call-bind: 1.0.5 + has-bigints: 1.0.2 + has-symbols: 1.0.3 + which-boxed-primitive: 1.0.2 + dev: true + + /update-browserslist-db@1.0.13(browserslist@4.22.1): + resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + dependencies: + browserslist: 4.22.1 + escalade: 3.1.1 + picocolors: 1.0.0 + dev: true + + /uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + dependencies: + punycode: 2.3.1 + dev: true + + /vite@5.0.2(sass@1.69.5): + resolution: {integrity: sha512-6CCq1CAJCNM1ya2ZZA7+jS2KgnhbzvxakmlIjN24cF/PXhRMzpM/z8QgsVJA/Dm5fWUWnVEsmtBoMhmerPxT0g==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || >=20.0.0 + less: '*' + lightningcss: ^1.21.0 + sass: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + dependencies: + esbuild: 0.19.7 + postcss: 8.4.31 + rollup: 4.5.2 + sass: 1.69.5 + optionalDependencies: + fsevents: 2.3.3 + dev: true + + /which-boxed-primitive@1.0.2: + resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} + dependencies: + is-bigint: 1.0.4 + is-boolean-object: 1.1.2 + is-number-object: 1.0.7 + is-string: 1.0.7 + is-symbol: 1.0.4 + dev: true + + /which-builtin-type@1.1.3: + resolution: {integrity: sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==} + engines: {node: '>= 0.4'} + dependencies: + function.prototype.name: 1.1.6 + has-tostringtag: 1.0.0 + is-async-function: 2.0.0 + is-date-object: 1.0.5 + is-finalizationregistry: 1.0.2 + is-generator-function: 1.0.10 + is-regex: 1.1.4 + is-weakref: 1.0.2 + isarray: 2.0.5 + which-boxed-primitive: 1.0.2 + which-collection: 1.0.1 + which-typed-array: 1.1.13 + dev: true + + /which-collection@1.0.1: + resolution: {integrity: sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==} + dependencies: + is-map: 2.0.2 + is-set: 2.0.2 + is-weakmap: 2.0.1 + is-weakset: 2.0.2 + dev: true + + /which-typed-array@1.1.13: + resolution: {integrity: sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.5 + call-bind: 1.0.5 + for-each: 0.3.3 + gopd: 1.0.1 + has-tostringtag: 1.0.0 + dev: true + + /which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + dependencies: + isexe: 2.0.0 + dev: true + + /wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + dev: true + + /yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + dev: true + + /yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + dev: true diff --git a/reference/P01CentralControl/vision/public/loading.css b/reference/P01CentralControl/vision/public/loading.css new file mode 100644 index 0000000..07f6728 --- /dev/null +++ b/reference/P01CentralControl/vision/public/loading.css @@ -0,0 +1,76 @@ +body{ + background: #111111; +} +#root{ + position: relative; + background: #fefefe; + height: 100vh; + width: 100vw; +} +.openRoot{ + animation: openRoot linear 1500ms; +} +#loading { + position: fixed; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + min-height: 200px; + min-width: 200px; + + display: flex; + align-items: center; + justify-content: center; + +} +#loaderBox{ + opacity: 1; + transition: opacity linear 500ms; +} +.hideLoader{ + opacity: 0 !important; +} + + +#loader { + position: relative; + width: 60px; + aspect-ratio: 2; + --_g: no-repeat radial-gradient(circle closest-side, #aaa 90%, #fff0); + background: var(--_g) 0% 50%, var(--_g) 50% 50%, var(--_g) 100% 50%; + background-size: calc(100% / 3) 50%; + animation: l3 1s infinite linear; +} +#loaderText{ + position: relative; + text-align: center; + color: #fefefe; + line-height: 40px; + user-select: none; + color: #666; +} + + +@keyframes l3 { + 20% { + background-position: 0% 0%, 50% 50%, 100% 50%; + } + 40% { + background-position: 0% 100%, 50% 0%, 100% 50%; + } + 60% { + background-position: 0% 50%, 50% 100%, 100% 0%; + } + 80% { + background-position: 0% 50%, 50% 50%, 100% 100%; + } +} +@keyframes openRoot { + from{ + transform: scale(0.7) + } + to{ + transform: scale(1) + } +} diff --git a/reference/P01CentralControl/vision/public/reset.css b/reference/P01CentralControl/vision/public/reset.css new file mode 100644 index 0000000..9d802ac --- /dev/null +++ b/reference/P01CentralControl/vision/public/reset.css @@ -0,0 +1,48 @@ +/* http://meyerweb.com/eric/tools/css/reset/ + v2.0 | 20110126 + License: none (public domain) +*/ + +html, body, div, span, applet, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, +del, dfn, em, img, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, +b, u, i, center, +dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td, +article, aside, canvas, details, embed, +figure, figcaption, footer, header, hgroup, +menu, nav, output, ruby, section, summary, +time, mark, audio, video { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; +} +/* HTML5 display-role reset for older browsers */ +article, aside, details, figcaption, figure, +footer, header, hgroup, menu, nav, section { + display: block; +} +body { + line-height: 1; +} +ol, ul { + list-style: none; +} +blockquote, q { + quotes: none; +} +blockquote:before, blockquote:after, +q:before, q:after { + content: ''; + content: none; +} +table { + border-collapse: collapse; + border-spacing: 0; +} diff --git a/reference/P01CentralControl/vision/public/vite.svg b/reference/P01CentralControl/vision/public/vite.svg new file mode 100644 index 0000000..e7b8dfb --- /dev/null +++ b/reference/P01CentralControl/vision/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/reference/P01CentralControl/vision/src/App.jsx b/reference/P01CentralControl/vision/src/App.jsx new file mode 100644 index 0000000..babf152 --- /dev/null +++ b/reference/P01CentralControl/vision/src/App.jsx @@ -0,0 +1,13 @@ +import {useRoutes} from "react-router-dom"; +import routes from "@routes"; + +function App() { + const elements = useRoutes(routes) + return ( + <> + {elements} + + ) +} + +export default App diff --git a/reference/P01CentralControl/vision/src/Components/HtmlLoading/Eye/index.jsx b/reference/P01CentralControl/vision/src/Components/HtmlLoading/Eye/index.jsx new file mode 100644 index 0000000..c97285c --- /dev/null +++ b/reference/P01CentralControl/vision/src/Components/HtmlLoading/Eye/index.jsx @@ -0,0 +1,7 @@ +import css from './index.module.scss'; + +export default function Eye(){ + return
+
+
+} diff --git a/reference/P01CentralControl/vision/src/Components/HtmlLoading/Eye/index.module.scss b/reference/P01CentralControl/vision/src/Components/HtmlLoading/Eye/index.module.scss new file mode 100644 index 0000000..01f7c8c --- /dev/null +++ b/reference/P01CentralControl/vision/src/Components/HtmlLoading/Eye/index.module.scss @@ -0,0 +1,38 @@ +.Eye{ + position: relative; + height: 200px; + width: 100%; + background: #333333; + display: flex; + align-items: center; + justify-content: center; + + .loader { + display: inline-flex; + gap: 10px; + } + + .loader:before, + .loader:after { + content: ""; + height: 20px; + aspect-ratio: 1; + border-radius: 50%; + background: radial-gradient(farthest-side,#000 95%,#0000) 35% 35%/6px 6px no-repeat + #fff; + transform: scaleX(var(--s,1)) rotate(0deg); + animation: l6 1s infinite linear; + } + + .loader:after { + --s: -1; + animation-delay: -0.1s; + } + + @keyframes l6 { + 100% { + transform: scaleX(var(--s,1)) rotate(360deg); + } + } + +} diff --git a/reference/P01CentralControl/vision/src/Components/HtmlLoading/One/index.jsx b/reference/P01CentralControl/vision/src/Components/HtmlLoading/One/index.jsx new file mode 100644 index 0000000..9d814ef --- /dev/null +++ b/reference/P01CentralControl/vision/src/Components/HtmlLoading/One/index.jsx @@ -0,0 +1,6 @@ +import css from './index.module.scss' +export default function One(){ + return
+
+
+} diff --git a/reference/P01CentralControl/vision/src/Components/HtmlLoading/One/index.module.scss b/reference/P01CentralControl/vision/src/Components/HtmlLoading/One/index.module.scss new file mode 100644 index 0000000..a941bda --- /dev/null +++ b/reference/P01CentralControl/vision/src/Components/HtmlLoading/One/index.module.scss @@ -0,0 +1,51 @@ +.One{ + position: relative; + height: 200px; + width: 100%; + display: flex; + align-items: center; + justify-content: center; + + + .loader { + position: relative; + display: block; + width: 44px; + height: 44px; + font-size: 15px; + box-shadow: 9px 9px 33px #d1d1d1, -9px -9px 33px #ffffff; + } + + .loader::before, + .loader::after { + content: ''; + position: absolute; + display: block; + } + + .loader_bubble::before { + top: 10px; + left: 10px; + width: 10px; + height: 10px; + background: #fff; + border-radius: 50%; + } + + .loader_bubble { + background: linear-gradient(180deg, rgb(0, 91, 228) 10%, rgb(75, 127, 240) 100%); + border-radius: 50%; + transform-origin: 50% 50%; + animation: bubble7234 1200ms cubic-bezier(0.645, 0.045, 0.355, 1) infinite; + } + + @keyframes bubble7234 { + 0% { + transform: translate3d(0,0,0) rotate(0); + } + + 100% { + transform: translate3d(0,0,0) rotate(360deg); + } + } +} diff --git a/reference/P01CentralControl/vision/src/Components/HtmlLoading/Pacman/index.jsx b/reference/P01CentralControl/vision/src/Components/HtmlLoading/Pacman/index.jsx new file mode 100644 index 0000000..173d198 --- /dev/null +++ b/reference/P01CentralControl/vision/src/Components/HtmlLoading/Pacman/index.jsx @@ -0,0 +1,15 @@ +import css from './index.module.scss' + +export default function Pacman(){ + return
+
+
+
+
+
+
+
+
+
+
+} diff --git a/reference/P01CentralControl/vision/src/Components/HtmlLoading/Pacman/index.module.scss b/reference/P01CentralControl/vision/src/Components/HtmlLoading/Pacman/index.module.scss new file mode 100644 index 0000000..4d9a65e --- /dev/null +++ b/reference/P01CentralControl/vision/src/Components/HtmlLoading/Pacman/index.module.scss @@ -0,0 +1,123 @@ +.Pacman{ + position: relative; + height: 200px; + width: 100%; + display: flex; + align-items: center; + justify-content: center; + background: #333333; + + .loader-wrapper { + position: relative; + //top: 0; + //left: 0; + //bottom: 0; + //right: 0; + //margin: auto; + } + + .loader-wrapper .packman::before { + content: ''; + position: absolute; + width: 50px; + height: 25px; + background-color: #EFF107; + border-radius: 100px 100px 0 0; + transform: translate(-50%, -50%); + animation: pac-top 0.5s linear infinite; + transform-origin: center bottom; + } + + .loader-wrapper .packman::after { + content: ''; + position: absolute; + width: 50px; + height: 25px; + background-color: #EFF107; + border-radius: 0 0 100px 100px; + transform: translate(-50%, 50%); + animation: pac-bot 0.5s linear infinite; + transform-origin: center top; + } + + @keyframes pac-top { + 0% { + transform: translate(-50%, -50%) rotate(0) + } + + 50% { + transform: translate(-50%, -50%) rotate(-30deg) + } + + 100% { + transform: translate(-50%, -50%) rotate(0) + } + } + + @keyframes pac-bot { + 0% { + transform: translate(-50%, 50%) rotate(0) + } + + 50% { + transform: translate(-50%, 50%) rotate(30deg) + } + + 100% { + transform: translate(-50%, 50%) rotate(0) + } + } + + .dot { + position: absolute; + z-index: -1; + top: 8px; + width: 10px; + height: 10px; + border-radius: 50%; + background: #fff; + } + + .dots .dot:nth-child(1) { + left: 90px; + animation: dot-stage1 0.5s infinite; + } + + .dots .dot:nth-child(2) { + left: 60px; + animation: dot-stage1 0.5s infinite; + } + + .dots .dot:nth-child(3) { + left: 30px; + animation: dot-stage1 0.5s infinite; + } + + .dots .dot:nth-child(4) { + left: 10px; + animation: dot-stage2 0.5s infinite; + } + + @keyframes dot-stage1 { + 0% { + transform: translate(0, 0); + } + + 100% { + transform: translate(-24px, 0); + } + } + + @keyframes dot-stage2 { + 0% { + transform: scale(1); + } + + 5%, 100% { + transform: scale(0); + } + } + + + +} diff --git a/reference/P01CentralControl/vision/src/Components/HtmlLoading/TableTennis/index.jsx b/reference/P01CentralControl/vision/src/Components/HtmlLoading/TableTennis/index.jsx new file mode 100644 index 0000000..3e05a02 --- /dev/null +++ b/reference/P01CentralControl/vision/src/Components/HtmlLoading/TableTennis/index.jsx @@ -0,0 +1,9 @@ +import css from './index.module.scss' + +export default function TableTennis(){ + return
+
+
+
+
+} diff --git a/reference/P01CentralControl/vision/src/Components/HtmlLoading/TableTennis/index.module.scss b/reference/P01CentralControl/vision/src/Components/HtmlLoading/TableTennis/index.module.scss new file mode 100644 index 0000000..b3e8d4e --- /dev/null +++ b/reference/P01CentralControl/vision/src/Components/HtmlLoading/TableTennis/index.module.scss @@ -0,0 +1,65 @@ +.TableTennis{ + position: relative; + height: 200px; + width: 100%; + background: #333; +} + + +$up-down6123 : up-down6123; +$ball-move8234: ball-move8234; + +.ball { + position: relative; + bottom: 50px; + left: calc(100% - 20px); + width: 50px; + height: 50px; + background: #fff; + border-radius: 50%; + animation: $ball-move8234 3s ease-in-out 1s infinite alternate; +} + +.ball::after { + position: absolute; + content: ''; + top: 25px; + right: 5px; + width: 5px; + height: 5px; + background: #000; + border-radius: 50%; +} + +.bar { + position: relative; + top:100px; + width: 200px; + height: 12.5px; + background: #FFDAAF; + border-radius: 30px; + transform: rotate(-15deg); + animation: $up-down6123 3s ease-in-out 1s infinite alternate; +} + +@keyframes up-down6123 { + from { + transform: rotate(-15deg); + } + + to { + transform: rotate(15deg); + } +} + +@keyframes ball-move8234 { + from { + left: calc(100% - 40px); + transform: rotate(360deg); + } + + to { + left: calc(0% - 20px); + transform: rotate(0deg); + } +} diff --git a/reference/P01CentralControl/vision/src/Components/HtmlLoading/Three/index.jsx b/reference/P01CentralControl/vision/src/Components/HtmlLoading/Three/index.jsx new file mode 100644 index 0000000..1996dad --- /dev/null +++ b/reference/P01CentralControl/vision/src/Components/HtmlLoading/Three/index.jsx @@ -0,0 +1,7 @@ +import css from './index.module.scss' + +export default function Three(){ + return
+
+
+} diff --git a/reference/P01CentralControl/vision/src/Components/HtmlLoading/Three/index.module.scss b/reference/P01CentralControl/vision/src/Components/HtmlLoading/Three/index.module.scss new file mode 100644 index 0000000..2f173af --- /dev/null +++ b/reference/P01CentralControl/vision/src/Components/HtmlLoading/Three/index.module.scss @@ -0,0 +1,34 @@ +.Three{ + position: relative; + height: 200px; + width: 100%; + display: flex; + align-items: center; + justify-content: center; + background: #111; + + + .loader { + width: 60px; + aspect-ratio: 2; + --_g: no-repeat radial-gradient(circle closest-side, #fff 90%, #fff0); + background: var(--_g) 0% 50%, var(--_g) 50% 50%, var(--_g) 100% 50%; + background-size: calc(100% / 3) 50%; + animation: l3 1s infinite linear; + } + @keyframes l3 { + 20% { + background-position: 0% 0%, 50% 50%, 100% 50%; + } + 40% { + background-position: 0% 100%, 50% 0%, 100% 50%; + } + 60% { + background-position: 0% 50%, 50% 100%, 100% 0%; + } + 80% { + background-position: 0% 50%, 50% 50%, 100% 100%; + } + } + +} diff --git a/reference/P01CentralControl/vision/src/Components/HtmlLoading/Two/index.jsx b/reference/P01CentralControl/vision/src/Components/HtmlLoading/Two/index.jsx new file mode 100644 index 0000000..8efb985 --- /dev/null +++ b/reference/P01CentralControl/vision/src/Components/HtmlLoading/Two/index.jsx @@ -0,0 +1,8 @@ +import css from './index.module.scss' + +export default function Two(){ + return
+ +
+
+} diff --git a/reference/P01CentralControl/vision/src/Components/HtmlLoading/Two/index.module.scss b/reference/P01CentralControl/vision/src/Components/HtmlLoading/Two/index.module.scss new file mode 100644 index 0000000..866fa72 --- /dev/null +++ b/reference/P01CentralControl/vision/src/Components/HtmlLoading/Two/index.module.scss @@ -0,0 +1,163 @@ +.Two{ + position: relative; + height: 200px; + width: 100%; + display: flex; + align-items: center; + justify-content: center; + + + + .chaotic-orbit { + --uib-size: 25px; + --uib-speed: 1.5s; + --uib-color: black; + position: relative; + display: flex; + align-items: center; + justify-content: center; + height: var(--uib-size); + width: var(--uib-size); + animation: rotate936 calc(var(--uib-speed) * 1.667) infinite linear; + } + + .chaotic-orbit::before, + .chaotic-orbit::after { + content: ''; + position: absolute; + height: 60%; + width: 60%; + border-radius: 50%; + background-color: var(--uib-color); + will-change: transform; + flex-shrink: 0; + } + + .chaotic-orbit::before { + animation: orbit var(--uib-speed) linear infinite; + } + + .chaotic-orbit::after { + animation: orbit var(--uib-speed) linear calc(var(--uib-speed) / -2) + infinite; + } + + @keyframes rotate936 { + 0% { + transform: rotate(0deg); + } + + 100% { + transform: rotate(360deg); + } + } + + @keyframes orbit { + 0% { + transform: translate(calc(var(--uib-size) * 0.5)) scale(0.73684); + opacity: 0.65; + } + + 5% { + transform: translate(calc(var(--uib-size) * 0.4)) scale(0.684208); + opacity: 0.58; + } + + 10% { + transform: translate(calc(var(--uib-size) * 0.3)) scale(0.631576); + opacity: 0.51; + } + + 15% { + transform: translate(calc(var(--uib-size) * 0.2)) scale(0.578944); + opacity: 0.44; + } + + 20% { + transform: translate(calc(var(--uib-size) * 0.1)) scale(0.526312); + opacity: 0.37; + } + + 25% { + transform: translate(0%) scale(0.47368); + opacity: 0.3; + } + + 30% { + transform: translate(calc(var(--uib-size) * -0.1)) scale(0.526312); + opacity: 0.37; + } + + 35% { + transform: translate(calc(var(--uib-size) * -0.2)) scale(0.578944); + opacity: 0.44; + } + + 40% { + transform: translate(calc(var(--uib-size) * -0.3)) scale(0.631576); + opacity: 0.51; + } + + 45% { + transform: translate(calc(var(--uib-size) * -0.4)) scale(0.684208); + opacity: 0.58; + } + + 50% { + transform: translate(calc(var(--uib-size) * -0.5)) scale(0.73684); + opacity: 0.65; + } + + 55% { + transform: translate(calc(var(--uib-size) * -0.4)) scale(0.789472); + opacity: 0.72; + } + + 60% { + transform: translate(calc(var(--uib-size) * -0.3)) scale(0.842104); + opacity: 0.79; + } + + 65% { + transform: translate(calc(var(--uib-size) * -0.2)) scale(0.894736); + opacity: 0.86; + } + + 70% { + transform: translate(calc(var(--uib-size) * -0.1)) scale(0.947368); + opacity: 0.93; + } + + 75% { + transform: translate(0%) scale(1); + opacity: 1; + } + + 80% { + transform: translate(calc(var(--uib-size) * 0.1)) scale(0.947368); + opacity: 0.93; + } + + 85% { + transform: translate(calc(var(--uib-size) * 0.2)) scale(0.894736); + opacity: 0.86; + } + + 90% { + transform: translate(calc(var(--uib-size) * 0.3)) scale(0.842104); + opacity: 0.79; + } + + 95% { + transform: translate(calc(var(--uib-size) * 0.4)) scale(0.789472); + opacity: 0.72; + } + + 100% { + transform: translate(calc(var(--uib-size) * 0.5)) scale(0.73684); + opacity: 0.65; + } + } + + +} diff --git a/reference/P01CentralControl/vision/src/Components/HtmlLoading/index.jsx b/reference/P01CentralControl/vision/src/Components/HtmlLoading/index.jsx new file mode 100644 index 0000000..480709f --- /dev/null +++ b/reference/P01CentralControl/vision/src/Components/HtmlLoading/index.jsx @@ -0,0 +1,18 @@ +import React from "react"; + +const TableTennis = React.lazy(() => import('@components/HtmlLoading/TableTennis')) +const Pacman = React.lazy(() => import("@components/HtmlLoading/Pacman/index.jsx")) +const Eye = React.lazy(() => import("@components/HtmlLoading/Eye/index.jsx")) +const One = React.lazy(() => import("@components/HtmlLoading/One/index.jsx")) +const Two = React.lazy(() => import("@components/HtmlLoading/Two/index.jsx")) +const Three = React.lazy(() => import("@components/HtmlLoading/Three/index.jsx")) +export default function HtmlLoading(){ + return
+ + + + + + +
+} diff --git a/reference/P01CentralControl/vision/src/main.jsx b/reference/P01CentralControl/vision/src/main.jsx new file mode 100644 index 0000000..8ee591c --- /dev/null +++ b/reference/P01CentralControl/vision/src/main.jsx @@ -0,0 +1,30 @@ +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.jsx' +import {BrowserRouter} from "react-router-dom"; +import PrivateRoute from "@routes/PrivateRoute.jsx"; + +ReactDOM.createRoot(document.getElementById('root')).render( + + + + + + + , +) + + +window.onload = function (){ + // 当所有资源加载完毕 + // 主加载框 + const loader = document.querySelector('#loading'); + // 加载动画 + const loaderBox = document.querySelector('#loaderBox'); + // 加载动画开始隐藏 + loaderBox.classList.add('hideLoader') + // 到时间移除加载框 + setTimeout(() => { + loader.remove() + }, 500) +} diff --git a/reference/P01CentralControl/vision/src/routes/PrivateRoute.jsx b/reference/P01CentralControl/vision/src/routes/PrivateRoute.jsx new file mode 100644 index 0000000..83c253a --- /dev/null +++ b/reference/P01CentralControl/vision/src/routes/PrivateRoute.jsx @@ -0,0 +1,18 @@ +import {useEffect} from "react"; +import { useLocation, useParams, useNavigate } from 'react-router-dom'; +export default function PrivateRoute(props){ + const location = useLocation(); + const params = useParams(); + const navigate = useNavigate() + useEffect(() => { + // console.log(location.pathname); // 获取当前路由路径 + // console.log(location.search); // 获取查询字符串 + // console.log(location.hash); // 获取 URL 中的哈希值 + // console.log(params); // 假设 URL 中有一个名为 "id" 的参数 + if(location.pathname == '/test'){ + navigate('/') + } + }, [0]); + + return props.children +} diff --git a/reference/P01CentralControl/vision/src/routes/index.jsx b/reference/P01CentralControl/vision/src/routes/index.jsx new file mode 100644 index 0000000..3113cd8 --- /dev/null +++ b/reference/P01CentralControl/vision/src/routes/index.jsx @@ -0,0 +1,48 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: react-template +// | @文件描述: index.jsx - +// | @创建时间: 2023-11-26 16:05 +// | @更新时间: 2023-11-26 16:05 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ + +import { Navigate } from 'react-router-dom' +import React, {lazy} from "react"; + +const Test = React.lazy(() => import("@views/Test/index.jsx")) +const HtmlLoading = React.lazy(() => import("@components/HtmlLoading/index.jsx")) + +// 首页 +const Index = lazy(() => { + console.log('开始加载') + console.time(1) + const components = import('@views/Index/index.jsx') + console.log('加载完成') + console.timeEnd(1) + return components +}) + + +const routes = [ + { + path: '/about', + element: + }, { + path: '/home', + element: + }, /*{ + path: '/', + element: + }*/, { + path: '/', + element: + } +] + +export default routes + diff --git a/reference/P01CentralControl/vision/src/store/index.js b/reference/P01CentralControl/vision/src/store/index.js new file mode 100644 index 0000000..264cf9a --- /dev/null +++ b/reference/P01CentralControl/vision/src/store/index.js @@ -0,0 +1,23 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: react-template +// | @文件描述: index.js - +// | @创建时间: 2023-11-26 16:47 +// | @更新时间: 2023-11-26 16:47 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ + +import { configureStore } from '@reduxjs/toolkit'; +import DefaultSlice from "@/store/slice/defaultSlice.js"; + +const store = configureStore({ + reducer: { + defaultSlice: DefaultSlice, + }, +}); + +export default store; diff --git a/reference/P01CentralControl/vision/src/store/slice/defaultSlice.js b/reference/P01CentralControl/vision/src/store/slice/defaultSlice.js new file mode 100644 index 0000000..98ffb46 --- /dev/null +++ b/reference/P01CentralControl/vision/src/store/slice/defaultSlice.js @@ -0,0 +1,63 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: react-template +// | @文件描述: defaultSlice.js - +// | @创建时间: 2023-11-26 17:20 +// | @更新时间: 2023-11-26 17:20 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ + + +import {createAsyncThunk, createSlice} from '@reduxjs/toolkit'; + +export const decremented = createAsyncThunk( + 'user/fetchData', + async (data, thunkAPI) => { + // 调用API + console.log(data, thunkAPI) + await new Promise(res => { + + setTimeout(() =>{ + res() + }, 1000) + }) + return; // 或根据你的API返回结构进行调整 + } +); + + +export const defaultSlice = createSlice({ + name: 'defaultSlice', + initialState: { + value: 0, + }, + reducers: { + incremented: (state,b) => { + state.value += 1; + }, + }, + extraReducers: { + // 当 fetchUserData action 被派发时,根据 action 的不同状态对 state 进行更新 + [decremented.pending]: (state, action) => { + // state.isLoading = true; + // state.error = null; + }, + [decremented.fulfilled]: (state, action) => { + // state.isLoading = false; + // state.data = action.payload; // 假设我们的API返回了用户的数据结构 + state.value -= 1; + }, + [decremented.rejected]: (state, action) => { + // state.isLoading = false; + // state.error = action.error.message; + }, + }, +}); + +export const { incremented } = defaultSlice.actions; + +export default defaultSlice.reducer; diff --git a/reference/P01CentralControl/vision/src/views/Index/index.jsx b/reference/P01CentralControl/vision/src/views/Index/index.jsx new file mode 100644 index 0000000..74d4a9c --- /dev/null +++ b/reference/P01CentralControl/vision/src/views/Index/index.jsx @@ -0,0 +1,14 @@ +// 本页样式 +import css from './index.module.scss' +// 主图 +import indexPhoto from './index.png' +export default function Index(){ + return
+
+
+ {/**/} +
+
+
+
+} diff --git a/reference/P01CentralControl/vision/src/views/Index/index.module.scss b/reference/P01CentralControl/vision/src/views/Index/index.module.scss new file mode 100644 index 0000000..2da8284 --- /dev/null +++ b/reference/P01CentralControl/vision/src/views/Index/index.module.scss @@ -0,0 +1,57 @@ +.Index{ + position: relative; + height: 100%; + width: 100%; + display: flex; + align-items: center; + justify-content: center; + background-image: url("index.png"); + + background-repeat: no-repeat; + background-position: center; + background-size: cover; + &:before{ + content: ' '; + position: absolute; + left: 0; + width: 0; + height: 100%; + width: 100%; + backdrop-filter: + blur(100px) // 模糊 + brightness(0.8) // 亮度 + contrast(1) // 对比度 + //grayscale(0.5) // 灰度 + //hue-rotate(90deg) // 色调 + saturate(5) + //opacity(1) + ; + //backdrop-filter: ; + } + & > div.container{ + position: relative; + border-radius: 5px; + box-shadow: 1px 1px 10px 0px #33333366; + background: #fefefe11; + padding: 10px; + box-sizing: border-box; + height: 320px; + aspect-ratio: 1/0.618; + display: flex; + & > div{ + position: relative; + flex: 1; + } + & > div.left{ + background-image: url("index.png"); + background-repeat: no-repeat; + background-position: center; + background-size: cover; + border-radius: 5px 0 0 5px; + } + & > div.right{ + + border-radius: 0 5px 5px 0; + } + } +} diff --git a/reference/P01CentralControl/vision/src/views/Index/index.png b/reference/P01CentralControl/vision/src/views/Index/index.png new file mode 100644 index 0000000..b9b7155 Binary files /dev/null and b/reference/P01CentralControl/vision/src/views/Index/index.png differ diff --git a/reference/P01CentralControl/vision/src/views/Test/index.jsx b/reference/P01CentralControl/vision/src/views/Test/index.jsx new file mode 100644 index 0000000..4467379 --- /dev/null +++ b/reference/P01CentralControl/vision/src/views/Test/index.jsx @@ -0,0 +1,24 @@ +import {useEffect, useState} from "react"; +import store from "@/store/index.js"; +import {incremented, decremented} from "@/store/slice/defaultSlice.js"; + +export default function Test(){ + + const [count, setCount] = useState(store.getState().defaultSlice.value); + + useEffect(() => { + console.log(store.getState()) + const unsubscribe = store.subscribe(() => { + setCount(store.getState().defaultSlice.value); + }); + return unsubscribe; // 在组件卸载时取消订阅 + }, []); + + + + return
+

{count}

+ + +
+} diff --git a/reference/P01CentralControl/vision/test/react-router-dom.md b/reference/P01CentralControl/vision/test/react-router-dom.md new file mode 100644 index 0000000..9c4f7f8 --- /dev/null +++ b/reference/P01CentralControl/vision/test/react-router-dom.md @@ -0,0 +1 @@ +https://blog.csdn.net/qq_30769437/article/details/128149273 diff --git a/reference/P01CentralControl/vision/test/redux.md b/reference/P01CentralControl/vision/test/redux.md new file mode 100644 index 0000000..31adbcc --- /dev/null +++ b/reference/P01CentralControl/vision/test/redux.md @@ -0,0 +1,314 @@ +如果你需要创建一个Redux应用,但不想使用react-redux和`createStore`(这通常是Redux的标准API用于创建store的方法),你可以使用Redux Toolkit中的`configureStore`作为`createStore`的替代方案来创建store。 + +Redux Toolkit 是官方推荐的方式来设置store,它提供了更简化的API和一些有用的工具,比如默认集成了redux-thunk中间件以及Redux DevTools扩展支持。下面是一个不使用react-redux的示例,但是如果你想完全不使用任何辅助工具或库,仅使用最基本的Redux API(这是不推荐的,因为你会失去许多便利和性能优化),那你将需要自己管理store的状态订阅和更新组件的渲染。 + +下面是一个不使用`createStore`和`react-redux`的Redux应用例子: + +目录结构: +``` +my-app/ + src/ + store/ + index.js // 创建和配置应用程序的Redux store + counterReducer.js // 管理计数状态的reducer + components/ + Counter.js // 一个使用Redux store的React组件 + App.js // 应用程序的根组件 + index.js // 应用程序的主入口文件 +``` + +`store/index.js`: +```javascript +import { configureStore } from '@reduxjs/toolkit'; +import counterReducer from './counterReducer'; + +const store = configureStore({ + reducer: { + counter: counterReducer, + }, +}); + +export default store; +``` + +`store/counterReducer.js`: +```javascript +const INCREMENT = 'INCREMENT'; +const DECREMENT = 'DECREMENT'; + +const initialState = { + value: 0, +}; + +function counterReducer(state = initialState, action) { + switch (action.type) { + case INCREMENT: + return { ...state, value: state.value + 1 }; + case DECREMENT: + return { ...state, value: state.value - 1 }; + default: + return state; + } +} + +export const increment = () => ({ type: INCREMENT }); +export const decrement = () => ({ type: DECREMENT }); + +export default counterReducer; +``` + +`components/Counter.js`: +```jsx +import React, { useState, useEffect } from 'react'; +import store from '../store'; +import { increment, decrement } from '../store/counterReducer'; + +export const Counter = () => { + const [count, setCount] = useState(store.getState().counter.value); + + useEffect(() => { + const unsubscribe = store.subscribe(() => { + setCount(store.getState().counter.value); + }); + return unsubscribe; // 在组件卸载时取消订阅 + }, []); + + return ( +
+

{count}

+ + +
+ ); +}; +``` + +`App.js`: +```jsx +import React from 'react'; +import { Counter } from './components/Counter'; + +const App = () => { + return ( +
+ +
+ ); +} + +export default App; +``` + +`index.js`: +```jsx +import React from 'react'; +import ReactDOM from 'react-dom'; +import App from './App'; +import store from './store'; +import { increment } from './store/counterReducer'; + +// 可以在这里测试我们的Redux store是否正常工作 +console.log(store.getState()); // 应该看到初始状态 +store.dispatch(increment()); +console.log(store.getState()); // 状态应该更新,并增加了1 + +ReactDOM.render( + + + , + document.getElementById('root') +); +``` + +在上述的示例中,我们使用`useEffect`来订阅Redux store和清理订阅,通过store的`getState`方法获取当前的状态,并通过`dispatch`方法来派发actions。这种方式下,我们没有使用react-redux,而是手动连接到Redux store并监听状态变化。 + +请注意,这样手动处理Redux可能会使你的应用程序难以管理和扩展,特别是在大型应用程序中,react-redux提供的`Provider`和`connect`方法或者hooks`useSelector`和`useDispatch`可以更好地帮助你管理连接逻辑和组件更新,提高应用的性能。 + + + + + + + + + + + + + + + + + + + + + + + + + + + +在 Redux Toolkit 中,`createSlice` 通常用于同步更新 state ,但当它与 `createAsyncThunk` 一起使用时,可以非常容易地用于异步更新。`createAsyncThunk` 会生成三种 action 类型(pending,fulfilled,rejected),你可以在 `createSlice` 的 `extraReducers` 属性中监听这些 action: + +```javascript +import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'; +import { userAPI } from './userAPI'; + +// 首先创建一个异步 thunk action +export const fetchUserData = createAsyncThunk( + 'user/fetchData', + async (userId, thunkAPI) => { + // 调用API + const response = await userAPI.fetchById(userId); + return response.data; // 或根据你的API返回结构进行调整 + } +); + +// 然后创建 slice,这里我们可以处理我们上面定义的三种状态的actions +const userSlice = createSlice({ + name: 'user', + initialState: { + data: null, + isLoading: false, + error: null, + }, + reducers: { + // 你的其他同步 reducers 可以在这里定义 + }, + extraReducers: { + // 当 fetchUserData action 被派发时,根据 action 的不同状态对 state 进行更新 + [fetchUserData.pending]: (state, action) => { + state.isLoading = true; + state.error = null; + }, + [fetchUserData.fulfilled]: (state, action) => { + state.isLoading = false; + state.data = action.payload; // 假设我们的API返回了用户的数据结构 + }, + [fetchUserData.rejected]: (state, action) => { + state.isLoading = false; + state.error = action.error.message; + }, + }, +}); + +export const { actions, reducer } = userSlice; +``` + +在这个例子中: + +- `fetchUserData.pending` 相关的 reducer 将在请求开始时将 `isLoading` 状态设置为 true。 +- `fetchUserData.fulfilled` 相关的 reducer 将在请求成功并收到数据时更新 `data` ,并将 `isLoading` 设置为 false。 +- `fetchUserData.rejected` 相关的 reducer 将在请求失败时设置错误信息,并将 `isLoading` 设置为 false。 + +通过使用 `createAsyncThunk` 和 `createSlice` 的 `extraReducers` ,我们也很方便的可以将异步行为整合到我们的 Redux state 管理中。 + + + + + + + + + + + + + +在视图(常常指的是 React 组件)中使用 `@reduxjs/toolkit` 中 `createAsyncThunk` 创建的异步 action 通常涉及以下几个步骤: + +1. 将 Redux store 和 React 组件连接起来,可以使用 `react-redux` 提供的 `useSelector` 来选择 state,以及 `useDispatch` 来派发 actions。 + +2. 创建视图(UI组件),并在适当的时候(如组件挂载或者用户互动事件)派发异步 action。 + +3. 显示加载状态、错误信息或者成功得到的数据。 + +下面是一个例子,展示了如何在一个 React 组件中使用异步 action: + +```jsx +import React, { useEffect } from 'react'; +import { useSelector, useDispatch } from 'react-redux'; +import { fetchUserData } from './userSlice'; +// 以上的 userSlice 是我们之前定义的包含 fetchUserData 异步 action 的文件 + +function UserComponent({ userId }) { + const dispatch = useDispatch(); + + // 从 Redux state 中选择数据 + const user = useSelector(state => state.user.data); + const isLoading = useSelector(state => state.user.isLoading); + const error = useSelector(state => state.user.error); + + // 当组件挂载时,派发 fetchUserData action + useEffect(() => { + dispatch(fetchUserData(userId)); + }, [userId, dispatch]); + + // 根据 state 渲染 UI + if (isLoading) { + return
Loading...
; + } + + if (error) { + return
Error: {error}
; + } + + return ( +
+

User Data

+ {/* 假设 user 对象有 name 属性 */} + {user ?

Name: {user.name}

:

No user details

} +
+ ); +} + +export default UserComponent; +``` + +在这个 React 组件中: + +- 使用 `useDispatch` hook 获取 `dispatch` 方法,以便于我们可以派发 actions。 +- 使用 `useSelector` hook 从 Redux store 中选择 `user.state` 中的各部分数据。 +- 使用 `useEffect` React hook 来触发 `fetchUserData` 异步 action。当 `userId` 改变或者组件首次渲染时会重新触发。 +- 在 UI 中根据 `isLoading`, `error`, 和 `user` 状态显示不同的内容。如果 `isLoading` 为 true,显示加载状态;如果 `error` 存在,则显示错误;否则显示用户信息。 + + + + + + + + +在 `createAsyncThunk` 中使用的 `thunkAPI` 对象是由 Redux Thunk 提供的一个参数,包含了几个有用的属性和方法,使得在 thunk 中可以执行更为复杂的逻辑。`thunkAPI` 在每次调用异步 thunk 函数时都会被提供,并且具有以下字段和方法: + +1. **dispatch**: 允许你在 thunk 中派发 action。 +2. **getState**: 允许你访问当前的 Redux store state。 +3. **extra**: 如果在创建 Redux store 的 `configureStore` 方法中定义了 `extraArgument`,则这里可以取得。 +4. **requestId**: 是对每次异步 thunk action 调用的唯一标识。 +5. **signal**: 是一个 `AbortSignal` 对象,与本次异步操作相关联,可以用来响应取消操作。 +6. **rejectWithValue**: 一个函数,允许你在发生错误时手动地派发一个拒绝 (rejected) action,并携带自定义的 payload 值。 +7. **fulfillWithValue**: 当你需要在 resolve (解决) action 中提供一个不同于异步操作返回结果的 payload 时,可以用这个函数。 +8. **rejectWithReason**: 类似 `rejectWithValue`,允许在 rejected action 中提供自定义拒绝原因,更明确地说明拒绝的原因。 + +这些功能给予开发者很大的灵活性去处理异步逻辑和实现复杂的异步操作流程。例如,使用 `dispatch` 来派发其他 actions,利用 `getState` 获取最新的 state 来指导后续逻辑,或使用 `rejectWithValue` 在出错时捕捉错误并优化错误处理。 + +以下是一个使用 `thunkAPI` 的例子: + +```javascript +export const fetchUserData = createAsyncThunk( + 'user/fetchData', + async (userId, thunkAPI) => { + try { + const response = await userAPI.fetchById(userId); + return response.data; + } catch (error) { + // 如果 API 抛出一个错误,我们可以选择发送一个拒绝action,并附带一个自定义的payload + return thunkAPI.rejectWithValue({errorMessage: 'Cannot load user data'}); + } + } +); +``` + +在这个例子中,如果 `userAPI.fetchById` 方法抛出一个错误,`thunkAPI.rejectWithValue` 方法则被用来派发一个拒绝的 action,并附上一个含错误信息的 payload。这使得 reducer 可以捕捉这个拒绝的 action,并根据附带的 payload 更新 state。 diff --git a/reference/P01CentralControl/vision/vite.config.js b/reference/P01CentralControl/vision/vite.config.js new file mode 100644 index 0000000..5385465 --- /dev/null +++ b/reference/P01CentralControl/vision/vite.config.js @@ -0,0 +1,17 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import path from 'path' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react()], + resolve: { + alias: { + '@': path.resolve(__dirname, './src'), + '@views':path.resolve(__dirname, './src/views'), + '@components': path.resolve(__dirname, './src/components'), + '@utils': path.resolve(__dirname, './src/utils'), + '@routes': path.resolve(__dirname, './src/routes') + }, + }, +}) diff --git a/reference/graphResource2/.eslintrc.cjs b/reference/graphResource2/.eslintrc.cjs new file mode 100644 index 0000000..ce0bb13 --- /dev/null +++ b/reference/graphResource2/.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/reference/graphResource2/.gitignore b/reference/graphResource2/.gitignore new file mode 100644 index 0000000..805bc40 --- /dev/null +++ b/reference/graphResource2/.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/reference/graphResource2/.prettierrc.json b/reference/graphResource2/.prettierrc.json new file mode 100644 index 0000000..f4f39af --- /dev/null +++ b/reference/graphResource2/.prettierrc.json @@ -0,0 +1,5 @@ +{ + "singleQuote": true, + "trailingComma": "all", + "tabWidth": 4 +} diff --git a/reference/graphResource2/GR3.xmind b/reference/graphResource2/GR3.xmind new file mode 100644 index 0000000..4bb5442 Binary files /dev/null and b/reference/graphResource2/GR3.xmind differ diff --git a/reference/graphResource2/OM系统资源结构实例.xmind b/reference/graphResource2/OM系统资源结构实例.xmind new file mode 100644 index 0000000..0727090 Binary files /dev/null and b/reference/graphResource2/OM系统资源结构实例.xmind differ diff --git a/reference/graphResource2/bootstrap.js b/reference/graphResource2/bootstrap.js new file mode 100644 index 0000000..c4ee125 --- /dev/null +++ b/reference/graphResource2/bootstrap.js @@ -0,0 +1,110 @@ +// | ------------------------------------------------------------ +// | @版本: 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"; +import initData from "#common/database/initData.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(`== 已成功与数据库建立连接。 ==`); + + await initData(sequelize) + + await 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/reference/graphResource2/development.env.js b/reference/graphResource2/development.env.js new file mode 100644 index 0000000..ac975ce --- /dev/null +++ b/reference/graphResource2/development.env.js @@ -0,0 +1,21 @@ +// | ------------------------------------------------------------ +// | @版本: 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 = { +} + +const devConfig = {...prodConfig, ...config} + +export default devConfig diff --git a/reference/graphResource2/gen-Model/models/init-models.js b/reference/graphResource2/gen-Model/models/init-models.js new file mode 100644 index 0000000..412134f --- /dev/null +++ b/reference/graphResource2/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/reference/graphResource2/gen-Model/models/lauchuser.js b/reference/graphResource2/gen-Model/models/lauchuser.js new file mode 100644 index 0000000..3fa6f0b --- /dev/null +++ b/reference/graphResource2/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/reference/graphResource2/gen-Model/models/lauchuserexpandfield.js b/reference/graphResource2/gen-Model/models/lauchuserexpandfield.js new file mode 100644 index 0000000..18c9177 --- /dev/null +++ b/reference/graphResource2/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/reference/graphResource2/gen-Model/models/lauchuserexpandrecord.js b/reference/graphResource2/gen-Model/models/lauchuserexpandrecord.js new file mode 100644 index 0000000..b19f526 --- /dev/null +++ b/reference/graphResource2/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/reference/graphResource2/gen-Model/models/lauchuserloginrecord.js b/reference/graphResource2/gen-Model/models/lauchuserloginrecord.js new file mode 100644 index 0000000..c1d1107 --- /dev/null +++ b/reference/graphResource2/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/reference/graphResource2/gen-Model/models/lauchuserpasswd.js b/reference/graphResource2/gen-Model/models/lauchuserpasswd.js new file mode 100644 index 0000000..ab60d82 --- /dev/null +++ b/reference/graphResource2/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/reference/graphResource2/gen-Model/models/lauchuserstructauthority.js b/reference/graphResource2/gen-Model/models/lauchuserstructauthority.js new file mode 100644 index 0000000..b18ded5 --- /dev/null +++ b/reference/graphResource2/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/reference/graphResource2/gen-Model/models/lauchuserstructorganization.js b/reference/graphResource2/gen-Model/models/lauchuserstructorganization.js new file mode 100644 index 0000000..0975916 --- /dev/null +++ b/reference/graphResource2/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/reference/graphResource2/gen-Model/models/lauchuserstructrelationorganizationaccent.js b/reference/graphResource2/gen-Model/models/lauchuserstructrelationorganizationaccent.js new file mode 100644 index 0000000..97c33f9 --- /dev/null +++ b/reference/graphResource2/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/reference/graphResource2/gen-Model/models/lauchuserstructrelationorganizationauthority.js b/reference/graphResource2/gen-Model/models/lauchuserstructrelationorganizationauthority.js new file mode 100644 index 0000000..6417ae4 --- /dev/null +++ b/reference/graphResource2/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/reference/graphResource2/gen-Model/使用方式.md b/reference/graphResource2/gen-Model/使用方式.md new file mode 100644 index 0000000..c6f1650 --- /dev/null +++ b/reference/graphResource2/gen-Model/使用方式.md @@ -0,0 +1 @@ +sequelize-auto -h 数据库的IP地址 -d 数据库名 -u 用户名 -x 密码 -p 端口 -t 表名 diff --git a/reference/graphResource2/graphResource2数据结构.xmind b/reference/graphResource2/graphResource2数据结构.xmind new file mode 100644 index 0000000..fb6d040 Binary files /dev/null and b/reference/graphResource2/graphResource2数据结构.xmind differ diff --git a/reference/graphResource2/package.json b/reference/graphResource2/package.json new file mode 100644 index 0000000..1f2e679 --- /dev/null +++ b/reference/graphResource2/package.json @@ -0,0 +1,58 @@ +{ + "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", + "start:testDev": "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": { + "axios": "^1.6.2", + "cross-env": "^7.0.3", + "eslint": "^8.52.0", + "eslint-config-prettier": "^9.0.0", + "eslint-plugin-prettier": "^5.0.0", + "loadtest": "^8.0.5", + "nodemon": "^3.0.1", + "prettier": "^3.0.3", + "sequelize-auto": "^0.8.8" + } +} diff --git a/reference/graphResource2/pnpm-lock.yaml b/reference/graphResource2/pnpm-lock.yaml new file mode 100644 index 0000000..8fd99fe --- /dev/null +++ b/reference/graphResource2/pnpm-lock.yaml @@ -0,0 +1,2618 @@ +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: + axios: + specifier: ^1.6.2 + version: 1.6.2 + 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) + loadtest: + specifier: ^8.0.5 + version: 8.0.5 + 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 + + /agent-base@4.3.0: + resolution: {integrity: sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==} + engines: {node: '>= 4.0.0'} + dependencies: + es6-promisify: 5.0.0 + dev: true + + /agentkeepalive@2.2.0: + resolution: {integrity: sha512-TnB6ziK363p7lR8QpeLC8aMr8EGYBKZTpgzQLfqTs3bR0Oo5VbKdwKf8h0dSzsYrB7lSCgfJnMZKqShvlq5Oyg==} + engines: {node: '>= 0.10.0'} + 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 + + /asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + dev: true + + /axios@1.6.2: + resolution: {integrity: sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==} + dependencies: + follow-redirects: 1.15.3 + form-data: 4.0.0 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + dev: true + + /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 + + /bufferutil@4.0.8: + resolution: {integrity: sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==} + engines: {node: '>=6.14.2'} + requiresBuild: true + dependencies: + node-gyp-build: 4.7.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 + + /combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + dependencies: + delayed-stream: 1.0.0 + dev: true + + /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 + + /confinode@2.1.1: + resolution: {integrity: sha512-u5u0ZHpYMnVWtelxjalNtLvL+SdP7B/7s0JTFUIkyvqqIf67DAvy6SKaE6WZiwbufLPk+6zJKsh5SdpbtbFi9g==} + engines: {node: '>=10.0.0'} + dependencies: + quick-lru: 5.1.1 + yaml: 1.10.2 + 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 + + /d@1.0.1: + resolution: {integrity: sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==} + dependencies: + es5-ext: 0.10.62 + type: 1.2.0 + dev: true + + /debug@2.6.9: + resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.0.0 + 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 + + /delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + 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 + + /es5-ext@0.10.62: + resolution: {integrity: sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==} + engines: {node: '>=0.10'} + requiresBuild: true + dependencies: + es6-iterator: 2.0.3 + es6-symbol: 3.1.3 + next-tick: 1.1.0 + dev: true + + /es6-iterator@2.0.3: + resolution: {integrity: sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==} + dependencies: + d: 1.0.1 + es5-ext: 0.10.62 + es6-symbol: 3.1.3 + dev: true + + /es6-promise@4.2.8: + resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==} + dev: true + + /es6-promisify@5.0.0: + resolution: {integrity: sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==} + dependencies: + es6-promise: 4.2.8 + dev: true + + /es6-symbol@3.1.3: + resolution: {integrity: sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==} + dependencies: + d: 1.0.1 + ext: 1.7.0 + dev: true + + /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 + + /ext@1.7.0: + resolution: {integrity: sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==} + dependencies: + type: 2.7.2 + dev: true + + /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 + + /follow-redirects@1.15.3: + resolution: {integrity: sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + dev: true + + /form-data@4.0.0: + resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} + engines: {node: '>= 6'} + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + dev: true + + /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 + + /https-proxy-agent@2.2.4: + resolution: {integrity: sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==} + engines: {node: '>= 4.5.0'} + dependencies: + agent-base: 4.3.0 + debug: 3.2.7(supports-color@5.5.0) + transitivePeerDependencies: + - supports-color + dev: true + + /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-typedarray@1.0.0: + resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} + 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 + + /loadtest@8.0.5: + resolution: {integrity: sha512-7a15RVrplinxEuqKJK0IOdQpH/KFWzTitxJKyRalC955gFiQQB/r0UYQkqKmaio+qFKF075c5eZSkgPTgSZWjA==} + engines: {node: '>=16'} + hasBin: true + dependencies: + agentkeepalive: 2.2.0 + confinode: 2.1.1 + https-proxy-agent: 2.2.4 + stdio: 0.2.7 + testing: 3.1.0 + websocket: 1.0.34 + transitivePeerDependencies: + - supports-color + 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'} + + /mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + dependencies: + mime-db: 1.52.0 + + /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.0.0: + resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} + dev: true + + /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 + + /next-tick@1.1.0: + resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==} + dev: true + + /node-gyp-build@4.7.1: + resolution: {integrity: sha512-wTSrZ+8lsRRa3I3H8Xr65dLWSgCvY2l4AOnaeKdPA9TB/WYMPaTcrzf3rXvFoVvjKNVnu0CcWSx54qq9GKRUYg==} + hasBin: true + dev: true + + /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 + + /proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + 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 + + /quick-lru@5.1.1: + resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} + engines: {node: '>=10'} + 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 + + /stdio@0.2.7: + resolution: {integrity: sha512-q7zge680s4BhYx91a8RqHWfiyHM9b+2ZwrNEJJkL6Y6I3F78p9Ag56enyMlpLckCH+bL1shV7YEK1cLXOaA3Bg==} + dev: true + + /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 + + /testing@3.1.0: + resolution: {integrity: sha512-CJXhYndfyUrznQOGeRb1snX0NYAqt54Rux9hrbcEqCeV9Omrq/vBkFw0J80XEsJ7vWNRI0g564l58UZgEHQFEA==} + engines: {node: '>16'} + 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 + + /type@1.2.0: + resolution: {integrity: sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==} + dev: true + + /type@2.7.2: + resolution: {integrity: sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==} + dev: true + + /typedarray-to-buffer@3.1.5: + resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} + dependencies: + is-typedarray: 1.0.0 + dev: true + + /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 + + /utf-8-validate@5.0.10: + resolution: {integrity: sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==} + engines: {node: '>=6.14.2'} + requiresBuild: true + dependencies: + node-gyp-build: 4.7.1 + dev: true + + /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 + + /websocket@1.0.34: + resolution: {integrity: sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ==} + engines: {node: '>=4.0.0'} + dependencies: + bufferutil: 4.0.8 + debug: 2.6.9 + es5-ext: 0.10.62 + typedarray-to-buffer: 3.1.5 + utf-8-validate: 5.0.10 + yaeti: 0.0.6 + transitivePeerDependencies: + - supports-color + dev: true + + /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 + + /yaeti@0.0.6: + resolution: {integrity: sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug==} + engines: {node: '>=0.10.32'} + dev: true + + /yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + + /yaml@1.10.2: + resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} + engines: {node: '>= 6'} + dev: true + + /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/reference/graphResource2/production.env.js b/reference/graphResource2/production.env.js new file mode 100644 index 0000000..bb86243 --- /dev/null +++ b/reference/graphResource2/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: 6000, + 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: 1000000, + }, + database:{ + mysql:{ + host: '127.0.0.1', + port: 3306, + username: 'root', + password: 'root', + database: 'graph_resource2' + } + } +} + +export default prodConfig diff --git a/reference/graphResource2/src/app.js b/reference/graphResource2/src/app.js new file mode 100644 index 0000000..0ae2c7c --- /dev/null +++ b/reference/graphResource2/src/app.js @@ -0,0 +1,136 @@ +// | ------------------------------------------------------------ +// | @版本: 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(async (ctx, next) => { + // 解析查询参数为空字符串的情况 + const query = ctx.request.query; + Object.keys(query).forEach(key => { + if (query[key] === '') { + query[key] = undefined; + } + }); + + await next(); + }); + + 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/reference/graphResource2/src/cache/index.js b/reference/graphResource2/src/cache/index.js new file mode 100644 index 0000000..5e5e575 --- /dev/null +++ b/reference/graphResource2/src/cache/index.js @@ -0,0 +1,787 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: graphResource2 +// | @文件描述: index.js - +// | @创建时间: 2023-12-01 21:38 +// | @更新时间: 2023-12-01 21:38 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ +import { DataTypes, Model, Op } from 'sequelize'; +import { makeTreeForList } from '#common/tools/makeTree.js'; +import makeObject from '#common/tools/makeObject.js'; + +// 数据库字段类型对照 +const SQLType = { + 0: { + name: '字符串', + identify: 'string', + length: [0, 4096], + sequelizeType: DataTypes.STRING, + }, + 1: { + name: '布尔值', + identify: 'boolean', + length: null, + sequelizeType: DataTypes.BOOLEAN, + }, + 2: { + name: '整数', + identify: 'integer', + length: null, + sequelizeType: DataTypes.INTEGER, + }, + 3: { + name: '数字', + identify: 'double', + length: null, + sequelizeType: DataTypes.DOUBLE, + }, +}; +// @ excludeFieldName - Object - 描述: 数据库排除字段 +const excludeFieldName = [ + [ + 'entityid', + 'uniquereference', + 'originnode', + 'creator', + 'isdelete', + 'entityname', + 'createtimestamp', + 'updatetimestamp', + ], +]; +// @ sequelizeFindAllType - Object - 描述: 查询参数 +const sequelizeFindAllType = { + raw: true, // 原始数据 + mapToModel: true, // 将下划线变成驼峰 +}; + +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'.padEnd(30, ' ')} | ${ + atomModelPoolEndTime - atomModelPoolStartTime + } ms`, + ); + + // atomModelCache + const baseDictPoolStartTime = performance.now(); + const baseDictPool = await makeBaseDictCache(sequelize); + global.resourceCache.baseDictPool = baseDictPool; + const baseDictPoolEndTime = performance.now(); + logger.fatal( + `${'数据字典缓存加载完毕: baseDictPool'.padEnd(30, ' ')} | ${ + baseDictPoolEndTime - baseDictPoolStartTime + } ms`, + ); + + // resourceCache + const resourcePoolStartTime = performance.now(); + const resourcePool = await makeResourceCache(sequelize); + global.resourceCache.resourcePool = resourcePool; + const resourcePoolEndTime = performance.now(); + logger.fatal( + `${'资源数据缓存加载完毕: resourcePool'.padEnd(30, ' ')} | ${ + resourcePoolEndTime - resourcePoolStartTime + } ms`, + ); +} + +async function makeAtomModelCache(sequelize) { + const atomModelList = await sequelize.models.AtomModel.findAll({ + // attributes:['*'], + // where: { + // isDelete:{ + // [Op.is]: null, + // } + // }, + raw: true, // 原始数据 + mapToModel: true, // 将下划线变成驼峰 + }); + const objectData = {}; + for (let i of atomModelList) { + objectData[i.atomModelId] = i; + } + const atomModelPool = { + length: atomModelList.length, + createtime: new Date().getTime(), + updatetime: new Date().getTime(), + allData: atomModelList, + normalData: atomModelList.filter((i) => !i.isDelete), + deleteData: atomModelList.filter((i) => i.isDelete), + objectData, + }; + return atomModelPool; +} + +async function makeBaseDictCache(sequelize) { + const baseDictList = await sequelize.models.BaseDict.findAll({ + // attributes:['*'], + // where: { + // isDelete:{ + // [Op.is]: null, + // } + // }, + raw: true, // 原始数据 + mapToModel: true, // 将下划线变成驼峰 + }); + const atomAllList = [], // 原始全量列表 + atomNormalList = [], // 原始正常数据列表 + atomDeleteList = [], // 原始删除数据列表 + atomObject = { + 0: { + children: [], + delChildren: [], + }, + }, // 包含根节点的原始字典关系对象 + reduceObject = { + 0: { + children: [], + delChildren: [], + }, + }, // 包含根节点的精简字典关系对象 + atomModelObject = { + 0: { + baseDictTree: [], + reduceBaseDictTree: [], + }, + }; // 元分类/模型分类下的树 + for (let i = 0; i < baseDictList.length; i++) { + const item = baseDictList[i]; + item.children = []; + item.delChildren = []; + atomObject[item.baseDictId] = item; + reduceObject[item.baseDictId] = { + atomModel: item.atomModel, + baseDictId: item.baseDictId, + baseDictName: item.baseDictName, + baseDictIdentify: item.baseDictIdentify, + baseDictDescribe: item.baseDictDescribe, + baseDictFather: item.baseDictFather, + children: [], + delChildren: [], + }; + // 以上建立精简数据和原始数据 + atomAllList.push(item); + if (item.isDelete) { + atomDeleteList.push(item); + } else { + atomNormalList.push(item); + } + // 以上将数据分类放入列表 + } + for (let i = 0; i < atomNormalList.length; i++) { + // 正常数据 + const dictId = atomNormalList[i].baseDictId; // 字典项ID + const fatherId = atomNormalList[i].baseDictFather; // 父ID + const aData = atomNormalList[i]; // 原始数据字典项 + const rData = reduceObject[dictId]; // 精简字典项 + atomObject[fatherId].children.push(aData); // 压入原始数据到原始对象 + reduceObject[fatherId].children.push(rData); // 压入精简数据到精简对象 + } + for (let i = 0; i < atomDeleteList.length; i++) { + // 已删除数据 + const dictId = atomDeleteList[i].baseDictId; // 字典项ID + const fatherId = atomDeleteList[i].baseDictFather; // 父ID + const aData = atomDeleteList[i]; // 原始数据字典项 + const rData = reduceObject[dictId]; // 精简字典项 + atomObject[fatherId].delChildren.push(aData); // 压入原始数据到原始对象 + reduceObject[fatherId].delChildren.push(rData); // 压入精简数据到精简对象 + } + const atomModelList = resourceCache.atomModelPool.normalData; + for (let i = 0; i < atomModelList.length; i++) { + const atomModel = atomModelList[i]; + const atomModelId = atomModel.atomModelId; + atomModelObject[atomModelId] = { + baseDictTree: [], + reduceBaseDictTree: [], + }; + atomModelObject[atomModelId].baseDictTree = atomObject[ + '0' + ].children.filter( + (dict) => !(dict.atomModel && atomModelId != dict.atomModel), + ); + atomModelObject[atomModelId].reduceBaseDictTree = reduceObject[ + '0' + ].children.filter( + (dict) => !(dict.atomModel && atomModelId != dict.atomModel), + ); + } + const baseDictPool = { + length: baseDictList.length, + createtime: new Date().getTime(), + updatetime: new Date().getTime(), + atomAllList, + atomNormalList, + atomDeleteList, + atomObject, + reduceObject, + atomModelObject, + }; + return baseDictPool; +} + +async function makeResourceCache(sequelize) { + // @ RAP - Object - 描述:元分类/模型缓存池 + const RAP = resourceCache.atomModelPool; + // @ RBP - Object - 描述:字典缓存池 + const RBP = resourceCache.baseDictPool; + // ! 获取资源类信息 ============================================================================= + console.time('获取资源类信息'); + // region 获取资源类信息 + const classList = await sequelize.models.ResourceClassBase.findAll({ + ...sequelizeFindAllType, + where: { + isDelete: { + [Op.is]: null, + }, + }, + }); + // @ classListForAtomModel - String - 描述:按照元分类/模型ID区分资源类 + const classListForAtomModel = {}; + for(let atomModel of RAP.normalData){ + classListForAtomModel[atomModel.atomModelId] = [] + } + // @ classIdList - Array[number] - 描述:资源类ID列表 + const classIdList = []; + // @ classObject - Object[resourceClassBase] - 描述:资源类对象 + const classObject = {}; + for (let i = 0; i < classList.length; i++) { + // 资源类对象 + const classItem = classList[i]; + // 资源类ID + const classId = classList[i].resourceClassBaseId; + // 将资源类ID放入资源类ID列表 + classIdList.push(classId); + // 将资源类对象放入集合中 + classObject[classId] = classItem; + // 读取atomModel,元分类/模型信息 + const atomModelId = classItem.atomModel; + // 从原分类/模型中拿到其名称 + classItem.atomModelName = RAP.objectData[atomModelId].atomModelName; + // 读取resourceClassBaseDefine, 资源类定义catch提的,目前缺省 + // | 待补充 + // 读取resourceClassBaseType,资源类型定义,0实体、1虚拟、2管理层级 + classItem.resourceClassBaseTypeName = { + 0: '实体资源类', + 1: '虚拟资源类', + 2: '层级管理资源类', + }[classItem.resourceClassBaseType]; + if(classListForAtomModel[classItem.atomModel] === undefined){ + classListForAtomModel[classItem.atomModel] = [] + } + classListForAtomModel[classItem.atomModel].push(classItem) + } + // console.log(classIdList) + // console.log(classObject) + // endregion + console.timeEnd('获取资源类信息'); + // ! 获取拓展字段信息 =========================================================================== + console.time('获取拓展字段信息'); + // region 获取拓展字段信息 + const classExpandList = + await sequelize.models.ResourceClassExpandField.findAll( + sequelizeFindAllType, + ); + // @ classExpandIdList - Array[number] - 描述:资源类拓展字段ID列表 + const classExpandIdList = []; + // @ classExpandObject - Object[resourceClassExpandField] - 描述:资源类拓展字段对象 + const classExpandObject = {}; + // @ classExpandForClassBaseObject - Object - 描述:基于资源类ID的资源拓展字段对象集合 + const classExpandForClassBaseObject = {}; + for (let i = 0; i < classExpandList.length; i++) { + const expandField = classExpandList[i]; + if (expandField.isDelete) { + // 如果删除 + continue; + } + const expandFieldId = expandField.resourceClassExpandFieldId; + if (expandField.resourceClassExpandFieldRelationType === 0) { + // ! 如果是字典值 + expandField.resourceClassExpandFieldRelation = + RBP.atomObject[ + expandField.resourceClassExpandFieldValue + ].baseDictName; + } else if (expandField.resourceClassExpandFieldRelationType === 1) { + // ! 如果是资源类 + expandField.resourceClassExpandFieldRelation = + classObject[ + expandField.resourceClassExpandFieldIdentify + ].resourceClassBaseName; + } else { + expandField.resourceClassExpandFieldRelation = null; + } + classExpandIdList.push(expandFieldId); + classExpandObject[expandFieldId] = expandField; + // 拓展字段中的资源类ID + const classId = expandField.resourceClassBase; + if (classExpandForClassBaseObject[classId] === undefined) { + classExpandForClassBaseObject[classId] = { + [expandField.resourceClassExpandFieldIdentify]: expandField, + }; + } else { + classExpandForClassBaseObject[classId][ + expandField.resourceClassExpandFieldIdentify + ] = expandField; + } + } + // console.log(classExpandForClassBaseObject) + // endregion + console.timeEnd('获取拓展字段信息'); + // ! 获取实体结构表 ============================================================================= + console.time('获取实体结构表'); + // region 获取实体结构表 + const entityStructList = + await sequelize.models.ResourceEntityStruct.findAll( + sequelizeFindAllType, + ); + // @ entityStructIdList - Array[number] - 描述:资源实体结构id列表 + const entityStructIdList = []; + // @ entityStructObject - Object[resourceEntityStruct] - 描述:资源实体结构对象集合 + const entityStructObject = {}; + // @ entityStructForClassBaseObject - Object - 描述:基于资源类ID的资源实体字段对象集合 + const entityStructForClassBaseObject = {}; + for (let i = 0; i < entityStructList.length; i++) { + const entityStruct = entityStructList[i]; + if (entityStruct.isDelete) { + // 如果删除 + continue; + } + const entityStructId = entityStruct.resourceEntityStructId; + entityStructIdList.push(entityStructId); + entityStructObject[entityStructId] = entityStruct; + // 获取存储类型和长度 + entityStruct.storageTypeValue = + SQLType[entityStruct.resourceEntityStructStorageType]; + // 这里的关联值不做处理 + // 拓展字段中的资源类ID + const classId = entityStruct.resourceClassBase; + if (entityStructForClassBaseObject[classId] === undefined) { + entityStructForClassBaseObject[classId] = { + [entityStruct.resourceEntityStructIdentify]: entityStruct, + }; + } else { + entityStructForClassBaseObject[classId][ + entityStruct.resourceEntityStructIdentify + ] = entityStruct; + } + } + // endregion + console.timeEnd('获取实体结构表'); + // ! 获取资源类关系表 =========================================================================== + console.time('获取资源类关系表'); + // region 获取资源类关系表 + const classRelationList = + await sequelize.models.ResourceClassRelation.findAll( + {...sequelizeFindAllType,where: { + isDelete: { + [Op.is]: null, + }, + },}, + ); + // @ classRelationIdList - String - 描述:获取资源类关系ID列表 + const classRelationIdList = []; + // @ classRelationObject - String - 描述:获取资源类关系对象集合 + const classRelationObject = {}; + // @ classRelationObjectForTargetClass - String - 描述:获取资源类关系对象集合继续目标资源类 + const classRelationObjectForTargetClass = {}; + for (let i = 0; i < classRelationList.length; i++) { + const classRelationItem = classRelationList[i]; + const classRelationItemId = classRelationItem.resourceClassRelationId; + const targetId = classRelationItem.resourceClassRelationTarget; + classRelationIdList.push(classRelationItemId); + classRelationObject[classRelationItemId] = classRelationItem; + if (classRelationObjectForTargetClass[targetId] === undefined) { + classRelationObjectForTargetClass[targetId] = [classRelationItem]; + } else { + classRelationObjectForTargetClass[targetId].push(classRelationItem); + } + } + // endregion + console.timeEnd('获取资源类关系表'); + + // | 这里生成基础数据模型 ============================================================================================= + console.time('==生成资源类基础数据模型=='); + // region 这里生成基础数据模型 + // ! 资源类 + class ClassModel { + constructor(classItem) { + // 设置基础信息值 + this.resourceClass = classItem; + } + get classId() { + return this.resourceClass.resourceClassBaseId; + } + get classIdentify() { + return this.resourceClass.resourceClassBaseIdentify; + } + get atomModel() { + return this.resourceClass.atomModel; + } + get className() { + return this.resourceClass.resourceClassBaseName; + } + get classExpand() { + let classExpand = classExpandForClassBaseObject[this.classId]; + if (classExpand === undefined) { + classExpand = {}; + } + return classExpand; + } + get entityStruct() { + let entityStruct = entityStructForClassBaseObject[this.classId]; + if (entityStruct === undefined) { + entityStruct = {}; + } + return entityStruct; + } + get classRelationList() { + if (classRelationObjectForTargetClass[this.classId] === undefined) { + return []; + } else { + return classRelationObjectForTargetClass[this.classId]; + } + } + get classRelationIdList() { + return this.classRelationList.map((i) => i.resourceClassRelationId); + } + async createSequelizeModel() { + class resourceEntity extends Model {} + // 定义资源实体名称字段 + const entityName = { + type: DataTypes.STRING(255), + allowNull: false, + comment: '资源实体名称', + }; + const entityStruct = this.entityStruct; + // 定义资源实体名称字段在数据库的备注 + if (entityStruct.entityName !== undefined) { + entityName.comment = + entityStruct.entityName.resourceEntityStructName + + '-' + + entityStruct.entityName.resourceEntityStructDescribe; + } + // 定义字段 + const defineField = { + // 在这里定义模型属性 + entityId: { + type: DataTypes.STRING(64), + primaryKey: true, + allowNull: false, + comment: '资源实体ID', + }, + // 自增列 + uniqueReference: { + type: DataTypes.INTEGER, + autoIncrement: true, + allowNull: false, + unique: true, // 使得自增值是唯一的 + comment: '唯一参考', + }, + entityName, + // 所在节点 + originNode: { + type: DataTypes.STRING, + allowNull: false, + comment: '所在的资源类节点', + }, + creator: { + type: DataTypes.STRING, + comment: '创建人', + }, + isDelete: { + type: DataTypes.STRING(64), + comment: '删除时间', + }, + }; + // 定义数据表 + const defineTable = { + // 这是其他模型参数 + sequelize, // 我们需要传递连接实例 + modelName: this.classIdentify.toLowerCase(), // 我们需要选择模型名称 + tableName: 'entity_' + this.classIdentify.toLowerCase(), + comment: '元分类/模型表', + timestamps: true, // 不要忘记启用时间戳! + createdAt: 'createTimestamp', // 不想要 createdAt + // 想要 updatedAt 但是希望名称叫做 updateTimestamp + updatedAt: 'updateTimestamp', + underscored: true, // 改成下划线格式 + }; + for (let fieldName in this.entityStruct) { + // 排除固定字段 + if (excludeFieldName.includes(fieldName.toLowerCase())) { + continue; + } + // 拿到字段详细信息 + const oneEntityStruct = this.entityStruct[fieldName]; + // 建立数据库表字段标准数据 + const oneField = { + type: DataTypes.STRING, // 对于意外数据,设置默认长度255的字符串 + comment: + oneEntityStruct.resourceEntityStructName + + '-' + + oneEntityStruct.resourceEntityStructDescribe, + }; + // 拿到自定义的存储类型 + const fieldStorageType = + this.entityStruct[fieldName] + .resourceEntityStructStorageType; + if ( + Object.keys(SQLType).includes(fieldStorageType.toString()) + ) { + // 如果该自定义存储类型在预设的存储类型中,设置自定义的存储类型 + oneField.type = SQLType[fieldStorageType].sequelizeType; + if ( + fieldStorageType == 0 && + oneEntityStruct.resourceEntityStructStorageLength < 4096 + ) { + // 如果是字符串,并且长度在0 > 4096,设置其长度 + oneField.type = oneField.type( + parseInt( + oneEntityStruct.resourceEntityStructStorageLength, + ), + ); + } + } + // 将该字段放入数据库字段定义对象中 + defineField[fieldName] = oneField; + } + resourceEntity.init(defineField, defineTable); + // 同步数据库 + await resourceEntity.sync(); // {alter: true}是修改,现在是如果存在就不更改表,后面修改表明,字段名,字段长度会在更新操作时添加 + this.sequelizeModel = resourceEntity; + } + get zeroInfo(){ + return { + resourceClassBaseId: this.resourceClass.resourceClassBaseId, + resourceClassBaseName: this.resourceClass.resourceClassBaseName, + resourceClassBaseColor: this.resourceClass.resourceClassBaseColor, + resourceClassBaseAvatar: this.resourceClass.resourceClassBaseAvatar, + } + } + get info(){ + return{ + ...this.resourceClass, + resourceClassExpandField: this.classExpand, + resourceEntityStruct: this.entityStruct, + resourceClassRelation: this.classRelationList + } + } + } + // @ classModelObject - Object - 描述:资源类数据模型对象集合 + const classModelObject = {}; + for (let classId of classIdList) { + if (classObject[classId].isDelete) { + // 排除删除的 + continue; + } + classModelObject[classId] = new ClassModel(classObject[classId]); + console.time(' 初始化资源实体表'+ classModelObject[classId].classIdentify) + await classModelObject[classId].createSequelizeModel(); + console.timeEnd(' 初始化资源实体表'+ classModelObject[classId].classIdentify) + } + // console.log((await sequelize.models.omencust.create({ + // entityId: 'omencust' + crypto.randomUUID(), + // originNode: '0-0-1', + // entityName: '中天合创', + // address: '鄂尔多斯', + // util: '54', + // project: '1' + // })).dataValues) + // endregion + console.timeEnd('==生成资源类基础数据模型=='); + + // | 这里生成关系节点数据模型 ========================================================================================== + console.time('==生成类关系节点数据模型=='); + // region 这里生成关系节点数据模型 + // 给每个类生成关联列表 + // @ classNodeObject - Object - 描述:类关系节点数据模型集合 + const classNodeObject = { + 0: { + classModel: {}, + nodeId: 0, + children: [], + father: null, + }, + }; + // ! 资源类节点 + class ClassNodeModel { + constructor(classModel, classRelationId) { + this.nodeId = classRelationId; + this.fatherId = + classRelationObject[ + classRelationId + ].resourceClassRelationFather; + this.children = []; + this.classData = classModel; + } + get classId() { + return this.classData.classId; + } + get classIdentify() { + return this.classData.classIdentify; + } + get atomModel() { + return this.classData.atomModel; + } + get className() { + return this.classData.className; + } + get classExpand() { + return this.classData.classExpand; + } + get entityStruct() { + return this.classData.entityStruct; + } + get classRelationList() { + return this.classData.classRelationList; + } + get classRelationIdList() { + return this.classData.classRelationIdList; + } + get nodeZeroInfo(){ + return { + ...this.classData.zeroInfo, + nodeId: this.nodeId, + fatherId: this.fatherId, + children: this.children.map(i => i.nodeZeroInfo) + } + } + } + // @ 生成类关系节点 + for (let classId of Object.keys(classModelObject)) { + const nowClassModel = classModelObject[classId]; + const nowRelationIdList = nowClassModel.classRelationIdList; + if (nowRelationIdList.length == 0) { + // @ 在数据库添加这条关系 + const newClassRelation = + await sequelize.models.ResourceClassRelation.create({ + resourceClassRelationFather: 0, + resourceClassRelationTarget: classId, + }); + const newClassRelationData = newClassRelation.dataValues; + const newClassRelationDataId = + newClassRelationData.resourceClassRelationId; + classRelationList.push(newClassRelationData) + classRelationIdList.push(newClassRelationDataId); + classRelationObject[newClassRelationDataId] = newClassRelationData; + classRelationObjectForTargetClass[classId] = [newClassRelationData]; + classNodeObject[newClassRelationDataId] = new ClassNodeModel( + nowClassModel, + newClassRelationDataId, + ); + } + for (let i = 0; i < nowRelationIdList.length; i++) { + const classRelationId = nowRelationIdList[i]; + classNodeObject[classRelationId] = new ClassNodeModel( + nowClassModel, + classRelationId, + ); + } + }; + // @ 构建类关系 + for (let i = 0; i < classRelationIdList.length; i++) { + const nodeId = classRelationList[i].resourceClassRelationId; + const classNode = classNodeObject[nodeId]; + const fatherId = classNodeObject[nodeId].fatherId; + classNodeObject[fatherId].children.push(classNode); + } + // console.log(classNodeObject) + // @ 根据关联元/模型分类资源类节点 + // @ classNodeObjectForAtomModel - String - 描述:关联元/模型下的根节点 + const classNodeObjectForAtomModel = {}; + // 根据元分类/模型创建根节点的空数组 + for (let i = 0; i < RAP.normalData.length; i++) { + classNodeObjectForAtomModel[RAP.normalData[i].atomModelId] = []; + } + // 将根节点放入 分类/模型创建根节点的空数组 中 + for (let i = 0; i < classNodeObject[0].children.length; i++) { + const nodeModel = classNodeObject[0].children[i]; + const atomModelId = nodeModel.atomModel; + if (classNodeObjectForAtomModel[atomModelId] === undefined) { + logger.warn('存在未找到元分类/模型的资源类:' + nodeModel.classId); + } else { + classNodeObjectForAtomModel[atomModelId].push(nodeModel); + } + } + // console.time('GET TREE') + // global.test = classNodeObjectForAtomModel[1][0].nodeZeroInfo + // console.timeEnd('GET TREE') + // console.time('GET TREE JSON') + // global.test2 = JSON.stringify(global.test, null, 3) + // console.timeEnd('GET TREE JSON') + // console.time('GET TREE JSON CONSOLE') + // console.log(global.test) + // console.timeEnd('GET TREE JSON CONSOLE') + console.timeEnd('==生成类关系节点数据模型=='); + // endregion + + // ! 获取资源实体 =============================================================================== + console.time('获取资源实体'); + // region 获取资源实体 + // @ entityListForClassId - Object[Array[Object[entity]]] - 描述:实体列表根据资源类ID区分的对象 + const entityListForClassId = {}; + // @ entityListForClassIdentify - Object[Array[Object[entity]]] - 描述:实体列表根据资源类Identify区分的对象 + const entityListForClassIdentify = {}; + for (let i of Object.keys(classModelObject)) { + const classModel = classModelObject[i]; + const classId = classModel.classId; + const classIdentify = classModel.classIdentify; + console.time(' 获取资源实体表信息' + classModel.classIdentify); + const entityList = await classModel.sequelizeModel.findAll({ + ...sequelizeFindAllType, + where: { + isDelete: { + [Op.is]: null, + }, + }, + }); + console.timeEnd(' 获取资源实体表信息' + classModel.classIdentify); + entityListForClassId[classId] = entityList; + entityListForClassIdentify[classIdentify] = entityList; + } + // endregion + console.timeEnd('获取资源实体'); + // ! 获取资源实体关系 + + return { + createtime: new Date().getTime(), + updatetime: new Date().getTime(), + // 资源类 + classList, + classIdList, + classObject, + classListForAtomModel, + // 资源类拓展字段 + classExpandList, + classExpandIdList, + classExpandObject, + classExpandForClassBaseObject, + // 资源实体结构 + entityStructList, + entityStructIdList, + entityStructObject, + entityStructForClassBaseObject, + // 资源类关系 + classRelationList, + classRelationIdList, + classRelationObject, + classRelationObjectForTargetClass, + // 资源类模型 + ClassModel, + classModelObject, + // 资源类节点模型 + classNodeObject, + ClassNodeModel, + classNodeObjectForAtomModel, + } +} diff --git a/reference/graphResource2/src/common/database/dataModels/atomModel.dataModel.js b/reference/graphResource2/src/common/database/dataModels/atomModel.dataModel.js new file mode 100644 index 0000000..0ac150e --- /dev/null +++ b/reference/graphResource2/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/reference/graphResource2/src/common/database/dataModels/baseDict.dataModel.js b/reference/graphResource2/src/common/database/dataModels/baseDict.dataModel.js new file mode 100644 index 0000000..db5e8d3 --- /dev/null +++ b/reference/graphResource2/src/common/database/dataModels/baseDict.dataModel.js @@ -0,0 +1,86 @@ +// | ------------------------------------------------------------ +// | @版本: 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, + 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: "字典项名称" + }, + baseDictIdentify:{ + type: DataTypes.STRING, + 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/reference/graphResource2/src/common/database/dataModels/resourceClassBase.dataModel.js b/reference/graphResource2/src/common/database/dataModels/resourceClassBase.dataModel.js new file mode 100644 index 0000000..0f4ac9c --- /dev/null +++ b/reference/graphResource2/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/reference/graphResource2/src/common/database/dataModels/resourceClassExpandField.dataModel.js b/reference/graphResource2/src/common/database/dataModels/resourceClassExpandField.dataModel.js new file mode 100644 index 0000000..c7aaf36 --- /dev/null +++ b/reference/graphResource2/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/reference/graphResource2/src/common/database/dataModels/resourceClassRelation.dataModel.js b/reference/graphResource2/src/common/database/dataModels/resourceClassRelation.dataModel.js new file mode 100644 index 0000000..25cf895 --- /dev/null +++ b/reference/graphResource2/src/common/database/dataModels/resourceClassRelation.dataModel.js @@ -0,0 +1,61 @@ +// | ------------------------------------------------------------ +// | @版本: 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' + }, + resourceClassRelationFather: { + type: DataTypes.INTEGER, + allowNull: false, + defaultValue: 0, + comment: '父资源类ID' + }, + resourceClassRelationTarget: { + 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/reference/graphResource2/src/common/database/dataModels/resourceEntityRelation.dataModel.js b/reference/graphResource2/src/common/database/dataModels/resourceEntityRelation.dataModel.js new file mode 100644 index 0000000..ed615a2 --- /dev/null +++ b/reference/graphResource2/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/reference/graphResource2/src/common/database/dataModels/resourceEntityStruct.dataModel.js b/reference/graphResource2/src/common/database/dataModels/resourceEntityStruct.dataModel.js new file mode 100644 index 0000000..33de542 --- /dev/null +++ b/reference/graphResource2/src/common/database/dataModels/resourceEntityStruct.dataModel.js @@ -0,0 +1,140 @@ +// | ------------------------------------------------------------ +// | @版本: 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, + default: 0, + 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, + }, + resourceEntityStructIsRequired: { + type: DataTypes.BOOLEAN, + allowNull: true, + comment: "是否必填" + }, + 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: '资源实体字段关联类型:0是字典、1是资源实体,但是选择资源类', + }, + resourceEntityStructRelationValue:{ + type: DataTypes.INTEGER, + comment: '资源实体字段关联值', + }, + resourceEntityStructDefaultValue:{ + type: DataTypes.STRING, + 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/reference/graphResource2/src/common/database/index.js b/reference/graphResource2/src/common/database/index.js new file mode 100644 index 0000000..c08c10b --- /dev/null +++ b/reference/graphResource2/src/common/database/index.js @@ -0,0 +1,61 @@ +// | ------------------------------------------------------------ +// | @版本: 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), + logging: false + }); + + 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/reference/graphResource2/src/common/database/initData.js b/reference/graphResource2/src/common/database/initData.js new file mode 100644 index 0000000..7526ddd --- /dev/null +++ b/reference/graphResource2/src/common/database/initData.js @@ -0,0 +1,353 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: graphResource2 +// | @文件描述: initData.js - +// | @创建时间: 2023-12-02 15:02 +// | @更新时间: 2023-12-02 15:02 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ + +// @ 运维资源类的类型字典 +const OMResourceType = [ + { + baseDictId: 1, + baseDictIsBase: 1, + baseDictOriginType: 0, + baseDictName: '运维资源类型', + baseDictDescribe: '在运维系统上使用的资源类用途定义,资源类和备件类', + baseDictFather: 0, + }, + { + baseDictId: 2, + baseDictIsBase: 1, + baseDictOriginType: 0, + baseDictName: '资源类型', + baseDictDescribe: '在广义上有ID区分自身的资源', + baseDictFather: 1, + }, + { + baseDictId: 3, + baseDictIsBase: 1, + baseDictOriginType: 0, + baseDictName: '备件类行', + baseDictDescribe: '在广义上没有ID进行区分的资源', + baseDictFather: 1, + } +] +// @ 单位 +const UnitType = [ + { + baseDictId: 11, + baseDictIsBase: 1, + baseDictOriginType: 0, + baseDictName: '数据单位', + baseDictDescribe: '对资源在物理上的统一衡量区分', + baseDictFather: 0, + }, + { + baseDictId: 12, + baseDictIsBase: 1, + baseDictOriginType: 0, + baseDictName: '长度单位', + baseDictDescribe: '对资源在长度上的统一衡量区分', + baseDictFather: 11, + }, + { + baseDictId: 13, + baseDictIsBase: 1, + baseDictOriginType: 0, + baseDictName: '米', + baseDictIdentify: 'm', + baseDictDescribe: '', + baseDictFather: 12, + }, + { + baseDictId: 14, + baseDictIsBase: 1, + baseDictOriginType: 0, + baseDictName: '厘米', + baseDictIdentify: 'cm', + baseDictDescribe: '', + baseDictFather: 12, + }, + { + baseDictId: 15, + baseDictIsBase: 1, + baseDictOriginType: 0, + baseDictName: '千米', + baseDictIdentify: 'km', + baseDictDescribe: '', + baseDictFather: 12, + }, + { + baseDictId: 16, + baseDictIsBase: 1, + baseDictOriginType: 0, + baseDictName: '毫米', + baseDictIdentify: 'mm', + baseDictDescribe: '', + baseDictFather: 12, + }, + { + baseDictId: 17, + baseDictIsBase: 1, + baseDictOriginType: 0, + baseDictName: '英寸', + baseDictIdentify: 'inch', + baseDictDescribe: '', + baseDictFather: 12, + }, + { + baseDictId: 18, + baseDictIsBase: 1, + baseDictOriginType: 0, + baseDictName: '英尺', + baseDictIdentify: 'ft', + baseDictDescribe: '', + baseDictFather: 12, + }, + { + baseDictId: 19, + baseDictIsBase: 1, + baseDictOriginType: 0, + baseDictName: '英里', + baseDictIdentify: 'mile', + baseDictDescribe: '', + baseDictFather: 12, + }, + { + baseDictId: 20, + baseDictIsBase: 1, + baseDictOriginType: 0, + baseDictName: '面积单位', + baseDictDescribe: '对资源在平面上的统一衡量区分', + baseDictFather: 11, + }, + { + baseDictId: 21, + baseDictIsBase: 1, + baseDictOriginType: 0, + baseDictName: '平方米', + baseDictIdentify: 'm²', + baseDictDescribe: '', + baseDictFather: 20, + }, + { + baseDictId: 22, + baseDictIsBase: 1, + baseDictOriginType: 0, + baseDictName: '平方厘米', + baseDictIdentify: 'cm²', + baseDictDescribe: '', + baseDictFather: 20, + }, + { + baseDictId: 23, + baseDictIsBase: 1, + baseDictOriginType: 0, + baseDictName: '平方毫米', + baseDictIdentify: 'mm²', + baseDictDescribe: '', + baseDictFather: 20, + }, + { + baseDictId: 24, + baseDictIsBase: 1, + baseDictOriginType: 0, + baseDictName: '平方千米', + baseDictIdentify: 'km²', + baseDictDescribe: '', + baseDictFather: 20, + }, + { + baseDictId: 26, + baseDictIsBase: 1, + baseDictOriginType: 0, + baseDictName: '英亩', + baseDictIdentify: 'acre', + baseDictDescribe: '', + baseDictFather: 20, + }, + { + baseDictId: 27, + baseDictIsBase: 1, + baseDictOriginType: 0, + baseDictName: '公顷', + baseDictIdentify: 'ha', + baseDictDescribe: '', + baseDictFather: 20, + }, + { + baseDictId: 28, + baseDictIsBase: 1, + baseDictOriginType: 0, + baseDictName: '亩', + baseDictIdentify: 'are', + baseDictDescribe: '', + baseDictFather: 20, + }, + { + baseDictId: 29, + baseDictIsBase: 1, + baseDictOriginType: 0, + baseDictName: '重量单位', + baseDictDescribe: '对资源在质量上的统一衡量区分', + baseDictFather: 11, + }, + { + baseDictId: 30, + baseDictIsBase: 1, + baseDictOriginType: 0, + baseDictName: '千克', + baseDictIdentify: 'kg', + baseDictDescribe: ' ', + baseDictFather: 29, + }, + { + baseDictId: 31, + baseDictIsBase: 1, + baseDictOriginType: 0, + baseDictName: '毫克', + baseDictIdentify: 'mg', + baseDictDescribe: ' ', + baseDictFather: 29, + }, + { + baseDictId: 32, + baseDictIsBase: 1, + baseDictOriginType: 0, + baseDictName: '克', + baseDictIdentify: 'g', + baseDictDescribe: ' ', + baseDictFather: 29, + }, + { + baseDictId: 33, + baseDictIsBase: 1, + baseDictOriginType: 0, + baseDictName: '盎司', + baseDictIdentify: 'oz', + baseDictDescribe: ' ', + baseDictFather: 29, + }, + { + baseDictId: 34, + baseDictIsBase: 1, + baseDictOriginType: 0, + baseDictName: '磅', + baseDictIdentify: 'lb', + baseDictDescribe: ' ', + baseDictFather: 29, + }, + { + baseDictId: 35, + baseDictIsBase: 1, + baseDictOriginType: 0, + baseDictName: '斤', + baseDictIdentify: '', + baseDictDescribe: ' ', + baseDictFather: 29, + }, + { + baseDictId: 36, + baseDictIsBase: 1, + baseDictOriginType: 0, + baseDictName: '公斤', + baseDictIdentify: 'kg', + baseDictDescribe: ' ', + baseDictFather: 29, + }, + { + baseDictId: 37, + baseDictIsBase: 1, + baseDictOriginType: 0, + baseDictName: '时间单位', + baseDictDescribe: '在时间上的统一衡量', + baseDictFather: 11, + }, + { + baseDictId: 38, + baseDictIsBase: 1, + baseDictOriginType: 0, + baseDictName: '秒', + baseDictIdentify: 's', + baseDictDescribe: ' ', + baseDictFather: 37, + }, + { + baseDictId: 39, + baseDictIsBase: 1, + baseDictOriginType: 0, + baseDictName: '分', + baseDictIdentify: 'min', + baseDictDescribe: ' ', + baseDictFather: 37, + }, + { + baseDictId: 40, + baseDictIsBase: 1, + baseDictOriginType: 0, + baseDictName: '时', + baseDictIdentify: 'h', + baseDictDescribe: ' ', + baseDictFather: 37, + }, + { + baseDictId: 41, + baseDictIsBase: 1, + baseDictOriginType: 0, + baseDictName: '天', + baseDictIdentify: 'd', + baseDictDescribe: ' ', + baseDictFather: 37, + }, + { + baseDictId: 42, + baseDictIsBase: 1, + baseDictOriginType: 0, + baseDictName: '周', + baseDictIdentify: 'week', + baseDictDescribe: ' ', + baseDictFather: 37, + }, + { + baseDictId: 43, + baseDictIsBase: 1, + baseDictOriginType: 0, + baseDictName: '月', + baseDictIdentify: 'month', + baseDictDescribe: ' ', + baseDictFather: 37, + }, + { + baseDictId: 44, + baseDictIsBase: 1, + baseDictOriginType: 0, + baseDictName: '年', + baseDictIdentify: 'year', + baseDictDescribe: ' ', + baseDictFather: 37, + }, + { + baseDictId: 45, + baseDictIsBase: 1, + baseDictOriginType: 0, + baseDictName: '毫秒', + baseDictIdentify: 'ms', + baseDictDescribe: ' ', + baseDictFather: 37, + }, +] + + + +export default function initData(sequelize){ + sequelize.models.BaseDict.bulkCreate(OMResourceType, { ignoreDuplicates: true }) + sequelize.models.BaseDict.bulkCreate(UnitType, { ignoreDuplicates: true }) +} + + diff --git a/reference/graphResource2/src/common/dto/index.js b/reference/graphResource2/src/common/dto/index.js new file mode 100644 index 0000000..001ed61 --- /dev/null +++ b/reference/graphResource2/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/reference/graphResource2/src/common/logger/index.js b/reference/graphResource2/src/common/logger/index.js new file mode 100644 index 0000000..55579ce --- /dev/null +++ b/reference/graphResource2/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/reference/graphResource2/src/common/tools/binarySearch.js b/reference/graphResource2/src/common/tools/binarySearch.js new file mode 100644 index 0000000..a5d095d --- /dev/null +++ b/reference/graphResource2/src/common/tools/binarySearch.js @@ -0,0 +1,105 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: graphResource2 +// | @文件描述: binarySearch.js - 二分法根据蓄力ID查找对象数组元素 +// | @创建时间: 2023-12-02 12:00 +// | @更新时间: 2023-12-02 12:00 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ + +export default function binarySearch(arr, id, att = undefined) { + let bi = 0, ai = arr.length -1; + if(!Object.keys(arr[0]).includes(att) && att !== undefined){ + throw new Error('不存在属性', att) + }else if(att === undefined){ + while (bi <= ai){ + const mi = Math.floor((bi + ai)/2); + const miId = arr[mi] + if(miId === id){ + return mi + }else if(miId < id){ + bi = mi + 1 + }else{ + ai = mi -1 + } + } + return -1 + } + while (bi <= ai){ + const mi = Math.floor((bi + ai)/2); + const miId = arr[mi][att] + if(miId === id){ + return mi + }else if(miId < id){ + bi = mi + 1 + }else{ + ai = mi -1 + } + } + return -1 +} + + + + + + + +function getIndexForWhile(list, id, att){ + let i = 0 + while (i < list.length){ + if (list[i][att] == id) { + return i + } + i++ + } + return -1 +} + +function getIndexForFor(list, id, att){ + for(let i =0; i< list.length;i++){ + if (list[i][att] == id) { + return i + } + } + return -1 +} + + +function getIndexForForIn(list, id, att){ + for(let i in list){ + if (list[i][att] == id) { + return i + } + } + return -1 +} +// const list = []; +// +// let i = 300; +// +// for (let j = 0; j < 200000; j++) { +// list[j] = { id: j + i }; +// } +// console.time('binarySearch'); +// let id = 200000; +// const i1 = binarySearch(list, id, 'id'); +// console.timeEnd('binarySearch'); +// +// console.time('getIndexForWhile'); +// const i2 = getIndexForWhile(list,id, 'id') +// console.timeEnd('getIndexForWhile'); +// +// console.time('getIndexForFor') +// const i3 = getIndexForFor(list, id, 'id') +// console.timeEnd('getIndexForFor') +// +// console.time('getIndexForForIn') +// const i4 = getIndexForForIn(list, id, 'id') +// console.timeEnd('getIndexForForIn') +// +// console.log(i1, i2, i3, i4) diff --git a/reference/graphResource2/src/common/tools/binarySearchMore.js b/reference/graphResource2/src/common/tools/binarySearchMore.js new file mode 100644 index 0000000..d8a8026 --- /dev/null +++ b/reference/graphResource2/src/common/tools/binarySearchMore.js @@ -0,0 +1,50 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: graphResource2 +// | @文件描述: binarySearchMore.js - +// | @创建时间: 2023-12-03 01:54 +// | @更新时间: 2023-12-03 01:54 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ + +function binarySearch2(arr, id, att, bi, ai) { + if(!Object.keys(arr[0]).includes(att)){ + throw new Error('不存在属性', att) + } + while (bi <= ai){ + const mi = Math.floor((bi + ai)/2); + const miId = arr[mi][att] + if(miId === id){ + return mi + }else if(miId < id){ + bi = mi + 1 + }else{ + ai = mi -1 + } + } + return -1 +} + +export default function binarySearchMore(arr, ids, att, bi, ai){ + if(ids.length == 0)return [] + const firstIndex = binarySearch2(arr, ids[0], att, bi, ai); + if(firstIndex != -1){ + bi = firstIndex + } + const lastIndex = binarySearch2(arr, ids.slice(-1)[0], att, bi, ai); + if(lastIndex != -1){ + ai = lastIndex + } + + const indexList = [firstIndex, lastIndex] + if(ids.length -2 == 1){ + indexList.push(binarySearch2(arr, ids[1], att, firstIndex, lastIndex)) + }else if(ids.length -2 > 1){ + indexList.push(...binarySearchMore(arr, ids.slice(1, -1), att, bi, ai)) + } + return indexList +} diff --git a/reference/graphResource2/src/common/tools/getArrayPage.js b/reference/graphResource2/src/common/tools/getArrayPage.js new file mode 100644 index 0000000..61d177a --- /dev/null +++ b/reference/graphResource2/src/common/tools/getArrayPage.js @@ -0,0 +1,23 @@ +// | ------------------------------------------------------------ +// | @版本: 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){ + if(!Array.isArray(array)){ + return [] + } + const startIndex = (pageNumber - 1) * pageSize; + + // 使用 slice() 方法获取分页内容 + const pageContent = array.slice(startIndex, startIndex + pageSize); + return pageContent +} diff --git a/reference/graphResource2/src/common/tools/getNoSpacesStr.js b/reference/graphResource2/src/common/tools/getNoSpacesStr.js new file mode 100644 index 0000000..139a779 --- /dev/null +++ b/reference/graphResource2/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/reference/graphResource2/src/common/tools/makeList.js b/reference/graphResource2/src/common/tools/makeList.js new file mode 100644 index 0000000..813d0a6 --- /dev/null +++ b/reference/graphResource2/src/common/tools/makeList.js @@ -0,0 +1,30 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: graphResource2 +// | @文件描述: makeList.js - +// | @创建时间: 2023-12-02 17:00 +// | @更新时间: 2023-12-02 17:00 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ + +export default function makeList(tree, childrenField = 'children'){ + const arr = getChildren(list, childrenField) + const setObj = new Set(arr) + return Array.from(setObj) +} + +function getChildren(list, childrenField){ + let arr = [] + for(let i = 0; i < list.length; i++){ + if(list[i][childrenField] && list[i][childrenField].length > 0){ + arr = [...arr, ...getChildren(list[i][childrenField], childrenField)] + }else{ + arr.push(list[i]) + } + } + return arr +} diff --git a/reference/graphResource2/src/common/tools/makeObject.js b/reference/graphResource2/src/common/tools/makeObject.js new file mode 100644 index 0000000..6c7a05b --- /dev/null +++ b/reference/graphResource2/src/common/tools/makeObject.js @@ -0,0 +1,23 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: graphResource2 +// | @文件描述: makeObject.js - 制造对象 +// | @创建时间: 2023-12-02 16:41 +// | @更新时间: 2023-12-02 16:41 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ + +export default function makeObject(list, idField, hasChildren = false){ + const newObject = {}; + for(let i = 0; i < list.length; i++){ + if(hasChildren){ + list[i].children = []; + newObject[list[i][idField]] = list[i] + } + } + return newObject +} diff --git a/reference/graphResource2/src/common/tools/makeTree.js b/reference/graphResource2/src/common/tools/makeTree.js new file mode 100644 index 0000000..e552b51 --- /dev/null +++ b/reference/graphResource2/src/common/tools/makeTree.js @@ -0,0 +1,37 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: graphResource2 +// | @文件描述: makeTree.js - 生成树 +// | @创建时间: 2023-12-02 15:45 +// | @更新时间: 2023-12-02 15:45 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ + + +export function makeTreeForList(list, object, referField, fatherField, hasDelete = true){ + if(!Object.keys(object).includes('0')){ + object['0'] = { + children: [] + } + } + for(let i = 0; i < list.length; i++){ + const fatherId = list[i][fatherField]; + if(list[i].isDelete && !hasDelete){ + continue + } + if(!fatherId){ + object['0'].children.push(list[i]) + continue + } + if(!object[fatherId].children){ + object[fatherId].children = [] + } + object[fatherId].children.push(list[i]) + } + return object['0'].children +} + diff --git a/reference/graphResource2/src/routes/graphResource2/atomModel/index.dto.js b/reference/graphResource2/src/routes/graphResource2/atomModel/index.dto.js new file mode 100644 index 0000000..bf2d915 --- /dev/null +++ b/reference/graphResource2/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/reference/graphResource2/src/routes/graphResource2/atomModel/index.js b/reference/graphResource2/src/routes/graphResource2/atomModel/index.js new file mode 100644 index 0000000..6e2ccc2 --- /dev/null +++ b/reference/graphResource2/src/routes/graphResource2/atomModel/index.js @@ -0,0 +1,230 @@ +// | ------------------------------------------------------------ +// | @版本: 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'; +import binarySearch from "#common/tools/binarySearch.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.normalData; + 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) => { + const deleteData = resourceCache.atomModelPool.deleteData.map((i) => ({ + atomModelId: i.atomModelId, + atomModelName: i.atomModelName, + })); + const narmalData = resourceCache.atomModelPool.normalData.map((i) => ({ + atomModelId: i.atomModelId, + atomModelName: i.atomModelName, + })); + ctx.body = { + deleteData, + narmalData, + }; +}); + +// @ 新建元分类 +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.allData.push(newAtomModel.dataValues); + resourceCache.atomModelPool.normalData.push(newAtomModel.dataValues); + resourceCache.atomModelPool.objectData[ + newAtomModel.dataValues.atomModelId + ] = newAtomModel.dataValues; + resourceCache.atomModelPool.length++; + resourceCache.atomModelPool.updatetime = new Date().getTime(); + + const RRP = resourceCache.resourcePool; + RRP.classListForAtomModel[newAtomModel.dataValues.atomModelId] = [] + RRP.classNodeObjectForAtomModel[newAtomModel.dataValues.atomModelId] = [] + + // 给元分类加入基础几点 + const RBP = resourceCache.baseDictPool + RBP.atomModelObject[newAtomModel.dataValues.atomModelId] = { + baseDictTree: [], + reduceBaseDictTree: [], + }; + RBP.atomModelObject[newAtomModel.dataValues.atomModelId].baseDictTree = RBP.atomObject[ + '0' + ].children.filter( + (dict) => !(dict.atomModel && newAtomModel.dataValues.atomModelId != dict.atomModel), + ); + RBP.atomModelObject[newAtomModel.dataValues.atomModelId].reduceBaseDictTree = RBP.reduceObject[ + '0' + ].children.filter( + (dict) => !(dict.atomModel && newAtomModel.dataValues.atomModelId != dict.atomModel), + ); + + + 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; + // 是否存在ID + const RAP = resourceCache.atomModelPool + const nowData = RAP.objectData[atomModelId] + if(!nowData || (nowData && nowData.isDelete)){ + ctx.throw(400, { e: '不存在元分类/模型记录' }); + return; + } + atomModelName = getNoSpacesStr(atomModelName).toUpperCase(); + // 名称查重 + const index = checkName(atomModelName); + if ( + index != -1 && + atomModelId != RAP.normalData[index].atomModelId + ) { + ctx.throw(400, { e: '元分类/模型名称重复' }); + return; + } + if ( + nowData.atomModelDescribe == atomModelDescribe && + nowData.atomModelName == atomModelName + ) { + ctx.body = { + message: '编辑元分类/模型成功', + }; + return; + } + nowData.atomModelName = atomModelName; + nowData.atomModelDescribe = + atomModelDescribe; + RAP.updatetime = new Date().getTime(); + ctx.body = { + message: '编辑元分类/模型成功', + }; + await next(); + await ctx.sequelize.models.AtomModel.update( + { atomModelName, atomModelDescribe }, + { where: { atomModelId } }, + ); +}); + +// @ 查重元分类名称 +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; + const RAP = resourceCache.atomModelPool + const normalIndex = binarySearch(RAP.normalData, atomModelId, 'atomModelId') + if (normalIndex == -1) { + ctx.throw(400, { e: '不存在此元分类/模型记录。' }); + return; + } + const allIndex = binarySearch(RAP.allData, atomModelId, 'atomModelId') + RAP.normalData.splice(normalIndex, 1); + RAP.allData.splice(allIndex, 1); + RAP.deleteData.push(RAP.objectData[atomModelId]) + RAP.length--; + RAP.updatetime = new Date().getTime(); + const DeleteTime = new Date().toISOString() + RAP.objectData[atomModelId].isDelete = DeleteTime + ctx.body = { message: '删除元分类/模型成功。' }; + await next(); + await ctx.sequelize.models.AtomModel.update( + { isDelete: DeleteTime }, + { where: { atomModelId } }, + ); +}); + +export default atomModel; + +// = 函数名: checkName +// = 描述: 查重模型名称 +// = 参数: None +// = 返回值: undefined +// = 创建人: expressgy +// = 创建时间: 2023-12-01 22:56:12 - +function checkName(name) { + for (let i = 0; i < resourceCache.atomModelPool.normalData.length; i++) { + if (name == resourceCache.atomModelPool.normalData[i].atomModelName) { + return i; + } + } + return -1; +} diff --git a/reference/graphResource2/src/routes/graphResource2/baseDict/index.dto.js b/reference/graphResource2/src/routes/graphResource2/baseDict/index.dto.js new file mode 100644 index 0000000..5a562d7 --- /dev/null +++ b/reference/graphResource2/src/routes/graphResource2/baseDict/index.dto.js @@ -0,0 +1,229 @@ +// | ------------------------------------------------------------ +// | @版本: 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'], + minimum: 0, + errorMessage: { + type: '元分类/模型ID必须是整数', + minimum: '元分类/模型ID是一个正整数', + }, + }, + reduce:{ + type: ['integer'], + minimum: 0, + default: 1, + 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'], + minimum: 0, + errorMessage: { + type: '元分类/模型ID必须是整数', + minimum: '元分类/模型ID是一个正整数', + }, + }, + baseDictName:{ + type: 'string', + minLength: 1, + maxLength: 255, + errorMessage: { + type: '字典项名称必须是一个字符串', + maxLength: '字典项名称长度超出限制255', + minLength: '字典项名称长度过短', + }, + }, + baseDictFather:{ + type: ['integer'], + minimum: 0, + default: 0, + errorMessage: { + type: '字典项父ID必须是整数', + minimum: '字典项父ID是一个正整数', + }, + }, + baseDictDescribe:{ + type: 'string', + minLength: 1, + maxLength: 2048, + errorMessage: { + type: '字典项名称必须是一个字符串', + maxLength: '字典项名称长度超出限制2048', + minLength: '字典项名称长度过短', + }, + }, + baseDictIdentify:{ + type: 'string', + maxLength: 255, + errorMessage: { + type: '字典项标记必须是一个字符串', + maxLength: '字典项名称长度超出限制255', + }, + }, + }, + required: ['baseDictName'], + errorMessage: { + required: { + baseDictName: '字典项名称为必填项', + }, + }, + }; + 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: '字典项名称长度过短', + }, + }, + baseDictIdentify:{ + type: 'string', + maxLength: 255, + errorMessage: { + type: '字典项标记必须是一个字符串', + maxLength: '字典项名称长度超出限制255', + }, + }, + }, + required: ['baseDictName', 'baseDictId'], + errorMessage: { + required: { + baseDictName: '字典项名称为必填项', + baseDictId: '字典ID为必填项', + }, + }, + }; + return makeDTO(data, schema); +} diff --git a/reference/graphResource2/src/routes/graphResource2/baseDict/index.js b/reference/graphResource2/src/routes/graphResource2/baseDict/index.js new file mode 100644 index 0000000..2c33738 --- /dev/null +++ b/reference/graphResource2/src/routes/graphResource2/baseDict/index.js @@ -0,0 +1,494 @@ +// | ------------------------------------------------------------ +// | @版本: 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 binarySearch from '#common/tools/binarySearch.js'; +import binarySearchMore from "#common/tools/binarySearchMore.js"; +import getNoSpacesStr from "#common/tools/getNoSpacesStr.js"; + +const baseDict = new Router(); + +// @ 获取字典树 +baseDict.get('/getBaseDictTree', async (ctx, next) => { + const verif = GetBaseDictTreeDTO(ctx.query); + if (!verif.status) { + ctx.throw(400, { e: verif.error.map((i) => i.message) }); + return; + } + const { atomModelId, reduce } = ctx.query; + + const RBP = resourceCache.baseDictPool; + // 是否是精简查询 + const isReduce = !(reduce && reduce == 0); + if (atomModelId) { + // 按元分类/模型查询 + if (Object.keys(RBP.atomModelObject).includes(atomModelId.toString())) { + // 找到了指定的元分类/模型,返回其下的根节点字典树 + ctx.body = isReduce + ? RBP.atomModelObject[atomModelId].reduceBaseDictTree + : RBP.atomModelObject[atomModelId].baseDictTree; + } else { + // 未找到指定的元分类/模型,返回默认的根节点字典树,基础数据 + ctx.body = isReduce + ? RBP.atomModelObject[0].reduceBaseDictTree + : RBP.atomModelObject[0].baseDictTree; + } + } else { + // 没有传递元分类/模型id查所有字典 + ctx.body = isReduce + ? RBP.reduceObject[0].children + : RBP.atomObject[0].children; + } +}); + +// @ 获取字典名列表 +baseDict.get('/getBaseDictList', async (ctx, next) => { + const verif = GetBaseDictListDTO(ctx.query); + if (!verif.status) + return ctx.throw(400, { e: verif.error.map((i) => i.message) }); + const { searchData, atomModelId } = ctx.query; + const RBP = resourceCache.baseDictPool; + if (atomModelId) { + // 有元分类/模型id + if (Object.keys(RBP.atomModelObject).includes(atomModelId.toString())) { + // 找到了指定的元分类/模型,返回其下的根节点字典树,不包含子节点 + ctx.body = RBP.atomModelObject[atomModelId].reduceBaseDictTree.map( + (item) => ({ + atomModel: item.atomModel, + baseDictId: item.baseDictId, + baseDictName: item.baseDictName, + baseDictIdentify: item.baseDictIdentify, + baseDictDescribe: item.baseDictDescribe, + }), + ); + } else { + // 未找到指定的元分类/模型,返回默认的根节点字典树,基础数据,不包含子节点 + ctx.body = RBP.atomModelObject[0].reduceBaseDictTree.map( + (item) => ({ + atomModel: item.atomModel, + baseDictId: item.baseDictId, + baseDictName: item.baseDictName, + baseDictIdentify: item.baseDictIdentify, + baseDictDescribe: item.baseDictDescribe, + }), + ); + } + } else { + // 没有传递元分类/模型id查所有根字典,不包含子节点 + ctx.body = RBP.reduceObject[0].children.map((item) => ({ + atomModel: item.atomModel, + baseDictId: item.baseDictId, + baseDictName: item.baseDictName, + baseDictIdentify: item.baseDictIdentify, + baseDictDescribe: item.baseDictDescribe, + })); + } + if (searchData) { + // 如果有模糊查询,对上面返回的数据进行查询过滤 + ctx.body = ctx.body.filter((i) => { + return ( + i.baseDictName + + i.baseDictIdentify + + i.baseDictDescribe + ).includes(searchData); + }); + } +}); + +// @ 通过字典ID获取完整字典结构 +baseDict.get('/getBaseDictStructForBaseDictId', async (ctx, next) => { + const verif = GetBaseDictStructForBaseDictIdDTO(ctx.query); + if (!verif.status) { + ctx.throw(400, { e: verif.error.map((i) => i.message) }); + return; + } + const { baseDictId } = ctx.query; + const RBP = resourceCache.baseDictPool; + if (Object.keys(RBP.reduceObject).includes(baseDictId.toString())) { + // 找到了目标字典项ID,查其精简树结构 + ctx.body = RBP.reduceObject[baseDictId]; + } else { + ctx.throw(400, { e: '未找到指定字典。' }); + } +}); + +// @ 删除字典项 +baseDict.delete('/deleteBaseDictItem', async (ctx, next) => { + const verif = DeleteBaseDictItemDTO(ctx.query); + if (!verif.status) { + return ctx.throw(400, { e: verif.error.map((i) => i.message) }); + } + const baseDictId = ctx.query.baseDictId; + // 查看是否存在该字典项 + const RBP = resourceCache.baseDictPool; + if (!(RBP.atomObject[baseDictId] && !RBP.atomObject[baseDictId].isDelete)) { + return ctx.throw(400, { e: '不存在该字典项' }); + } + // 获取目标字典项ID及所有子节点id + + const baseDictIdList = getAllChildrenBaseDictId(baseDictId); + const deleteTime = new Date().toISOString(); + // 修改两个对象中的isDelete + baseDictIdList.push(baseDictId) + for (let i = 0; i < baseDictIdList.length; i++) { + RBP.atomObject[baseDictIdList[i]].isDelete = deleteTime; + RBP.reduceObject[baseDictIdList[i]].isDelete = deleteTime; + } + // 移除normalList的删除项 + // 给删除ID排序 + baseDictIdList.sort((a, b) => a-b) + // 获取坐标 + const indexList = binarySearchMore(RBP.atomNormalList, baseDictIdList, 'baseDictId', 0, RBP.atomNormalList.length) + // 坐标排序 + indexList.sort((a, b) => a-b) + // 批量删除 + for(let i = indexList.length - 1; i >=0; i--){ + // 从后面删除不影响前面的 + RBP.atomNormalList.splice(indexList[i], 1) + } + // 增加DeleteList项 + RBP.atomDeleteList.push(...baseDictIdList.map(i => RBP.atomObject[i])) + // 将节点从children移出至delChildren + // 移除子元素 + moveChildrenToDelChildren(RBP.atomObject[baseDictId]); + moveChildrenToDelChildren(RBP.reduceObject[baseDictId]); + // 移除本身 + // 原始值 + const fatherBaseDict = RBP.atomObject[RBP.atomObject[baseDictId].baseDictFather]; + // 这里使用二分法是因为确定children升序排列,精简和原始位置一样 + const index = binarySearch(fatherBaseDict.children, baseDictId, 'baseDictId'); + fatherBaseDict.children.splice(index, 1); + fatherBaseDict.delChildren.push(RBP.atomObject[baseDictId]) + fatherBaseDict.delChildren.sort((a, b) => a.baseDictId - b.baseDictId) + // 精简值 + const fatherBaseDictReduce = RBP.reduceObject[RBP.reduceObject[baseDictId].baseDictFather]; + fatherBaseDictReduce.children.splice(index, 1); + fatherBaseDictReduce.delChildren.push(RBP.reduceObject[baseDictId]) + fatherBaseDictReduce.delChildren.sort((a, b) => a.baseDictId - b.baseDictId) + + ctx.body = { + message: '删除节点成功' + }; + await next(); + await ctx.sequelize.models.BaseDict.update( + { + isDelete: deleteTime, + }, + { where: { baseDictId: baseDictIdList } }, + ); +}); + +// @ 新建字典项 +baseDict.post('/createBaseDictItem', async (ctx, next) => { + const verif = CreateBaseDictItemDTO(ctx.request.body); + if (!verif.status) + return ctx.throw(400, { e: verif.error.map((i) => i.message) }); + const atomModelId = ctx.request.body.atomModelId; // 元分类/模型ID + const baseDictName = getNoSpacesStr(ctx.request.body.baseDictName); // 字典项名称 + const baseDictFather = ctx.request.body.baseDictFather; // 父节点ID + const baseDictDescribe = ctx.request.body.baseDictDescribe; // 字典项描述 + const baseDictIdentify = ctx.request.body.baseDictIdentify; // 字典项标志 + const RBP = resourceCache.baseDictPool; + + if (baseDictFather == 0) { + // 根节点 + if (!atomModelId) { + // 检查是否存在元分类/模型ID + return ctx.throw(400, { e: '根字典需要携带元分类/模型ID' }); + } + const hasAtomModel = binarySearch( + resourceCache.atomModelPool.normalData, + atomModelId, + 'atomModelId', + ); + // 判断字典缓存是否存在元分类 + if (hasAtomModel == -1) { + // 检查是否存在元分类/模型 + return ctx.throw(400, { e: '不存在目标元分类/模型' }); + } + const check = checkRootDictName(baseDictName, atomModelId); + if (check != -1) { + // 检查是否重名 + return ctx.throw(400, { e: '该根字典项在目标元分类/模型下重名' }); + } + // 写入数据库 + const newBaseDict = await ctx.sequelize.models.BaseDict.create({ + atomModel: atomModelId, + baseDictName, + baseDictFather, + baseDictDescribe, + baseDictIdentify, + }); + // 获取原始数据 + const newBaseDictItem = newBaseDict.dataValues; + newBaseDictItem.children = []; + newBaseDictItem.delChildren = []; + // 压入原始全量字典列表缓存 + RBP.atomAllList.push(newBaseDictItem); + // 压入原始正常字典列表缓存 + RBP.atomNormalList.push(newBaseDictItem); + // 建立原始字典对象 + RBP.atomObject[newBaseDictItem.baseDictId] = newBaseDictItem; + // 建立原始字典对象关系 + RBP.atomObject['0'].children.push(newBaseDictItem); + // 生成简化数据 + const reduceData = { + atomModel: newBaseDictItem.atomModel, + baseDictId: newBaseDictItem.baseDictId, + baseDictName: newBaseDictItem.baseDictName, + baseDictIdentify: newBaseDictItem.baseDictIdentify, + baseDictDescribe: newBaseDictItem.baseDictDescribe, + baseDictFather: newBaseDictItem.baseDictFather, + children: [], + delChildren: [], + }; + // 建立简化字典对象 + RBP.reduceObject[newBaseDictItem.baseDictId] = reduceData; + // 建立简化字典对象关系 + RBP.reduceObject['0'].children.push(reduceData); + if ( + !Object.keys(RBP.atomModelObject).includes(atomModelId.toString()) + ) { + // 判断缓存是否存在元分类/模型对象 + // 建立元分类字典缓存对象 + RBP.atomModelObject[atomModelId] = { + baseDictTree: [], + reduceBaseDictTree: [], + }; + } + // 分别压入精简原始字典对象到根节点树 + RBP.atomModelObject[atomModelId].baseDictTree.push(newBaseDictItem); + RBP.atomModelObject[atomModelId].reduceBaseDictTree.push(reduceData); + return (ctx.body = { + message: '添加字典项成功', + data: newBaseDictItem, + }); + } else { + // 子节点 + // 判断父节点是否存在 + if ( + !RBP.atomObject[baseDictFather] || + (RBP.atomObject[baseDictFather] && + RBP.atomObject[baseDictFather].isDelete) + ) { + return ctx.throw(400, { e: '不存在父节点' }); + } + // 获取根节点元分类/模型ID + const rootAtomModelId = getRootAtomModelId(baseDictFather); + if (atomModelId != undefined && atomModelId != rootAtomModelId) { + return ctx.throw(400, { + e: '目标元分类/模型与根字典元分类/模型不匹配', + }); + } + // 查同级节点重名 + const check = checkTargetChildrenDictName(baseDictFather, baseDictName); + if (check != -1) { + return ctx.throw(400, { e: '该根字典项在目标字典下重名' }); + } + // 写入数据库 + const newBaseDict = await ctx.sequelize.models.BaseDict.create({ + atomModel: atomModelId, + baseDictName, + baseDictFather, + baseDictDescribe, + baseDictIdentify, + }); + // 获取原始数据 + const newBaseDictItem = newBaseDict.dataValues; + newBaseDictItem.children = []; + newBaseDictItem.delChildren = []; + // 压入原始全量字典列表缓存 + RBP.atomAllList.push(newBaseDictItem); + // 压入原始正常字典列表缓存 + RBP.atomNormalList.push(newBaseDictItem); + // 建立原始字典对象 + RBP.atomObject[newBaseDictItem.baseDictId] = newBaseDictItem; + // 建立原始字典对象关系 + RBP.atomObject[baseDictFather].children.push(newBaseDictItem); + // 生成简化数据 + const reduceData = { + atomModel: newBaseDictItem.atomModel, + baseDictId: newBaseDictItem.baseDictId, + baseDictName: newBaseDictItem.baseDictName, + baseDictIdentify: newBaseDictItem.baseDictIdentify, + baseDictDescribe: newBaseDictItem.baseDictDescribe, + baseDictFather: newBaseDictItem.baseDictFather, + children: [], + delChildren: [], + }; + // 建立简化字典对象 + RBP.reduceObject[newBaseDictItem.baseDictId] = reduceData; + // 建立简化字典对象关系 + RBP.reduceObject[baseDictFather].children.push(reduceData); + // 检查一下AtomModelObject + // console.log(JSON.stringify(RBP.atomModelObject[atomModelId].baseDictTree,null,4)); + // console.log(JSON.stringify(RBP.atomModelObject[atomModelId].reduceBaseDictTree, null, 4)); + return (ctx.body = { + message: '添加字典项成功', + data: newBaseDictItem, + }); + } +}); + +// @ 编辑字典项 +baseDict.post('/editBaseDictItem', async (ctx, next) => { + const verif = EditBaseDictItemDTO(ctx.request.body); + if (!verif.status) { + return ctx.throw(400, { e: verif.error.map((i) => i.message) }); + } + const baseDictId = ctx.request.body.baseDictId; + const baseDictName = getNoSpacesStr(ctx.request.body.baseDictName); + const baseDictDescribe = ctx.request.body.baseDictDescribe; + const baseDictIdentify = ctx.request.body.baseDictIdentify; + const RBP = resourceCache.baseDictPool; + // 检查字典项是否存在 + if (!(RBP.atomObject[baseDictId] && !RBP.atomObject[baseDictId].isDelete)) { + return ctx.throw(400, { e: '待修改的字典项不存在' }); + } + // 查重名 + const baseDictFather = RBP.atomObject[baseDictId].baseDictFather; + if (baseDictFather == 0) { + const check = checkRootDictName( + baseDictName, + RBP.atomObject[baseDictId].atomModel, + ); + if ( + check != -1 && + RBP.atomObject[baseDictFather].children[check].baseDictId != + baseDictId + ) { + return ctx.throw(400, { e: '待修改的字典项在目标字典下重名' }); + } + } else { + const check = checkTargetChildrenDictName(baseDictFather, baseDictName); + if ( + check != -1 && + RBP.atomObject[baseDictFather].children[check].baseDictId != + baseDictId + ) { + return ctx.throw(400, { e: '待修改的字典项在目标字典下重名' }); + } + } + // 更新原始对象字典 + RBP.atomObject[baseDictId].baseDictId = baseDictId; + RBP.atomObject[baseDictId].baseDictName = baseDictName; + RBP.atomObject[baseDictId].baseDictDescribe = baseDictDescribe; + RBP.atomObject[baseDictId].baseDictIdentify = baseDictIdentify; + // 更新精简对象字典 + RBP.reduceObject[baseDictId].baseDictId = baseDictId; + RBP.reduceObject[baseDictId].baseDictName = baseDictName; + RBP.reduceObject[baseDictId].baseDictDescribe = baseDictDescribe; + RBP.reduceObject[baseDictId].baseDictIdentify = baseDictIdentify; + // 检查一下AtomModelObject + // console.log(JSON.stringify(RBP.atomModelObject[RBP.atomObject[baseDictId].atomModel].baseDictTree,null,4)); + // console.log(JSON.stringify(RBP.atomModelObject[RBP.atomObject[baseDictId].atomModel].reduceBaseDictTree, null, 4)); + ctx.body = { + message: '字典项更新成功', + }; + await next(); + await ctx.sequelize.models.BaseDict.update( + { + baseDictName, + baseDictDescribe, + baseDictIdentify, + }, + { where: { baseDictId } }, + ); +}); + +export default baseDict; + +// 查重根节点的字典名字 +function checkRootDictName(baseDictName, atomModelId) { + const RBP = resourceCache.baseDictPool; + const normalRootList = RBP.reduceObject[0].children; + for (let i = 0; i < normalRootList.length; i++) { + if ( + normalRootList[i].baseDictName == baseDictName && + normalRootList[i].atomModel == atomModelId + ) { + return i; + } + } + return -1; +} + +// 查重目标节点的子节点名字 +function checkTargetChildrenDictName(baseDictFather, baseDictName) { + const RBP = resourceCache.baseDictPool; + const targetList = RBP.atomObject[baseDictFather].children; + for (let i = 0; i < targetList.length; i++) { + if (targetList[i].baseDictName == baseDictName) { + return i; + } + } + return -1; +} + +// 获取字典项的根节点上的元分类/模型ID +function getRootAtomModelId(baseDictFather) { + const fatherNode = resourceCache.baseDictPool.atomObject[baseDictFather]; + if (fatherNode.baseDictFather == 0) { + return fatherNode.atomModel; + } else { + return getRootAtomModelId(fatherNode.baseDictFather); + } +} + +// 查字典项下所有的子节点id +function getAllChildrenBaseDictId(baseDictId) { + const baseDictIdList = []; + for ( + let i = 0; + i < resourceCache.baseDictPool.atomObject[baseDictId].children.length; + i++ + ) { + if ( + resourceCache.baseDictPool.atomObject[baseDictId].children[i] + .children.length > 0 + ) { + baseDictIdList.push( + ...getAllChildrenBaseDictId( + resourceCache.baseDictPool.atomObject[baseDictId].children[ + i + ].baseDictId, + ), + ); + } + baseDictIdList.push( + resourceCache.baseDictPool.atomObject[baseDictId].children[i] + .baseDictId, + ); + } + return baseDictIdList; +} + +// 把children移动至delChildren +function moveChildrenToDelChildren(obj) { + if (obj.children.length > 0) { + for (let i = 0; i < obj.children.length; i++) { + moveChildrenToDelChildren(obj.children[i]); + } + } + obj.delChildren.push(...obj.children); + obj.delChildren.sort((a, b) => a.baseDictId - b.baseDictId); + obj.children = []; +} diff --git a/reference/graphResource2/src/routes/graphResource2/index.js b/reference/graphResource2/src/routes/graphResource2/index.js new file mode 100644 index 0000000..036a95a --- /dev/null +++ b/reference/graphResource2/src/routes/graphResource2/index.js @@ -0,0 +1,65 @@ +// | ------------------------------------------------------------ +// | @版本: 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"; +import resourceClass from "#routes/graphResource2/resourceClass/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('/resourceClass', resourceClass.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/reference/graphResource2/src/routes/graphResource2/resourceClass/index.dto.js b/reference/graphResource2/src/routes/graphResource2/resourceClass/index.dto.js new file mode 100644 index 0000000..760cd03 --- /dev/null +++ b/reference/graphResource2/src/routes/graphResource2/resourceClass/index.dto.js @@ -0,0 +1,655 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: graphResource2 +// | @文件描述: index.dto.js - +// | @创建时间: 2023-12-03 15:30 +// | @更新时间: 2023-12-03 15:30 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ + +import makeDTO from '#common/dto/index.js'; + +export function GetBaseDictTreeDTO(data) { + const schema = { + type: 'object', + properties: { + atomModelId: { + type: ['integer'], + minimum: 0, + errorMessage: { + type: '元分类/模型ID必须是整数', + minimum: '元分类/模型ID是一个正整数', + }, + }, + reduce: { + type: ['integer'], + minimum: 0, + default: 1, + errorMessage: { + type: '元分类/模型ID必须是整数', + minimum: '元分类/模型ID是一个正整数', + }, + }, + }, + }; + return makeDTO(data, schema); +} + +// @ 获取资源类列表 +export function GetResourceClassListDTO(data) { + const schema = { + type: 'object', + properties: { + atomModelId: { + type: ['integer'], + minimum: 0, + errorMessage: { + type: '元分类/模型ID必须是整数', + minimum: '元分类/模型ID是一个正整数', + }, + }, + searchData: { + type: 'string', + maxLength: 255, + errorMessage: { + type: '查询内容必须是一个字符串', + maxLength: '查询内容长度超出限制255', + }, + }, + }, + required: ['atomModelId'], + errorMessage: { + required: { + atomModelId: '元分类/模型ID为必填项', + }, + }, + }; + return makeDTO(data, schema); +} + +// @ 获取资源类分页 +export function GetResourceClassPageDTO(data) { + const schema = { + type: 'object', + properties: { + atomModelId: { + type: ['integer'], + minimum: 0, + errorMessage: { + type: '元分类/模型ID必须是整数', + minimum: '元分类/模型ID是一个正整数', + }, + }, + searchData: { + type: 'string', + maxLength: 255, + errorMessage: { + type: '查询内容必须是一个字符串', + maxLength: '查询内容长度超出限制255', + }, + }, + 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', + }, + }, + }, + required: ['atomModelId'], + errorMessage: { + required: { + atomModelId: '元分类/模型ID为必填项', + }, + }, + }; + return makeDTO(data, schema); +} + +// @ 获取资源类树 +export function GetResourceClassTreeDTO(data) { + const schema = { + type: 'object', + properties: { + atomModelId: { + type: ['integer'], + minimum: 0, + errorMessage: { + type: '元分类/模型ID必须是整数', + minimum: '元分类/模型ID是一个正整数', + }, + }, + searchData: { + type: 'string', + maxLength: 255, + errorMessage: { + type: '查询内容必须是一个字符串', + maxLength: '查询内容长度超出限制255', + }, + }, + }, + required: ['atomModelId'], + errorMessage: { + required: { + atomModelId: '元分类/模型ID为必填项', + }, + }, + }; + return makeDTO(data, schema); +} + +// @ 添加资源类 +export function CreateResourceClassItemDTO(data) { + const schema = { + type: 'object', + properties: { + atomModelId: { + type: ['integer'], + minimum: 0, + errorMessage: { + type: '元分类/模型ID必须是整数', + minimum: '元分类/模型ID是一个正整数', + }, + }, + resourceClassBaseDefine: { + type: ['integer'], + minimum: 0, + errorMessage: { + type: '资源类来源必须是整数', + minimum: '资源类来源是一个正整数', + }, + }, + resourceClassBaseName: { + type: 'string', + minLength: 1, + maxLength: 255, + errorMessage: { + type: '资源类名必须是一个字符串', + maxLength: '资源类名长度超出限制255', + minLength: '资源类名长度过短', + }, + }, + resourceClassBaseDescribe: { + type: 'string', + minLength: 1, + maxLength: 2048, + errorMessage: { + type: '资源类描述必须是一个字符串', + maxLength: '资源类描述长度超出限制2048', + minLength: '资源类描述长度过短', + }, + }, + resourceClassBaseType: { + type: ['integer'], + minimum: 0, + default: 0, + errorMessage: { + type: '资源类业务类型必须是整数', + minimum: '资源类业务类型是一个正整数', + }, + }, + resourceClassBaseIdentify: { + type: 'string', + minLength: 8, + maxLength: 8, + pattern: '^[a-zA-Z\\s]+$', + errorMessage: { + type: '资源类标识必须是一个字符串', + maxLength: '资源类标识是一个8位字符串', + minLength: '资源类标识是一个8位字符串', + pattern: '资源类标识必须为纯英文', + }, + }, + resourceClassBaseColor: { + type: 'string', + minLength: 1, + maxLength: 255, + errorMessage: { + type: '资源类颜色描述必须是一个字符串', + maxLength: '资源类颜色描述长度超出限制255', + minLength: '资源类颜色描述长度过短', + }, + }, + resourceClassBaseAvatar: { + type: 'string', + minLength: 1, + maxLength: 255, + errorMessage: { + type: '资源类图标必须是一个字符串', + maxLength: '资源类图标长度超出限制255', + minLength: '资源类图标长度过短', + }, + }, + resourceClassRelationId: { + type: ['integer'], + minimum: 0, + default: 0, + errorMessage: { + type: '父资源类节点ID必须是整数', + minimum: '父资源类节点ID是一个正整数', + }, + }, + }, + required: [ + 'atomModelId', + 'resourceClassBaseIdentify', + 'resourceClassBaseDescribe', + 'resourceClassBaseName', + ], + errorMessage: { + required: { + atomModelId: '元分类/模型ID为必填项', + resourceClassBaseIdentify: '资源类标识为必填项', + resourceClassBaseDescribe: '资源类描述为必填项', + resourceClassBaseName: '资源类名称为必填项', + }, + }, + }; + return makeDTO(data, schema); +} + +// @ 编辑资源类 +export function EditResourceClassItemDTO(data) { + const schema = { + type: 'object', + properties: { + resourceClassBaseId: { + type: ['integer'], + minimum: 0, + errorMessage: { + type: '资源类ID必须是整数', + minimum: '资源类ID是一个正整数', + }, + }, + resourceClassBaseDefine: { + type: ['integer'], + minimum: 0, + errorMessage: { + type: '资源类来源必须是整数', + minimum: '资源类来源是一个正整数', + }, + }, + resourceClassBaseName: { + type: 'string', + minLength: 1, + maxLength: 255, + errorMessage: { + type: '资源类名必须是一个字符串', + maxLength: '资源类名长度超出限制255', + minLength: '资源类名长度过短', + }, + }, + resourceClassBaseDescribe: { + type: 'string', + minLength: 1, + maxLength: 2048, + errorMessage: { + type: '资源类描述必须是一个字符串', + maxLength: '资源类描述长度超出限制2048', + minLength: '资源类描述长度过短', + }, + }, + resourceClassBaseType: { + type: ['integer'], + minimum: 0, + default: 0, + errorMessage: { + type: '资源类业务类型必须是整数', + minimum: '资源类业务类型是一个正整数', + }, + }, + resourceClassBaseIdentify: { + type: 'string', + minLength: 8, + maxLength: 8, + pattern: '^[a-zA-Z\\s]+$', + errorMessage: { + type: '资源类标识必须是一个字符串', + maxLength: '资源类标识是一个8位字符串', + minLength: '资源类标识是一个8位字符串', + pattern: '资源类标识必须为纯英文', + }, + }, + resourceClassBaseColor: { + type: 'string', + minLength: 1, + maxLength: 255, + errorMessage: { + type: '资源类颜色描述必须是一个字符串', + maxLength: '资源类颜色描述长度超出限制255', + minLength: '资源类颜色描述长度过短', + }, + }, + resourceClassBaseAvatar: { + type: 'string', + minLength: 1, + maxLength: 255, + errorMessage: { + type: '资源类图标必须是一个字符串', + maxLength: '资源类图标长度超出限制255', + minLength: '资源类图标长度过短', + }, + }, + }, + required: [ + 'resourceClassBaseId', + 'resourceClassBaseIdentify', + 'resourceClassBaseName', + ], + errorMessage: { + required: { + resourceClassBaseId: '资源类ID为必填项', + resourceClassBaseIdentify: '资源类标识为必填项', + resourceClassBaseName: '资源类名称为必填项', + }, + }, + }; + return makeDTO(data, schema); +} + +// @ 删除资源类 +export function DeleteResourceClassItemDTO(data) { + const schema = { + type: 'object', + properties: { + nodeId: { + type: ['integer'], + minimum: 0, + errorMessage: { + type: '资源类节点ID必须是整数', + minimum: '资源类节点ID是一个正整数', + }, + }, + }, + required: ['nodeId'], + errorMessage: { + required: { + nodeId: '资源类节点ID为必填项', + }, + }, + }; + return makeDTO(data, schema); +} + +// @ 创建资源类关联 +export function CreateResourceClassRelationDTO(data) { + const schema = { + type: 'object', + properties: { + resourceClassRelationFather: { + type: ['integer'], + minimum: 0, + errorMessage: { + type: '父级资源类ID必须是整数', + minimum: '父级资源类ID是一个正整数', + }, + }, + resourceClassRelationTarget: { + type: ['integer'], + minimum: 0, + errorMessage: { + type: '父级资源类ID必须是整数', + minimum: '目标资源类ID是一个正整数', + }, + }, + }, + required: [ + 'resourceClassRelationFather', + 'resourceClassRelationTarget', + ], + errorMessage: { + required: { + resourceClassRelationFather: '父级资源类ID为必填项', + resourceClassRelationTarget: '目标资源类ID为必填项', + }, + }, + }; + return makeDTO(data, schema); +} + +// @ 删除资源类关联 +export function DeleteResourceClassRelationDTO(data) { + const schema = { + type: 'object', + properties: { + resourceClassRelationId: { + type: ['integer'], + minimum: 0, + errorMessage: { + type: '资源类关联ID必须是整数', + minimum: '资源类关联ID是一个正整数', + }, + }, + }, + required: ['resourceClassRelationId'], + errorMessage: { + required: { + resourceClassRelationId: '资源类关联ID为必填项', + }, + }, + }; + return makeDTO(data, schema); +} + +// @ 获取资源类完整信息 +export function GetResourceClassCompleteInfoDTO(data) { + const schema = { + type: 'object', + properties: { + resourceClassBaseId: { + type: ['integer'], + minimum: 0, + errorMessage: { + type: '资源类关联ID必须是整数', + minimum: '资源类关联ID是一个正整数', + }, + }, + resourceClassBaseIdentify: { + type: 'string', + minLength: 8, + maxLength: 8, + pattern: '^[a-zA-Z\\s]+$', + errorMessage: { + type: '资源类标识必须是一个字符串', + maxLength: '资源类标识是一个8位字符串', + minLength: '资源类标识是一个8位字符串', + pattern: '资源类标识必须为纯英文', + }, + }, + }, + }; + return makeDTO(data, schema); +} + +// @ 创建资源类拓展字段 +export function CreateResourceClassExpandFieldItemDTO(data) { + const schema = { + type: 'object', + properties: { + resourceClassBaseId: { + type: ['integer'], + minimum: 0, + errorMessage: { + type: '资源类ID必须是整数', + minimum: '资源类ID是一个正整数', + }, + }, + resourceClassExpandFieldName: { + type: 'string', + minLength: 1, + maxLength: 255, + errorMessage: { + type: '资源类拓展字段名必须是一个字符串', + maxLength: '资源类拓展字段名长度超出限制255', + minLength: '资源类拓展字段名长度过短', + }, + }, + resourceClassExpandFieldIdentify: { + type: 'string', + minLength: 1, + maxLength: 64, + pattern: '^[a-zA-Z\\s]+$', + errorMessage: { + type: '资源类拓展字段标识必须是一个字符串', + maxLength: '资源类拓展字段标识是一个8位字符串', + minLength: '资源类拓展字段标识是一个8位字符串', + pattern: '资源类拓展字段标识必须为纯英文', + }, + }, + resourceClassExpandFieldDisplayType: { + type: ['integer'], + minimum: 0, + default: 0, + errorMessage: { + type: '拓展字段显示类型必须是整数', + minimum: '拓展字段显示类型是一个正整数', + }, + }, + resourceClassExpandFieldRelationType: { + type: ['integer'], + minimum: 0, + errorMessage: { + type: '拓展字段关联类型必须是整数', + minimum: '拓展字段关联类型是一个正整数', + }, + }, + resourceClassExpandFieldValue: { + type: 'string', + minLength: 1, + maxLength: 255, + errorMessage: { + type: '资源类拓展字段值必须是一个字符串', + maxLength: '资源类拓展字段值长度超出限制255', + minLength: '资源类拓展字段值长度过短', + }, + }, + }, + required: ['resourceClassBaseId', 'resourceClassExpandFieldName', 'resourceClassExpandFieldIdentify', 'resourceClassExpandFieldValue'], + errorMessage: { + required: { + resourceClassBaseId: '资源类ID为必填项', + resourceClassExpandFieldName: '资源类拓展字段名为必填项', + resourceClassExpandFieldIdentify: '资源类拓展字段标识为必填项', + resourceClassExpandFieldValue: '资源类拓展字段值为必填项', + }, + }, + }; + return makeDTO(data, schema); +} + +// @ 编辑资源类拓展字段 +export function EditResourceClassExpandFieldItemDTO(data) { + const schema = { + type: 'object', + properties: { + resourceClassExpandFieldId: { + type: ['integer'], + minimum: 0, + errorMessage: { + type: '资源类拓展字段ID必须是整数', + minimum: '资源类拓展字段ID是一个正整数', + }, + }, + resourceClassExpandFieldName: { + type: 'string', + minLength: 1, + maxLength: 255, + errorMessage: { + type: '资源类拓展字段名必须是一个字符串', + maxLength: '资源类拓展字段名长度超出限制255', + minLength: '资源类拓展字段名长度过短', + }, + }, + resourceClassExpandFieldIdentify: { + type: 'string', + minLength: 1, + maxLength: 64, + pattern: '^[a-zA-Z\\s]+$', + errorMessage: { + type: '资源类拓展字段标识必须是一个字符串', + maxLength: '资源类拓展字段标识是一个8位字符串', + minLength: '资源类拓展字段标识是一个8位字符串', + pattern: '资源类拓展字段标识必须为纯英文', + }, + }, + resourceClassExpandFieldDisplayType: { + type: ['integer'], + minimum: 0, + default: 0, + errorMessage: { + type: '拓展字段显示类型必须是整数', + minimum: '拓展字段显示类型是一个正整数', + }, + }, + resourceClassExpandFieldRelationType: { + type: ['integer'], + minimum: 0, + errorMessage: { + type: '拓展字段关联类型必须是整数', + minimum: '拓展字段关联类型是一个正整数', + }, + }, + resourceClassExpandFieldValue: { + type: 'string', + minLength: 1, + maxLength: 255, + errorMessage: { + type: '资源类拓展字段值必须是一个字符串', + maxLength: '资源类拓展字段值长度超出限制255', + minLength: '资源类拓展字段值长度过短', + }, + }, + }, + required: ['resourceClassExpandFieldId', 'resourceClassExpandFieldName', 'resourceClassExpandFieldIdentify', 'resourceClassExpandFieldValue'], + errorMessage: { + required: { + resourceClassExpandFieldId: '资源类拓展字段ID为必填项', + resourceClassExpandFieldName: '资源类拓展字段名为必填项', + resourceClassExpandFieldIdentify: '资源类拓展字段标识为必填项', + resourceClassExpandFieldValue: '资源类拓展字段值为必填项', + }, + }, + }; + return makeDTO(data, schema); +} + +// @ 删除资源类拓展字段 +export function DeleteResourceClassExpandFieldItemDTO(data) { + const schema = { + type: 'object', + properties: { + resourceClassExpandFieldId: { + type: ['integer'], + minimum: 0, + errorMessage: { + type: '资源类拓展字段ID必须是整数', + minimum: '资源类拓展字段ID是一个正整数', + }, + }, + }, + required: ['resourceClassExpandFieldId', ], + errorMessage: { + required: { + resourceClassExpandFieldId: '资源类拓展字段ID为必填项', + }, + }, + }; + return makeDTO(data, schema); +} diff --git a/reference/graphResource2/src/routes/graphResource2/resourceClass/index.js b/reference/graphResource2/src/routes/graphResource2/resourceClass/index.js new file mode 100644 index 0000000..e18bd12 --- /dev/null +++ b/reference/graphResource2/src/routes/graphResource2/resourceClass/index.js @@ -0,0 +1,650 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: graphResource2 +// | @文件描述: index.js - +// | @创建时间: 2023-12-03 15:24 +// | @更新时间: 2023-12-03 15:24 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ +import Router from 'koa-router'; +import { + CreateResourceClassExpandFieldItemDTO, + CreateResourceClassItemDTO, + CreateResourceClassRelationDTO, + DeleteResourceClassExpandFieldItemDTO, + DeleteResourceClassItemDTO, + DeleteResourceClassRelationDTO, + EditResourceClassExpandFieldItemDTO, + EditResourceClassItemDTO, + GetResourceClassCompleteInfoDTO, + GetResourceClassListDTO, + GetResourceClassPageDTO, + GetResourceClassTreeDTO, +} from '#routes/graphResource2/resourceClass/index.dto.js'; +import getPage from '#common/tools/getArrayPage.js'; +import getNoSpacesStr from '#common/tools/getNoSpacesStr.js'; +import binarySearch from '#common/tools/binarySearch.js'; +import binarySearchMore from '#common/tools/binarySearchMore.js'; +import { Op } from 'sequelize'; + +const resourceClass = new Router(); + +// @ 获取资源类列表 +resourceClass.get('/getResourceClassList', async (ctx, next) => { + const verif = GetResourceClassListDTO(ctx.query); + if (!verif.status) { + return ctx.throw(400, { e: verif.error.map((i) => i.message) }); + } + const RAP = resourceCache.atomModelPool; + const { searchData, atomModelId } = ctx.query; + if (!RAP.normalData.some((i) => i.atomModelId == atomModelId)) { + return ctx.throw(400, { e: '不存在该元分类/模型' }); + } + const RRP = resourceCache.resourcePool; + const classListForAtomModel = RRP.classListForAtomModel[atomModelId].map( + (i) => ({ + resourceClassBaseId: i.resourceClassBaseId, + resourceClassBaseName: i.resourceClassBaseName, + resourceClassBaseIdentify: i.resourceClassBaseIdentify, + resourceClassBaseColor: i.resourceClassBaseColor, + resourceClassBaseAvatar: i.resourceClassBaseAvatar, + }), + ); + ctx.body = classListForAtomModel; + if (searchData) { + ctx.body = classListForAtomModel.filter((i) => + i.resourceClassBaseName.includes(searchData.trim()), + ); + } +}); + +// @ 获取资源类分页 +resourceClass.get('/getResourceClassPage', async (ctx, next) => { + const verif = GetResourceClassPageDTO(ctx.query); + if (!verif.status) { + return ctx.throw(400, { e: verif.error.map((i) => i.message) }); + } + const RAP = resourceCache.atomModelPool; + const { searchData, atomModelId, pageSize, pageNum } = ctx.query; + if (!RAP.normalData.some((i) => i.atomModelId == atomModelId)) { + return ctx.throw(400, { e: '不存在该元分类/模型' }); + } + const RRP = resourceCache.resourcePool; + let classListForAtomModel = RRP.classListForAtomModel[atomModelId]; + if (searchData) { + classListForAtomModel = classListForAtomModel.filter((i) => + i.resourceClassBaseName.includes(searchData.trim()), + ); + } + const pageList = getPage(classListForAtomModel, pageSize, pageNum); + ctx.body = { + total: classListForAtomModel.length, + data: classListForAtomModel, + }; +}); + +// @ 获取资源类树 +resourceClass.get('/getResourceClassTree', async (ctx, next) => { + const verif = GetResourceClassTreeDTO(ctx.query); + if (!verif.status) { + return ctx.throw(400, { e: verif.error.map((i) => i.message) }); + } + const RAP = resourceCache.atomModelPool; + const { searchData, atomModelId } = ctx.query; + if (!RAP.normalData.some((i) => i.atomModelId == atomModelId)) { + return ctx.throw(400, { e: '不存在该元分类/模型' }); + } + const RRP = resourceCache.resourcePool; + ctx.body = RRP.classNodeObjectForAtomModel[atomModelId].map( + (i) => i.nodeZeroInfo, + ); +}); + +// @ 添加资源类 +resourceClass.post('/createResourceClassItem', async (ctx, next) => { + const verif = CreateResourceClassItemDTO(ctx.request.body); + if (!verif.status) { + return ctx.throw(400, { e: verif.error.map((i) => i.message) }); + } + const { + atomModelId, + resourceClassBaseName, + resourceClassBaseDescribe, + resourceClassBaseIdentify, + resourceClassBaseAvatar, + resourceClassBaseDefine, + resourceClassBaseColor, + resourceClassRelationId, + resourceClassBaseType, + } = ctx.request.body; + const RAP = resourceCache.atomModelPool; + const RRP = resourceCache.resourcePool; + // @ 判断是否存在元分类/模型 + if (!RAP.normalData.some((i) => i.atomModelId == atomModelId)) { + return ctx.throw(400, { e: '不存在目标元分类/模型' }); + } + // @ 判断是否重名 + if ( + RRP.classListForAtomModel[atomModelId].some( + (i) => + i.resourceClassBaseName == + getNoSpacesStr(resourceClassBaseName), + ) + ) { + return ctx.throw(400, { e: '资源类在目标元分类/模型已存在' }); + } + // @ 判断是否已存在资源类标识 + if ( + RRP.classList.some( + (i) => + i.resourceClassBaseIdentify == + getNoSpacesStr(resourceClassBaseIdentify).toUpperCase(), + ) + ) { + return ctx.throw(400, { e: '资源类标识已存在' }); + } + // @ 判断是否存在父节点 + if (resourceClassRelationId != 0) { + if (RRP.classRelationObject[resourceClassRelationId] == undefined) { + return ctx.throw(400, { e: '不存在目标资源类树节点' }); + } + if ( + !RRP.classListForAtomModel[atomModelId].some( + (i) => + i.resourceClassBaseId == + RRP.classRelationObject[resourceClassRelationId] + .resourceClassRelationTarget, + ) + ) { + return ctx.throw(400, { + e: '目标资源类树节点不存在于目标元分类/模型中', + }); + } + } + + // 写入资源类 + const newClassItem = await ctx.sequelize.models.ResourceClassBase.create({ + atomModel: atomModelId, + resourceClassBaseName: getNoSpacesStr(resourceClassBaseName), + resourceClassBaseDescribe, + resourceClassBaseIdentify: getNoSpacesStr( + resourceClassBaseIdentify, + ).toUpperCase(), + resourceClassBaseAvatar, + resourceClassBaseDefine, + resourceClassBaseColor, + resourceClassBaseType, + }); + const newClassData = newClassItem.dataValues; + const classId = newClassData.resourceClassBaseId; + // | 建立缓存 + // @ 资源类基础信息 + // ! 写入classList + RRP.classList.push(newClassData); + // ! 写入classListForAtomModel + if (RRP.classListForAtomModel[atomModelId] === undefined) { + RRP.classListForAtomModel[atomModelId] = []; + } + RRP.classListForAtomModel[atomModelId].push(newClassData); + // ! 写入classIdList + RRP.classIdList.push(classId); + // ! 写入classObject + RRP.classObject[classId] = newClassData; + + // @ 资源类拓展字段信息 + // ! 写入classExpandForClassBaseObject + RRP.classExpandForClassBaseObject[classId] = {}; + + // @ 资源实体结构表 + // ! 写入entityStructForClassBaseObject + RRP.entityStructForClassBaseObject[classId] = {}; + + // @ 资源类关系 + // ! 写入classRelationObjectForTargetClass + RRP.classRelationObjectForTargetClass[classId] = []; + // @ 获取目标资源关系节点的资源类ID + const fatherClassId = + resourceClassRelationId == 0 + ? 0 + : RRP.classRelationObject[resourceClassRelationId] + .resourceClassRelationTarget; + // 在数据库添加这条关系 + const newClassRelation = + await ctx.sequelize.models.ResourceClassRelation.create({ + resourceClassRelationFather: fatherClassId, + resourceClassRelationTarget: classId, + }); + const newClassRelationData = newClassRelation.dataValues; + const newRelationId = newClassRelationData.resourceClassRelationId; + + RRP.classRelationList.push(newClassRelationData); + RRP.classRelationIdList.push(newRelationId); + RRP.classRelationObject[newRelationId] = newClassRelationData; + RRP.classRelationObjectForTargetClass[classId].push(newClassRelationData); + + // @ 资源类数据模型对象集合 + // ! 写入classModelObject + RRP.classModelObject[classId] = new RRP.ClassModel( + RRP.classObject[classId], + ); + await RRP.classModelObject[ + newClassData.resourceClassBaseId + ].createSequelizeModel(); + + // @ 关系节点数据模型 + // ! 这里生成关系节点数据模型 + // 拿到当前资源类模型 + const nowClassModel = RRP.classModelObject[classId]; + // 获取当前资源类模型的关联列表 + const nowRelationList = nowClassModel.classRelationList; + // 拿到父节点和节点ID + const nodeId = nowRelationList[0].resourceClassRelationId; + const classNode = new RRP.ClassNodeModel(nowClassModel, nodeId); + RRP.classNodeObject[nodeId] = classNode; + RRP.classNodeObject[resourceClassRelationId].children.push(classNode); + + if (resourceClassRelationId == 0) { + RRP.classNodeObjectForAtomModel[atomModelId].push(classNode); + } + + ctx.body = { + message: '创建资源类成功', + data: { + resourceClassBase: newClassData, + resourceClassRelation: newClassRelationData, + }, + }; +}); + +// @ 编辑资源类 +resourceClass.post('/editResourceClassItem', async (ctx, next) => { + const verif = EditResourceClassItemDTO(ctx.request.body); + if (!verif.status) { + return ctx.throw(400, { e: verif.error.map((i) => i.message) }); + } + const { + resourceClassBaseName, + resourceClassBaseDescribe, + resourceClassBaseIdentify, + resourceClassBaseId, + resourceClassBaseAvatar, + resourceClassBaseDefine, + resourceClassBaseColor, + resourceClassBaseType, + } = ctx.request.body; + const RRP = resourceCache.resourcePool; + let oldName, oldIdentify, atomModelId; + // @ 判断ID是否存在 + if (!RRP.classIdList.includes(resourceClassBaseId)) { + return ctx.throw(400, { e: '资源类不存在' }); + } else { + oldName = RRP.classObject[resourceClassBaseId].resourceClassBaseId; + oldIdentify = + RRP.classObject[resourceClassBaseId].resourceClassBaseIdentify; + atomModelId = RRP.classObject[resourceClassBaseId].atomModel; + } + // @ 判断名称是否重复 + if ( + RRP.classListForAtomModel[atomModelId].some( + (i) => + i.resourceClassBaseName == + getNoSpacesStr(resourceClassBaseName) && + i.resourceClassBaseId != resourceClassBaseId, + ) + ) { + return ctx.throw(400, { e: '资源类重名' }); + } + // @ 判断标识是否重复 + if ( + RRP.classList.some( + (i) => + i.resourceClassBaseIdentify == + getNoSpacesStr(resourceClassBaseIdentify).toUpperCase() && + i.resourceClassBaseId != resourceClassBaseId, + ) + ) { + return ctx.throw(400, { e: '资源类标识已存在' }); + } + // 修改信息 + RRP.classObject[resourceClassBaseId].resourceClassBaseName = getNoSpacesStr( + resourceClassBaseName, + ); + RRP.classObject[resourceClassBaseId].resourceClassBaseDescribe = + resourceClassBaseDescribe; + RRP.classObject[resourceClassBaseId].resourceClassBaseIdentify = + getNoSpacesStr(resourceClassBaseIdentify).toUpperCase(); + RRP.classObject[resourceClassBaseId].resourceClassBaseId = + resourceClassBaseId; + RRP.classObject[resourceClassBaseId].resourceClassBaseAvatar = + resourceClassBaseAvatar; + RRP.classObject[resourceClassBaseId].resourceClassBaseDefine = + resourceClassBaseDefine; + RRP.classObject[resourceClassBaseId].resourceClassBaseColor = + resourceClassBaseColor; + RRP.classObject[resourceClassBaseId].resourceClassBaseType = + resourceClassBaseType; + + // @ 是否修改标识 + if ( + oldIdentify != getNoSpacesStr(resourceClassBaseIdentify).toUpperCase() + ) { + // 需要更改表明 + // ! 删除模型 + delete ctx.sequelize.models[oldIdentify.toLowerCase()]; + // ! 修改表名 + const results = await ctx.sequelize.queryInterface.renameTable( + 'entity_' + oldIdentify.toLowerCase(), + 'entity_' + getNoSpacesStr(resourceClassBaseIdentify).toLowerCase(), + ); + // ! 启动新模型 + await RRP.classModelObject[resourceClassBaseId].createSequelizeModel(); + // | 更新资源实体ID + } + ctx.body = { + message: '修改资源类信息成功', + }; + await next(); + await ctx.sequelize.models.ResourceClassBase.update( + { + resourceClassBaseName: getNoSpacesStr(resourceClassBaseName), + resourceClassBaseDescribe: resourceClassBaseDescribe, + resourceClassBaseIdentify: getNoSpacesStr( + resourceClassBaseIdentify, + ).toUpperCase(), + resourceClassBaseId: resourceClassBaseId, + resourceClassBaseAvatar: resourceClassBaseAvatar, + resourceClassBaseDefine: resourceClassBaseDefine, + resourceClassBaseColor: resourceClassBaseColor, + resourceClassBaseType: resourceClassBaseType, + }, + { + where: { + resourceClassBaseId, + }, + }, + ); +}); + +// @ 删除资源类 +resourceClass.delete('/deleteResourceClassItem', async (ctx, next) => { + const verif = DeleteResourceClassItemDTO(ctx.query); + if (!verif.status) { + return ctx.throw(400, { e: verif.error.map((i) => i.message) }); + } + const nodeId = ctx.query.nodeId; + // 判断是否存在节点 + const RRP = resourceCache.resourcePool; + const findNodeId = binarySearch(RRP.classRelationIdList, nodeId); + if (findNodeId == -1) { + return ctx.throw(400, { e: '不存在此资源类节点ID' }); + } + const classNodeObject = RRP.classNodeObject[nodeId]; + if (classNodeObject.children.length != 0) { + return ctx.throw(400, { + e: '该资源类节点下存在子节点,无法删除,请先删除子节点。', + }); + } + const classId = classNodeObject.classId; + const fatherId = classNodeObject.fatherId; + const atomModel = classNodeObject.atomModel; + const classIdentify = classNodeObject.classIdentify; + + let entityListB, expandListB; + + // @ 删掉关联列表 + RRP.classRelationList.splice(findNodeId, 1); + // @ 删掉关联ID列表 + RRP.classRelationIdList.splice(findNodeId, 1); + // @ 删掉关联ID对象集合 + delete RRP.classRelationObject[nodeId]; + // @ 删除资源类的关联对象中的当前节点 + const relationList = RRP.classRelationObjectForTargetClass[classId]; + relationList.splice( + binarySearch(relationList, nodeId, 'resourceClassRelationId'), + 1, + ); + + // @ 删除父节点下的children的此节点 + RRP.classNodeObject[fatherId].children.splice( + binarySearch(RRP.classNodeObject[fatherId].children, nodeId, 'nodeId'), + 1, + ); + // @ 删除节点列表上的此节点 + delete RRP.classNodeObject[nodeId]; + // 删除原分类下的根节点 + if (fatherId == 0) { + RRP.classNodeObjectForAtomModel[atomModel].splice( + binarySearch( + RRP.classNodeObjectForAtomModel[atomModel], + nodeId, + 'nodeId', + ), + 1, + ); + } + if (classNodeObject.classRelationIdList.length == 0) { + // 最后一个节点了,删掉的话就删掉了资源类 + // @ 删掉资源类的关联列表 + delete RRP.classRelationObjectForTargetClass[classId]; + // @ 删资源类 + const classIdIndex = binarySearch(RRP.classIdList, classId); + RRP.classList.splice(classIdIndex, 1); + RRP.classIdList.splice(classIdIndex, 1); + delete RRP.classObject[classId]; + RRP.classListForAtomModel[atomModel].splice( + binarySearch( + RRP.classListForAtomModel[atomModel], + classId, + 'resourceClassBaseId', + ), + ); + // @ 删资源类拓展字段 + if ( + Object.keys(RRP.classExpandForClassBaseObject).includes( + classId.toString(), + ) + ) { + const expandList = RRP.classExpandForClassBaseObject[classId]; + const expandIdList = Object.keys(expandList).map((i) => { + delete RRP.classExpandObject[ + expandList[i].resourceClassExpandFieldId + ]; + return expandList[i].resourceClassExpandFieldId; + }); + expandListB = expandIdList; + delete RRP.classExpandForClassBaseObject[classId]; + const expandIdIndexList = binarySearchMore( + RRP.classExpandList, + expandIdList, + 'resourceClassExpandFieldId', + 0, + RRP.classExpandList.length, + ).sort((a, b) => b - a); + for (let i of expandIdIndexList) { + RRP.classExpandList.splice(i, 1); + RRP.classExpandIdList.splice(i, 1); + } + } + + // @ 删除资源实体字段 + if ( + Object.keys(RRP.entityStructForClassBaseObject).includes( + classId.toString(), + ) + ) { + const entityNameObject = + RRP.entityStructForClassBaseObject[classId]; + const entityIdList = Object.keys(entityNameObject).map((i) => { + delete RRP.entityStructObject[ + entityNameObject[i].resourceEntityStructId + ]; + return entityNameObject[i].resourceEntityStructId; + }); + entityListB = entityIdList; + delete RRP.entityStructForClassBaseObject[classId]; + const entityIndexList = binarySearchMore( + RRP.entityStructList, + entityIdList, + 'resourceEntityStructId', + 0, + RRP.entityStructList.length, + ).sort((a, b) => b - a); + for (let i of entityIndexList) { + RRP.entityStructList.splice(i, 1); + RRP.entityStructIdList.splice(i, 1); + } + } + // ! @ 删资源对象 + // @ 删除表 + const data = await ctx.sequelize.query( + 'DROP TABLE IF EXISTS ' + 'entity_' + classIdentify.toLowerCase(), + ); + // 删除资源对象缓存 + } + ctx.body = { + message: '删除资源类节点成功。', + }; + // 删除关联 + ctx.sequelize.models.ResourceClassRelation.update( + { + isDelete: new Date().toISOString(), + }, + { + where: { + resourceClassRelationId: nodeId, + }, + }, + ); + + if (classNodeObject.classRelationIdList.length == 0) { + // 删除资源类 + ctx.sequelize.models.ResourceClassBase.update( + { + isDelete: new Date().toISOString(), + }, + { + where: { + resourceClassBaseId: classId, + }, + }, + ); + // 删除拓展字段 + if (expandListB) { + ctx.sequelize.models.ResourceClassExpandField.update( + { + isDelete: new Date().toISOString(), + }, + { + where: { + resourceClassExpandFieldId: { + [Op.in]: expandListB, + }, + }, + }, + ); + } + + // 删除实体字段 + if (entityListB) { + ctx.sequelize.models.ResourceEntityStruct.update( + { + isDelete: new Date().toISOString(), + }, + { + where: { + resourceEntityStructId: { + [Op.in]: entityListB, + }, + }, + }, + ); + } + } +}); + +// @ 创建资源类关联 +resourceClass.post('/createResourceClassRelation', async (ctx, next) => { + const verif = CreateResourceClassRelationDTO(ctx.request.body); + if (!verif.status) { + return ctx.throw(400, { e: verif.error.map((i) => i.message) }); + } + ctx.body = 7; +}); + +// @ 删除资源类关联 +resourceClass.delete('/deleteResourceClassRelation', async (ctx, next) => { + const verif = DeleteResourceClassRelationDTO(ctx.query); + if (!verif.status) { + return ctx.throw(400, { e: verif.error.map((i) => i.message) }); + } + const RRP = resourceCache.resourcePool; + ctx.body = 8; +}); + +// @ 获取资源类完整信息 +resourceClass.get('/getResourceClassCompleteInfo', async (ctx, next) => { + const verif = GetResourceClassCompleteInfoDTO(ctx.query); + if (!verif.status) { + return ctx.throw(400, { e: verif.error.map((i) => i.message) }); + } + const { resourceClassBaseId, resourceClassBaseIdentify } = ctx.query; + const RRP = resourceCache.resourcePool; + let classId; + if (resourceClassBaseIdentify) { + RRP.classIdList.find((i) => { + if ( + RRP.classModelObject[i].classIdentify == + getNoSpacesStr(resourceClassBaseIdentify).toUpperCase() + ) { + classId = RRP.classModelObject[i].classId; + } + }); + if (!classId) { + return ctx.throw(400, { e: '未找到该资源类' }); + } + } + if (resourceClassBaseId) { + if (RRP.classIdList.includes(resourceClassBaseId)) { + classId = resourceClassBaseId; + } else { + return ctx.throw(400, { e: '未找到该资源类' }); + } + } + ctx.body = RRP.classModelObject[classId].info; +}); + +// @ 创建资源类拓展字段 +resourceClass.post('/createResourceClassExpandFieldItem', async (ctx, next) => { + const verif = CreateResourceClassExpandFieldItemDTO(ctx.request.body); + if (!verif.status) { + return ctx.throw(400, { e: verif.error.map((i) => i.message) }); + } + ctx.body = 10; +}); + +// @ 编辑资源类拓展字段 +resourceClass.post('/editResourceClassExpandFieldItem', async (ctx, next) => { + const verif = EditResourceClassExpandFieldItemDTO(ctx.request.body); + if (!verif.status) { + return ctx.throw(400, { e: verif.error.map((i) => i.message) }); + } + ctx.body = 11; +}); + +// @ 删除资源类拓展字段 +resourceClass.delete( + '/deleteResourceClassExpandFieldItem', + async (ctx, next) => { + const verif = DeleteResourceClassExpandFieldItemDTO(ctx.query); + if (!verif.status) { + return ctx.throw(400, { e: verif.error.map((i) => i.message) }); + } + ctx.body = 12; + }, +); + +export default resourceClass; diff --git a/reference/graphResource2/src/routes/index.dto.js b/reference/graphResource2/src/routes/index.dto.js new file mode 100644 index 0000000..7cc85b9 --- /dev/null +++ b/reference/graphResource2/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/reference/graphResource2/src/routes/index.js b/reference/graphResource2/src/routes/index.js new file mode 100644 index 0000000..6c015a2 --- /dev/null +++ b/reference/graphResource2/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/reference/graphResource2/test/ajvTest.js b/reference/graphResource2/test/ajvTest.js new file mode 100644 index 0000000..ebcc887 --- /dev/null +++ b/reference/graphResource2/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/reference/graphResource2/test/koa-body使用.md b/reference/graphResource2/test/koa-body使用.md new file mode 100644 index 0000000..ce2162f --- /dev/null +++ b/reference/graphResource2/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/reference/graphResource2/test/koa-compress说明.md b/reference/graphResource2/test/koa-compress说明.md new file mode 100644 index 0000000..4e23269 --- /dev/null +++ b/reference/graphResource2/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/reference/graphResource2/test/koa-ratelimit限制批量请求工具的应用.md b/reference/graphResource2/test/koa-ratelimit限制批量请求工具的应用.md new file mode 100644 index 0000000..8f682ce --- /dev/null +++ b/reference/graphResource2/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/reference/graphResource2/test/koa-send方法.md b/reference/graphResource2/test/koa-send方法.md new file mode 100644 index 0000000..29bca8d --- /dev/null +++ b/reference/graphResource2/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/reference/graphResource2/test/koa修改code.md b/reference/graphResource2/test/koa修改code.md new file mode 100644 index 0000000..9257db2 --- /dev/null +++ b/reference/graphResource2/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。 diff --git a/reference/graphResource2/test/makeClass.js b/reference/graphResource2/test/makeClass.js new file mode 100644 index 0000000..22becfd --- /dev/null +++ b/reference/graphResource2/test/makeClass.js @@ -0,0 +1,131 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: graphResource2 +// | @文件描述: makeClass.js - +// | @创建时间: 2023-12-03 16:41 +// | @更新时间: 2023-12-03 16:41 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ + + +const obj = { + id: 1, + name: '何希', + age: 25 +} + +const f1 = { + id: 2, + name: '何希的妈妈', + age: 45 +} + +const f2 = { + id: 3, + name: '何希的爸爸', + age: 45 +} + +class resourceClass{ + baseInfo; + expandInfo; + fatherObject = {} + constructor(baseInfo, expandInfo = {}) { + this.baseInfo = baseInfo; + this.expandInfo = expandInfo + } + addFather(obj){ + this.fatherObject[obj.id] = obj + } + delFather(obj){ + delete this.fatherObject[obj.id] + } + get baseInfo(){ + return this.baseInfo + } + get expandInfo(){ + return this.expandInfo + } + get fatherId(){ + return Object.keys(this.fatherObject) + } + get fatherObj(){ + return this.fatherObj + } + get fatherList(){ + return Object.keys(this.fatherObj).map(i => this.fatherObject[i]) + } +} + +function makeClass(obj1, obj2 = {}){ + return new resourceClass(obj1, obj2) +} + + + +const R1 = makeClass(obj); +const R2 = makeClass(obj); + +obj.age++ + +console.log(R1.baseInfo) +console.log(R1) +console.log(R2.baseInfo) + + + +const resourceCache = { + // 基础数据库信息 + baseData:{ + // 基础资源类信息 + resourceClassList: [], + resourceClassObject:{}, + // 拓展资源类信息 + resourceClassExpandFieldList: [], + resourceClassExpandFieldObject: {}, + // 实体字段信息 + resourceEntityStructList: [], + resourceEntityStructObject: {}, + // 资源实体信息 + resourceEntityList: [], + resourceEntityObject: {}, + // 资源类关系信息 + resourceClassRelationList: [], + resourceClassRelationObject: {} + }, + // 合成资源信息,计算数据 + computedData:{ + // 资源类完整数据 - 继承于baseData-resourceClassObject + resourceClassObject: { + resourceClassId: { + // 基础资源类信息,查找字典值 + baseClassData: { + + }, + // 拓展资源类信息,查找字典值 + expandClassData:{ + + }, + // 资源实体结构转化为对象格式 + entityStructData:{ + + }, + // 资源类的父节点,及其关联下的子节点 + relationClass:{ + fatherId:['childId'] + } + } + } + }, + // 资源关联信息 + relationData:{} +} + +// 第一步加载数据库数据 + + + diff --git a/reference/graphResource2/test/slice.js b/reference/graphResource2/test/slice.js new file mode 100644 index 0000000..cc2749c --- /dev/null +++ b/reference/graphResource2/test/slice.js @@ -0,0 +1,15 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: graphResource2 +// | @文件描述: slice.js - +// | @创建时间: 2023-12-03 01:43 +// | @更新时间: 2023-12-03 01:43 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ + + +console.log([1, 2, 3].slice(1)) diff --git a/reference/graphResource2/test/testClassExtents.js b/reference/graphResource2/test/testClassExtents.js new file mode 100644 index 0000000..633894e --- /dev/null +++ b/reference/graphResource2/test/testClassExtents.js @@ -0,0 +1,36 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: graphResource2 +// | @文件描述: testClassExtents.js - +// | @创建时间: 2023-12-03 17:58 +// | @更新时间: 2023-12-03 17:58 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ +console.log('START') +console.time(1) +let list = [] + +const a1 = performance.now(); +for(let i = 0; i < 100000000; i ++){ + list.push({ + name: '何希', + age: 35, + love: 'GY', + key: parseInt(Math.random() * 100000000) + }) +} +console.log('A') +const a2 = performance.now(); +const data = list.filter(i => { + return (i.name + i.love + i.key).includes('GY21') +}) +const a3 = performance.now(); + +console.log('makeData', a2-a1) +console.log('filterData', a3-a2) +console.log(data.length) +console.timeEnd(1) diff --git a/reference/graphResource2/test/压力/getClassTreeForAtomMOdel.js b/reference/graphResource2/test/压力/getClassTreeForAtomMOdel.js new file mode 100644 index 0000000..72a62f4 --- /dev/null +++ b/reference/graphResource2/test/压力/getClassTreeForAtomMOdel.js @@ -0,0 +1,39 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: graphResource2 +// | @文件描述: getClassTreeForAtomMOdel.js - +// | @创建时间: 2023-12-06 21:23 +// | @更新时间: 2023-12-06 21:23 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ +import loadtest from 'loadtest' + +// 定义要测试的目标 URL +const url = 'http://localhost:3001' +// 定义 loadtest 的参数 +const options = { + url: url, + maxRequests: 50000, // 总请求数 + concurrency: 20 // 并发请求数 +}; + +loadtest.loadTest(options, function(error, result) { + if (error) { + console.error('压力测试失败:', error); + } else { + console.log('压力测试结果:'); + console.log('总请求数:', result.totalRequests); + console.log('请求失败数:', result.totalErrors); + console.log('总运行时间(秒):', result.totalTimeSeconds); + console.log('平均延迟时间(毫秒):', result.meanLatencyMs); + console.log('最小延迟时间(毫秒):', result.minLatencyMs); + console.log('最大延迟时间(毫秒):', result.maxLatencyMs); + // console.log('请求总字节数:', result.requestBytes); + // console.log('响应总字节数:', result.responseBytes); + console.log('每秒请求数:', result.rps); + } +}); diff --git a/reference/react-template/.eslintrc.cjs b/reference/react-template/.eslintrc.cjs new file mode 100644 index 0000000..c26b102 --- /dev/null +++ b/reference/react-template/.eslintrc.cjs @@ -0,0 +1,21 @@ +module.exports = { + root: true, + env: { browser: true, es2020: true }, + extends: [ + 'eslint:recommended', + 'plugin:react/recommended', + 'plugin:react/jsx-runtime', + 'plugin:react-hooks/recommended', + ], + ignorePatterns: ['dist', '.eslintrc.cjs'], + parserOptions: { ecmaVersion: 'latest', sourceType: 'module' }, + settings: { react: { version: '18.2' } }, + plugins: ['react-refresh'], + rules: { + 'react-refresh/only-export-components': [ + 'warn', + { allowConstantExport: true }, + ], + indent: [2, 4, { SwitchCase: 1 }], + }, +} diff --git a/reference/react-template/.gitignore b/reference/react-template/.gitignore new file mode 100644 index 0000000..a547bf3 --- /dev/null +++ b/reference/react-template/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/reference/react-template/README.md b/reference/react-template/README.md new file mode 100644 index 0000000..f768e33 --- /dev/null +++ b/reference/react-template/README.md @@ -0,0 +1,8 @@ +# React + Vite + +This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. + +Currently, two official plugins are available: + +- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh +- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh diff --git a/reference/react-template/index.html b/reference/react-template/index.html new file mode 100644 index 0000000..685ea89 --- /dev/null +++ b/reference/react-template/index.html @@ -0,0 +1,26 @@ + + + + + + + + + + Vite + React + + +
+
+
+
+
+
+
waiting
+
+
+ + + diff --git a/reference/react-template/package.json b/reference/react-template/package.json new file mode 100644 index 0000000..a2f5ff4 --- /dev/null +++ b/reference/react-template/package.json @@ -0,0 +1,30 @@ +{ + "name": "react-template", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0", + "preview": "vite preview" + }, + "dependencies": { + "@reduxjs/toolkit": "^1.9.7", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-router-dom": "^6.20.0", + "redux": "^4.2.1", + "sass": "^1.69.5" + }, + "devDependencies": { + "@types/react": "^18.2.37", + "@types/react-dom": "^18.2.15", + "@vitejs/plugin-react": "^4.2.0", + "eslint": "^8.53.0", + "eslint-plugin-react": "^7.33.2", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-react-refresh": "^0.4.4", + "vite": "^5.0.0" + } +} diff --git a/reference/react-template/pnpm-lock.yaml b/reference/react-template/pnpm-lock.yaml new file mode 100644 index 0000000..546f4f8 --- /dev/null +++ b/reference/react-template/pnpm-lock.yaml @@ -0,0 +1,2543 @@ +lockfileVersion: '6.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +dependencies: + '@reduxjs/toolkit': + specifier: ^1.9.7 + version: 1.9.7(react@18.2.0) + react: + specifier: ^18.2.0 + version: 18.2.0 + react-dom: + specifier: ^18.2.0 + version: 18.2.0(react@18.2.0) + react-router-dom: + specifier: ^6.20.0 + version: 6.20.0(react-dom@18.2.0)(react@18.2.0) + redux: + specifier: ^4.2.1 + version: 4.2.1 + sass: + specifier: ^1.69.5 + version: 1.69.5 + +devDependencies: + '@types/react': + specifier: ^18.2.37 + version: 18.2.38 + '@types/react-dom': + specifier: ^18.2.15 + version: 18.2.17 + '@vitejs/plugin-react': + specifier: ^4.2.0 + version: 4.2.0(vite@5.0.2) + eslint: + specifier: ^8.53.0 + version: 8.54.0 + eslint-plugin-react: + specifier: ^7.33.2 + version: 7.33.2(eslint@8.54.0) + eslint-plugin-react-hooks: + specifier: ^4.6.0 + version: 4.6.0(eslint@8.54.0) + eslint-plugin-react-refresh: + specifier: ^0.4.4 + version: 0.4.4(eslint@8.54.0) + vite: + specifier: ^5.0.0 + version: 5.0.2(sass@1.69.5) + +packages: + + /@aashutoshrathi/word-wrap@1.2.6: + resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==} + engines: {node: '>=0.10.0'} + dev: true + + /@ampproject/remapping@2.2.1: + resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==} + engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/gen-mapping': 0.3.3 + '@jridgewell/trace-mapping': 0.3.20 + dev: true + + /@babel/code-frame@7.23.4: + resolution: {integrity: sha512-r1IONyb6Ia+jYR2vvIDhdWdlTGhqbBoFqLTQidzZ4kepUFH15ejXvFHxCVbtl7BOXIudsIubf4E81xeA3h3IXA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/highlight': 7.23.4 + chalk: 2.4.2 + dev: true + + /@babel/compat-data@7.23.3: + resolution: {integrity: sha512-BmR4bWbDIoFJmJ9z2cZ8Gmm2MXgEDgjdWgpKmKWUt54UGFJdlj31ECtbaDvCG/qVdG3AQ1SfpZEs01lUFbzLOQ==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/core@7.23.3: + resolution: {integrity: sha512-Jg+msLuNuCJDyBvFv5+OKOUjWMZgd85bKjbICd3zWrKAo+bJ49HJufi7CQE0q0uR8NGyO6xkCACScNqyjHSZew==} + engines: {node: '>=6.9.0'} + dependencies: + '@ampproject/remapping': 2.2.1 + '@babel/code-frame': 7.23.4 + '@babel/generator': 7.23.4 + '@babel/helper-compilation-targets': 7.22.15 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.3) + '@babel/helpers': 7.23.4 + '@babel/parser': 7.23.4 + '@babel/template': 7.22.15 + '@babel/traverse': 7.23.4 + '@babel/types': 7.23.4 + convert-source-map: 2.0.0 + debug: 4.3.4 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/generator@7.23.4: + resolution: {integrity: sha512-esuS49Cga3HcThFNebGhlgsrVLkvhqvYDTzgjfFFlHJcIfLe5jFmRRfCQ1KuBfc4Jrtn3ndLgKWAKjBE+IraYQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.4 + '@jridgewell/gen-mapping': 0.3.3 + '@jridgewell/trace-mapping': 0.3.20 + jsesc: 2.5.2 + dev: true + + /@babel/helper-compilation-targets@7.22.15: + resolution: {integrity: sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/compat-data': 7.23.3 + '@babel/helper-validator-option': 7.22.15 + browserslist: 4.22.1 + lru-cache: 5.1.1 + semver: 6.3.1 + dev: true + + /@babel/helper-environment-visitor@7.22.20: + resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-function-name@7.23.0: + resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.22.15 + '@babel/types': 7.23.4 + dev: true + + /@babel/helper-hoist-variables@7.22.5: + resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.4 + dev: true + + /@babel/helper-module-imports@7.22.15: + resolution: {integrity: sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.4 + dev: true + + /@babel/helper-module-transforms@7.23.3(@babel/core@7.23.3): + resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.23.3 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-module-imports': 7.22.15 + '@babel/helper-simple-access': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/helper-validator-identifier': 7.22.20 + dev: true + + /@babel/helper-plugin-utils@7.22.5: + resolution: {integrity: sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-simple-access@7.22.5: + resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.4 + dev: true + + /@babel/helper-split-export-declaration@7.22.6: + resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.4 + dev: true + + /@babel/helper-string-parser@7.23.4: + resolution: {integrity: sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-validator-identifier@7.22.20: + resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-validator-option@7.22.15: + resolution: {integrity: sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helpers@7.23.4: + resolution: {integrity: sha512-HfcMizYz10cr3h29VqyfGL6ZWIjTwWfvYBMsBVGwpcbhNGe3wQ1ZXZRPzZoAHhd9OqHadHqjQ89iVKINXnbzuw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.22.15 + '@babel/traverse': 7.23.4 + '@babel/types': 7.23.4 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/highlight@7.23.4: + resolution: {integrity: sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': 7.22.20 + chalk: 2.4.2 + js-tokens: 4.0.0 + dev: true + + /@babel/parser@7.23.4: + resolution: {integrity: sha512-vf3Xna6UEprW+7t6EtOmFpHNAuxw3xqPZghy+brsnusscJRW5BMUzzHZc5ICjULee81WeUV2jjakG09MDglJXQ==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.23.4 + dev: true + + /@babel/plugin-transform-react-jsx-self@7.23.3(@babel/core@7.23.3): + resolution: {integrity: sha512-qXRvbeKDSfwnlJnanVRp0SfuWE5DQhwQr5xtLBzp56Wabyo+4CMosF6Kfp+eOD/4FYpql64XVJ2W0pVLlJZxOQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.3 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-transform-react-jsx-source@7.23.3(@babel/core@7.23.3): + resolution: {integrity: sha512-91RS0MDnAWDNvGC6Wio5XYkyWI39FMFO+JK9+4AlgaTH+yWwVTsw7/sn6LK0lH7c5F+TFkpv/3LfCJ1Ydwof/g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.3 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/runtime@7.23.4: + resolution: {integrity: sha512-2Yv65nlWnWlSpe3fXEyX5i7fx5kIKo4Qbcj+hMO0odwaneFjfXw5fdum+4yL20O0QiaHpia0cYQ9xpNMqrBwHg==} + engines: {node: '>=6.9.0'} + dependencies: + regenerator-runtime: 0.14.0 + dev: false + + /@babel/template@7.22.15: + resolution: {integrity: sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.23.4 + '@babel/parser': 7.23.4 + '@babel/types': 7.23.4 + dev: true + + /@babel/traverse@7.23.4: + resolution: {integrity: sha512-IYM8wSUwunWTB6tFC2dkKZhxbIjHoWemdK+3f8/wq8aKhbUscxD5MX72ubd90fxvFknaLPeGw5ycU84V1obHJg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.23.4 + '@babel/generator': 7.23.4 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-hoist-variables': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/parser': 7.23.4 + '@babel/types': 7.23.4 + debug: 4.3.4 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/types@7.23.4: + resolution: {integrity: sha512-7uIFwVYpoplT5jp/kVv6EF93VaJ8H+Yn5IczYiaAi98ajzjfoZfslet/e0sLh+wVBjb2qqIut1b0S26VSafsSQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': 7.23.4 + '@babel/helper-validator-identifier': 7.22.20 + to-fast-properties: 2.0.0 + dev: true + + /@esbuild/android-arm64@0.19.7: + resolution: {integrity: sha512-YEDcw5IT7hW3sFKZBkCAQaOCJQLONVcD4bOyTXMZz5fr66pTHnAet46XAtbXAkJRfIn2YVhdC6R9g4xa27jQ1w==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm@0.19.7: + resolution: {integrity: sha512-YGSPnndkcLo4PmVl2tKatEn+0mlVMr3yEpOOT0BeMria87PhvoJb5dg5f5Ft9fbCVgtAz4pWMzZVgSEGpDAlww==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-x64@0.19.7: + resolution: {integrity: sha512-jhINx8DEjz68cChFvM72YzrqfwJuFbfvSxZAk4bebpngGfNNRm+zRl4rtT9oAX6N9b6gBcFaJHFew5Blf6CvUw==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-arm64@0.19.7: + resolution: {integrity: sha512-dr81gbmWN//3ZnBIm6YNCl4p3pjnabg1/ZVOgz2fJoUO1a3mq9WQ/1iuEluMs7mCL+Zwv7AY5e3g1hjXqQZ9Iw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-x64@0.19.7: + resolution: {integrity: sha512-Lc0q5HouGlzQEwLkgEKnWcSazqr9l9OdV2HhVasWJzLKeOt0PLhHaUHuzb8s/UIya38DJDoUm74GToZ6Wc7NGQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-arm64@0.19.7: + resolution: {integrity: sha512-+y2YsUr0CxDFF7GWiegWjGtTUF6gac2zFasfFkRJPkMAuMy9O7+2EH550VlqVdpEEchWMynkdhC9ZjtnMiHImQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-x64@0.19.7: + resolution: {integrity: sha512-CdXOxIbIzPJmJhrpmJTLx+o35NoiKBIgOvmvT+jeSadYiWJn0vFKsl+0bSG/5lwjNHoIDEyMYc/GAPR9jxusTA==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm64@0.19.7: + resolution: {integrity: sha512-inHqdOVCkUhHNvuQPT1oCB7cWz9qQ/Cz46xmVe0b7UXcuIJU3166aqSunsqkgSGMtUCWOZw3+KMwI6otINuC9g==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm@0.19.7: + resolution: {integrity: sha512-Y+SCmWxsJOdQtjcBxoacn/pGW9HDZpwsoof0ttL+2vGcHokFlfqV666JpfLCSP2xLxFpF1lj7T3Ox3sr95YXww==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ia32@0.19.7: + resolution: {integrity: sha512-2BbiL7nLS5ZO96bxTQkdO0euGZIUQEUXMTrqLxKUmk/Y5pmrWU84f+CMJpM8+EHaBPfFSPnomEaQiG/+Gmh61g==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-loong64@0.19.7: + resolution: {integrity: sha512-BVFQla72KXv3yyTFCQXF7MORvpTo4uTA8FVFgmwVrqbB/4DsBFWilUm1i2Oq6zN36DOZKSVUTb16jbjedhfSHw==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-mips64el@0.19.7: + resolution: {integrity: sha512-DzAYckIaK+pS31Q/rGpvUKu7M+5/t+jI+cdleDgUwbU7KdG2eC3SUbZHlo6Q4P1CfVKZ1lUERRFP8+q0ob9i2w==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ppc64@0.19.7: + resolution: {integrity: sha512-JQ1p0SmUteNdUaaiRtyS59GkkfTW0Edo+e0O2sihnY4FoZLz5glpWUQEKMSzMhA430ctkylkS7+vn8ziuhUugQ==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-riscv64@0.19.7: + resolution: {integrity: sha512-xGwVJ7eGhkprY/nB7L7MXysHduqjpzUl40+XoYDGC4UPLbnG+gsyS1wQPJ9lFPcxYAaDXbdRXd1ACs9AE9lxuw==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-s390x@0.19.7: + resolution: {integrity: sha512-U8Rhki5PVU0L0nvk+E8FjkV8r4Lh4hVEb9duR6Zl21eIEYEwXz8RScj4LZWA2i3V70V4UHVgiqMpszXvG0Yqhg==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-x64@0.19.7: + resolution: {integrity: sha512-ZYZopyLhm4mcoZXjFt25itRlocKlcazDVkB4AhioiL9hOWhDldU9n38g62fhOI4Pth6vp+Mrd5rFKxD0/S+7aQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/netbsd-x64@0.19.7: + resolution: {integrity: sha512-/yfjlsYmT1O3cum3J6cmGG16Fd5tqKMcg5D+sBYLaOQExheAJhqr8xOAEIuLo8JYkevmjM5zFD9rVs3VBcsjtQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/openbsd-x64@0.19.7: + resolution: {integrity: sha512-MYDFyV0EW1cTP46IgUJ38OnEY5TaXxjoDmwiTXPjezahQgZd+j3T55Ht8/Q9YXBM0+T9HJygrSRGV5QNF/YVDQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/sunos-x64@0.19.7: + resolution: {integrity: sha512-JcPvgzf2NN/y6X3UUSqP6jSS06V0DZAV/8q0PjsZyGSXsIGcG110XsdmuWiHM+pno7/mJF6fjH5/vhUz/vA9fw==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-arm64@0.19.7: + resolution: {integrity: sha512-ZA0KSYti5w5toax5FpmfcAgu3ZNJxYSRm0AW/Dao5up0YV1hDVof1NvwLomjEN+3/GMtaWDI+CIyJOMTRSTdMw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-ia32@0.19.7: + resolution: {integrity: sha512-CTOnijBKc5Jpk6/W9hQMMvJnsSYRYgveN6O75DTACCY18RA2nqka8dTZR+x/JqXCRiKk84+5+bRKXUSbbwsS0A==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-x64@0.19.7: + resolution: {integrity: sha512-gRaP2sk6hc98N734luX4VpF318l3w+ofrtTu9j5L8EQXF+FzQKV6alCOHMVoJJHvVK/mGbwBXfOL1HETQu9IGQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@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 + + /@jridgewell/gen-mapping@0.3.3: + resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} + engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/set-array': 1.1.2 + '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/trace-mapping': 0.3.20 + dev: true + + /@jridgewell/resolve-uri@3.1.1: + resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==} + engines: {node: '>=6.0.0'} + dev: true + + /@jridgewell/set-array@1.1.2: + resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} + engines: {node: '>=6.0.0'} + dev: true + + /@jridgewell/sourcemap-codec@1.4.15: + resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + dev: true + + /@jridgewell/trace-mapping@0.3.20: + resolution: {integrity: sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==} + dependencies: + '@jridgewell/resolve-uri': 3.1.1 + '@jridgewell/sourcemap-codec': 1.4.15 + 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 + + /@reduxjs/toolkit@1.9.7(react@18.2.0): + resolution: {integrity: sha512-t7v8ZPxhhKgOKtU+uyJT13lu4vL7az5aFi4IdoDs/eS548edn2M8Ik9h8fxgvMjGoAUVFSt6ZC1P5cWmQ014QQ==} + peerDependencies: + react: ^16.9.0 || ^17.0.0 || ^18 + react-redux: ^7.2.1 || ^8.0.2 + peerDependenciesMeta: + react: + optional: true + react-redux: + optional: true + dependencies: + immer: 9.0.21 + react: 18.2.0 + redux: 4.2.1 + redux-thunk: 2.4.2(redux@4.2.1) + reselect: 4.1.8 + dev: false + + /@remix-run/router@1.13.0: + resolution: {integrity: sha512-5dMOnVnefRsl4uRnAdoWjtVTdh8e6aZqgM4puy9nmEADH72ck+uXwzpJLEKE9Q6F8ZljNewLgmTfkxUrBdv4WA==} + engines: {node: '>=14.0.0'} + dev: false + + /@rollup/rollup-android-arm-eabi@4.5.2: + resolution: {integrity: sha512-ee7BudTwwrglFYSc3UnqInDDjCLWHKrFmGNi4aK7jlEyg4CyPa1DCMrZfsN1O13YT76UFEqXz2CoN7BCGpUlJw==} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-android-arm64@4.5.2: + resolution: {integrity: sha512-xOuhj9HHtn8128ir8veoQsBbAUBasDbHIBniYTEx02pAmu9EXL+ZjJqngnNEy6ZgZ4h1JwL33GMNu3yJL5Mzow==} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-darwin-arm64@4.5.2: + resolution: {integrity: sha512-NTGJWoL8bKyqyWFn9/RzSv4hQ4wTbaAv0lHHRwf4OnpiiP4P8W0jiXbm8Nc5BCXKmWAwuvJY82mcIU2TayC20g==} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-darwin-x64@4.5.2: + resolution: {integrity: sha512-hlKqj7bpPvU15sZo4za14u185lpMzdwWLMc9raMqPK4wywt0wR23y1CaVQ4oAFXat3b5/gmRntyfpwWTKl+vvA==} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm-gnueabihf@4.5.2: + resolution: {integrity: sha512-7ZIZx8c3u+pfI0ohQsft/GywrXez0uR6dUP0JhBuCK3sFO5TfdLn/YApnVkvPxuTv3+YKPIZend9Mt7Cz6sS3Q==} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm64-gnu@4.5.2: + resolution: {integrity: sha512-7Pk/5mO11JW/cH+a8lL/i0ZxmRGrbpYqN0VwO2DHhU+SJWWOH2zE1RAcPaj8KqiwC8DCDIJOSxjV9+9lLb6aeA==} + cpu: [arm64] + os: [linux] + libc: [glibc] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm64-musl@4.5.2: + resolution: {integrity: sha512-KrRnuG5phJx756e62wxvWH2e+TK84MP2IVuPwfge+GBvWqIUfVzFRn09TKruuQBXzZp52Vyma7FjMDkwlA9xpg==} + cpu: [arm64] + os: [linux] + libc: [musl] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-x64-gnu@4.5.2: + resolution: {integrity: sha512-My+53GasPa2D2tU5dXiyHYwrELAUouSfkNlZ3bUKpI7btaztO5vpALEs3mvFjM7aKTvEbc7GQckuXeXIDKQ0fg==} + cpu: [x64] + os: [linux] + libc: [glibc] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-x64-musl@4.5.2: + resolution: {integrity: sha512-/f0Q6Sc+Vw54Ws6N8fxaEe4R7at3b8pFyv+O/F2VaQ4hODUJcRUcCBJh6zuqtgQQt7w845VTkGLFgWZkP3tUoQ==} + cpu: [x64] + os: [linux] + libc: [musl] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-win32-arm64-msvc@4.5.2: + resolution: {integrity: sha512-NCKuuZWLht6zj7s6EIFef4BxCRX1GMr83S2W4HPCA0RnJ4iHE4FS1695q6Ewoa6A9nFjJe1//yUu0kgBU07Edw==} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-win32-ia32-msvc@4.5.2: + resolution: {integrity: sha512-J5zL3riR4AOyU/J3M/i4k/zZ8eP1yT+nTmAKztCXJtnI36jYH0eepvob22mAQ/kLwfsK2TB6dbyVY1F8c/0H5A==} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-win32-x64-msvc@4.5.2: + resolution: {integrity: sha512-pL0RXRHuuGLhvs7ayX/SAHph1hrDPXOM5anyYUQXWJEENxw3nfHkzv8FfVlEVcLyKPAEgDRkd6RKZq2SMqS/yg==} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@types/babel__core@7.20.5: + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + dependencies: + '@babel/parser': 7.23.4 + '@babel/types': 7.23.4 + '@types/babel__generator': 7.6.7 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.20.4 + dev: true + + /@types/babel__generator@7.6.7: + resolution: {integrity: sha512-6Sfsq+EaaLrw4RmdFWE9Onp63TOUue71AWb4Gpa6JxzgTYtimbM086WnYTy2U67AofR++QKCo08ZP6pwx8YFHQ==} + dependencies: + '@babel/types': 7.23.4 + dev: true + + /@types/babel__template@7.4.4: + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + dependencies: + '@babel/parser': 7.23.4 + '@babel/types': 7.23.4 + dev: true + + /@types/babel__traverse@7.20.4: + resolution: {integrity: sha512-mSM/iKUk5fDDrEV/e83qY+Cr3I1+Q3qqTuEn++HAWYjEa1+NxZr6CNrcJGf2ZTnq4HoFGC3zaTPZTobCzCFukA==} + dependencies: + '@babel/types': 7.23.4 + dev: true + + /@types/prop-types@15.7.11: + resolution: {integrity: sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==} + dev: true + + /@types/react-dom@18.2.17: + resolution: {integrity: sha512-rvrT/M7Df5eykWFxn6MYt5Pem/Dbyc1N8Y0S9Mrkw2WFCRiqUgw9P7ul2NpwsXCSM1DVdENzdG9J5SreqfAIWg==} + dependencies: + '@types/react': 18.2.38 + dev: true + + /@types/react@18.2.38: + resolution: {integrity: sha512-cBBXHzuPtQK6wNthuVMV6IjHAFkdl/FOPFIlkd81/Cd1+IqkHu/A+w4g43kaQQoYHik/ruaQBDL72HyCy1vuMw==} + dependencies: + '@types/prop-types': 15.7.11 + '@types/scheduler': 0.16.8 + csstype: 3.1.2 + dev: true + + /@types/scheduler@0.16.8: + resolution: {integrity: sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==} + dev: true + + /@ungap/structured-clone@1.2.0: + resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} + dev: true + + /@vitejs/plugin-react@4.2.0(vite@5.0.2): + resolution: {integrity: sha512-+MHTH/e6H12kRp5HUkzOGqPMksezRMmW+TNzlh/QXfI8rRf6l2Z2yH/v12no1UvTwhZgEDMuQ7g7rrfMseU6FQ==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + vite: ^4.2.0 || ^5.0.0 + dependencies: + '@babel/core': 7.23.3 + '@babel/plugin-transform-react-jsx-self': 7.23.3(@babel/core@7.23.3) + '@babel/plugin-transform-react-jsx-source': 7.23.3(@babel/core@7.23.3) + '@types/babel__core': 7.20.5 + react-refresh: 0.14.0 + vite: 5.0.2(sass@1.69.5) + transitivePeerDependencies: + - supports-color + dev: true + + /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@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 + + /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: true + + /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 + + /argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + dev: true + + /array-buffer-byte-length@1.0.0: + resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==} + dependencies: + call-bind: 1.0.5 + is-array-buffer: 3.0.2 + dev: true + + /array-includes@3.1.7: + resolution: {integrity: sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + get-intrinsic: 1.2.2 + is-string: 1.0.7 + dev: true + + /array.prototype.flat@1.3.2: + resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + es-shim-unscopables: 1.0.2 + dev: true + + /array.prototype.flatmap@1.3.2: + resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + es-shim-unscopables: 1.0.2 + dev: true + + /array.prototype.tosorted@1.1.2: + resolution: {integrity: sha512-HuQCHOlk1Weat5jzStICBCd83NxiIMwqDg/dHEsoefabn/hJRj5pVdWcPUSpRrwhwxZOsQassMpgN/xRYFBMIg==} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + es-shim-unscopables: 1.0.2 + get-intrinsic: 1.2.2 + dev: true + + /arraybuffer.prototype.slice@1.0.2: + resolution: {integrity: sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==} + engines: {node: '>= 0.4'} + dependencies: + array-buffer-byte-length: 1.0.0 + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + get-intrinsic: 1.2.2 + is-array-buffer: 3.0.2 + is-shared-array-buffer: 1.0.2 + dev: true + + /asynciterator.prototype@1.0.0: + resolution: {integrity: sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg==} + dependencies: + has-symbols: 1.0.3 + dev: true + + /available-typed-arrays@1.0.5: + resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==} + engines: {node: '>= 0.4'} + dev: true + + /balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + dev: true + + /binary-extensions@2.2.0: + resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} + engines: {node: '>=8'} + + /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 + + /browserslist@4.22.1: + resolution: {integrity: sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + dependencies: + caniuse-lite: 1.0.30001564 + electron-to-chromium: 1.4.594 + node-releases: 2.0.13 + update-browserslist-db: 1.0.13(browserslist@4.22.1) + dev: true + + /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: true + + /callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + dev: true + + /caniuse-lite@1.0.30001564: + resolution: {integrity: sha512-DqAOf+rhof+6GVx1y+xzbFPeOumfQnhYzVnZD6LAXijR77yPtm9mfOcqOnT3mpnJiZVT+kwLAFnRlZcIz+c6bg==} + 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: true + + /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 + + /color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + dependencies: + color-name: 1.1.3 + dev: true + + /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: true + + /color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + dev: true + + /concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + dev: true + + /convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + 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 + + /csstype@3.1.2: + resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==} + 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 + dev: true + + /deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + 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: true + + /define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.1 + has-property-descriptors: 1.0.1 + object-keys: 1.1.1 + dev: true + + /doctrine@2.1.0: + resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} + engines: {node: '>=0.10.0'} + dependencies: + esutils: 2.0.3 + dev: true + + /doctrine@3.0.0: + resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} + engines: {node: '>=6.0.0'} + dependencies: + esutils: 2.0.3 + dev: true + + /electron-to-chromium@1.4.594: + resolution: {integrity: sha512-xT1HVAu5xFn7bDfkjGQi9dNpMqGchUkebwf1GL7cZN32NSwwlHRPMSDJ1KN6HkS0bWUtndbSQZqvpQftKG2uFQ==} + dev: true + + /es-abstract@1.22.3: + resolution: {integrity: sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==} + engines: {node: '>= 0.4'} + dependencies: + array-buffer-byte-length: 1.0.0 + arraybuffer.prototype.slice: 1.0.2 + available-typed-arrays: 1.0.5 + call-bind: 1.0.5 + es-set-tostringtag: 2.0.2 + es-to-primitive: 1.2.1 + function.prototype.name: 1.1.6 + get-intrinsic: 1.2.2 + get-symbol-description: 1.0.0 + globalthis: 1.0.3 + gopd: 1.0.1 + has-property-descriptors: 1.0.1 + has-proto: 1.0.1 + has-symbols: 1.0.3 + hasown: 2.0.0 + internal-slot: 1.0.6 + is-array-buffer: 3.0.2 + is-callable: 1.2.7 + is-negative-zero: 2.0.2 + is-regex: 1.1.4 + is-shared-array-buffer: 1.0.2 + is-string: 1.0.7 + is-typed-array: 1.1.12 + is-weakref: 1.0.2 + object-inspect: 1.13.1 + object-keys: 1.1.1 + object.assign: 4.1.4 + regexp.prototype.flags: 1.5.1 + safe-array-concat: 1.0.1 + safe-regex-test: 1.0.0 + string.prototype.trim: 1.2.8 + string.prototype.trimend: 1.0.7 + string.prototype.trimstart: 1.0.7 + typed-array-buffer: 1.0.0 + typed-array-byte-length: 1.0.0 + typed-array-byte-offset: 1.0.0 + typed-array-length: 1.0.4 + unbox-primitive: 1.0.2 + which-typed-array: 1.1.13 + dev: true + + /es-iterator-helpers@1.0.15: + resolution: {integrity: sha512-GhoY8uYqd6iwUl2kgjTm4CZAf6oo5mHK7BPqx3rKgx893YSsy0LGHV6gfqqQvZt/8xM8xeOnfXBCfqclMKkJ5g==} + dependencies: + asynciterator.prototype: 1.0.0 + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + es-set-tostringtag: 2.0.2 + function-bind: 1.1.2 + get-intrinsic: 1.2.2 + globalthis: 1.0.3 + has-property-descriptors: 1.0.1 + has-proto: 1.0.1 + has-symbols: 1.0.3 + internal-slot: 1.0.6 + iterator.prototype: 1.1.2 + safe-array-concat: 1.0.1 + dev: true + + /es-set-tostringtag@2.0.2: + resolution: {integrity: sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.2 + has-tostringtag: 1.0.0 + hasown: 2.0.0 + dev: true + + /es-shim-unscopables@1.0.2: + resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==} + dependencies: + hasown: 2.0.0 + dev: true + + /es-to-primitive@1.2.1: + resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} + engines: {node: '>= 0.4'} + dependencies: + is-callable: 1.2.7 + is-date-object: 1.0.5 + is-symbol: 1.0.4 + dev: true + + /esbuild@0.19.7: + resolution: {integrity: sha512-6brbTZVqxhqgbpqBR5MzErImcpA0SQdoKOkcWK/U30HtQxnokIpG3TX2r0IJqbFUzqLjhU/zC1S5ndgakObVCQ==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/android-arm': 0.19.7 + '@esbuild/android-arm64': 0.19.7 + '@esbuild/android-x64': 0.19.7 + '@esbuild/darwin-arm64': 0.19.7 + '@esbuild/darwin-x64': 0.19.7 + '@esbuild/freebsd-arm64': 0.19.7 + '@esbuild/freebsd-x64': 0.19.7 + '@esbuild/linux-arm': 0.19.7 + '@esbuild/linux-arm64': 0.19.7 + '@esbuild/linux-ia32': 0.19.7 + '@esbuild/linux-loong64': 0.19.7 + '@esbuild/linux-mips64el': 0.19.7 + '@esbuild/linux-ppc64': 0.19.7 + '@esbuild/linux-riscv64': 0.19.7 + '@esbuild/linux-s390x': 0.19.7 + '@esbuild/linux-x64': 0.19.7 + '@esbuild/netbsd-x64': 0.19.7 + '@esbuild/openbsd-x64': 0.19.7 + '@esbuild/sunos-x64': 0.19.7 + '@esbuild/win32-arm64': 0.19.7 + '@esbuild/win32-ia32': 0.19.7 + '@esbuild/win32-x64': 0.19.7 + dev: true + + /escalade@3.1.1: + resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} + engines: {node: '>=6'} + dev: true + + /escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + dev: true + + /escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + dev: true + + /eslint-plugin-react-hooks@4.6.0(eslint@8.54.0): + resolution: {integrity: sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==} + engines: {node: '>=10'} + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 + dependencies: + eslint: 8.54.0 + dev: true + + /eslint-plugin-react-refresh@0.4.4(eslint@8.54.0): + resolution: {integrity: sha512-eD83+65e8YPVg6603Om2iCIwcQJf/y7++MWm4tACtEswFLYMwxwVWAfwN+e19f5Ad/FOyyNg9Dfi5lXhH3Y3rA==} + peerDependencies: + eslint: '>=7' + dependencies: + eslint: 8.54.0 + dev: true + + /eslint-plugin-react@7.33.2(eslint@8.54.0): + resolution: {integrity: sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==} + engines: {node: '>=4'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 + dependencies: + array-includes: 3.1.7 + array.prototype.flatmap: 1.3.2 + array.prototype.tosorted: 1.1.2 + doctrine: 2.1.0 + es-iterator-helpers: 1.0.15 + eslint: 8.54.0 + estraverse: 5.3.0 + jsx-ast-utils: 3.3.5 + minimatch: 3.1.2 + object.entries: 1.1.7 + object.fromentries: 2.0.7 + object.hasown: 1.1.3 + object.values: 1.1.7 + prop-types: 15.8.1 + resolve: 2.0.0-next.5 + semver: 6.3.1 + string.prototype.matchall: 4.0.10 + 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 + + /fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + 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 + + /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 + + /fill-range@7.0.1: + resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} + engines: {node: '>=8'} + dependencies: + to-regex-range: 5.0.1 + + /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 + + /for-each@0.3.3: + resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} + dependencies: + is-callable: 1.2.7 + dev: true + + /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 + optional: true + + /function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + dev: true + + /function.prototype.name@1.1.6: + resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + functions-have-names: 1.2.3 + dev: true + + /functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + dev: true + + /gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + 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: true + + /get-symbol-description@1.0.0: + resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + get-intrinsic: 1.2.2 + dev: true + + /glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + dependencies: + is-glob: 4.0.3 + + /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@11.12.0: + resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} + engines: {node: '>=4'} + dev: true + + /globals@13.23.0: + resolution: {integrity: sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==} + engines: {node: '>=8'} + dependencies: + type-fest: 0.20.2 + dev: true + + /globalthis@1.0.3: + resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} + engines: {node: '>= 0.4'} + dependencies: + define-properties: 1.2.1 + dev: true + + /gopd@1.0.1: + resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + dependencies: + get-intrinsic: 1.2.2 + dev: true + + /graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + dev: true + + /has-bigints@1.0.2: + resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} + dev: true + + /has-flag@3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} + dev: true + + /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: true + + /has-proto@1.0.1: + resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} + engines: {node: '>= 0.4'} + dev: true + + /has-symbols@1.0.3: + resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} + engines: {node: '>= 0.4'} + dev: true + + /has-tostringtag@1.0.0: + resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==} + engines: {node: '>= 0.4'} + dependencies: + has-symbols: 1.0.3 + dev: true + + /hasown@2.0.0: + resolution: {integrity: sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==} + engines: {node: '>= 0.4'} + dependencies: + function-bind: 1.1.2 + dev: true + + /ignore@5.3.0: + resolution: {integrity: sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==} + engines: {node: '>= 4'} + dev: true + + /immer@9.0.21: + resolution: {integrity: sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==} + dev: false + + /immutable@4.3.4: + resolution: {integrity: sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==} + + /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 + + /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==} + dev: true + + /internal-slot@1.0.6: + resolution: {integrity: sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.2 + hasown: 2.0.0 + side-channel: 1.0.4 + dev: true + + /is-array-buffer@3.0.2: + resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==} + dependencies: + call-bind: 1.0.5 + get-intrinsic: 1.2.2 + is-typed-array: 1.1.12 + dev: true + + /is-async-function@2.0.0: + resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.0 + dev: true + + /is-bigint@1.0.4: + resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} + dependencies: + has-bigints: 1.0.2 + dev: true + + /is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + dependencies: + binary-extensions: 2.2.0 + + /is-boolean-object@1.1.2: + resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + has-tostringtag: 1.0.0 + dev: true + + /is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + dev: true + + /is-core-module@2.13.1: + resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} + dependencies: + hasown: 2.0.0 + dev: true + + /is-date-object@1.0.5: + resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.0 + dev: true + + /is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + /is-finalizationregistry@1.0.2: + resolution: {integrity: sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==} + dependencies: + call-bind: 1.0.5 + 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: true + + /is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + dependencies: + is-extglob: 2.1.1 + + /is-map@2.0.2: + resolution: {integrity: sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==} + dev: true + + /is-negative-zero@2.0.2: + resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==} + engines: {node: '>= 0.4'} + dev: true + + /is-number-object@1.0.7: + resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.0 + dev: true + + /is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + /is-path-inside@3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + dev: true + + /is-regex@1.1.4: + resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + has-tostringtag: 1.0.0 + dev: true + + /is-set@2.0.2: + resolution: {integrity: sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==} + dev: true + + /is-shared-array-buffer@1.0.2: + resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==} + dependencies: + call-bind: 1.0.5 + dev: true + + /is-string@1.0.7: + resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.0 + dev: true + + /is-symbol@1.0.4: + resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} + engines: {node: '>= 0.4'} + dependencies: + has-symbols: 1.0.3 + dev: true + + /is-typed-array@1.1.12: + resolution: {integrity: sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==} + engines: {node: '>= 0.4'} + dependencies: + which-typed-array: 1.1.13 + dev: true + + /is-weakmap@2.0.1: + resolution: {integrity: sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==} + dev: true + + /is-weakref@1.0.2: + resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} + dependencies: + call-bind: 1.0.5 + dev: true + + /is-weakset@2.0.2: + resolution: {integrity: sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==} + dependencies: + call-bind: 1.0.5 + get-intrinsic: 1.2.2 + dev: true + + /isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + dev: true + + /isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + dev: true + + /iterator.prototype@1.1.2: + resolution: {integrity: sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==} + dependencies: + define-properties: 1.2.1 + get-intrinsic: 1.2.2 + has-symbols: 1.0.3 + reflect.getprototypeof: 1.0.4 + set-function-name: 2.0.1 + dev: true + + /js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + /js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + dependencies: + argparse: 2.0.1 + dev: true + + /jsesc@2.5.2: + resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} + engines: {node: '>=4'} + hasBin: true + 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-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + dev: true + + /json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + dev: true + + /jsx-ast-utils@3.3.5: + resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} + engines: {node: '>=4.0'} + dependencies: + array-includes: 3.1.7 + array.prototype.flat: 1.3.2 + object.assign: 4.1.4 + object.values: 1.1.7 + dev: true + + /keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + dependencies: + json-buffer: 3.0.1 + dev: true + + /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.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + dev: true + + /loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + dependencies: + js-tokens: 4.0.0 + + /lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + dependencies: + yallist: 3.1.1 + dev: true + + /minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + dependencies: + brace-expansion: 1.1.11 + dev: true + + /ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + dev: true + + /nanoid@3.3.7: + resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + dev: true + + /natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + dev: true + + /node-releases@2.0.13: + resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==} + dev: true + + /normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + /object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + dev: true + + /object-inspect@1.13.1: + resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} + dev: true + + /object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + dev: true + + /object.assign@4.1.4: + resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + has-symbols: 1.0.3 + object-keys: 1.1.1 + dev: true + + /object.entries@1.1.7: + resolution: {integrity: sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + dev: true + + /object.fromentries@2.0.7: + resolution: {integrity: sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + dev: true + + /object.hasown@1.1.3: + resolution: {integrity: sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA==} + dependencies: + define-properties: 1.2.1 + es-abstract: 1.22.3 + dev: true + + /object.values@1.1.7: + resolution: {integrity: sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + dev: true + + /once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + dependencies: + wrappy: 1.0.2 + 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 + + /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-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + dev: true + + /picocolors@1.0.0: + resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + dev: true + + /picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + /postcss@8.4.31: + resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.7 + picocolors: 1.0.0 + source-map-js: 1.0.2 + dev: true + + /prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + dev: true + + /prop-types@15.8.1: + resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + dependencies: + loose-envify: 1.4.0 + object-assign: 4.1.1 + react-is: 16.13.1 + dev: true + + /punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + dev: true + + /queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + dev: true + + /react-dom@18.2.0(react@18.2.0): + resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} + peerDependencies: + react: ^18.2.0 + dependencies: + loose-envify: 1.4.0 + react: 18.2.0 + scheduler: 0.23.0 + dev: false + + /react-is@16.13.1: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + dev: true + + /react-refresh@0.14.0: + resolution: {integrity: sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==} + engines: {node: '>=0.10.0'} + dev: true + + /react-router-dom@6.20.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-CbcKjEyiSVpA6UtCHOIYLUYn/UJfwzp55va4yEfpk7JBN3GPqWfHrdLkAvNCcpXr8QoihcDMuk0dzWZxtlB/mQ==} + engines: {node: '>=14.0.0'} + peerDependencies: + react: '>=16.8' + react-dom: '>=16.8' + dependencies: + '@remix-run/router': 1.13.0 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + react-router: 6.20.0(react@18.2.0) + dev: false + + /react-router@6.20.0(react@18.2.0): + resolution: {integrity: sha512-pVvzsSsgUxxtuNfTHC4IxjATs10UaAtvLGVSA1tbUE4GDaOSU1Esu2xF5nWLz7KPiMuW8BJWuPFdlGYJ7/rW0w==} + engines: {node: '>=14.0.0'} + peerDependencies: + react: '>=16.8' + dependencies: + '@remix-run/router': 1.13.0 + react: 18.2.0 + dev: false + + /react@18.2.0: + resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} + engines: {node: '>=0.10.0'} + dependencies: + loose-envify: 1.4.0 + dev: false + + /readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + dependencies: + picomatch: 2.3.1 + + /redux-thunk@2.4.2(redux@4.2.1): + resolution: {integrity: sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==} + peerDependencies: + redux: ^4 + dependencies: + redux: 4.2.1 + dev: false + + /redux@4.2.1: + resolution: {integrity: sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==} + dependencies: + '@babel/runtime': 7.23.4 + dev: false + + /reflect.getprototypeof@1.0.4: + resolution: {integrity: sha512-ECkTw8TmJwW60lOTR+ZkODISW6RQ8+2CL3COqtiJKLd6MmB45hN51HprHFziKLGkAuTGQhBb91V8cy+KHlaCjw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + get-intrinsic: 1.2.2 + globalthis: 1.0.3 + which-builtin-type: 1.1.3 + dev: true + + /regenerator-runtime@0.14.0: + resolution: {integrity: sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==} + dev: false + + /regexp.prototype.flags@1.5.1: + resolution: {integrity: sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + set-function-name: 2.0.1 + dev: true + + /reselect@4.1.8: + resolution: {integrity: sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ==} + dev: false + + /resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + dev: true + + /resolve@2.0.0-next.5: + resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} + hasBin: true + dependencies: + is-core-module: 2.13.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + dev: true + + /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 + + /rollup@4.5.2: + resolution: {integrity: sha512-CRK1uoROBfkcqrZKyaFcqCcZWNsvJ6yVYZkqTlRocZhO2s5yER6Z3f/QaYtO8RGyloPnmhwgzuPQpNGeK210xQ==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.5.2 + '@rollup/rollup-android-arm64': 4.5.2 + '@rollup/rollup-darwin-arm64': 4.5.2 + '@rollup/rollup-darwin-x64': 4.5.2 + '@rollup/rollup-linux-arm-gnueabihf': 4.5.2 + '@rollup/rollup-linux-arm64-gnu': 4.5.2 + '@rollup/rollup-linux-arm64-musl': 4.5.2 + '@rollup/rollup-linux-x64-gnu': 4.5.2 + '@rollup/rollup-linux-x64-musl': 4.5.2 + '@rollup/rollup-win32-arm64-msvc': 4.5.2 + '@rollup/rollup-win32-ia32-msvc': 4.5.2 + '@rollup/rollup-win32-x64-msvc': 4.5.2 + fsevents: 2.3.3 + dev: true + + /run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + dependencies: + queue-microtask: 1.2.3 + dev: true + + /safe-array-concat@1.0.1: + resolution: {integrity: sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==} + engines: {node: '>=0.4'} + dependencies: + call-bind: 1.0.5 + get-intrinsic: 1.2.2 + has-symbols: 1.0.3 + isarray: 2.0.5 + dev: true + + /safe-regex-test@1.0.0: + resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==} + dependencies: + call-bind: 1.0.5 + get-intrinsic: 1.2.2 + is-regex: 1.1.4 + dev: true + + /sass@1.69.5: + resolution: {integrity: sha512-qg2+UCJibLr2LCVOt3OlPhr/dqVHWOa9XtZf2OjbLs/T4VPSJ00udtgJxH3neXZm+QqX8B+3cU7RaLqp1iVfcQ==} + engines: {node: '>=14.0.0'} + hasBin: true + dependencies: + chokidar: 3.5.3 + immutable: 4.3.4 + source-map-js: 1.0.2 + + /scheduler@0.23.0: + resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==} + dependencies: + loose-envify: 1.4.0 + dev: false + + /semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + dev: true + + /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: true + + /set-function-name@2.0.1: + resolution: {integrity: sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.1 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.1 + dev: true + + /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: true + + /source-map-js@1.0.2: + resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} + engines: {node: '>=0.10.0'} + + /string.prototype.matchall@4.0.10: + resolution: {integrity: sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ==} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + get-intrinsic: 1.2.2 + has-symbols: 1.0.3 + internal-slot: 1.0.6 + regexp.prototype.flags: 1.5.1 + set-function-name: 2.0.1 + side-channel: 1.0.4 + dev: true + + /string.prototype.trim@1.2.8: + resolution: {integrity: sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + dev: true + + /string.prototype.trimend@1.0.7: + resolution: {integrity: sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + dev: true + + /string.prototype.trimstart@1.0.7: + resolution: {integrity: sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + dev: true + + /strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + dependencies: + ansi-regex: 5.0.1 + 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 + dev: true + + /supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + dependencies: + has-flag: 4.0.0 + dev: true + + /supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + dev: true + + /text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + dev: true + + /to-fast-properties@2.0.0: + resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} + engines: {node: '>=4'} + 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 + + /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 + + /typed-array-buffer@1.0.0: + resolution: {integrity: sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + get-intrinsic: 1.2.2 + is-typed-array: 1.1.12 + dev: true + + /typed-array-byte-length@1.0.0: + resolution: {integrity: sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + for-each: 0.3.3 + has-proto: 1.0.1 + is-typed-array: 1.1.12 + dev: true + + /typed-array-byte-offset@1.0.0: + resolution: {integrity: sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.5 + call-bind: 1.0.5 + for-each: 0.3.3 + has-proto: 1.0.1 + is-typed-array: 1.1.12 + dev: true + + /typed-array-length@1.0.4: + resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==} + dependencies: + call-bind: 1.0.5 + for-each: 0.3.3 + is-typed-array: 1.1.12 + dev: true + + /unbox-primitive@1.0.2: + resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} + dependencies: + call-bind: 1.0.5 + has-bigints: 1.0.2 + has-symbols: 1.0.3 + which-boxed-primitive: 1.0.2 + dev: true + + /update-browserslist-db@1.0.13(browserslist@4.22.1): + resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + dependencies: + browserslist: 4.22.1 + escalade: 3.1.1 + picocolors: 1.0.0 + dev: true + + /uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + dependencies: + punycode: 2.3.1 + dev: true + + /vite@5.0.2(sass@1.69.5): + resolution: {integrity: sha512-6CCq1CAJCNM1ya2ZZA7+jS2KgnhbzvxakmlIjN24cF/PXhRMzpM/z8QgsVJA/Dm5fWUWnVEsmtBoMhmerPxT0g==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || >=20.0.0 + less: '*' + lightningcss: ^1.21.0 + sass: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + dependencies: + esbuild: 0.19.7 + postcss: 8.4.31 + rollup: 4.5.2 + sass: 1.69.5 + optionalDependencies: + fsevents: 2.3.3 + dev: true + + /which-boxed-primitive@1.0.2: + resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} + dependencies: + is-bigint: 1.0.4 + is-boolean-object: 1.1.2 + is-number-object: 1.0.7 + is-string: 1.0.7 + is-symbol: 1.0.4 + dev: true + + /which-builtin-type@1.1.3: + resolution: {integrity: sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==} + engines: {node: '>= 0.4'} + dependencies: + function.prototype.name: 1.1.6 + has-tostringtag: 1.0.0 + is-async-function: 2.0.0 + is-date-object: 1.0.5 + is-finalizationregistry: 1.0.2 + is-generator-function: 1.0.10 + is-regex: 1.1.4 + is-weakref: 1.0.2 + isarray: 2.0.5 + which-boxed-primitive: 1.0.2 + which-collection: 1.0.1 + which-typed-array: 1.1.13 + dev: true + + /which-collection@1.0.1: + resolution: {integrity: sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==} + dependencies: + is-map: 2.0.2 + is-set: 2.0.2 + is-weakmap: 2.0.1 + is-weakset: 2.0.2 + dev: true + + /which-typed-array@1.1.13: + resolution: {integrity: sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.5 + call-bind: 1.0.5 + for-each: 0.3.3 + gopd: 1.0.1 + has-tostringtag: 1.0.0 + dev: true + + /which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + dependencies: + isexe: 2.0.0 + dev: true + + /wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + dev: true + + /yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + dev: true + + /yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + dev: true diff --git a/reference/react-template/public/loading.css b/reference/react-template/public/loading.css new file mode 100644 index 0000000..301dd60 --- /dev/null +++ b/reference/react-template/public/loading.css @@ -0,0 +1,100 @@ +body{ + background: #111111; +} +#root{ + position: relative; + background: #fefefe; + height: 100vh; + width: 100vw; +} +.openRoot{ + animation: openRoot linear 1500ms; +} +#loading { + position: fixed; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + min-height: 200px; + min-width: 200px; + + display: flex; + align-items: center; + justify-content: center; + +} +#loaderBox{ + opacity: 1; + transition: opacity linear 1000ms; +} +.hideLoader{ + opacity: 0 !important; +} + +#upFace{ + position: absolute; + height: 50%; + width: 100%; + top: 0; + left: 0; + background: #111; + transition: top linear 1500ms; +} +#downFace{ + position: absolute; + height: 50%; + width: 100%; + bottom: 0; + left: 0; + background: #111; + transition: bottom linear 1500ms; +} +.upOpen{ + top: -50vh !important; +} +.downOpen{ + bottom: -50vh !important; +} + +#loader { + position: relative; + width: 60px; + aspect-ratio: 2; + --_g: no-repeat radial-gradient(circle closest-side, #aaa 90%, #fff0); + background: var(--_g) 0% 50%, var(--_g) 50% 50%, var(--_g) 100% 50%; + background-size: calc(100% / 3) 50%; + animation: l3 1s infinite linear; +} +#loaderText{ + position: relative; + text-align: center; + color: #fefefe; + line-height: 40px; + user-select: none; + color: #666; +} + + +@keyframes l3 { + 20% { + background-position: 0% 0%, 50% 50%, 100% 50%; + } + 40% { + background-position: 0% 100%, 50% 0%, 100% 50%; + } + 60% { + background-position: 0% 50%, 50% 100%, 100% 0%; + } + 80% { + background-position: 0% 50%, 50% 50%, 100% 100%; + } +} +@keyframes openRoot { + from{ + transform: scale(0.7) + } + to{ + transform: scale(1) + } +} diff --git a/reference/react-template/public/reset.css b/reference/react-template/public/reset.css new file mode 100644 index 0000000..9d802ac --- /dev/null +++ b/reference/react-template/public/reset.css @@ -0,0 +1,48 @@ +/* http://meyerweb.com/eric/tools/css/reset/ + v2.0 | 20110126 + License: none (public domain) +*/ + +html, body, div, span, applet, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, +del, dfn, em, img, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, +b, u, i, center, +dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td, +article, aside, canvas, details, embed, +figure, figcaption, footer, header, hgroup, +menu, nav, output, ruby, section, summary, +time, mark, audio, video { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; +} +/* HTML5 display-role reset for older browsers */ +article, aside, details, figcaption, figure, +footer, header, hgroup, menu, nav, section { + display: block; +} +body { + line-height: 1; +} +ol, ul { + list-style: none; +} +blockquote, q { + quotes: none; +} +blockquote:before, blockquote:after, +q:before, q:after { + content: ''; + content: none; +} +table { + border-collapse: collapse; + border-spacing: 0; +} diff --git a/reference/react-template/public/vite.svg b/reference/react-template/public/vite.svg new file mode 100644 index 0000000..e7b8dfb --- /dev/null +++ b/reference/react-template/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/reference/react-template/src/App.jsx b/reference/react-template/src/App.jsx new file mode 100644 index 0000000..babf152 --- /dev/null +++ b/reference/react-template/src/App.jsx @@ -0,0 +1,13 @@ +import {useRoutes} from "react-router-dom"; +import routes from "@routes"; + +function App() { + const elements = useRoutes(routes) + return ( + <> + {elements} + + ) +} + +export default App diff --git a/reference/react-template/src/Components/HtmlLoading/Eye/index.jsx b/reference/react-template/src/Components/HtmlLoading/Eye/index.jsx new file mode 100644 index 0000000..c97285c --- /dev/null +++ b/reference/react-template/src/Components/HtmlLoading/Eye/index.jsx @@ -0,0 +1,7 @@ +import css from './index.module.scss'; + +export default function Eye(){ + return
+
+
+} diff --git a/reference/react-template/src/Components/HtmlLoading/Eye/index.module.scss b/reference/react-template/src/Components/HtmlLoading/Eye/index.module.scss new file mode 100644 index 0000000..01f7c8c --- /dev/null +++ b/reference/react-template/src/Components/HtmlLoading/Eye/index.module.scss @@ -0,0 +1,38 @@ +.Eye{ + position: relative; + height: 200px; + width: 100%; + background: #333333; + display: flex; + align-items: center; + justify-content: center; + + .loader { + display: inline-flex; + gap: 10px; + } + + .loader:before, + .loader:after { + content: ""; + height: 20px; + aspect-ratio: 1; + border-radius: 50%; + background: radial-gradient(farthest-side,#000 95%,#0000) 35% 35%/6px 6px no-repeat + #fff; + transform: scaleX(var(--s,1)) rotate(0deg); + animation: l6 1s infinite linear; + } + + .loader:after { + --s: -1; + animation-delay: -0.1s; + } + + @keyframes l6 { + 100% { + transform: scaleX(var(--s,1)) rotate(360deg); + } + } + +} diff --git a/reference/react-template/src/Components/HtmlLoading/One/index.jsx b/reference/react-template/src/Components/HtmlLoading/One/index.jsx new file mode 100644 index 0000000..9d814ef --- /dev/null +++ b/reference/react-template/src/Components/HtmlLoading/One/index.jsx @@ -0,0 +1,6 @@ +import css from './index.module.scss' +export default function One(){ + return
+
+
+} diff --git a/reference/react-template/src/Components/HtmlLoading/One/index.module.scss b/reference/react-template/src/Components/HtmlLoading/One/index.module.scss new file mode 100644 index 0000000..a941bda --- /dev/null +++ b/reference/react-template/src/Components/HtmlLoading/One/index.module.scss @@ -0,0 +1,51 @@ +.One{ + position: relative; + height: 200px; + width: 100%; + display: flex; + align-items: center; + justify-content: center; + + + .loader { + position: relative; + display: block; + width: 44px; + height: 44px; + font-size: 15px; + box-shadow: 9px 9px 33px #d1d1d1, -9px -9px 33px #ffffff; + } + + .loader::before, + .loader::after { + content: ''; + position: absolute; + display: block; + } + + .loader_bubble::before { + top: 10px; + left: 10px; + width: 10px; + height: 10px; + background: #fff; + border-radius: 50%; + } + + .loader_bubble { + background: linear-gradient(180deg, rgb(0, 91, 228) 10%, rgb(75, 127, 240) 100%); + border-radius: 50%; + transform-origin: 50% 50%; + animation: bubble7234 1200ms cubic-bezier(0.645, 0.045, 0.355, 1) infinite; + } + + @keyframes bubble7234 { + 0% { + transform: translate3d(0,0,0) rotate(0); + } + + 100% { + transform: translate3d(0,0,0) rotate(360deg); + } + } +} diff --git a/reference/react-template/src/Components/HtmlLoading/Pacman/index.jsx b/reference/react-template/src/Components/HtmlLoading/Pacman/index.jsx new file mode 100644 index 0000000..173d198 --- /dev/null +++ b/reference/react-template/src/Components/HtmlLoading/Pacman/index.jsx @@ -0,0 +1,15 @@ +import css from './index.module.scss' + +export default function Pacman(){ + return
+
+
+
+
+
+
+
+
+
+
+} diff --git a/reference/react-template/src/Components/HtmlLoading/Pacman/index.module.scss b/reference/react-template/src/Components/HtmlLoading/Pacman/index.module.scss new file mode 100644 index 0000000..4d9a65e --- /dev/null +++ b/reference/react-template/src/Components/HtmlLoading/Pacman/index.module.scss @@ -0,0 +1,123 @@ +.Pacman{ + position: relative; + height: 200px; + width: 100%; + display: flex; + align-items: center; + justify-content: center; + background: #333333; + + .loader-wrapper { + position: relative; + //top: 0; + //left: 0; + //bottom: 0; + //right: 0; + //margin: auto; + } + + .loader-wrapper .packman::before { + content: ''; + position: absolute; + width: 50px; + height: 25px; + background-color: #EFF107; + border-radius: 100px 100px 0 0; + transform: translate(-50%, -50%); + animation: pac-top 0.5s linear infinite; + transform-origin: center bottom; + } + + .loader-wrapper .packman::after { + content: ''; + position: absolute; + width: 50px; + height: 25px; + background-color: #EFF107; + border-radius: 0 0 100px 100px; + transform: translate(-50%, 50%); + animation: pac-bot 0.5s linear infinite; + transform-origin: center top; + } + + @keyframes pac-top { + 0% { + transform: translate(-50%, -50%) rotate(0) + } + + 50% { + transform: translate(-50%, -50%) rotate(-30deg) + } + + 100% { + transform: translate(-50%, -50%) rotate(0) + } + } + + @keyframes pac-bot { + 0% { + transform: translate(-50%, 50%) rotate(0) + } + + 50% { + transform: translate(-50%, 50%) rotate(30deg) + } + + 100% { + transform: translate(-50%, 50%) rotate(0) + } + } + + .dot { + position: absolute; + z-index: -1; + top: 8px; + width: 10px; + height: 10px; + border-radius: 50%; + background: #fff; + } + + .dots .dot:nth-child(1) { + left: 90px; + animation: dot-stage1 0.5s infinite; + } + + .dots .dot:nth-child(2) { + left: 60px; + animation: dot-stage1 0.5s infinite; + } + + .dots .dot:nth-child(3) { + left: 30px; + animation: dot-stage1 0.5s infinite; + } + + .dots .dot:nth-child(4) { + left: 10px; + animation: dot-stage2 0.5s infinite; + } + + @keyframes dot-stage1 { + 0% { + transform: translate(0, 0); + } + + 100% { + transform: translate(-24px, 0); + } + } + + @keyframes dot-stage2 { + 0% { + transform: scale(1); + } + + 5%, 100% { + transform: scale(0); + } + } + + + +} diff --git a/reference/react-template/src/Components/HtmlLoading/TableTennis/index.jsx b/reference/react-template/src/Components/HtmlLoading/TableTennis/index.jsx new file mode 100644 index 0000000..3e05a02 --- /dev/null +++ b/reference/react-template/src/Components/HtmlLoading/TableTennis/index.jsx @@ -0,0 +1,9 @@ +import css from './index.module.scss' + +export default function TableTennis(){ + return
+
+
+
+
+} diff --git a/reference/react-template/src/Components/HtmlLoading/TableTennis/index.module.scss b/reference/react-template/src/Components/HtmlLoading/TableTennis/index.module.scss new file mode 100644 index 0000000..b3e8d4e --- /dev/null +++ b/reference/react-template/src/Components/HtmlLoading/TableTennis/index.module.scss @@ -0,0 +1,65 @@ +.TableTennis{ + position: relative; + height: 200px; + width: 100%; + background: #333; +} + + +$up-down6123 : up-down6123; +$ball-move8234: ball-move8234; + +.ball { + position: relative; + bottom: 50px; + left: calc(100% - 20px); + width: 50px; + height: 50px; + background: #fff; + border-radius: 50%; + animation: $ball-move8234 3s ease-in-out 1s infinite alternate; +} + +.ball::after { + position: absolute; + content: ''; + top: 25px; + right: 5px; + width: 5px; + height: 5px; + background: #000; + border-radius: 50%; +} + +.bar { + position: relative; + top:100px; + width: 200px; + height: 12.5px; + background: #FFDAAF; + border-radius: 30px; + transform: rotate(-15deg); + animation: $up-down6123 3s ease-in-out 1s infinite alternate; +} + +@keyframes up-down6123 { + from { + transform: rotate(-15deg); + } + + to { + transform: rotate(15deg); + } +} + +@keyframes ball-move8234 { + from { + left: calc(100% - 40px); + transform: rotate(360deg); + } + + to { + left: calc(0% - 20px); + transform: rotate(0deg); + } +} diff --git a/reference/react-template/src/Components/HtmlLoading/Three/index.jsx b/reference/react-template/src/Components/HtmlLoading/Three/index.jsx new file mode 100644 index 0000000..1996dad --- /dev/null +++ b/reference/react-template/src/Components/HtmlLoading/Three/index.jsx @@ -0,0 +1,7 @@ +import css from './index.module.scss' + +export default function Three(){ + return
+
+
+} diff --git a/reference/react-template/src/Components/HtmlLoading/Three/index.module.scss b/reference/react-template/src/Components/HtmlLoading/Three/index.module.scss new file mode 100644 index 0000000..2f173af --- /dev/null +++ b/reference/react-template/src/Components/HtmlLoading/Three/index.module.scss @@ -0,0 +1,34 @@ +.Three{ + position: relative; + height: 200px; + width: 100%; + display: flex; + align-items: center; + justify-content: center; + background: #111; + + + .loader { + width: 60px; + aspect-ratio: 2; + --_g: no-repeat radial-gradient(circle closest-side, #fff 90%, #fff0); + background: var(--_g) 0% 50%, var(--_g) 50% 50%, var(--_g) 100% 50%; + background-size: calc(100% / 3) 50%; + animation: l3 1s infinite linear; + } + @keyframes l3 { + 20% { + background-position: 0% 0%, 50% 50%, 100% 50%; + } + 40% { + background-position: 0% 100%, 50% 0%, 100% 50%; + } + 60% { + background-position: 0% 50%, 50% 100%, 100% 0%; + } + 80% { + background-position: 0% 50%, 50% 50%, 100% 100%; + } + } + +} diff --git a/reference/react-template/src/Components/HtmlLoading/Two/index.jsx b/reference/react-template/src/Components/HtmlLoading/Two/index.jsx new file mode 100644 index 0000000..8efb985 --- /dev/null +++ b/reference/react-template/src/Components/HtmlLoading/Two/index.jsx @@ -0,0 +1,8 @@ +import css from './index.module.scss' + +export default function Two(){ + return
+ +
+
+} diff --git a/reference/react-template/src/Components/HtmlLoading/Two/index.module.scss b/reference/react-template/src/Components/HtmlLoading/Two/index.module.scss new file mode 100644 index 0000000..866fa72 --- /dev/null +++ b/reference/react-template/src/Components/HtmlLoading/Two/index.module.scss @@ -0,0 +1,163 @@ +.Two{ + position: relative; + height: 200px; + width: 100%; + display: flex; + align-items: center; + justify-content: center; + + + + .chaotic-orbit { + --uib-size: 25px; + --uib-speed: 1.5s; + --uib-color: black; + position: relative; + display: flex; + align-items: center; + justify-content: center; + height: var(--uib-size); + width: var(--uib-size); + animation: rotate936 calc(var(--uib-speed) * 1.667) infinite linear; + } + + .chaotic-orbit::before, + .chaotic-orbit::after { + content: ''; + position: absolute; + height: 60%; + width: 60%; + border-radius: 50%; + background-color: var(--uib-color); + will-change: transform; + flex-shrink: 0; + } + + .chaotic-orbit::before { + animation: orbit var(--uib-speed) linear infinite; + } + + .chaotic-orbit::after { + animation: orbit var(--uib-speed) linear calc(var(--uib-speed) / -2) + infinite; + } + + @keyframes rotate936 { + 0% { + transform: rotate(0deg); + } + + 100% { + transform: rotate(360deg); + } + } + + @keyframes orbit { + 0% { + transform: translate(calc(var(--uib-size) * 0.5)) scale(0.73684); + opacity: 0.65; + } + + 5% { + transform: translate(calc(var(--uib-size) * 0.4)) scale(0.684208); + opacity: 0.58; + } + + 10% { + transform: translate(calc(var(--uib-size) * 0.3)) scale(0.631576); + opacity: 0.51; + } + + 15% { + transform: translate(calc(var(--uib-size) * 0.2)) scale(0.578944); + opacity: 0.44; + } + + 20% { + transform: translate(calc(var(--uib-size) * 0.1)) scale(0.526312); + opacity: 0.37; + } + + 25% { + transform: translate(0%) scale(0.47368); + opacity: 0.3; + } + + 30% { + transform: translate(calc(var(--uib-size) * -0.1)) scale(0.526312); + opacity: 0.37; + } + + 35% { + transform: translate(calc(var(--uib-size) * -0.2)) scale(0.578944); + opacity: 0.44; + } + + 40% { + transform: translate(calc(var(--uib-size) * -0.3)) scale(0.631576); + opacity: 0.51; + } + + 45% { + transform: translate(calc(var(--uib-size) * -0.4)) scale(0.684208); + opacity: 0.58; + } + + 50% { + transform: translate(calc(var(--uib-size) * -0.5)) scale(0.73684); + opacity: 0.65; + } + + 55% { + transform: translate(calc(var(--uib-size) * -0.4)) scale(0.789472); + opacity: 0.72; + } + + 60% { + transform: translate(calc(var(--uib-size) * -0.3)) scale(0.842104); + opacity: 0.79; + } + + 65% { + transform: translate(calc(var(--uib-size) * -0.2)) scale(0.894736); + opacity: 0.86; + } + + 70% { + transform: translate(calc(var(--uib-size) * -0.1)) scale(0.947368); + opacity: 0.93; + } + + 75% { + transform: translate(0%) scale(1); + opacity: 1; + } + + 80% { + transform: translate(calc(var(--uib-size) * 0.1)) scale(0.947368); + opacity: 0.93; + } + + 85% { + transform: translate(calc(var(--uib-size) * 0.2)) scale(0.894736); + opacity: 0.86; + } + + 90% { + transform: translate(calc(var(--uib-size) * 0.3)) scale(0.842104); + opacity: 0.79; + } + + 95% { + transform: translate(calc(var(--uib-size) * 0.4)) scale(0.789472); + opacity: 0.72; + } + + 100% { + transform: translate(calc(var(--uib-size) * 0.5)) scale(0.73684); + opacity: 0.65; + } + } + + +} diff --git a/reference/react-template/src/Components/HtmlLoading/index.jsx b/reference/react-template/src/Components/HtmlLoading/index.jsx new file mode 100644 index 0000000..480709f --- /dev/null +++ b/reference/react-template/src/Components/HtmlLoading/index.jsx @@ -0,0 +1,18 @@ +import React from "react"; + +const TableTennis = React.lazy(() => import('@components/HtmlLoading/TableTennis')) +const Pacman = React.lazy(() => import("@components/HtmlLoading/Pacman/index.jsx")) +const Eye = React.lazy(() => import("@components/HtmlLoading/Eye/index.jsx")) +const One = React.lazy(() => import("@components/HtmlLoading/One/index.jsx")) +const Two = React.lazy(() => import("@components/HtmlLoading/Two/index.jsx")) +const Three = React.lazy(() => import("@components/HtmlLoading/Three/index.jsx")) +export default function HtmlLoading(){ + return
+ + + + + + +
+} diff --git a/reference/react-template/src/main.jsx b/reference/react-template/src/main.jsx new file mode 100644 index 0000000..f4af1c2 --- /dev/null +++ b/reference/react-template/src/main.jsx @@ -0,0 +1,45 @@ +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.jsx' +import {BrowserRouter} from "react-router-dom"; +import PrivateRoute from "@routes/PrivateRoute.jsx"; + +ReactDOM.createRoot(document.getElementById('root')).render( + + + + + + + , +) + + +window.onload = loading +function loading(){ + const nowTime = new Date().getTime() + console.log('staring...'); + const passTime = nowTime - window.startime; + console.log(window.location.pathname == '/') + if(window.location.pathname == '/' && passTime < 500){ + setTimeout(() => { + startLoad() + }, 550 - passTime) + }else{ + startLoad() + } +} +function startLoad(){ + const loader = document.querySelector('#loading'); + const upFace = document.querySelector('#upFace'); + const downFace = document.querySelector('#downFace'); + const root = document.querySelector('#root'); + const loaderBox = document.querySelector('#loaderBox'); + upFace.classList.add('upOpen') + downFace.classList.add('downOpen') + root.classList.add('openRoot') + loaderBox.classList.add('hideLoader') + setTimeout(() => { + loader.remove() + }, 1500) +} diff --git a/reference/react-template/src/routes/PrivateRoute.jsx b/reference/react-template/src/routes/PrivateRoute.jsx new file mode 100644 index 0000000..83c253a --- /dev/null +++ b/reference/react-template/src/routes/PrivateRoute.jsx @@ -0,0 +1,18 @@ +import {useEffect} from "react"; +import { useLocation, useParams, useNavigate } from 'react-router-dom'; +export default function PrivateRoute(props){ + const location = useLocation(); + const params = useParams(); + const navigate = useNavigate() + useEffect(() => { + // console.log(location.pathname); // 获取当前路由路径 + // console.log(location.search); // 获取查询字符串 + // console.log(location.hash); // 获取 URL 中的哈希值 + // console.log(params); // 假设 URL 中有一个名为 "id" 的参数 + if(location.pathname == '/test'){ + navigate('/') + } + }, [0]); + + return props.children +} diff --git a/reference/react-template/src/routes/index.jsx b/reference/react-template/src/routes/index.jsx new file mode 100644 index 0000000..e8546db --- /dev/null +++ b/reference/react-template/src/routes/index.jsx @@ -0,0 +1,37 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: react-template +// | @文件描述: index.jsx - +// | @创建时间: 2023-11-26 16:05 +// | @更新时间: 2023-11-26 16:05 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ + +import { Navigate } from 'react-router-dom' +import React from "react"; + +const Test = React.lazy(() => import("@views/Test/index.jsx")) +const HtmlLoading = React.lazy(() => import("@components/HtmlLoading/index.jsx")) + +const routes = [ + { + path: '/about', + element: + }, { + path: '/home', + element: + }, /*{ + path: '/', + element: + }*/, { + path: '/', + element: + } +] + +export default routes + diff --git a/reference/react-template/src/store/index.js b/reference/react-template/src/store/index.js new file mode 100644 index 0000000..264cf9a --- /dev/null +++ b/reference/react-template/src/store/index.js @@ -0,0 +1,23 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: react-template +// | @文件描述: index.js - +// | @创建时间: 2023-11-26 16:47 +// | @更新时间: 2023-11-26 16:47 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ + +import { configureStore } from '@reduxjs/toolkit'; +import DefaultSlice from "@/store/slice/defaultSlice.js"; + +const store = configureStore({ + reducer: { + defaultSlice: DefaultSlice, + }, +}); + +export default store; diff --git a/reference/react-template/src/store/slice/defaultSlice.js b/reference/react-template/src/store/slice/defaultSlice.js new file mode 100644 index 0000000..98ffb46 --- /dev/null +++ b/reference/react-template/src/store/slice/defaultSlice.js @@ -0,0 +1,63 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: react-template +// | @文件描述: defaultSlice.js - +// | @创建时间: 2023-11-26 17:20 +// | @更新时间: 2023-11-26 17:20 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ + + +import {createAsyncThunk, createSlice} from '@reduxjs/toolkit'; + +export const decremented = createAsyncThunk( + 'user/fetchData', + async (data, thunkAPI) => { + // 调用API + console.log(data, thunkAPI) + await new Promise(res => { + + setTimeout(() =>{ + res() + }, 1000) + }) + return; // 或根据你的API返回结构进行调整 + } +); + + +export const defaultSlice = createSlice({ + name: 'defaultSlice', + initialState: { + value: 0, + }, + reducers: { + incremented: (state,b) => { + state.value += 1; + }, + }, + extraReducers: { + // 当 fetchUserData action 被派发时,根据 action 的不同状态对 state 进行更新 + [decremented.pending]: (state, action) => { + // state.isLoading = true; + // state.error = null; + }, + [decremented.fulfilled]: (state, action) => { + // state.isLoading = false; + // state.data = action.payload; // 假设我们的API返回了用户的数据结构 + state.value -= 1; + }, + [decremented.rejected]: (state, action) => { + // state.isLoading = false; + // state.error = action.error.message; + }, + }, +}); + +export const { incremented } = defaultSlice.actions; + +export default defaultSlice.reducer; diff --git a/reference/react-template/src/views/Test/index.jsx b/reference/react-template/src/views/Test/index.jsx new file mode 100644 index 0000000..4467379 --- /dev/null +++ b/reference/react-template/src/views/Test/index.jsx @@ -0,0 +1,24 @@ +import {useEffect, useState} from "react"; +import store from "@/store/index.js"; +import {incremented, decremented} from "@/store/slice/defaultSlice.js"; + +export default function Test(){ + + const [count, setCount] = useState(store.getState().defaultSlice.value); + + useEffect(() => { + console.log(store.getState()) + const unsubscribe = store.subscribe(() => { + setCount(store.getState().defaultSlice.value); + }); + return unsubscribe; // 在组件卸载时取消订阅 + }, []); + + + + return
+

{count}

+ + +
+} diff --git a/reference/react-template/test/react-router-dom.md b/reference/react-template/test/react-router-dom.md new file mode 100644 index 0000000..9c4f7f8 --- /dev/null +++ b/reference/react-template/test/react-router-dom.md @@ -0,0 +1 @@ +https://blog.csdn.net/qq_30769437/article/details/128149273 diff --git a/reference/react-template/test/redux.md b/reference/react-template/test/redux.md new file mode 100644 index 0000000..31adbcc --- /dev/null +++ b/reference/react-template/test/redux.md @@ -0,0 +1,314 @@ +如果你需要创建一个Redux应用,但不想使用react-redux和`createStore`(这通常是Redux的标准API用于创建store的方法),你可以使用Redux Toolkit中的`configureStore`作为`createStore`的替代方案来创建store。 + +Redux Toolkit 是官方推荐的方式来设置store,它提供了更简化的API和一些有用的工具,比如默认集成了redux-thunk中间件以及Redux DevTools扩展支持。下面是一个不使用react-redux的示例,但是如果你想完全不使用任何辅助工具或库,仅使用最基本的Redux API(这是不推荐的,因为你会失去许多便利和性能优化),那你将需要自己管理store的状态订阅和更新组件的渲染。 + +下面是一个不使用`createStore`和`react-redux`的Redux应用例子: + +目录结构: +``` +my-app/ + src/ + store/ + index.js // 创建和配置应用程序的Redux store + counterReducer.js // 管理计数状态的reducer + components/ + Counter.js // 一个使用Redux store的React组件 + App.js // 应用程序的根组件 + index.js // 应用程序的主入口文件 +``` + +`store/index.js`: +```javascript +import { configureStore } from '@reduxjs/toolkit'; +import counterReducer from './counterReducer'; + +const store = configureStore({ + reducer: { + counter: counterReducer, + }, +}); + +export default store; +``` + +`store/counterReducer.js`: +```javascript +const INCREMENT = 'INCREMENT'; +const DECREMENT = 'DECREMENT'; + +const initialState = { + value: 0, +}; + +function counterReducer(state = initialState, action) { + switch (action.type) { + case INCREMENT: + return { ...state, value: state.value + 1 }; + case DECREMENT: + return { ...state, value: state.value - 1 }; + default: + return state; + } +} + +export const increment = () => ({ type: INCREMENT }); +export const decrement = () => ({ type: DECREMENT }); + +export default counterReducer; +``` + +`components/Counter.js`: +```jsx +import React, { useState, useEffect } from 'react'; +import store from '../store'; +import { increment, decrement } from '../store/counterReducer'; + +export const Counter = () => { + const [count, setCount] = useState(store.getState().counter.value); + + useEffect(() => { + const unsubscribe = store.subscribe(() => { + setCount(store.getState().counter.value); + }); + return unsubscribe; // 在组件卸载时取消订阅 + }, []); + + return ( +
+

{count}

+ + +
+ ); +}; +``` + +`App.js`: +```jsx +import React from 'react'; +import { Counter } from './components/Counter'; + +const App = () => { + return ( +
+ +
+ ); +} + +export default App; +``` + +`index.js`: +```jsx +import React from 'react'; +import ReactDOM from 'react-dom'; +import App from './App'; +import store from './store'; +import { increment } from './store/counterReducer'; + +// 可以在这里测试我们的Redux store是否正常工作 +console.log(store.getState()); // 应该看到初始状态 +store.dispatch(increment()); +console.log(store.getState()); // 状态应该更新,并增加了1 + +ReactDOM.render( + + + , + document.getElementById('root') +); +``` + +在上述的示例中,我们使用`useEffect`来订阅Redux store和清理订阅,通过store的`getState`方法获取当前的状态,并通过`dispatch`方法来派发actions。这种方式下,我们没有使用react-redux,而是手动连接到Redux store并监听状态变化。 + +请注意,这样手动处理Redux可能会使你的应用程序难以管理和扩展,特别是在大型应用程序中,react-redux提供的`Provider`和`connect`方法或者hooks`useSelector`和`useDispatch`可以更好地帮助你管理连接逻辑和组件更新,提高应用的性能。 + + + + + + + + + + + + + + + + + + + + + + + + + + + +在 Redux Toolkit 中,`createSlice` 通常用于同步更新 state ,但当它与 `createAsyncThunk` 一起使用时,可以非常容易地用于异步更新。`createAsyncThunk` 会生成三种 action 类型(pending,fulfilled,rejected),你可以在 `createSlice` 的 `extraReducers` 属性中监听这些 action: + +```javascript +import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'; +import { userAPI } from './userAPI'; + +// 首先创建一个异步 thunk action +export const fetchUserData = createAsyncThunk( + 'user/fetchData', + async (userId, thunkAPI) => { + // 调用API + const response = await userAPI.fetchById(userId); + return response.data; // 或根据你的API返回结构进行调整 + } +); + +// 然后创建 slice,这里我们可以处理我们上面定义的三种状态的actions +const userSlice = createSlice({ + name: 'user', + initialState: { + data: null, + isLoading: false, + error: null, + }, + reducers: { + // 你的其他同步 reducers 可以在这里定义 + }, + extraReducers: { + // 当 fetchUserData action 被派发时,根据 action 的不同状态对 state 进行更新 + [fetchUserData.pending]: (state, action) => { + state.isLoading = true; + state.error = null; + }, + [fetchUserData.fulfilled]: (state, action) => { + state.isLoading = false; + state.data = action.payload; // 假设我们的API返回了用户的数据结构 + }, + [fetchUserData.rejected]: (state, action) => { + state.isLoading = false; + state.error = action.error.message; + }, + }, +}); + +export const { actions, reducer } = userSlice; +``` + +在这个例子中: + +- `fetchUserData.pending` 相关的 reducer 将在请求开始时将 `isLoading` 状态设置为 true。 +- `fetchUserData.fulfilled` 相关的 reducer 将在请求成功并收到数据时更新 `data` ,并将 `isLoading` 设置为 false。 +- `fetchUserData.rejected` 相关的 reducer 将在请求失败时设置错误信息,并将 `isLoading` 设置为 false。 + +通过使用 `createAsyncThunk` 和 `createSlice` 的 `extraReducers` ,我们也很方便的可以将异步行为整合到我们的 Redux state 管理中。 + + + + + + + + + + + + + +在视图(常常指的是 React 组件)中使用 `@reduxjs/toolkit` 中 `createAsyncThunk` 创建的异步 action 通常涉及以下几个步骤: + +1. 将 Redux store 和 React 组件连接起来,可以使用 `react-redux` 提供的 `useSelector` 来选择 state,以及 `useDispatch` 来派发 actions。 + +2. 创建视图(UI组件),并在适当的时候(如组件挂载或者用户互动事件)派发异步 action。 + +3. 显示加载状态、错误信息或者成功得到的数据。 + +下面是一个例子,展示了如何在一个 React 组件中使用异步 action: + +```jsx +import React, { useEffect } from 'react'; +import { useSelector, useDispatch } from 'react-redux'; +import { fetchUserData } from './userSlice'; +// 以上的 userSlice 是我们之前定义的包含 fetchUserData 异步 action 的文件 + +function UserComponent({ userId }) { + const dispatch = useDispatch(); + + // 从 Redux state 中选择数据 + const user = useSelector(state => state.user.data); + const isLoading = useSelector(state => state.user.isLoading); + const error = useSelector(state => state.user.error); + + // 当组件挂载时,派发 fetchUserData action + useEffect(() => { + dispatch(fetchUserData(userId)); + }, [userId, dispatch]); + + // 根据 state 渲染 UI + if (isLoading) { + return
Loading...
; + } + + if (error) { + return
Error: {error}
; + } + + return ( +
+

User Data

+ {/* 假设 user 对象有 name 属性 */} + {user ?

Name: {user.name}

:

No user details

} +
+ ); +} + +export default UserComponent; +``` + +在这个 React 组件中: + +- 使用 `useDispatch` hook 获取 `dispatch` 方法,以便于我们可以派发 actions。 +- 使用 `useSelector` hook 从 Redux store 中选择 `user.state` 中的各部分数据。 +- 使用 `useEffect` React hook 来触发 `fetchUserData` 异步 action。当 `userId` 改变或者组件首次渲染时会重新触发。 +- 在 UI 中根据 `isLoading`, `error`, 和 `user` 状态显示不同的内容。如果 `isLoading` 为 true,显示加载状态;如果 `error` 存在,则显示错误;否则显示用户信息。 + + + + + + + + +在 `createAsyncThunk` 中使用的 `thunkAPI` 对象是由 Redux Thunk 提供的一个参数,包含了几个有用的属性和方法,使得在 thunk 中可以执行更为复杂的逻辑。`thunkAPI` 在每次调用异步 thunk 函数时都会被提供,并且具有以下字段和方法: + +1. **dispatch**: 允许你在 thunk 中派发 action。 +2. **getState**: 允许你访问当前的 Redux store state。 +3. **extra**: 如果在创建 Redux store 的 `configureStore` 方法中定义了 `extraArgument`,则这里可以取得。 +4. **requestId**: 是对每次异步 thunk action 调用的唯一标识。 +5. **signal**: 是一个 `AbortSignal` 对象,与本次异步操作相关联,可以用来响应取消操作。 +6. **rejectWithValue**: 一个函数,允许你在发生错误时手动地派发一个拒绝 (rejected) action,并携带自定义的 payload 值。 +7. **fulfillWithValue**: 当你需要在 resolve (解决) action 中提供一个不同于异步操作返回结果的 payload 时,可以用这个函数。 +8. **rejectWithReason**: 类似 `rejectWithValue`,允许在 rejected action 中提供自定义拒绝原因,更明确地说明拒绝的原因。 + +这些功能给予开发者很大的灵活性去处理异步逻辑和实现复杂的异步操作流程。例如,使用 `dispatch` 来派发其他 actions,利用 `getState` 获取最新的 state 来指导后续逻辑,或使用 `rejectWithValue` 在出错时捕捉错误并优化错误处理。 + +以下是一个使用 `thunkAPI` 的例子: + +```javascript +export const fetchUserData = createAsyncThunk( + 'user/fetchData', + async (userId, thunkAPI) => { + try { + const response = await userAPI.fetchById(userId); + return response.data; + } catch (error) { + // 如果 API 抛出一个错误,我们可以选择发送一个拒绝action,并附带一个自定义的payload + return thunkAPI.rejectWithValue({errorMessage: 'Cannot load user data'}); + } + } +); +``` + +在这个例子中,如果 `userAPI.fetchById` 方法抛出一个错误,`thunkAPI.rejectWithValue` 方法则被用来派发一个拒绝的 action,并附上一个含错误信息的 payload。这使得 reducer 可以捕捉这个拒绝的 action,并根据附带的 payload 更新 state。 diff --git a/reference/react-template/vite.config.js b/reference/react-template/vite.config.js new file mode 100644 index 0000000..5385465 --- /dev/null +++ b/reference/react-template/vite.config.js @@ -0,0 +1,17 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import path from 'path' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react()], + resolve: { + alias: { + '@': path.resolve(__dirname, './src'), + '@views':path.resolve(__dirname, './src/views'), + '@components': path.resolve(__dirname, './src/components'), + '@utils': path.resolve(__dirname, './src/utils'), + '@routes': path.resolve(__dirname, './src/routes') + }, + }, +}) diff --git a/src/common/logger/index.back.js b/src/common/logger/index.back.js new file mode 100644 index 0000000..951b6b2 --- /dev/null +++ b/src/common/logger/index.back.js @@ -0,0 +1,146 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: hutao +// | @文件描述: index.back.js - +// | @创建时间: 2024-03-15 15:27 +// | @更新时间: 2024-03-15 15:27 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ +const winston = require("winston"); +require("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' + } +} +// 创建颜色方法 +const colorizer = winston.format.colorize(); +colorizer.addColors(myCustomLevels.levelsColor) + +const logger = winston.createLogger({ + // colorize: true, + // prettyPrint: true, + // json:true, + level: 'trace', // 日志打印等级 + levels: myCustomLevels.levels,// 日志等级列表 + exitOnError: false,// 如果为false,处理异常不会导致process.exit + silent: false, // 如果为true,所有日志被抑制 + format: winston.format.combine( + // winston.format.label({ label: '测试' }),// 自定义标签 + // winston.format.align(),//加了打印不出来对象 + // winston.format.prettyPrint(), + // 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()}] ${data}` + // return colorizer.colorize( + // i.level, + // `${i.timestamp} [${i.level.padEnd(5, ' ').toUpperCase()}] ${data}`, + // ); + }, + ), + ), + transports: [ + new winston.transports.DailyRotateFile({ + filename: "winston-logs/%DATE%-INFO--winston.log", + level: "info", + datePattern: "YYYY-MM-DD", + zippedArchive: true,// 启用压缩 + maxSize: "10m",// 单文件大小 + maxFiles: "30d",// 存储时间 + // format: winston.format.combine( + // winston.format.printf(i => `${i.timestamp} [${i.level.padEnd(5, ' ').toUpperCase()}] ${i.message}`), + // ) + }), + new winston.transports.DailyRotateFile({ + filename: "winston-logs/%DATE%-ERROR-winston.log", + level: "error", + datePattern: "YYYY-MM-DD", + zippedArchive: true, + maxSize: "10m", + maxFiles: "365d", + // format: winston.format.combine( + // winston.format.printf(i => `${i.timestamp} [${i.level.padEnd(5, ' ').toUpperCase()}] ${i.message}`), + // ) + }), + ], + // winston可以捕获和记录异常 + exceptionHandlers: [ + new winston.transports.File({ filename: 'winston-logs/winston-exceptions.log' }) + ], + // 捕获uncaughtRejection事件 + rejectionHandlers: [ + new winston.transports.File({ filename: 'winston-logs/rejections.log' }) + ] +}); +// 后续加入记录器,这里可以加入环境变量的判断,当为生产模式时,取消控制台的打印操作。 +logger.add(new winston.transports.Console({ + format:winston.format.combine( + winston.format.printf( + (i) => { + const splatList = Array.from(Object.getOwnPropertySymbols(i)) + const splat = splatList && splatList.filter(item => item.toString() === 'Symbol(message)') + const splatName = splat.length == 1 ? splat[0] : null + const data = splatName ? i[splatName] : i.message + return colorizer.colorize( + i.level, + data + ); + }, + ), + ) +})) +function getStack(){ + (function throwNewError() { + try { + throw new Error() + } catch (err) { + console.trace('AA') + console.log('AAA') + const stack = err.stack; + console.log(stack) + const stackList = stack.split('\n') + const fileStackList = stackList.map(i => i.trim()) + let stackPost; + console.log('BBB') + for (let i in fileStackList) { + if (fileStackList[i].indexOf('throwNewError') != -1) { + stackPost = Number(i) + break + } + } + const stackLine = fileStackList[stackPost + 3]; + console.log('CCC') + // const dirname = __dirname.split(path.sep).join(path.posix.sep) + console.log(stackLine.split(__dirname).slice(-1)[0]) + } + })() +} +module.exports = logger diff --git a/src/common/logger/index.js b/src/common/logger/index.js new file mode 100644 index 0000000..8a3e36a --- /dev/null +++ b/src/common/logger/index.js @@ -0,0 +1,78 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: hutao +// | @文件描述: index.js - +// | @创建时间: 2024-03-15 14:38 +// | @更新时间: 2024-03-15 14:38 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ +import winston from "winston" +import DailyRotateFile from "winston-daily-rotate-file"; +import fastifyPlugin from "fastify-plugin"; + +async function registerLogger(fastify, option){ + const consoleLog = new winston.transports.Console({ + level: "debug", + format: winston.format.combine( + winston.format.timestamp({ format: "HH:mm:ss:SSS" }), + winston.format.colorize(), + winston.format.printf( + info => `${info.timestamp} [${info.level}] ${info.message}` + ) + ), + }) + + const logger = winston.createLogger({ + exitOnError: false,// 如果为false,处理异常不会导致process.exit + silent: false, // 如果为true,所有日志被抑制 + format: winston.format.combine( + winston.format.timestamp({ format: "YYYY-MM-DD HH:mm:ss:SSS" }), + winston.format.printf( + info => ` ${info.timestamp} [${info.level}]: ${info.message}` + ) + ), + transports: [ + new DailyRotateFile({ + filename: "logs/%DATE%-INFO--winston.log", + level: "info", + datePattern: "YYYY-MM-DD", + zippedArchive: true,// 启用压缩 + maxSize: "10m",// 单文件大小 + maxFiles: "30d",// 存储时间 + // format: winston.format.combine( + // winston.format.printf(i => `${i.timestamp} [${i.level.padEnd(5, ' ').toUpperCase()}] ${i.message}`), + // ) + }), + new DailyRotateFile({ + filename: "logs/%DATE%-ERROR-winston.log", + level: "error", + datePattern: "YYYY-MM-DD", + zippedArchive: true, + maxSize: "10m", + maxFiles: "365d", + // format: winston.format.combine( + // winston.format.printf(i => `${i.timestamp} [${i.level.padEnd(5, ' ').toUpperCase()}] ${i.message}`), + // ) + }), + ], + // // winston可以捕获和记录异常 + // exceptionHandlers: [ + // new winston.transports.File({ filename: 'logs/winston-exceptions.log' }),consoleLog + // ], + // // 捕获uncaughtRejection事件 + // rejectionHandlers: [ + // new winston.transports.File({ filename: 'logs/rejections.log' }),consoleLog + // ] + }); +// 后续加入记录器,这里可以加入环境变量的判断,当为生产模式时,取消控制台的打印操作。 + process.env.NODE_ENV === 'development' && logger.add(consoleLog) + fastify.decorate('logger', logger) +} + + + +export default fastifyPlugin(registerLogger) diff --git a/src/databaseModel/demo/demo.bulkCreate.js b/src/databaseModel/demo/demo.bulkCreate.js new file mode 100644 index 0000000..385d370 --- /dev/null +++ b/src/databaseModel/demo/demo.bulkCreate.js @@ -0,0 +1,46 @@ + +// @ 运维资源类的类型字典 +import {mountBaseDict} from "#databaseModel/demo.model.js"; + +const OMResourceType = [ + { + baseDictId: 1, + baseDictIsBase: 1, + baseDictOriginType: 0, + baseDictName: '运维资源类型', + baseDictDescribe: '在运维系统上使用的资源类用途定义,资源类和备件类', + baseDictFather: 0, + }, +] +// @ 单位 +const UnitType = [ + { + baseDictId: 11, + baseDictIsBase: 1, + baseDictOriginType: 0, + baseDictName: '数据单位', + baseDictDescribe: '对资源在物理上的统一衡量区分', + baseDictFather: 0, + }, + { + baseDictId: 12, + baseDictIsBase: 1, + baseDictOriginType: 0, + baseDictName: '长度单位', + baseDictDescribe: '对资源在长度上的统一衡量区分', + baseDictFather: 11, + }, + { + baseDictId: 13, + baseDictIsBase: 1, + baseDictOriginType: 0, + baseDictName: '米', + baseDictIdentify: 'm', + baseDictDescribe: '', + baseDictFather: 12, + }, +] + +await mountBaseDict(sequelize, DataTypes); +await sequelize.models.BaseDict.bulkCreate(OMResourceType, { ignoreDuplicates: true }) +await sequelize.models.BaseDict.bulkCreate(UnitType, { ignoreDuplicates: true }) \ No newline at end of file diff --git a/src/databaseModel/demo/demo.model.js b/src/databaseModel/demo/demo.model.js new file mode 100644 index 0000000..9d5f69e --- /dev/null +++ b/src/databaseModel/demo/demo.model.js @@ -0,0 +1,98 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: hutao +// | @文件描述: demo.model.js - +// | @创建时间: 2024-03-15 17:10 +// | @更新时间: 2024-03-15 17:10 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ +// | ------------------------------------------------------------ +// | @版本: 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, DataTypes} from 'sequelize'; + +export function mountBaseDict(sequelize) { + class BaseDict extends Model { + } + + BaseDict.init({ + // 在这里定义模型属性 + baseDictId: { + type: DataTypes.INTEGER, + autoIncrement: true, + primaryKey: true, + allowNull: false, + comment: '基础字典Id' + }, + atomModel: { + type: DataTypes.INTEGER, + 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: "字典项名称" + }, + baseDictIdentify:{ + type: DataTypes.STRING, + 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/databaseModel/index.js b/src/databaseModel/index.js new file mode 100644 index 0000000..2fb04e8 --- /dev/null +++ b/src/databaseModel/index.js @@ -0,0 +1,49 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: hutao +// | @文件描述: index.js - +// | @创建时间: 2024-03-15 17:09 +// | @更新时间: 2024-03-15 17:09 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ + +import mountUserRegister from "#databaseModel/user/userRegister.model.js"; +import mountUserPassword from "#databaseModel/user/userPassword.model.js"; +import mountUserInfoStruct from "#databaseModel/user/userInfoStruct.model.js"; +import mountUserInfoRecord from "#databaseModel/user/userInfoRecord.model.js"; +import initUserInfoStructBaseData from "#databaseModel/user/userInfoStruct.init.js" + +export default async function initDatabase(sequelize) { + + + /** + * + * + * await mountBaseDict(sequelize, DataTypes); + * await sequelize.models.BaseDict.bulkCreate(OMResourceType, { ignoreDuplicates: true }) + * + * + * */ + + // 注册 用户注册表 + await mountUserRegister(sequelize); + // 注册 用户密码表 + await mountUserPassword(sequelize); + // 注册 用户信息结构表 + await mountUserInfoStruct(sequelize); + // 注册 用户信息表 + await mountUserInfoRecord(sequelize); + + + // 同步表 + await sequelize.sync({alter: true}); + + + // 初始化 用户信息结构表数据 + await initUserInfoStructBaseData(sequelize); + +} diff --git a/src/databaseModel/user/userInfoRecord.model.js b/src/databaseModel/user/userInfoRecord.model.js new file mode 100644 index 0000000..bfff0fd --- /dev/null +++ b/src/databaseModel/user/userInfoRecord.model.js @@ -0,0 +1,56 @@ +/** + * 用户信息表 + * + * */ +import {Model, DataTypes} from 'sequelize'; + +export default function mountUserInfoRecord(sequelize){ + class UserInfoRecord extends Model{ + + } + UserInfoRecord.init({ + userInfoRecordSequence:{ + type: DataTypes.INTEGER, + autoIncrement: true, + primaryKey: true, + allowNull: false, + comment: '用户信息字段序列', + }, + userId:{ + type: DataTypes.STRING, + allowNull: false, + comment: '用户ID', + }, + userInfoStructSequence:{ + type: DataTypes.INTEGER, + allowNull: false, + comment: '用户信息结构序列', + }, + userInfoFieldData:{ + type: DataTypes.STRING, + comment: '用户信息字段数据', + defaultValue: '', + }, + creator: { + type: DataTypes.STRING, + comment: '创建人', + }, + isDelete: { + type: DataTypes.STRING(64), + comment: '删除时间', + }, + }, { + // 这是其他模型参数 + sequelize, // 我们需要传递连接实例 + modelName: 'UserInfoRecord', // 我们需要选择模型名称 + // tableName: 'baseDict', + comment: "用户信息表", + timestamps: true, // 不要忘记启用时间戳! + createdAt: 'createTimestamp', // 不想要 createdAt + // 想要 updatedAt 但是希望名称叫做 updateTimestamp + updatedAt: 'updateTimestamp', + underscored: true, // 改成下划线格式 + }) + + return UserInfoRecord +} diff --git a/src/databaseModel/user/userInfoStruct.init.js b/src/databaseModel/user/userInfoStruct.init.js new file mode 100644 index 0000000..5134485 --- /dev/null +++ b/src/databaseModel/user/userInfoStruct.init.js @@ -0,0 +1,49 @@ +/** + * 用户信息结构表的基础数据 + * */ +export default async function initUserInfoStructBaseData(sequelize){ + const InfoStruct = [ + { + userInfoStructSequence: 1, + fieldName: '头像', + fieldDescribe: '图标', + fieldDisplayType: 'link', + fieldIcon: '', + creator: 'expressgy' + }, + { + userInfoStructSequence: 2, + fieldName: '性别', + fieldDescribe: '性别:0是女生1是男生', + fieldDisplayType: 'text', + fieldIcon: '', + creator: 'expressgy' + }, + { + userInfoStructSequence: 3, + fieldName: '签名', + fieldDescribe: '描述啦', + fieldDisplayType: 'textarea', + fieldIcon: '', + creator: 'expressgy' + }, + { + userInfoStructSequence: 4, + fieldName: '生日', + fieldDescribe: '出生年月日', + fieldDisplayType: 'text', + fieldIcon: '', + creator: 'expressgy' + }, + { + userInfoStructSequence: 5, + fieldName: '手机', + fieldDescribe: '手机号码', + fieldIcon: '', + fieldDisplayType: 'text', + creator: 'expressgy' + }, + ]; + + await sequelize.models.UserInfoStruct.bulkCreate(InfoStruct, { ignoreDuplicates: true }) +} diff --git a/src/databaseModel/user/userInfoStruct.model.js b/src/databaseModel/user/userInfoStruct.model.js new file mode 100644 index 0000000..6191c5d --- /dev/null +++ b/src/databaseModel/user/userInfoStruct.model.js @@ -0,0 +1,59 @@ +/** + * 用户信息结构表 + * + * */ +import {Model, DataTypes} from 'sequelize'; + +export default function mountUserInfoStruct(sequelize) { + class UserInfoStruct extends Model{ + + } + UserInfoStruct.init({ + userInfoStructSequence: { + type: DataTypes.INTEGER, + autoIncrement: true, + primaryKey: true, + allowNull: false, + comment: '用户信息结构序列', + }, + fieldName: { + type: DataTypes.STRING(16), + allowNull: false, + comment: '字段名称', + }, + fieldDescribe: { + type: DataTypes.STRING, + comment: '字段描述', + }, + fieldDisplayType: { + type: DataTypes.INTEGER, + allowNull: false, + comment: '字段显示类型', + }, + fieldIcon:{ + type: DataTypes.STRING, + comment: '字段图标', + }, + creator: { + type: DataTypes.STRING, + comment: '创建人', + }, + isDelete: { + type: DataTypes.STRING(64), + comment: '删除时间', + }, + }, { + // 这是其他模型参数 + sequelize, // 我们需要传递连接实例 + modelName: 'UserInfoStruct', // 我们需要选择模型名称 + // tableName: 'baseDict', + comment: "用户信息结构表", + timestamps: true, // 不要忘记启用时间戳! + createdAt: 'createTimestamp', // 不想要 createdAt + // 想要 updatedAt 但是希望名称叫做 updateTimestamp + updatedAt: 'updateTimestamp', + underscored: true, // 改成下划线格式 + }) + + return UserInfoStruct +} diff --git a/src/databaseModel/user/userPassword.model.js b/src/databaseModel/user/userPassword.model.js new file mode 100644 index 0000000..d5579be --- /dev/null +++ b/src/databaseModel/user/userPassword.model.js @@ -0,0 +1,46 @@ +/** + * 用户密码表 + * + * */ +import {Model, DataTypes} from 'sequelize'; + +export default function mountUserPassword(sequelize){ + class UserPassword extends Model{ + + } + UserPassword.init({ + userPasswordSequence:{ + type: DataTypes.INTEGER, + autoIncrement: true, + primaryKey: true, + allowNull: false, + comment: '密码序列', + }, + userId:{ + type: DataTypes.STRING, + allowNull: false, + comment: '用户ID', + }, + creator: { + type: DataTypes.STRING, + comment: '创建人', + }, + isDelete: { + type: DataTypes.STRING(64), + comment: '删除时间', + }, + }, { + // 这是其他模型参数 + sequelize, // 我们需要传递连接实例 + modelName: 'UserPassword', // 我们需要选择模型名称 + // tableName: 'baseDict', + comment: "用户密码表", + timestamps: true, // 不要忘记启用时间戳! + createdAt: 'createTimestamp', // 不想要 createdAt + // 想要 updatedAt 但是希望名称叫做 updateTimestamp + updatedAt: 'updateTimestamp', + underscored: true, // 改成下划线格式 + }) + + return UserPassword +} diff --git a/src/databaseModel/user/userRegister.model.js b/src/databaseModel/user/userRegister.model.js new file mode 100644 index 0000000..3bb7f8d --- /dev/null +++ b/src/databaseModel/user/userRegister.model.js @@ -0,0 +1,57 @@ +/** + * 用户注册表 + * + * */ +import {Model, DataTypes} from 'sequelize'; + +export default function mountUserRegister(sequelize){ + class UserRegister extends Model{ + + } + UserRegister.init({ + userId:{ + type: DataTypes.STRING, + // autoIncrement: true, + primaryKey: true, + allowNull: false, + comment: '用户ID', + }, + username:{ + type: DataTypes.STRING(128), + allowNull: false, + comment: "用户名" + }, + mail:{ + type: DataTypes.STRING, + allowNull: false, + comment: "邮箱" + }, + useStatus:{ + type: DataTypes.INTEGER, + allowNull: false, + comment: '账号状态(0是启用,1是禁用)', + defaultValue: 0, + }, + creator: { + type: DataTypes.STRING, + comment: '创建人', + }, + isDelete: { + type: DataTypes.STRING(64), + comment: '删除时间', + }, + }, { + // 这是其他模型参数 + sequelize, // 我们需要传递连接实例 + modelName: 'UserRegister', // 我们需要选择模型名称 + // tableName: 'baseDict', + comment: "用户注册表", + timestamps: true, // 不要忘记启用时间戳! + createdAt: 'createTimestamp', // 不想要 createdAt + // 想要 updatedAt 但是希望名称叫做 updateTimestamp + updatedAt: 'updateTimestamp', + underscored: true, // 改成下划线格式 + }) + + return UserRegister +} diff --git a/src/plugins/ajv/index.js b/src/plugins/ajv/index.js new file mode 100644 index 0000000..5ebc668 --- /dev/null +++ b/src/plugins/ajv/index.js @@ -0,0 +1,82 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: P01CentralControl +// | @文件描述: index.js - +// | @创建时间: 2024-01-15 10:49 +// | @更新时间: 2024-01-15 10:49 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ +import Ajv from 'ajv'; +// ajv错误消息回应 +import ajvErrors from 'ajv-errors'; + + + +// 将字符串转化为全小写 +export function isLowerCase(ajv){ + ajv.addKeyword({ + keyword: 'isLowerCase', + // 开启错误收集 + errors: true, + modifying: true, + validate: function validateIsEven(schema, data, parentSchema, dataCxt) { + if(typeof data == 'string'){ + dataCxt.parentData[dataCxt.parentDataProperty] = dataCxt.parentData[dataCxt.parentDataProperty].trim().toLowerCase(); + return true; + }else{ + validateIsEven.errors = [ { + message: '错误的数据' + } ]; + return false; + } + } + }); +} + +// 去除两端空格 +export function isTrim(ajv){ + ajv.addKeyword({ + keyword: 'isTrim', + type: 'string', + // 开启错误收集 + errors: true, + modifying: true, + validate: function validateIsEven(schema, data, parentSchema, dataCxt) { + if(typeof data == 'string'){ + dataCxt.parentData[dataCxt.parentDataProperty] = dataCxt.parentData[dataCxt.parentDataProperty].trim(); + return true; + }else{ + validateIsEven.errors = [ { + message: 'is note String' + } ]; + return false; + } + } + }); +} + + + +// 给fastify添加自定义的参数校验规则 +function customAjv(fastify, options){ + // 创建一个新的 AJV 实例 + // 创建一个新的 AJV 实例 + const ajv = new Ajv({ + removeAdditional: true, + useDefaults: true, + coerceTypes: true, + // jsonPointers: true, + allErrors: true + }); + ajvErrors(ajv); + isLowerCase(ajv); + // 使用自定义的 AJV 实例为 Fastify 设置验证器编译器 + fastify.setValidatorCompiler(({ schema, method, url, httpPart }) => { + return ajv.compile(schema); + }); +} + diff --git a/src/plugins/sequelize/index.js b/src/plugins/sequelize/index.js new file mode 100644 index 0000000..41c89b8 --- /dev/null +++ b/src/plugins/sequelize/index.js @@ -0,0 +1,59 @@ +// | ------------------------------------------------------------ +// | @版本: version 0.1 +// | @创建人: 【Nie-x7129】 +// | @E-mail: x71291@outlook.com +// | @所在项目: hutao +// | @文件描述: index.js - +// | @创建时间: 2024-03-15 16:11 +// | @更新时间: 2024-03-15 16:11 +// | @修改记录: +// | -*-*-*- (时间--修改人--修改说明) -*-*-*- +// | = +// | ------------------------------------------------------------ + +import { Sequelize } from 'sequelize'; +import fastifyPlugin from "fastify-plugin"; +import initDatabase from "#databaseModel/index.js" + +async function registerSequelize(fastify, option){ + const { database, username, password, host, port } = fastify.config.get('db') + 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), + // logging: fastify.logger.debug.bind(fastify.logger) + logging: false + }); + + // 加载数据表模型 + await initDatabase(sequelize) + // 测试链接 + await sequelize.authenticate().catch(e => { + console.error(`数据库连接失败, ${e}`); + throw new Error(e) + }); + // 将数据库加入上下文 + fastify.decorate('sequelize', sequelize) + // fastify.logger.info(fastify.color.bold.blue(`== 已成功与数据库建立连接。 ==`)); + // 获取表信息 + sequelize.getQueryInterface().showAllTables().then(data => { + console.log(data) + }).catch(e => { + console.error(e) + }) +} + +export default fastifyPlugin(registerSequelize) diff --git a/src/routes/index.js b/src/routes/index.js new file mode 100644 index 0000000..a06fef2 --- /dev/null +++ b/src/routes/index.js @@ -0,0 +1,8 @@ +export default async function root(fastify, option){ + // fastify.get('', async (request, reply) => { + // return {name: 'api'} + // }) + fastify.get('/', async (request, reply) => { + return "name" + }) +}