From e59f9a96593555f40dd2e3bad140e6e61caf4c02 Mon Sep 17 00:00:00 2001 From: Hide_D Date: Sat, 23 Sep 2023 16:29:18 +0000 Subject: [PATCH] =?UTF-8?q?monorepo=20=EB=B2=84=EC=A0=84=20=EC=A4=80?= =?UTF-8?q?=EB=B9=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## @strpc 기존 RPC를 package화 ### @strpc/express express의 middleware + router 결함 ## @sammo 게임 전체 - server, client - gateway_server, gateway_client --- .eslintrc.cjs | 17 + .gitignore | 30 + .nvmrc | 1 + .prettierrc.json | 8 + .vscode/extensions.json | 3 + @sammo/api_def/package.json | 29 + @sammo/api_def/src/def/index.ts | 1 + @sammo/api_def/src/gateway.ts | 71 + @sammo/api_def/src/index.ts | 33 + @sammo/api_def/tsconfig.json | 20 + @sammo/client/env.d.ts | 1 + @sammo/client/index.html | 13 + @sammo/client/package.json | 52 + @sammo/client/public/favicon.ico | Bin 0 -> 4286 bytes @sammo/client/src/App.vue | 85 + @sammo/client/src/assets/base.css | 86 + @sammo/client/src/assets/logo.svg | 1 + @sammo/client/src/assets/main.css | 35 + @sammo/client/src/components/HelloWorld.vue | 41 + @sammo/client/src/components/TheWelcome.vue | 86 + @sammo/client/src/components/WelcomeItem.vue | 87 + .../src/components/icons/IconCommunity.vue | 7 + .../components/icons/IconDocumentation.vue | 7 + .../src/components/icons/IconEcosystem.vue | 7 + .../src/components/icons/IconSupport.vue | 7 + .../src/components/icons/IconTooling.vue | 19 + @sammo/client/src/main.ts | 14 + @sammo/client/src/router/index.ts | 23 + @sammo/client/src/stores/counter.ts | 12 + @sammo/client/src/views/AboutView.vue | 15 + @sammo/client/src/views/HomeView.vue | 9 + @sammo/client/tsconfig.app.json | 12 + @sammo/client/tsconfig.json | 28 + @sammo/client/tsconfig.node.json | 18 + @sammo/client/vite.config.ts | 17 + @sammo/crypto/.eslintrc.cjs | 12 + @sammo/crypto/jest.config.mjs | 38 + @sammo/crypto/package.json | 48 + @sammo/crypto/src/AES.test.ts | 92 + @sammo/crypto/src/AES.ts | 61 + @sammo/crypto/src/ECDHe.ts | 63 + @sammo/crypto/src/ECDHe_AES.ts | 48 + @sammo/crypto/src/ECDSA.test.ts | 32 + @sammo/crypto/src/ECDSA.ts | 81 + @sammo/crypto/src/ECKey.test.ts | 35 + @sammo/crypto/src/ECKey.ts | 62 + @sammo/crypto/src/LiteHashDRBG.ts | 262 + @sammo/crypto/src/PBKDF2.ts | 48 + @sammo/crypto/src/RNG.ts | 13 + @sammo/crypto/src/RandUtil.ts | 144 + @sammo/crypto/src/RawTypes.ts | 50 + @sammo/crypto/src/SHA2.test.ts | 10 + @sammo/crypto/src/SHA2.ts | 19 + @sammo/crypto/src/TypeLength.ts | 6 + @sammo/crypto/src/index.ts | 108 + @sammo/crypto/src/types.ts | 13 + @sammo/crypto/src/utils.ts | 73 + @sammo/crypto/tsconfig.jest.json | 6 + @sammo/crypto/tsconfig.json | 12 + @sammo/game_logic/package.json | 23 + @sammo/game_logic/src/generalStats.ts | 140 + @sammo/game_logic/src/index.ts | 1 + @sammo/game_logic/tsconfig.json | 21 + @sammo/gateway_client/env.d.ts | 1 + @sammo/gateway_client/index.html | 13 + @sammo/gateway_client/package.json | 51 + @sammo/gateway_client/public/favicon.ico | Bin 0 -> 4286 bytes @sammo/gateway_client/src/App.vue | 85 + @sammo/gateway_client/src/assets/base.css | 86 + @sammo/gateway_client/src/assets/logo.svg | 1 + @sammo/gateway_client/src/assets/main.css | 35 + .../src/components/HelloWorld.vue | 41 + .../src/components/TheWelcome.vue | 86 + .../src/components/WelcomeItem.vue | 87 + .../src/components/icons/IconCommunity.vue | 7 + .../components/icons/IconDocumentation.vue | 7 + .../src/components/icons/IconEcosystem.vue | 7 + .../src/components/icons/IconSupport.vue | 7 + .../src/components/icons/IconTooling.vue | 19 + @sammo/gateway_client/src/main.ts | 14 + @sammo/gateway_client/src/router/index.ts | 23 + @sammo/gateway_client/src/stores/counter.ts | 12 + @sammo/gateway_client/src/views/AboutView.vue | 15 + @sammo/gateway_client/src/views/HomeView.vue | 9 + @sammo/gateway_client/tsconfig.app.json | 12 + @sammo/gateway_client/tsconfig.json | 28 + @sammo/gateway_client/tsconfig.node.json | 18 + @sammo/gateway_client/vite.config.ts | 17 + @sammo/gateway_server/package.json | 37 + @sammo/gateway_server/src/MongoSequence.ts | 25 + .../src/api/GetGameLoginToken.ts | 22 + .../gateway_server/src/api/Install/index.ts | 0 .../src/api/Install/initAdmin.ts | 0 .../src/api/Login/ChangePassword.ts | 18 + .../gateway_server/src/api/Login/LoginByID.ts | 62 + .../src/api/Login/LoginByToken.ts | 50 + .../gateway_server/src/api/Login/ReqNonce.ts | 30 + @sammo/gateway_server/src/api/Login/index.ts | 11 + @sammo/gateway_server/src/api/index.ts | 9 + @sammo/gateway_server/src/connectDB.ts | 22 + @sammo/gateway_server/src/constPath.ts | 3 + @sammo/gateway_server/src/dotenv.ts | 47 + @sammo/gateway_server/src/exports.ts | 9 + @sammo/gateway_server/src/index.ts | 34 + .../src/procDecorator/ReqGatewayLogin.ts | 33 + .../gateway_server/src/schema/LoginToken.ts | 23 + .../src/schema/SchemaSequence.ts | 23 + .../src/schema/ServerVersion.ts | 19 + @sammo/gateway_server/src/schema/User.ts | 90 + @sammo/gateway_server/src/schema/UserLog.ts | 30 + @sammo/gateway_server/tsconfig.json | 27 + @sammo/secure_token/package.json | 26 + @sammo/secure_token/src/EncryptedSimple.ts | 79 + @sammo/secure_token/src/SecureToken.ts | 225 + @sammo/secure_token/src/index.ts | 4 + @sammo/secure_token/src/zodSecureToken.ts | 52 + @sammo/secure_token/tsconfig.json | 15 + @sammo/server/package.json | 37 + @sammo/server/src/MongoSequence.ts | 25 + @sammo/server/src/api/index.ts | 5 + @sammo/server/src/connectDB.ts | 22 + @sammo/server/src/constPath.ts | 3 + @sammo/server/src/dotenv.d.ts | 32 + @sammo/server/src/dotenv.ts | 49 + @sammo/server/src/index.ts | 31 + .../server/src/procDecorator/ReqGameLogin.ts | 36 + @sammo/server/src/procDecorator/ReqLogin.ts | 32 + @sammo/server/src/schema/SchemaSequence.ts | 23 + @sammo/server/src/serverConfig.ts | 9 + @sammo/server/tsconfig.json | 30 + @sammo/server_util/package.json | 25 + @sammo/server_util/src/StartSession.ts | 58 + .../server_util/src/UniqueNumberAllocator.ts | 198 + @sammo/server_util/src/index.ts | 2 + @sammo/server_util/tsconfig.json | 36 + @sammo/util/package.json | 28 + @sammo/util/src/bsonify.ts | 263 + @sammo/util/src/converter/combineArray.ts | 11 + @sammo/util/src/converter/combineObject.ts | 8 + .../converter/convertBytesLikeToUint8Array.ts | 28 + @sammo/util/src/converter/convertIDArray.ts | 9 + .../src/converter/convertIterableToMap.ts | 10 + @sammo/util/src/converter/entriesWithType.ts | 7 + @sammo/util/src/converter/index.ts | 5 + .../src/converter/merge2DArrToObjectArr.ts | 20 + @sammo/util/src/converter/mergeKVArray.ts | 35 + @sammo/util/src/datetime/formatTime.ts | 18 + @sammo/util/src/datetime/getDateTimeNow.ts | 4 + @sammo/util/src/datetime/index.ts | 3 + @sammo/util/src/datetime/joinYearMonth.ts | 3 + @sammo/util/src/datetime/parseTime.ts | 5 + @sammo/util/src/datetime/parseYearMonth.ts | 3 + @sammo/util/src/error.ts | 43 + @sammo/util/src/index.ts | 44 + @sammo/util/src/jsonify.ts | 238 + @sammo/util/src/korean/JosaUtil.ts | 586 ++ @sammo/util/src/korean/automata초성.ts | 101 + @sammo/util/src/korean/convertSearch초성.ts | 9 + @sammo/util/src/korean/filter초성.ts | 17 + .../util/src/korean/filter초성withAlphabet.ts | 24 + @sammo/util/src/korean/index.ts | 5 + @sammo/util/src/simpleSerialize.ts | 18 + @sammo/util/src/string/index.ts | 5 + @sammo/util/src/string/mb_strimwidth.ts | 31 + @sammo/util/src/string/mb_strwidth.ts | 24 + @sammo/util/src/string/nl2br.ts | 4 + @sammo/util/src/string/numberWithCommas.ts | 5 + @sammo/util/src/string/randStr.ts | 25 + @sammo/util/src/strongType.ts | 51 + @sammo/util/src/types.ts | 15 + @sammo/util/src/unwrap.ts | 25 + @sammo/util/src/web.ts | 34 + @sammo/util/tsconfig.json | 25 + @strpc/client_ky/package.json | 27 + @strpc/client_ky/src/callClientAPI.ts | 158 + @strpc/client_ky/src/index.ts | 15 + @strpc/client_ky/tsconfig.json | 12 + @strpc/def/package.json | 17 + @strpc/def/src/clientAPIPathGen.ts | 38 + @strpc/def/src/index.ts | 23 + @strpc/def/src/tail.ts | 177 + @strpc/def/src/types.ts | 191 + @strpc/def/tsconfig.json | 9 + @strpc/express/package.json | 33 + @strpc/express/src/defs.ts | 213 + @strpc/express/src/generator.ts | 161 + @strpc/express/src/index.ts | 3 + @strpc/express/src/proc_decorator.ts | 186 + @strpc/express/tsconfig.json | 12 + LICENSE | 2 +- README.md | 2 - package.json | 47 + pnpm-lock.yaml | 6441 +++++++++++++++++ pnpm-workspace.yaml | 4 + schemats.d.ts | 1079 +++ tsconfig.base.json | 30 + tsconfig.json | 17 + 197 files changed, 15458 insertions(+), 3 deletions(-) create mode 100644 .eslintrc.cjs create mode 100644 .gitignore create mode 100644 .nvmrc create mode 100644 .prettierrc.json create mode 100644 .vscode/extensions.json create mode 100644 @sammo/api_def/package.json create mode 100644 @sammo/api_def/src/def/index.ts create mode 100644 @sammo/api_def/src/gateway.ts create mode 100644 @sammo/api_def/src/index.ts create mode 100644 @sammo/api_def/tsconfig.json create mode 100644 @sammo/client/env.d.ts create mode 100644 @sammo/client/index.html create mode 100644 @sammo/client/package.json create mode 100644 @sammo/client/public/favicon.ico create mode 100644 @sammo/client/src/App.vue create mode 100644 @sammo/client/src/assets/base.css create mode 100644 @sammo/client/src/assets/logo.svg create mode 100644 @sammo/client/src/assets/main.css create mode 100644 @sammo/client/src/components/HelloWorld.vue create mode 100644 @sammo/client/src/components/TheWelcome.vue create mode 100644 @sammo/client/src/components/WelcomeItem.vue create mode 100644 @sammo/client/src/components/icons/IconCommunity.vue create mode 100644 @sammo/client/src/components/icons/IconDocumentation.vue create mode 100644 @sammo/client/src/components/icons/IconEcosystem.vue create mode 100644 @sammo/client/src/components/icons/IconSupport.vue create mode 100644 @sammo/client/src/components/icons/IconTooling.vue create mode 100644 @sammo/client/src/main.ts create mode 100644 @sammo/client/src/router/index.ts create mode 100644 @sammo/client/src/stores/counter.ts create mode 100644 @sammo/client/src/views/AboutView.vue create mode 100644 @sammo/client/src/views/HomeView.vue create mode 100644 @sammo/client/tsconfig.app.json create mode 100644 @sammo/client/tsconfig.json create mode 100644 @sammo/client/tsconfig.node.json create mode 100644 @sammo/client/vite.config.ts create mode 100644 @sammo/crypto/.eslintrc.cjs create mode 100644 @sammo/crypto/jest.config.mjs create mode 100644 @sammo/crypto/package.json create mode 100644 @sammo/crypto/src/AES.test.ts create mode 100644 @sammo/crypto/src/AES.ts create mode 100644 @sammo/crypto/src/ECDHe.ts create mode 100644 @sammo/crypto/src/ECDHe_AES.ts create mode 100644 @sammo/crypto/src/ECDSA.test.ts create mode 100644 @sammo/crypto/src/ECDSA.ts create mode 100644 @sammo/crypto/src/ECKey.test.ts create mode 100644 @sammo/crypto/src/ECKey.ts create mode 100644 @sammo/crypto/src/LiteHashDRBG.ts create mode 100644 @sammo/crypto/src/PBKDF2.ts create mode 100644 @sammo/crypto/src/RNG.ts create mode 100644 @sammo/crypto/src/RandUtil.ts create mode 100644 @sammo/crypto/src/RawTypes.ts create mode 100644 @sammo/crypto/src/SHA2.test.ts create mode 100644 @sammo/crypto/src/SHA2.ts create mode 100644 @sammo/crypto/src/TypeLength.ts create mode 100644 @sammo/crypto/src/index.ts create mode 100644 @sammo/crypto/src/types.ts create mode 100644 @sammo/crypto/src/utils.ts create mode 100644 @sammo/crypto/tsconfig.jest.json create mode 100644 @sammo/crypto/tsconfig.json create mode 100644 @sammo/game_logic/package.json create mode 100644 @sammo/game_logic/src/generalStats.ts create mode 100644 @sammo/game_logic/src/index.ts create mode 100644 @sammo/game_logic/tsconfig.json create mode 100644 @sammo/gateway_client/env.d.ts create mode 100644 @sammo/gateway_client/index.html create mode 100644 @sammo/gateway_client/package.json create mode 100644 @sammo/gateway_client/public/favicon.ico create mode 100644 @sammo/gateway_client/src/App.vue create mode 100644 @sammo/gateway_client/src/assets/base.css create mode 100644 @sammo/gateway_client/src/assets/logo.svg create mode 100644 @sammo/gateway_client/src/assets/main.css create mode 100644 @sammo/gateway_client/src/components/HelloWorld.vue create mode 100644 @sammo/gateway_client/src/components/TheWelcome.vue create mode 100644 @sammo/gateway_client/src/components/WelcomeItem.vue create mode 100644 @sammo/gateway_client/src/components/icons/IconCommunity.vue create mode 100644 @sammo/gateway_client/src/components/icons/IconDocumentation.vue create mode 100644 @sammo/gateway_client/src/components/icons/IconEcosystem.vue create mode 100644 @sammo/gateway_client/src/components/icons/IconSupport.vue create mode 100644 @sammo/gateway_client/src/components/icons/IconTooling.vue create mode 100644 @sammo/gateway_client/src/main.ts create mode 100644 @sammo/gateway_client/src/router/index.ts create mode 100644 @sammo/gateway_client/src/stores/counter.ts create mode 100644 @sammo/gateway_client/src/views/AboutView.vue create mode 100644 @sammo/gateway_client/src/views/HomeView.vue create mode 100644 @sammo/gateway_client/tsconfig.app.json create mode 100644 @sammo/gateway_client/tsconfig.json create mode 100644 @sammo/gateway_client/tsconfig.node.json create mode 100644 @sammo/gateway_client/vite.config.ts create mode 100644 @sammo/gateway_server/package.json create mode 100644 @sammo/gateway_server/src/MongoSequence.ts create mode 100644 @sammo/gateway_server/src/api/GetGameLoginToken.ts create mode 100644 @sammo/gateway_server/src/api/Install/index.ts create mode 100644 @sammo/gateway_server/src/api/Install/initAdmin.ts create mode 100644 @sammo/gateway_server/src/api/Login/ChangePassword.ts create mode 100644 @sammo/gateway_server/src/api/Login/LoginByID.ts create mode 100644 @sammo/gateway_server/src/api/Login/LoginByToken.ts create mode 100644 @sammo/gateway_server/src/api/Login/ReqNonce.ts create mode 100644 @sammo/gateway_server/src/api/Login/index.ts create mode 100644 @sammo/gateway_server/src/api/index.ts create mode 100644 @sammo/gateway_server/src/connectDB.ts create mode 100644 @sammo/gateway_server/src/constPath.ts create mode 100644 @sammo/gateway_server/src/dotenv.ts create mode 100644 @sammo/gateway_server/src/exports.ts create mode 100644 @sammo/gateway_server/src/index.ts create mode 100644 @sammo/gateway_server/src/procDecorator/ReqGatewayLogin.ts create mode 100644 @sammo/gateway_server/src/schema/LoginToken.ts create mode 100644 @sammo/gateway_server/src/schema/SchemaSequence.ts create mode 100644 @sammo/gateway_server/src/schema/ServerVersion.ts create mode 100644 @sammo/gateway_server/src/schema/User.ts create mode 100644 @sammo/gateway_server/src/schema/UserLog.ts create mode 100644 @sammo/gateway_server/tsconfig.json create mode 100644 @sammo/secure_token/package.json create mode 100644 @sammo/secure_token/src/EncryptedSimple.ts create mode 100644 @sammo/secure_token/src/SecureToken.ts create mode 100644 @sammo/secure_token/src/index.ts create mode 100644 @sammo/secure_token/src/zodSecureToken.ts create mode 100644 @sammo/secure_token/tsconfig.json create mode 100644 @sammo/server/package.json create mode 100644 @sammo/server/src/MongoSequence.ts create mode 100644 @sammo/server/src/api/index.ts create mode 100644 @sammo/server/src/connectDB.ts create mode 100644 @sammo/server/src/constPath.ts create mode 100644 @sammo/server/src/dotenv.d.ts create mode 100644 @sammo/server/src/dotenv.ts create mode 100644 @sammo/server/src/index.ts create mode 100644 @sammo/server/src/procDecorator/ReqGameLogin.ts create mode 100644 @sammo/server/src/procDecorator/ReqLogin.ts create mode 100644 @sammo/server/src/schema/SchemaSequence.ts create mode 100644 @sammo/server/src/serverConfig.ts create mode 100644 @sammo/server/tsconfig.json create mode 100644 @sammo/server_util/package.json create mode 100644 @sammo/server_util/src/StartSession.ts create mode 100644 @sammo/server_util/src/UniqueNumberAllocator.ts create mode 100644 @sammo/server_util/src/index.ts create mode 100644 @sammo/server_util/tsconfig.json create mode 100644 @sammo/util/package.json create mode 100644 @sammo/util/src/bsonify.ts create mode 100644 @sammo/util/src/converter/combineArray.ts create mode 100644 @sammo/util/src/converter/combineObject.ts create mode 100644 @sammo/util/src/converter/convertBytesLikeToUint8Array.ts create mode 100644 @sammo/util/src/converter/convertIDArray.ts create mode 100644 @sammo/util/src/converter/convertIterableToMap.ts create mode 100644 @sammo/util/src/converter/entriesWithType.ts create mode 100644 @sammo/util/src/converter/index.ts create mode 100644 @sammo/util/src/converter/merge2DArrToObjectArr.ts create mode 100644 @sammo/util/src/converter/mergeKVArray.ts create mode 100644 @sammo/util/src/datetime/formatTime.ts create mode 100644 @sammo/util/src/datetime/getDateTimeNow.ts create mode 100644 @sammo/util/src/datetime/index.ts create mode 100644 @sammo/util/src/datetime/joinYearMonth.ts create mode 100644 @sammo/util/src/datetime/parseTime.ts create mode 100644 @sammo/util/src/datetime/parseYearMonth.ts create mode 100644 @sammo/util/src/error.ts create mode 100644 @sammo/util/src/index.ts create mode 100644 @sammo/util/src/jsonify.ts create mode 100644 @sammo/util/src/korean/JosaUtil.ts create mode 100644 @sammo/util/src/korean/automata초성.ts create mode 100644 @sammo/util/src/korean/convertSearch초성.ts create mode 100644 @sammo/util/src/korean/filter초성.ts create mode 100644 @sammo/util/src/korean/filter초성withAlphabet.ts create mode 100644 @sammo/util/src/korean/index.ts create mode 100644 @sammo/util/src/simpleSerialize.ts create mode 100644 @sammo/util/src/string/index.ts create mode 100644 @sammo/util/src/string/mb_strimwidth.ts create mode 100644 @sammo/util/src/string/mb_strwidth.ts create mode 100644 @sammo/util/src/string/nl2br.ts create mode 100644 @sammo/util/src/string/numberWithCommas.ts create mode 100644 @sammo/util/src/string/randStr.ts create mode 100644 @sammo/util/src/strongType.ts create mode 100644 @sammo/util/src/types.ts create mode 100644 @sammo/util/src/unwrap.ts create mode 100644 @sammo/util/src/web.ts create mode 100644 @sammo/util/tsconfig.json create mode 100644 @strpc/client_ky/package.json create mode 100644 @strpc/client_ky/src/callClientAPI.ts create mode 100644 @strpc/client_ky/src/index.ts create mode 100644 @strpc/client_ky/tsconfig.json create mode 100644 @strpc/def/package.json create mode 100644 @strpc/def/src/clientAPIPathGen.ts create mode 100644 @strpc/def/src/index.ts create mode 100644 @strpc/def/src/tail.ts create mode 100644 @strpc/def/src/types.ts create mode 100644 @strpc/def/tsconfig.json create mode 100644 @strpc/express/package.json create mode 100644 @strpc/express/src/defs.ts create mode 100644 @strpc/express/src/generator.ts create mode 100644 @strpc/express/src/index.ts create mode 100644 @strpc/express/src/proc_decorator.ts create mode 100644 @strpc/express/tsconfig.json delete mode 100644 README.md create mode 100644 package.json create mode 100644 pnpm-lock.yaml create mode 100644 pnpm-workspace.yaml create mode 100644 schemats.d.ts create mode 100644 tsconfig.base.json create mode 100644 tsconfig.json diff --git a/.eslintrc.cjs b/.eslintrc.cjs new file mode 100644 index 0000000..fb490e0 --- /dev/null +++ b/.eslintrc.cjs @@ -0,0 +1,17 @@ +/* eslint-env node */ +require('@rushstack/eslint-patch/modern-module-resolution') + +module.exports = { + root: true, + parser: "vue-eslint-parser", + 'extends': [ + 'plugin:vue/vue3-essential', + 'plugin:@typescript-eslint/recommended', + 'eslint:recommended', + '@vue/eslint-config-typescript', + '@vue/eslint-config-prettier/skip-formatting', + ], + parserOptions: { + ecmaVersion: 'latest', + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..48b0266 --- /dev/null +++ b/.gitignore @@ -0,0 +1,30 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +.DS_Store +dist +dist_server +coverage +*.local + +/cypress/videos/ +/cypress/screenshots/ + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +*.tsbuildinfo \ No newline at end of file diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000..2edeafb --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +20 \ No newline at end of file diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..66e2335 --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,8 @@ +{ + "$schema": "https://json.schemastore.org/prettierrc", + "semi": false, + "tabWidth": 2, + "singleQuote": true, + "printWidth": 100, + "trailingComma": "none" +} \ No newline at end of file diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..c0a6e5a --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,3 @@ +{ + "recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"] +} diff --git a/@sammo/api_def/package.json b/@sammo/api_def/package.json new file mode 100644 index 0000000..cea9f64 --- /dev/null +++ b/@sammo/api_def/package.json @@ -0,0 +1,29 @@ +{ + "name": "@sammo/api_def", + "version": "1.0.1", + "description": "", + "main": "dist/index.js", + "exports": { + ".": "./dist/index.js", + "./gateway": "./dist/gateway.js", + "./def": "./dist/def/index.js" + }, + "scripts": { + "build": "tsc --build" + }, + "author": "", + "type": "module", + "license": "MIT", + "dependencies": { + "@sammo/crypto": "workspace:^", + "@sammo/secure_token": "workspace:^", + "@sammo/util": "workspace:^", + "@strpc/def": "workspace:^" + }, + "devDependencies": { + "zod": "^3.22.2" + }, + "peerDependencies": { + "zod": "^3.22.2" + } +} diff --git a/@sammo/api_def/src/def/index.ts b/@sammo/api_def/src/def/index.ts new file mode 100644 index 0000000..d360e8a --- /dev/null +++ b/@sammo/api_def/src/def/index.ts @@ -0,0 +1 @@ +export const hello = "hello"; \ No newline at end of file diff --git a/@sammo/api_def/src/gateway.ts b/@sammo/api_def/src/gateway.ts new file mode 100644 index 0000000..80f5224 --- /dev/null +++ b/@sammo/api_def/src/gateway.ts @@ -0,0 +1,71 @@ +import { GET, POST, type DefAPINamespace } from "@strpc/def"; + +//굳이 할 필요는 없지만, d.ts가 깔끔해짐 +import type { + InvalidResponse, ValidResponse +} from "@strpc/def"; +import type { + ArgDeleteAPI, + ArgGetAPI, + ArgHeadAPI, + ArgPatchAPI, + ArgPostAPI, + ArgPutAPI, + EmptyDeleteAPI, + EmptyGetAPI, + EmptyHeadAPI, + EmptyPatchAPI, + EmptyPostAPI, + EmptyPutAPI, +} from "@strpc/def/types"; + + +export type LoginResponse = { + result: true, + nextToken: [number, string] | undefined, +} + +export type LoginFailed = { + result: false, + reqOTP: boolean, + reason: string, +} + + +export type AutoLoginNonceResponse = { + result: true, + loginNonce: string, +}; + +export type AutoLoginResponse = { + result: true, + nextToken: [number, string] | undefined, +} + + +export type AutoLoginFailed = { + result: false, + silent: boolean, + reason: string, +} + +/** @internal */ +export const structure = { + Login: { + LoginByID: POST<{ + id: string, + password: string, + }, LoginResponse, LoginFailed>(), + LoginByToken: POST<{ + hashedToken: string, + token_id: number, + }, AutoLoginResponse, AutoLoginFailed>(), + ReqNonce: GET(), + }, + GetGameLoginToken: GET<{ + result: true, + gameLoginToken: string, + userID: number, + }>(), + +} satisfies DefAPINamespace; \ No newline at end of file diff --git a/@sammo/api_def/src/index.ts b/@sammo/api_def/src/index.ts new file mode 100644 index 0000000..cc4d393 --- /dev/null +++ b/@sammo/api_def/src/index.ts @@ -0,0 +1,33 @@ +import type { + DefAPINamespace, +} from "@strpc/def"; + +//굳이 할 필요는 없지만, d.ts가 깔끔해짐 +import type { + InvalidResponse, ValidResponse +} from "@strpc/def"; +import type { + ArgDeleteAPI, + ArgGetAPI, + ArgHeadAPI, + ArgPatchAPI, + ArgPostAPI, + ArgPutAPI, + EmptyDeleteAPI, + EmptyGetAPI, + EmptyHeadAPI, + EmptyPatchAPI, + EmptyPostAPI, + EmptyPutAPI, +} from "@strpc/def/types"; +import { GET, POST } from '@strpc/def'; + +export type { + InferResponse, + InferError, + InferQuery, +} from "@strpc/def"; +export type * as def from './def/index.js'; + +export const structure = { +} satisfies DefAPINamespace; \ No newline at end of file diff --git a/@sammo/api_def/tsconfig.json b/@sammo/api_def/tsconfig.json new file mode 100644 index 0000000..64b1d1c --- /dev/null +++ b/@sammo/api_def/tsconfig.json @@ -0,0 +1,20 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist", + }, + "references": [ + { + + "path": "../util" + }, + { + "path": "../secure_token" + }, + { + "path": "../../@strpc/def" + } + ] + } + \ No newline at end of file diff --git a/@sammo/client/env.d.ts b/@sammo/client/env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/@sammo/client/env.d.ts @@ -0,0 +1 @@ +/// diff --git a/@sammo/client/index.html b/@sammo/client/index.html new file mode 100644 index 0000000..a888544 --- /dev/null +++ b/@sammo/client/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite App + + +
+ + + diff --git a/@sammo/client/package.json b/@sammo/client/package.json new file mode 100644 index 0000000..31e2b5f --- /dev/null +++ b/@sammo/client/package.json @@ -0,0 +1,52 @@ +{ + "name": "@sammo/client", + "version": "1.0.1", + "description": "", + "main": "dist/index.js", + "scripts": { + "dev": "vite", + "build": "run-p type-check build-only", + "preview": "vite preview", + "build-only": "vite build", + "type-check": "vue-tsc --noEmit -p tsconfig.app.json --composite false", + "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore", + "format": "prettier --write src/" + }, + "author": "", + "type": "module", + "license": "MIT", + "dependencies": { + "@popperjs/core": "^2.11.8", + "@sammo/game_logic": "workspace:^", + "@sammo/util": "workspace:^", + "@strpc/def": "workspace:^", + "bootstrap": "^5.3.1", + "bootstrap-vue-next": "^0.9.26", + "bson": "^5.4.0", + "date-fns": "^2.30.0", + "ky": "^1.0.1", + "lodash-es": "^4.17.21", + "pinia": "^2.1.4", + "vue": "^3.3.4", + "vue-router": "^4.2.4" + }, + "devDependencies": { + "@tsconfig/node20": "^20.1.2", + "@types/lodash-es": "^4.17.9", + "@types/node": "^20.6.3", + "@vue/eslint-config-prettier": "^8.0.0", + "@vue/eslint-config-typescript": "^11.0.3", + "@vue/tsconfig": "^0.4.0", + "eslint": "^8.50.0", + "eslint-plugin-vue": "^9.15.1", + "prettier": "^3.0.0", + "ts-node": "^10.9.1", + "tslib": "^2.6.2", + "vite": "^4.4.6", + "vue-tsc": "^1.8.6", + "zod": "^3.22.2" + }, + "peerDependencies": { + "zod": "^3.22.2" + } +} \ No newline at end of file diff --git a/@sammo/client/public/favicon.ico b/@sammo/client/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..df36fcfb72584e00488330b560ebcf34a41c64c2 GIT binary patch literal 4286 zcmds*O-Phc6o&64GDVCEQHxsW(p4>LW*W<827=Unuo8sGpRux(DN@jWP-e29Wl%wj zY84_aq9}^Am9-cWTD5GGEo#+5Fi2wX_P*bo+xO!)p*7B;iKlbFd(U~_d(U?#hLj56 zPhFkj-|A6~Qk#@g^#D^U0XT1cu=c-vu1+SElX9NR;kzAUV(q0|dl0|%h|dI$%VICy zJnu2^L*Te9JrJMGh%-P79CL0}dq92RGU6gI{v2~|)p}sG5x0U*z<8U;Ij*hB9z?ei z@g6Xq-pDoPl=MANPiR7%172VA%r)kevtV-_5H*QJKFmd;8yA$98zCxBZYXTNZ#QFk2(TX0;Y2dt&WitL#$96|gJY=3xX zpCoi|YNzgO3R`f@IiEeSmKrPSf#h#Qd<$%Ej^RIeeYfsxhPMOG`S`Pz8q``=511zm zAm)MX5AV^5xIWPyEu7u>qYs?pn$I4nL9J!=K=SGlKLXpE<5x+2cDTXq?brj?n6sp= zphe9;_JHf40^9~}9i08r{XM$7HB!`{Ys~TK0kx<}ZQng`UPvH*11|q7&l9?@FQz;8 zx!=3<4seY*%=OlbCbcae?5^V_}*K>Uo6ZWV8mTyE^B=DKy7-sdLYkR5Z?paTgK-zyIkKjIcpyO z{+uIt&YSa_$QnN_@t~L014dyK(fOOo+W*MIxbA6Ndgr=Y!f#Tokqv}n<7-9qfHkc3 z=>a|HWqcX8fzQCT=dqVbogRq!-S>H%yA{1w#2Pn;=e>JiEj7Hl;zdt-2f+j2%DeVD zsW0Ab)ZK@0cIW%W7z}H{&~yGhn~D;aiP4=;m-HCo`BEI+Kd6 z={Xwx{TKxD#iCLfl2vQGDitKtN>z|-AdCN|$jTFDg0m3O`WLD4_s#$S literal 0 HcmV?d00001 diff --git a/@sammo/client/src/App.vue b/@sammo/client/src/App.vue new file mode 100644 index 0000000..7905b05 --- /dev/null +++ b/@sammo/client/src/App.vue @@ -0,0 +1,85 @@ + + + + + diff --git a/@sammo/client/src/assets/base.css b/@sammo/client/src/assets/base.css new file mode 100644 index 0000000..8816868 --- /dev/null +++ b/@sammo/client/src/assets/base.css @@ -0,0 +1,86 @@ +/* color palette from */ +:root { + --vt-c-white: #ffffff; + --vt-c-white-soft: #f8f8f8; + --vt-c-white-mute: #f2f2f2; + + --vt-c-black: #181818; + --vt-c-black-soft: #222222; + --vt-c-black-mute: #282828; + + --vt-c-indigo: #2c3e50; + + --vt-c-divider-light-1: rgba(60, 60, 60, 0.29); + --vt-c-divider-light-2: rgba(60, 60, 60, 0.12); + --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65); + --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48); + + --vt-c-text-light-1: var(--vt-c-indigo); + --vt-c-text-light-2: rgba(60, 60, 60, 0.66); + --vt-c-text-dark-1: var(--vt-c-white); + --vt-c-text-dark-2: rgba(235, 235, 235, 0.64); +} + +/* semantic color variables for this project */ +:root { + --color-background: var(--vt-c-white); + --color-background-soft: var(--vt-c-white-soft); + --color-background-mute: var(--vt-c-white-mute); + + --color-border: var(--vt-c-divider-light-2); + --color-border-hover: var(--vt-c-divider-light-1); + + --color-heading: var(--vt-c-text-light-1); + --color-text: var(--vt-c-text-light-1); + + --section-gap: 160px; +} + +@media (prefers-color-scheme: dark) { + :root { + --color-background: var(--vt-c-black); + --color-background-soft: var(--vt-c-black-soft); + --color-background-mute: var(--vt-c-black-mute); + + --color-border: var(--vt-c-divider-dark-2); + --color-border-hover: var(--vt-c-divider-dark-1); + + --color-heading: var(--vt-c-text-dark-1); + --color-text: var(--vt-c-text-dark-2); + } +} + +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; + font-weight: normal; +} + +body { + min-height: 100vh; + color: var(--color-text); + background: var(--color-background); + transition: + color 0.5s, + background-color 0.5s; + line-height: 1.6; + font-family: + Inter, + -apple-system, + BlinkMacSystemFont, + 'Segoe UI', + Roboto, + Oxygen, + Ubuntu, + Cantarell, + 'Fira Sans', + 'Droid Sans', + 'Helvetica Neue', + sans-serif; + font-size: 15px; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} diff --git a/@sammo/client/src/assets/logo.svg b/@sammo/client/src/assets/logo.svg new file mode 100644 index 0000000..7565660 --- /dev/null +++ b/@sammo/client/src/assets/logo.svg @@ -0,0 +1 @@ + diff --git a/@sammo/client/src/assets/main.css b/@sammo/client/src/assets/main.css new file mode 100644 index 0000000..e8667cd --- /dev/null +++ b/@sammo/client/src/assets/main.css @@ -0,0 +1,35 @@ +@import './base.css'; + +#app { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + + font-weight: normal; +} + +a, +.green { + text-decoration: none; + color: hsla(160, 100%, 37%, 1); + transition: 0.4s; +} + +@media (hover: hover) { + a:hover { + background-color: hsla(160, 100%, 37%, 0.2); + } +} + +@media (min-width: 1024px) { + body { + display: flex; + place-items: center; + } + + #app { + display: grid; + grid-template-columns: 1fr 1fr; + padding: 0 2rem; + } +} diff --git a/@sammo/client/src/components/HelloWorld.vue b/@sammo/client/src/components/HelloWorld.vue new file mode 100644 index 0000000..38d821e --- /dev/null +++ b/@sammo/client/src/components/HelloWorld.vue @@ -0,0 +1,41 @@ + + + + + diff --git a/@sammo/client/src/components/TheWelcome.vue b/@sammo/client/src/components/TheWelcome.vue new file mode 100644 index 0000000..a70765c --- /dev/null +++ b/@sammo/client/src/components/TheWelcome.vue @@ -0,0 +1,86 @@ + + + diff --git a/@sammo/client/src/components/WelcomeItem.vue b/@sammo/client/src/components/WelcomeItem.vue new file mode 100644 index 0000000..6d7086a --- /dev/null +++ b/@sammo/client/src/components/WelcomeItem.vue @@ -0,0 +1,87 @@ + + + diff --git a/@sammo/client/src/components/icons/IconCommunity.vue b/@sammo/client/src/components/icons/IconCommunity.vue new file mode 100644 index 0000000..2dc8b05 --- /dev/null +++ b/@sammo/client/src/components/icons/IconCommunity.vue @@ -0,0 +1,7 @@ + diff --git a/@sammo/client/src/components/icons/IconDocumentation.vue b/@sammo/client/src/components/icons/IconDocumentation.vue new file mode 100644 index 0000000..6d4791c --- /dev/null +++ b/@sammo/client/src/components/icons/IconDocumentation.vue @@ -0,0 +1,7 @@ + diff --git a/@sammo/client/src/components/icons/IconEcosystem.vue b/@sammo/client/src/components/icons/IconEcosystem.vue new file mode 100644 index 0000000..c3a4f07 --- /dev/null +++ b/@sammo/client/src/components/icons/IconEcosystem.vue @@ -0,0 +1,7 @@ + diff --git a/@sammo/client/src/components/icons/IconSupport.vue b/@sammo/client/src/components/icons/IconSupport.vue new file mode 100644 index 0000000..7452834 --- /dev/null +++ b/@sammo/client/src/components/icons/IconSupport.vue @@ -0,0 +1,7 @@ + diff --git a/@sammo/client/src/components/icons/IconTooling.vue b/@sammo/client/src/components/icons/IconTooling.vue new file mode 100644 index 0000000..660598d --- /dev/null +++ b/@sammo/client/src/components/icons/IconTooling.vue @@ -0,0 +1,19 @@ + + diff --git a/@sammo/client/src/main.ts b/@sammo/client/src/main.ts new file mode 100644 index 0000000..24c9c4b --- /dev/null +++ b/@sammo/client/src/main.ts @@ -0,0 +1,14 @@ +import './assets/main.css' + +import { createApp } from 'vue' +import { createPinia } from 'pinia' + +import App from './App.vue' +import router from './router/index.js' + +const app = createApp(App) + +app.use(createPinia()) +app.use(router) + +app.mount('#app') diff --git a/@sammo/client/src/router/index.ts b/@sammo/client/src/router/index.ts new file mode 100644 index 0000000..a49ae50 --- /dev/null +++ b/@sammo/client/src/router/index.ts @@ -0,0 +1,23 @@ +import { createRouter, createWebHistory } from 'vue-router' +import HomeView from '../views/HomeView.vue' + +const router = createRouter({ + history: createWebHistory(import.meta.env.BASE_URL), + routes: [ + { + path: '/', + name: 'home', + component: HomeView + }, + { + path: '/about', + name: 'about', + // route level code-splitting + // this generates a separate chunk (About.[hash].js) for this route + // which is lazy-loaded when the route is visited. + component: () => import('../views/AboutView.vue') + } + ] +}) + +export default router diff --git a/@sammo/client/src/stores/counter.ts b/@sammo/client/src/stores/counter.ts new file mode 100644 index 0000000..b6757ba --- /dev/null +++ b/@sammo/client/src/stores/counter.ts @@ -0,0 +1,12 @@ +import { ref, computed } from 'vue' +import { defineStore } from 'pinia' + +export const useCounterStore = defineStore('counter', () => { + const count = ref(0) + const doubleCount = computed(() => count.value * 2) + function increment() { + count.value++ + } + + return { count, doubleCount, increment } +}) diff --git a/@sammo/client/src/views/AboutView.vue b/@sammo/client/src/views/AboutView.vue new file mode 100644 index 0000000..756ad2a --- /dev/null +++ b/@sammo/client/src/views/AboutView.vue @@ -0,0 +1,15 @@ + + + diff --git a/@sammo/client/src/views/HomeView.vue b/@sammo/client/src/views/HomeView.vue new file mode 100644 index 0000000..d5c0217 --- /dev/null +++ b/@sammo/client/src/views/HomeView.vue @@ -0,0 +1,9 @@ + + + diff --git a/@sammo/client/tsconfig.app.json b/@sammo/client/tsconfig.app.json new file mode 100644 index 0000000..3af40b0 --- /dev/null +++ b/@sammo/client/tsconfig.app.json @@ -0,0 +1,12 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], + "exclude": ["src/**/__tests__/*"], + "compilerOptions": { + "composite": true, + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + } + } \ No newline at end of file diff --git a/@sammo/client/tsconfig.json b/@sammo/client/tsconfig.json new file mode 100644 index 0000000..7087b3f --- /dev/null +++ b/@sammo/client/tsconfig.json @@ -0,0 +1,28 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist", + }, + "exclude": [ + + ], + "references": [ + { + + "path": "../util" + }, + { + "path": "../secure_token" + }, + { + "path": "../../@strpc/def" + }, + { + "path": "./tsconfig.node.json" + }, + { + "path": "./tsconfig.app.json" + }, + ] + } diff --git a/@sammo/client/tsconfig.node.json b/@sammo/client/tsconfig.node.json new file mode 100644 index 0000000..9ccb58a --- /dev/null +++ b/@sammo/client/tsconfig.node.json @@ -0,0 +1,18 @@ +{ + "extends": "@tsconfig/node20/tsconfig.json", + "include": [ + "vite.config.*", + "vitest.config.*", + "cypress.config.*", + "nightwatch.conf.*", + "playwright.config.*" + ], + "compilerOptions": { + "composite": true, + "module": "ESNext", + "moduleResolution": "Bundler", + "types": ["node"], + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + } +} diff --git a/@sammo/client/vite.config.ts b/@sammo/client/vite.config.ts new file mode 100644 index 0000000..e22c48f --- /dev/null +++ b/@sammo/client/vite.config.ts @@ -0,0 +1,17 @@ +import { fileURLToPath, URL } from 'node:url' + +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [ + vue(), + ], + resolve: { + alias: { + '@': fileURLToPath(new URL('./src', import.meta.url)), + '@util': fileURLToPath(new URL('./server/util', import.meta.url)), + } + } +}) diff --git a/@sammo/crypto/.eslintrc.cjs b/@sammo/crypto/.eslintrc.cjs new file mode 100644 index 0000000..5f11f1e --- /dev/null +++ b/@sammo/crypto/.eslintrc.cjs @@ -0,0 +1,12 @@ +module.exports = { + root: false, + extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'], + parser: '@typescript-eslint/parser', + plugins: ['@typescript-eslint'], + env: { + node: true, + }, + rules: { + '@typescript-eslint/no-unused-vars': 'off' + }, +} diff --git a/@sammo/crypto/jest.config.mjs b/@sammo/crypto/jest.config.mjs new file mode 100644 index 0000000..5e1b8a8 --- /dev/null +++ b/@sammo/crypto/jest.config.mjs @@ -0,0 +1,38 @@ +/** @type {import('ts-jest').JestConfigWithTsJest} */ +const jestConfig = { + preset: 'ts-jest/presets/default-esm', + extensionsToTreatAsEsm: ['.ts'], + testEnvironment: 'node', + rootDir: '.', + transform: { + '^.+\\.tsx?$': [ + 'ts-jest', + { + useESM: true, + tsconfig: 'tsconfig.jest.json', + }, + ], + }, + moduleFileExtensions: [ + 'js', + 'mjs', + 'ts', + 'mts', + 'tsx', + 'jsx', + ], + moduleNameMapper: { + '^(\\.{1,2}/.*)\\.js$': '$1', + "^lodash-es$": "lodash", + "^lodash-es/(.*)$": "/node_modules/lodash/$1", + }, + modulePathIgnorePatterns: [ + '/dist/', + ], + moduleDirectories: [ + "node_modules", + ".*/@sammo/util" + ], +}; + +export default jestConfig \ No newline at end of file diff --git a/@sammo/crypto/package.json b/@sammo/crypto/package.json new file mode 100644 index 0000000..69bda7b --- /dev/null +++ b/@sammo/crypto/package.json @@ -0,0 +1,48 @@ +{ + "name": "@sammo/crypto", + "version": "1.0.1", + "description": "", + "main": "dist/index.js", + "exports": { + ".": "./dist/index.js", + "./AES": "./dist/AES.js", + "./ECDSA": "./dist/ECDSA.js", + "./ECDHe": "./dist/ECDHe.js", + "./ECDHe_AES": "./dist/ECDHe_AES.js", + "./ECKey": "./dist/ECKey.js", + "./PBKDF2": "./dist/PBKDF2.js", + "./SHA2": "./dist/SHA2.js", + "./RawTypes": "./dist/RawTypes.js" + }, + "scripts": { + "build": "tsc --build", + "test": "jest" + }, + "author": "", + "type": "module", + "license": "MIT", + "dependencies": { + "@sammo/util": "workspace:^" + }, + "devDependencies": { + "@types/jest": "^29.5.4", + "@types/lodash": "^4.14.198", + "@types/lodash-es": "^4.17.9", + "@types/node": "^20.6.0", + "@typescript-eslint/eslint-plugin": "^6.7.0", + "@typescript-eslint/parser": "^6.7.0", + "bson": "^5.4.0", + "buffer": "^6.0.3", + "eslint": "^8.49.0", + "jest": "^29.7.0", + "lodash-es": "^4.17.21", + "ts-jest": "^29.1.1", + "tslib": "^2.6.2", + "typescript": "^5.2.2" + }, + "peerDependencies": { + "bson": "^5.4.0", + "buffer": "^6.0.3", + "lodash-es": "^4.17.21" + } +} diff --git a/@sammo/crypto/src/AES.test.ts b/@sammo/crypto/src/AES.test.ts new file mode 100644 index 0000000..741b6e8 --- /dev/null +++ b/@sammo/crypto/src/AES.test.ts @@ -0,0 +1,92 @@ +import { AES_GCM_Decrypt, AES_GCM_Encrypt } from "./AES.js"; + +type TestType = { + key: Buffer, + IV: Buffer, + PT: Buffer, + AAD?: Buffer, + CT: Buffer, + failed?: boolean, +}; + +type RawTestType = { + key: string, + IV: string, + PT: string, + AAD?: string, + CT: string, + failed?: boolean, +} + +function convertItem(obj: RawTestType): TestType { + return { + key: Buffer.from(obj.key, 'hex'), + IV: Buffer.from(obj.IV, 'hex'), + PT: Buffer.from(obj.PT, 'hex'), + AAD: obj.AAD ? Buffer.from(obj.AAD, 'hex') : undefined, + CT: Buffer.from(obj.CT, 'hex'), + failed: obj.failed, + } +} + +const tests: TestType[] = [ + { + key: '92e11dcdaa866f5ce790fd24501f92509aacf4cb8b1339d50c9c1240935dd08b', + IV : 'ac93a1a6145299bde902f21a', + PT : '2d71bcfa914e4ac045b2aa60955fad24', + AAD: '1e0889016f67601c8ebea4943bc23ad6', + CT : '8995ae2e6df3dbf96fac7b7137bae67feca5aa77d51d4a0a14d9c51e1da474ab', + failed: false, + }, + { + key: 'b52c505a37d78eda5dd34f20c22540ea1b58963cf8e5bf8ffa85f9f2492505b4', + IV : '516c33929df5a3284ff463d7', + PT : '', + AAD: '', + CT : 'bdc1ac884d332457a1d2664f168c76f0', + failed: false, + }, + { + key: '886cff5f3e6b8d0e1ad0a38fcdb26de97e8acbe79f6bed66959a598fa5047d65', + IV : '3a8efa1cd74bbab5448f9945', + PT : '', + AAD: '519fee519d25c7a304d6c6aa1897ee1eb8c59655', + CT : 'f6d47505ec96c98a42dc3ae719877b87', + failed: false, + }, + { + key: '460fc864972261c2560e1eb88761ff1c992b982497bd2ac36c04071cbb8e5d99', + IV : '8a4a16b9e210eb68bcb6f58d', + PT : '99e4e926ffe927f691893fb79a96b067', + AAD: '', + CT : '133fc15751621b5f325c7ff71ce08324ec4e87e0cf74a13618d0b68636ba9fa7', + failed: false, + }, +].map(convertItem) + + + + +test.each(tests)('encrypt(%#)', async (item) => { + for (const item of tests) { + + if(item.failed){ + expect(() => AES_GCM_Encrypt(item.key, item.IV, item.PT, item.AAD)).rejects.toThrow('Invalid'); + return; + } + const ct = await AES_GCM_Encrypt(item.key, item.IV, item.PT, item.AAD); + expect(ct).toEqual(item.CT.buffer); + } +}) + +test.each(tests)('decrypt(%#)', async (item) => { + for (const item of tests) { + + if(item.failed){ + expect(() => AES_GCM_Decrypt(item.key, item.IV, item.CT, item.AAD)).rejects.toThrow('Invalid'); + return; + } + const pt = await AES_GCM_Decrypt(item.key, item.IV, item.CT, item.AAD); + expect(pt).toEqual(item.PT.buffer); + } +}) \ No newline at end of file diff --git a/@sammo/crypto/src/AES.ts b/@sammo/crypto/src/AES.ts new file mode 100644 index 0000000..617713b --- /dev/null +++ b/@sammo/crypto/src/AES.ts @@ -0,0 +1,61 @@ +import type { BufferSource } from "@sammo/util"; + +const subtle = globalThis.crypto.subtle; + + +export async function AES_GCM_Encrypt(key: BufferSource | CryptoKey, iv: BufferSource, msg: BufferSource, aad?: BufferSource): Promise { + const keyObj = key instanceof CryptoKey ? key : await subtle.importKey("raw", key, { + name: "AES-GCM", + }, false, ["encrypt"]); + + const ciphertext = await subtle.encrypt({ + name: "AES-GCM", + iv, + additionalData: aad + }, keyObj, msg); + + return ciphertext; +} + + +export async function AES_GCM_Decrypt(key: BufferSource | CryptoKey, iv: BufferSource, ciphertext: BufferSource, aad?: BufferSource): Promise { + const keyObj = key instanceof CryptoKey ? key : await subtle.importKey("raw", key, { + name: "AES-GCM", + }, false, ["decrypt"]); + + const plaintext = await subtle.decrypt({ + name: "AES-GCM", + iv: iv, + additionalData: aad + }, keyObj, ciphertext); + //아마도 tag 검증 실패시 예외가 발생할 것으로 예상 + + return plaintext; +} + +export async function AES_CBC_Encrypt(key: BufferSource | CryptoKey, iv: BufferSource, msg: BufferSource): Promise { + const keyObj = key instanceof CryptoKey ? key : await subtle.importKey("raw", key, { + name: "AES-CBC", + }, false, ["encrypt"]); + + const ciphertext = await subtle.encrypt({ + name: "AES-CBC", + iv, + }, keyObj, msg); + + return ciphertext; +} + + +export async function AES_CBC_Decrypt(key: BufferSource | CryptoKey, iv: BufferSource, ciphertext: BufferSource): Promise { + const keyObj = key instanceof CryptoKey ? key : await subtle.importKey("raw", key, { + name: "AES-CBC", + }, false, ["decrypt"]); + + const plaintext = await subtle.decrypt({ + name: "AES-CBC", + iv: iv, + }, keyObj, ciphertext); + + return plaintext; +} \ No newline at end of file diff --git a/@sammo/crypto/src/ECDHe.ts b/@sammo/crypto/src/ECDHe.ts new file mode 100644 index 0000000..73e43a0 --- /dev/null +++ b/@sammo/crypto/src/ECDHe.ts @@ -0,0 +1,63 @@ +import { wrapBuffer } from "@sammo/util"; +import { ECDSA_sign, ECDSA_verify } from "./ECDSA.js"; +import { verifyKeyFromSignKey } from "./ECKey.js"; +import type { ECDHe_P384_PublicKey, ECDHe_P384_KeyPair, ECDSA_PKCS8_P384_SignKey, ECDHe_P384_PrivateKey, ECDHe_P384_PublicKeyInfo, ECDHe_P384_LiteKeyPair } from "./RawTypes.js"; + +const subtle = globalThis.crypto.subtle; + +export const curveName: EcKeyGenParams | EcKeyImportParams = { + name: 'ECDH', + namedCurve: 'P-384' +} + +export async function genECDHeKey(signKey: ECDSA_PKCS8_P384_SignKey): Promise { + const keyPairP = subtle.generateKey(curveName, true, ['deriveKey', 'deriveBits']); + const verifyKeyP = verifyKeyFromSignKey(signKey); + + const rawKeyPair = await keyPairP; + const publicKey = wrapBuffer(await subtle.exportKey('spki', rawKeyPair.publicKey)); + const privateKey = wrapBuffer(await subtle.exportKey('pkcs8', rawKeyPair.privateKey)); + + const signatureP = ECDSA_sign(signKey, privateKey); + + return { + publicInfo: { + publicKey, + verifyKey: await verifyKeyP, + sign: await signatureP + }, + privateKey, + } +} + +export async function genECDHeLiteKey(): Promise { + const keyPair = await subtle.generateKey(curveName, true, ['deriveKey', 'deriveBits']); + const publicKey = wrapBuffer(await subtle.exportKey('spki', keyPair.publicKey)); + const privateKey = wrapBuffer(await subtle.exportKey('pkcs8', keyPair.privateKey)); + + return { + publicKey, + privateKey + }; +} + +export async function deriveKey(other: ECDHe_P384_PublicKeyInfo, me: ECDHe_P384_LiteKeyPair | ECDHe_P384_KeyPair, keySizeBit?: number): Promise; +export async function deriveKey(other: ECDHe_P384_PublicKeyInfo | ECDHe_P384_PublicKey, me: ECDHe_P384_KeyPair, keySizeBit?: number): Promise; + +export async function deriveKey(other: ECDHe_P384_PublicKeyInfo | ECDHe_P384_PublicKey, me: ECDHe_P384_KeyPair | ECDHe_P384_LiteKeyPair, keySizeBit = 256): Promise { + + const rawPublicKey = other instanceof Uint8Array ? other : other.publicKey; + const rawPrivateKey = me.privateKey; + const publicKeyP = subtle.importKey('spki', rawPublicKey, curveName, true, ['deriveBits']); + const privateKeyP = subtle.importKey('pkcs8', rawPrivateKey, curveName, true, ['deriveBits']); + + if (!(other instanceof Uint8Array) && !(await ECDSA_verify(other.verifyKey, other.publicKey, other.sign))) { + throw new Error("Invalid signature"); + } + + return await subtle.deriveBits({ + name: 'ECDH', + public: await publicKeyP + + }, await privateKeyP, keySizeBit); +} \ No newline at end of file diff --git a/@sammo/crypto/src/ECDHe_AES.ts b/@sammo/crypto/src/ECDHe_AES.ts new file mode 100644 index 0000000..7111bcc --- /dev/null +++ b/@sammo/crypto/src/ECDHe_AES.ts @@ -0,0 +1,48 @@ +import { AES_GCM_Decrypt, AES_GCM_Encrypt } from "./AES.js"; +import { deriveKey } from "./ECDHe.js"; +import type { ECDHe_P384_KeyPair, ECDHe_P384_LiteKeyPair, ECDHe_P384_PublicKey, ECDHe_P384_PublicKeyInfo } from "./RawTypes.js"; + +export type EncryptedItem = { + ct: Uint8Array; +} + +const keySizeBit = 256; + +export async function ECDHe_AES_GCM_Encrypt(other: ECDHe_P384_PublicKeyInfo, me: ECDHe_P384_LiteKeyPair | ECDHe_P384_KeyPair, iv: BufferSource, msg: BufferSource, aad?: BufferSource): Promise; +export async function ECDHe_AES_GCM_Encrypt(other: ECDHe_P384_PublicKey, me: ECDHe_P384_KeyPair, iv: BufferSource, msg: BufferSource, aad?: BufferSource): Promise; +export async function ECDHe_AES_GCM_Encrypt(other: ECDHe_P384_PublicKeyInfo, me: ECDHe_P384_LiteKeyPair, iv: BufferSource, msg: BufferSource, aad?: BufferSource): Promise; + +export async function ECDHe_AES_GCM_Encrypt(other: ECDHe_P384_PublicKeyInfo | ECDHe_P384_PublicKey, me: ECDHe_P384_KeyPair | ECDHe_P384_LiteKeyPair, iv: BufferSource, msg: BufferSource, aad?: BufferSource): Promise{ + let key: ArrayBuffer; + if('publicInfo' in me){ + key = await deriveKey(other, me, keySizeBit); + } + else if('publicKey' in other){ + key = await deriveKey(other, me, keySizeBit); + } + else{ + throw new Error("Invalid argument: may be trying to do ECDH, not ECDHe."); + } + + return AES_GCM_Encrypt(key, iv, msg, aad); +} + +export async function ECDHe_AES_GCM_Decrypt(other: ECDHe_P384_PublicKeyInfo, me: ECDHe_P384_LiteKeyPair | ECDHe_P384_KeyPair, iv: BufferSource, ciphertext: BufferSource, aad?: BufferSource): Promise; +export async function ECDHe_AES_GCM_Decrypt(other: ECDHe_P384_PublicKey, me: ECDHe_P384_KeyPair, iv: BufferSource, ciphertext: BufferSource, aad?: BufferSource): Promise; +export async function ECDHe_AES_GCM_Decrypt(other: ECDHe_P384_PublicKeyInfo, me: ECDHe_P384_LiteKeyPair, iv: BufferSource, ciphertext: BufferSource, aad?: BufferSource): Promise; + + +export async function ECDHe_AES_GCM_Decrypt(other: ECDHe_P384_PublicKeyInfo | ECDHe_P384_PublicKey, me: ECDHe_P384_KeyPair | ECDHe_P384_LiteKeyPair, iv: BufferSource, ciphertext: BufferSource, aad?: BufferSource): Promise{ + let key: ArrayBuffer; + if('publicInfo' in me){ + key = await deriveKey(other, me, keySizeBit); + } + else if('publicKey' in other){ + key = await deriveKey(other, me, keySizeBit); + } + else{ + throw new Error("Invalid argument: may be trying to do ECDH, not ECDHe."); + } + + return AES_GCM_Decrypt(key, iv, ciphertext, aad); +} \ No newline at end of file diff --git a/@sammo/crypto/src/ECDSA.test.ts b/@sammo/crypto/src/ECDSA.test.ts new file mode 100644 index 0000000..e86eaad --- /dev/null +++ b/@sammo/crypto/src/ECDSA.test.ts @@ -0,0 +1,32 @@ +import { ECDSA_sign_bson, ECDSA_verify_bson } from "./ECDSA.js"; +import { genKey } from "./ECKey.js"; +import { randomBytes } from "./utils.js"; +test('basic sign', async () => { + const [signKey, verifyKey] = await genKey(); + + const misVerifyKey = Buffer.alloc(verifyKey.length); + verifyKey.copy(misVerifyKey); + misVerifyKey[misVerifyKey.length - 2] ^= 1; //1bit + + const msg = randomBytes(100); + const misMsg = Buffer.alloc(msg.length); + msg.copy(misMsg); + misMsg[1] ^= 1; + + const signature = await ECDSA_sign_bson(signKey, msg); + expect(signature.length).toEqual(96); + + const misSignature = Buffer.alloc(signature.length); + signature.copy(misSignature); + misSignature[misSignature.length - 2] ^= 3; + + const t0P = ECDSA_verify_bson(verifyKey, msg, signature); + const f1P = ECDSA_verify_bson(misVerifyKey, msg, signature); + const f2P = ECDSA_verify_bson(verifyKey, misMsg, signature); + const f3P = ECDSA_verify_bson(verifyKey, msg, misSignature); + + expect(await t0P).toEqual(true); + expect(await f1P).toEqual(false); + expect(await f2P).toEqual(false); + expect(await f3P).toEqual(false); +}) diff --git a/@sammo/crypto/src/ECDSA.ts b/@sammo/crypto/src/ECDSA.ts new file mode 100644 index 0000000..8d24dea --- /dev/null +++ b/@sammo/crypto/src/ECDSA.ts @@ -0,0 +1,81 @@ +import { BSON } from "bson"; +import { type Bsonifiable, bsonify, type Jsonifiable, jsonify } from "@sammo/util"; +import { importSignKey, importVerifyKey } from "./ECKey.js"; +import type { ECDSASignature, ECDSA_PKCS8_P384_SignKey, ECDSA_P384_VerifyKey, ECDSASignatureBSON, ECDSASignatureJSON, ECDSASignatureRaw } from "./RawTypes.js"; +import { isBufferSource } from './types.js'; +import { isArray, isDate, isObject } from "lodash-es"; + +// 간편하게 저장하기 위해서 그냥! 매번 복잡한 일을 하도록 하자 +const subtle = globalThis.crypto.subtle; + +const hashName: EcdsaParams = { + name: 'ECDSA', + hash: 'SHA-512' +} + +export async function ECDSA_sign(sign_key: ECDSA_PKCS8_P384_SignKey, msg: BufferSource): Promise { + const subtleSignKeyP = importSignKey(sign_key); + return Buffer.from(await subtle.sign(hashName, await subtleSignKeyP, msg)); +} + + +export async function ECDSA_sign_bson(sign_key: ECDSA_PKCS8_P384_SignKey, msg: Bsonifiable): Promise +export async function ECDSA_sign_bson(sign_key: ECDSA_PKCS8_P384_SignKey, msg: BufferSource): Promise +export async function ECDSA_sign_bson(sign_key: ECDSA_PKCS8_P384_SignKey, msg: Bsonifiable | BufferSource): Promise { + if (!isBufferSource(msg)) { + msg = BSON.serialize(bsonify(msg as Record)); + return await ECDSA_sign(sign_key, msg) as ECDSASignatureBSON; + } + return ECDSA_sign(sign_key, msg); +} + +export async function ECDSA_sign_json(sign_key: ECDSA_PKCS8_P384_SignKey, msg: Bsonifiable): Promise +export async function ECDSA_sign_json(sign_key: ECDSA_PKCS8_P384_SignKey, msg: BufferSource): Promise +export async function ECDSA_sign_json(sign_key: ECDSA_PKCS8_P384_SignKey, msg: Jsonifiable | BufferSource): Promise { + if (!isBufferSource(msg)) { + msg = Buffer.from(JSON.stringify(jsonify(msg as Record)), 'utf-8'); + return await ECDSA_sign(sign_key, msg) as ECDSASignatureJSON; + } + return ECDSA_sign(sign_key, msg); +} + +export async function ECDSA_verify(verify_key: ECDSA_P384_VerifyKey, msg: BufferSource, sign: ECDSASignature): Promise { + try { + const subtleVerifyKeyP = importVerifyKey(verify_key); + return await subtle.verify(hashName, await subtleVerifyKeyP, sign, msg); + } + catch (e) { + return false; + } +} + +export async function ECDSA_verify_bson(verify_key: ECDSA_P384_VerifyKey, msg: Bsonifiable, sign: ECDSASignatureBSON): Promise; +export async function ECDSA_verify_bson(verify_key: ECDSA_P384_VerifyKey, msg: BufferSource, sign: ECDSASignatureRaw): Promise; +export async function ECDSA_verify_bson(verify_key: ECDSA_P384_VerifyKey, msg: Bsonifiable | BufferSource, sign: ECDSASignatureBSON | ECDSASignatureRaw): Promise { + + try { + if (!isBufferSource(msg)) { + msg = BSON.serialize(bsonify(msg as Record)); + } + return ECDSA_verify(verify_key, msg, sign); + } + catch (e) { + return false; + } +} + +export async function ECDSA_verify_json(verify_key: ECDSA_P384_VerifyKey, msg: Bsonifiable, sign: ECDSASignatureJSON): Promise; +export async function ECDSA_verify_json(verify_key: ECDSA_P384_VerifyKey, msg: BufferSource, sign: ECDSASignatureRaw): Promise; +export async function ECDSA_verify_json(verify_key: ECDSA_P384_VerifyKey, msg: Jsonifiable | BufferSource, sign: ECDSASignatureJSON | ECDSASignatureRaw): Promise { + + try { + if (!isBufferSource(msg)) { + const x = JSON.stringify(jsonify(msg as Record)); + msg = Buffer.from(x, 'utf-8'); + } + return ECDSA_verify(verify_key, msg, sign); + } + catch (e) { + return false; + } +} diff --git a/@sammo/crypto/src/ECKey.test.ts b/@sammo/crypto/src/ECKey.test.ts new file mode 100644 index 0000000..00baf63 --- /dev/null +++ b/@sammo/crypto/src/ECKey.test.ts @@ -0,0 +1,35 @@ +import { genKey, verifyKeyFromSignKey, pemFromVerifyKey, importVerifyKey, importSignKey, pemFromSignKey } from "./ECKey.js"; +import { TypeLength } from "./TypeLength.js"; +import { decodePEM } from "./utils.js"; + +test('gen_key', async () => { + const [signKey, verifyKey] = await genKey(); + + expect(signKey.length).toEqual(TypeLength.ECDSA_PKCS8_P384_SignKey); + expect(verifyKey.length).toEqual(TypeLength.ECDSA_SPKI_P384_VerifyKey); + + const pemVerifyKey = await pemFromVerifyKey(verifyKey); + const verifyKey2 = decodePEM(pemVerifyKey, 'PUBLIC KEY')[0]; + expect(verifyKey).toEqual(verifyKey2); + +}); + +test('convert', async () => { + const [signKey, verifyKey] = await genKey(); + + const newVerifyKey = await verifyKeyFromSignKey(signKey); + + expect(verifyKey).toEqual(newVerifyKey); +}) + +test('import sign_key', async() => { + const [signKey, verifyKey] = await genKey(); + + const pemSignKey = pemFromSignKey(signKey); + const signKey2 = decodePEM(pemSignKey, 'EC PRIVATE KEY')[0]; + + const signKeyObj = await importSignKey(signKey, true); + const signKeyObj2 = await importSignKey(signKey2, true); + + expect(signKeyObj).toEqual(signKeyObj2); +}) \ No newline at end of file diff --git a/@sammo/crypto/src/ECKey.ts b/@sammo/crypto/src/ECKey.ts new file mode 100644 index 0000000..be1b854 --- /dev/null +++ b/@sammo/crypto/src/ECKey.ts @@ -0,0 +1,62 @@ + +import type { ECDSA_PKCS8_P384_SignKey, ECDSA_P384_VerifyKey } from "./RawTypes.js"; +import { encodePEM } from "./utils.js"; + +// 간편하게 저장하기 위해서 그냥! 매번 복잡한 일을 하도록 하자 + +const subtle = globalThis.crypto.subtle; + +export const curveName: EcKeyGenParams | EcKeyImportParams = { + name: 'ECDSA', + namedCurve: 'P-384' +} + +export async function importSignKey(signKey: ECDSA_PKCS8_P384_SignKey, allowExport?: boolean): Promise { + return await subtle.importKey('pkcs8', signKey, curveName, allowExport ?? false, ['sign']); +} + +export async function importVerifyKeyRaw(verifyKey: ECDSA_P384_VerifyKey, allowExport?: boolean): Promise { + return await subtle.importKey('raw', verifyKey, curveName, allowExport ?? false, ['verify']) +} + +export async function exportVerifyKeyRaw(verifyKey: ECDSA_P384_VerifyKey): Promise{ + const key = await importVerifyKeyRaw(verifyKey); + return Buffer.from(await subtle.exportKey('raw', key)); +} + +export async function importVerifyKey(verifyKey: ECDSA_P384_VerifyKey, allowExport?: boolean): Promise { + return await subtle.importKey('spki', verifyKey, curveName, allowExport ?? false, ['verify']) +} + + +export async function genKey(): Promise<[ECDSA_PKCS8_P384_SignKey, ECDSA_P384_VerifyKey]> { + const keyPair = await subtle.generateKey(curveName, true, ['sign', 'verify']); + const signKey = subtle.exportKey('pkcs8', keyPair.privateKey); + const verifyKey = subtle.exportKey('spki', keyPair.publicKey); + return [Buffer.from(await signKey), Buffer.from(await verifyKey)]; +} + +export async function pemFromVerifyKey(verifyKey: ECDSA_P384_VerifyKey): Promise { + const subtleVerifyKey = await importVerifyKey(verifyKey, true); + const spkiRaw = await subtle.exportKey('spki', subtleVerifyKey) + return encodePEM(Buffer.from(spkiRaw), 'PUBLIC KEY'); +} + +export function pemFromSignKey(signKey: ECDSA_PKCS8_P384_SignKey): string { + return encodePEM(signKey, 'EC PRIVATE KEY'); +} + +export async function verifyKeyFromSignKey(signKey: ECDSA_PKCS8_P384_SignKey): Promise { + const subtleSignKey = await importSignKey(signKey, true); + const jwk = await subtle.exportKey('jwk', subtleSignKey); + delete jwk.d; + delete jwk.dp; + delete jwk.dq; + delete jwk.q; + delete jwk.qi; + jwk.key_ops = ["verify"]; + + const subtleVerifyKey = await subtle.importKey('jwk', jwk, curveName, true, ['verify']); + const verifyKey = await subtle.exportKey('spki', subtleVerifyKey); + return Buffer.from(verifyKey); +} \ No newline at end of file diff --git a/@sammo/crypto/src/LiteHashDRBG.ts b/@sammo/crypto/src/LiteHashDRBG.ts new file mode 100644 index 0000000..1b7341c --- /dev/null +++ b/@sammo/crypto/src/LiteHashDRBG.ts @@ -0,0 +1,262 @@ +import type { RNG } from "./RNG.js"; +import { sha512 } from './SHA2.js'; +import { convertBytesLikeToUint8Array } from "@sammo/util/converter"; +import type { BytesLike } from "@sammo/util"; +import { delay } from "@sammo/util"; + +const maxRngSupportBit = 53; +const maxInt = 0x1f_ffff_ffff_ffff; // NOTE: b 0, 10000110011, 11...11 +const maxIntMore1 = 0x20_0000_0000_0000n; //NOTE: b 0, 10000110100, 00...00 +const maxIntMore1f = Number(maxIntMore1); +export const bufferByteSize = 512 / 8; //SHA512 + +const intBitMapMask = new Map([ + [0x1n, 1], + [0x3n, 2], + [0x7n, 3], + [0xfn, 4], + [0x1fn, 5], + [0x3fn, 6], + [0x7fn, 7], + [0xffn, 8], + [0x1ffn, 9], + [0x3ffn, 10], + [0x7ffn, 11], + [0xfffn, 12], + [0x1fffn, 13], + [0x3fffn, 14], + [0x7fffn, 15], + [0xffffn, 16], + [0x1ffffn, 17], + [0x3ffffn, 18], + [0x7ffffn, 19], + [0xfffffn, 20], + [0x1fffffn, 21], + [0x3fffffn, 22], + [0x7fffffn, 23], + [0xffffffn, 24], + [0x1ffffffn, 25], + [0x3ffffffn, 26], + [0x7ffffffn, 27], + [0xfffffffn, 28], + [0x1fffffffn, 29], + [0x3fffffffn, 30], + [0x7fffffffn, 31], + [0xffffffffn, 32], + [0x1ffffffffn, 33], + [0x3ffffffffn, 34], + [0x7ffffffffn, 35], + [0xfffffffffn, 36], + [0x1fffffffffn, 37], + [0x3fffffffffn, 38], + [0x7fffffffffn, 39], + [0xffffffffffn, 40], + [0x1ffffffffffn, 41], + [0x3ffffffffffn, 42], + [0x7ffffffffffn, 43], + [0xfffffffffffn, 44], + [0x1fffffffffffn, 45], + [0x3fffffffffffn, 46], + [0x7fffffffffffn, 47], + [0xffffffffffffn, 48], + [0x1ffffffffffffn, 49], + [0x3ffffffffffffn, 50], + [0x7ffffffffffffn, 51], + [0xfffffffffffffn, 52], + [0x1fffffffffffffn, 53], +]); + +function calcBitMask(n: bigint): bigint { + n |= n >> 1n; + n |= n >> 2n; + n |= n >> 4n; + n |= n >> 8n; + n |= n >> 16n; + n |= n >> 32n; + + return n; +} +export class LiteHashDRBG implements RNG { + + protected buffer!: ArrayBuffer; + protected bufferIdx!: number; + protected hq: DataView; + protected hqIdxPos: number; + + protected ready: Promise; + + public constructor(protected seed: BytesLike, protected stateIdx = 0, bufferIdx = 0) { + if (bufferIdx < 0) { + throw new Error(`bufferIdx ${bufferIdx} < 0`); + } + if (bufferIdx >= bufferByteSize) { + throw new Error(`bufferidx ${bufferIdx} >= ${bufferByteSize}`); + } + if (stateIdx < 0) { + throw new Error(`stateIdx ${stateIdx} < 0`); + } + + const seedU8 = convertBytesLikeToUint8Array(seed); + const hqBuffer = new ArrayBuffer(seedU8.byteLength + 4); + const hqU8 = new Uint8Array(hqBuffer); + + hqU8.set(seedU8, 0); + this.hq = new DataView(hqBuffer); + this.hqIdxPos = seedU8.byteLength; + + this.ready = this.genNextBlock(); + this.bufferIdx = bufferIdx; + } + + protected async genNextBlock(): Promise { + this.bufferIdx = 0; + this.hq.setUint32(this.hqIdxPos, this.stateIdx, true); + this.stateIdx += 1; + const digest = await sha512(this.hq.buffer); + this.buffer = digest; + } + + public getMaxInt(): number { + return maxInt; + } + + public async nextBytes(bytes: number, baseBytes?: number): Promise { + bytes |= 0; + if (bytes <= 0) { + throw new Error(`${bytes} <= 0`); + } + + const ticket = this.ready; + + let waiter: Promise = Promise.resolve(undefined); + + let nextBlockWait: (() => void) | null = (() => { throw 'something wrong'; }); + + this.ready = new Promise((resolve, reject) => { + waiter = (async () => { + await ticket; + nextBlockWait = resolve; + + if (this.bufferIdx + bytes <= bufferByteSize) { + if (baseBytes === undefined || bytes >= baseBytes) { + const result = this.buffer.slice(this.bufferIdx, this.bufferIdx + bytes); + this.bufferIdx += bytes; + if (this.bufferIdx === bufferByteSize) { + nextBlockWait = null; + this.genNextBlock().then(resolve, reject); + } + return new Uint8Array(result); + } + + const resultBuffer = new ArrayBuffer(Math.max(bytes, baseBytes ?? 0)); + const result = new Uint8Array(resultBuffer); + result.set(new Uint8Array(this.buffer, this.bufferIdx, bytes)); + this.bufferIdx += bytes; + if (this.bufferIdx === bufferByteSize) { + nextBlockWait = null; + this.genNextBlock().then(resolve, reject); + } + return result; + } + + const resultBuffer = new ArrayBuffer(baseBytes ? Math.max(bytes, baseBytes) : bytes); + const result = new Uint8Array(resultBuffer); + + result.set(new Uint8Array(this.buffer, this.bufferIdx)); + let offset = bufferByteSize - this.bufferIdx; + let remain = bytes - offset; + + while (remain > bufferByteSize) { + await this.genNextBlock(); + result.set(new Uint8Array(this.buffer), offset); + offset += bufferByteSize; + remain -= bufferByteSize; + } + + if (remain === 0) { + nextBlockWait = null; + this.genNextBlock().then(resolve, reject); + return result; + } + + await this.genNextBlock(); + result.set(new Uint8Array(this.buffer, 0, remain), offset); + this.bufferIdx = remain; + return result; + })(); + + }); + + //이 코드를 통해 Promise 내부가 실행된다 + await delay(0); + + const nextBlock = await waiter; + if (nextBlockWait) { + nextBlockWait(); + } + return nextBlock as Uint8Array; + } + + public async nextBits(bits: number, baseBytes?: number): Promise { + await this.ready; + + bits |= 0; + const bytes = (bits + 7) >> 3; + const headBits = bits & 0x7; + + const result = await this.nextBytes(bytes, baseBytes); + if (headBits === 0) { + return result; + } + + result[bytes - 1] &= 0xff >> (8 - headBits); + return result; + } + + protected async _nextInt(bits: number): Promise { + const buffer = await this.nextBits(bits, 8); + const dataView = new DataView(buffer.buffer); + return dataView.getBigUint64(0, true); + } + + public async nextInt(max?: number): Promise { + if (max === undefined || max === maxInt) { + return Number(await this._nextInt(maxRngSupportBit)); + } + if (max > maxInt) { + throw new Error('Over max int'); + } + if (max === 0) { + return 0; + } + if (max < 0) { + return -this.nextInt(-max); + } + + const mask = calcBitMask(BigInt(max)); + const bits = intBitMapMask.get(mask) as number; + + let n = Number(this._nextInt(bits)); + while (n > max) { + n = Number(this._nextInt(bits)); + } + return n; + } + + public async nextFloat1(): Promise { + // eslint-disable-next-line no-constant-condition + while (true) { + const nInt = await this._nextInt(maxRngSupportBit + 1); + if (nInt < maxIntMore1) { + return Number(nInt) / maxIntMore1f; + } + if (nInt === maxIntMore1) { + return 1; + } + } + } + + public static build(seed: BytesLike, stateIdx = 0): LiteHashDRBG { + return new LiteHashDRBG(seed, stateIdx); + } +} \ No newline at end of file diff --git a/@sammo/crypto/src/PBKDF2.ts b/@sammo/crypto/src/PBKDF2.ts new file mode 100644 index 0000000..5ebd091 --- /dev/null +++ b/@sammo/crypto/src/PBKDF2.ts @@ -0,0 +1,48 @@ +const subtle = globalThis.crypto.subtle; + +export type ValidEncAlg = 'AES256-GCM' | 'AES128-GCM' | 'AES256-CBC' | 'AES128-CBC'; + +const encAlgMap: Record = { + 'AES256-GCM': { + name: 'AES-GCM', + length: 256, + }, + 'AES128-GCM' : { + name: 'AES-GCM', + length: 128, + }, + 'AES256-CBC' : { + name: 'AES-CBC', + length: 256, + }, + 'AES128-CBC' : { + name: 'AES-CBC', + length: 128, + }, +} + +export async function PBKDF2_SHA512(password: string, salt: BufferSource, alg: ValidEncAlg = 'AES256-GCM', iterations = 600000): Promise { + const param: Pbkdf2Params = { + name: 'PBKDF2', + hash: 'SHA-512', + salt: salt, + iterations, + }; + + const encoder = new TextEncoder(); + const baseKey = await subtle.importKey( + "raw", + encoder.encode(password), + { name: "PBKDF2" }, + false, + ["deriveBits", "deriveKey"] + ); + + return await subtle.deriveKey( + param, + baseKey, + encAlgMap[alg], + true, + ["encrypt", "decrypt"] + ); +} \ No newline at end of file diff --git a/@sammo/crypto/src/RNG.ts b/@sammo/crypto/src/RNG.ts new file mode 100644 index 0000000..63bc789 --- /dev/null +++ b/@sammo/crypto/src/RNG.ts @@ -0,0 +1,13 @@ +export interface RNG { + + /** + * nextInt()가 반환 가능한 최댓값 + */ + getMaxInt(): number; + + nextBytes(bytes: number): Promise; + nextBits(bits: number): Promise; + + nextInt(max?: number): Promise; + nextFloat1(): Promise; +} \ No newline at end of file diff --git a/@sammo/crypto/src/RandUtil.ts b/@sammo/crypto/src/RandUtil.ts new file mode 100644 index 0000000..56a8af7 --- /dev/null +++ b/@sammo/crypto/src/RandUtil.ts @@ -0,0 +1,144 @@ +import type { RNG } from './RNG.js'; + +export class RandUtil { + constructor(protected rng: RNG) { + + } + + public nextFloat1(): Promise { + return this.rng.nextFloat1(); + } + + public async nextRange(min: number, max: number): Promise { + const range = max - min; + return await this.nextFloat1() * (range) + min; + } + + public async nextRangeInt(min: number, max: number): Promise { + const range = max - min; + return await this.rng.nextInt(range) + min; + } + + public nextInt(max?: number): Promise { + return this.rng.nextInt(max); + } + + public async nextBit(): Promise { + const view = new DataView(await this.rng.nextBits(1) as ArrayBufferLike); + return view.getUint8(0) != 0; + } + + public async nextBool(prob = 0.5): Promise { + if (prob >= 1) { + return true; + } + if (prob === 0.5){ + return this.nextBit(); + } + if (prob <= 0){ + return false; + } + return await this.nextFloat1() < prob; + } + + public async shuffle(srcArray: T[]): Promise { + const cnt = srcArray.length; + if(cnt === 0){ + return []; + } + if (cnt > this.rng.getMaxInt()) { + throw 'Invalid random int range'; + } + + const result: T[] = Array.from(srcArray); + for (let srcIdx = 0; srcIdx < cnt; srcIdx += 1) { + const destIdx = await this.rng.nextInt(cnt - srcIdx - 1) + srcIdx; + if(srcIdx === destIdx){ + continue; + } + [result[srcIdx], result[destIdx]] = [result[destIdx], result[srcIdx]]; + } + + return result; + } + + //Object는 integer key에 예외가 있어 shuffleAssoc은 없음 + + public async choice(items: T[] | Record | Set): Promise { + if (items instanceof Array) { + if(items.length === 0){ + throw new Error('Empty items'); + } + const idx = await this.rng.nextInt(items.length - 1); + return items[idx]; + } + + if (items instanceof Set) { + return this.choice(Array.from(items.values())); + } + + return items[await this.choice(Array.from(Object.keys(items)))]; + } + + public async choiceUsingWeight(items: Record): Promise { + if(Object.keys(items).length === 0){ + throw new Error('Empty items'); + } + let sum = 0; + for (const value of Object.values(items)) { + if (value <= 0) { + continue; + } + sum += value; + } + + let rd = await this.nextFloat1() * sum; + + for (const [item, value] of Object.entries(items)) { + if (value <= 0) { + if (rd <= 0) { + return item; + } + continue; + } + + if (rd <= value) { + return item; + } + rd -= value; + } + + throw new Error('Unreacheable'); + } + + public async choiceUsingWeightPair(items: [T, number][]): Promise { + if(items.length === 0){ + throw new Error('Empty items'); + } + let sum = 0; + for (const [, value] of items) { + if (value <= 0) { + continue; + } + sum += value; + } + + let rd = await this.nextFloat1() * sum; + + for (const [item, value] of items) { + if (value <= 0) { + if (rd <= 0) { + return item; + } + continue; + } + + if (rd <= value) { + return item; + } + rd -= value; + } + + throw new Error('Unreacheable'); + } +} \ No newline at end of file diff --git a/@sammo/crypto/src/RawTypes.ts b/@sammo/crypto/src/RawTypes.ts new file mode 100644 index 0000000..459c0e3 --- /dev/null +++ b/@sammo/crypto/src/RawTypes.ts @@ -0,0 +1,50 @@ +import type { WrappedBuffer } from "@sammo/util"; + +export interface ECDSA_PKCS8_P384_SignKey extends WrappedBuffer{ + _w_type?: "ECDSA_PKCS8_P384_SignKey"; +} + +export interface ECDSA_P384_VerifyKey extends WrappedBuffer{ + _w_type?: "ECDSA_P384_VerifyKey"; +} + +export interface ECDSASignatureRaw extends WrappedBuffer{ + _w_type?: "ECDSASignature"; +} + +export interface ECDSASignatureBSON extends WrappedBuffer{ + _w_type?: "ECDSASignatureBSON"; +} + +export interface ECDSASignatureJSON extends WrappedBuffer{ + _w_type?: "ECDSASignatureJSON"; +} + +export type ECDSASignature = ECDSASignatureRaw | ECDSASignatureBSON | ECDSASignatureJSON; + +export interface ECDHe_P384_PublicKey extends WrappedBuffer{ + _w_type?: "ECDHe_P384_PublicKey"; +} + +export interface ECDHe_P384_PrivateKey extends WrappedBuffer{ + _w_type?: "ECDHe_P384_PrivateKey"; +} + +export interface ECDHe_P384_LiteKeyPair { + publicKey: ECDHe_P384_PublicKey; + privateKey: ECDHe_P384_PrivateKey; +} + +export interface ECDHe_P384_PublicKeyInfo { + publicKey: ECDHe_P384_PublicKey; + verifyKey: ECDSA_P384_VerifyKey; + sign: ECDSASignatureRaw; //sign of publicKey +} +export interface ECDHe_P384_KeyPair{ + publicInfo: ECDHe_P384_PublicKeyInfo; + privateKey: ECDHe_P384_PrivateKey; +} + +export { + TypeLength +} from "./TypeLength.js"; \ No newline at end of file diff --git a/@sammo/crypto/src/SHA2.test.ts b/@sammo/crypto/src/SHA2.test.ts new file mode 100644 index 0000000..20008ae --- /dev/null +++ b/@sammo/crypto/src/SHA2.test.ts @@ -0,0 +1,10 @@ +import { sha256, sha512 } from "./SHA2.js"; + +test('sha2', async () => { + const msg = Buffer.from('hello'); + const answer256 = Buffer.from('2CF24DBA5FB0A30E26E83B2AC5B9E29E1B161E5C1FA7425E73043362938B9824', 'hex'); + const answer512 = Buffer.from('9B71D224BD62F3785D96D46AD3EA3D73319BFBC2890CAADAE2DFF72519673CA72323C3D99BA5C11D7C7ACC6E14B8C5DA0C4663475C2E5C3ADEF46F73BCDEC043', 'hex'); + + expect(await sha256(msg)).toEqual(answer256.buffer); + expect(await sha512(msg)).toEqual(answer512.buffer); +}); \ No newline at end of file diff --git a/@sammo/crypto/src/SHA2.ts b/@sammo/crypto/src/SHA2.ts new file mode 100644 index 0000000..0947bda --- /dev/null +++ b/@sammo/crypto/src/SHA2.ts @@ -0,0 +1,19 @@ +import { isBufferSource } from "./types.js"; +import { BSON } from "bson"; +import { type Bsonifiable, bsonify } from "@sammo/util"; +import { isArray, isDate, isObject } from "lodash-es"; +const subtle = globalThis.crypto.subtle; + +export async function sha256(msg: Bsonifiable | BufferSource): Promise { + if (!isBufferSource(msg)) { + msg = BSON.serialize(bsonify(msg)); + } + return await subtle.digest('SHA-256', msg); +} + +export async function sha512(msg: Bsonifiable | BufferSource): Promise { + if (!isBufferSource(msg)) { + msg = BSON.serialize(bsonify(msg)); + } + return await subtle.digest('SHA-512', msg); +} diff --git a/@sammo/crypto/src/TypeLength.ts b/@sammo/crypto/src/TypeLength.ts new file mode 100644 index 0000000..89d5c0d --- /dev/null +++ b/@sammo/crypto/src/TypeLength.ts @@ -0,0 +1,6 @@ +export enum TypeLength { + //ECDSA P384 서명 + ECDSA_PKCS8_P384_SignKey = 185, + ECDSA_SPKI_P384_VerifyKey = 120, + ECDSASignature = 96, +} \ No newline at end of file diff --git a/@sammo/crypto/src/index.ts b/@sammo/crypto/src/index.ts new file mode 100644 index 0000000..38c3534 --- /dev/null +++ b/@sammo/crypto/src/index.ts @@ -0,0 +1,108 @@ +import { InvalidArgument } from '@sammo/util'; + +export class InvalidVType extends InvalidArgument { + public override name = 'InvalidVType'; +} + +export class InvalidArgumentBufferSize extends InvalidArgument { + public override name = 'InvalidArgumentBufferSize'; +} + +export class RuntimeError extends Error { + public override name = 'RuntimeError'; + constructor(public override message: string = '') { + super(message); + } + override toString(): string { + if (this.message) { + return this.name + ': ' + this.message; + } + else { + return this.name; + } + } +} + +export class NotNullExpected extends RuntimeError { + public override name = 'NotNullExpected'; +} + +export class PrivilegedGenViolation extends RuntimeError { + public override name = 'PrivilegedGenViolation'; +} + +export type MergeableBuffer = MergeableBuffer[] | Buffer; + +export function calcMergeableBuffer(item: MergeableBuffer): number { + if (item instanceof Buffer) { + return item.byteLength; + } + let bufferSize = 0; + for (const subItem of item) { + bufferSize += calcMergeableBuffer(subItem); + } + return bufferSize; +} + +export function mergeBuffer(...buffers: MergeableBuffer[]): Buffer { + if (buffers.length == 0) { + return Buffer.alloc(0); + } + if (buffers.length == 1) { + const item = buffers[0]; + if (item instanceof Buffer) { + return item; + } + } + + const fillBuffer = function (item: MergeableBuffer, bufferIdx: number): number { + if (item instanceof Buffer) { + result.set(item, bufferIdx); + bufferIdx += item.byteLength; + return bufferIdx; + } + for (const subItem of item) { + bufferIdx = fillBuffer(subItem, bufferIdx); + } + return bufferIdx; + } + + const bufferSize = calcMergeableBuffer(buffers); + const result = Buffer.alloc(bufferSize); + + fillBuffer(buffers, 0); + return result; +} + +type ErrType = { new(msg?: string): T } +type Nullable = T | null | undefined + +export function unwrap(result: Nullable): T { + if (result === null || result === undefined) { + throw new NotNullExpected(); + } + return result; +} + +export function unwrap_err(result: Nullable, errType: ErrType, errMsg?: string): T { + if (result === null || result === undefined) { + throw new errType(errMsg); + } + return result; +} + +export * as AES from './AES.js'; +export * as ECDSA from './ECDSA.js'; +export * as ECKey from './ECKey.js'; +export * as PBKDF2 from './PBKDF2.js'; +export * as SHA2 from './SHA2.js'; +export * as ECDHe from './ECDHe.js'; +export * as ECDHe_AES from './ECDHe_AES.js'; + +export * as RawTypes from './RawTypes.js'; + +export * from './utils.js'; +export * from './types.js'; +export { TypeLength } from './TypeLength.js'; + +export * from "./LiteHashDRBG.js" \ No newline at end of file diff --git a/@sammo/crypto/src/types.ts b/@sammo/crypto/src/types.ts new file mode 100644 index 0000000..609c844 --- /dev/null +++ b/@sammo/crypto/src/types.ts @@ -0,0 +1,13 @@ + +export function isBufferSource(obj: unknown): obj is BufferSource { + if (obj instanceof ArrayBuffer){ + return true; + } + if('SharedArrayBuffer' in globalThis && obj instanceof SharedArrayBuffer){ + return true; + } + if (ArrayBuffer.isView(obj)){ + return true; + } + return false; +} \ No newline at end of file diff --git a/@sammo/crypto/src/utils.ts b/@sammo/crypto/src/utils.ts new file mode 100644 index 0000000..75a02b8 --- /dev/null +++ b/@sammo/crypto/src/utils.ts @@ -0,0 +1,73 @@ +import type { WrappedBuffer } from "@sammo/util"; + +const crypto = globalThis.crypto; + +export function randomBytes(length: number): Buffer { + const buffer = Buffer.alloc(length); + crypto.getRandomValues(buffer); + return buffer; +} + +//TODO: 필요할때마다 확장 +export type ValidPEMType = 'PUBLIC KEY' | 'EC PRIVATE KEY' | 'CERTIFICATE'; + +/** + * PEM string에 내부 타입으로 WrappedBuffer를 보관한 형태 + */ +// eslint-disable-next-line @typescript-eslint/ban-types +export type PEMString = string & { + /** 타입구분자. 항상 undefined일 것이다 */ + _pem_b_type?: T; + _pem_type?: S; +} + +export function encodePEM(data: T, pemType: S): PEMString; +export function encodePEM(data: Buffer, pemType: ValidPEMType): string; +export function encodePEM(data: Buffer, pemType: ValidPEMType): string { + const base64text = data.toString('base64'); + const splitText = base64text.match(/.{1,64}/g)?.join('\n') ?? ''; + + return `-----BEGIN ${pemType}----- +${splitText} +-----END ${pemType}----- +`; +} + + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type InferPEMType> = Exclude; +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type InferPEMBuffer> = Exclude; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function decodePEM>(pem: T, pemType: InferPEMType): InferPEMBuffer[]; +export function decodePEM(pem: string, pemType?: ValidPEMType): Buffer[]; +export function decodePEM(pem: string, pemType?: ValidPEMType): Buffer[] { + const tag = pemType ?? "[A-Z0-9 ]+"; + const pattern = new RegExp(`-{5}BEGIN ${tag}-{5}([a-zA-Z0-9=+\\/\\n\\r]+)-{5}END ${tag}-{5}`, "g"); + + const res: Buffer[] = []; + let matches: RegExpExecArray | null = null; + // eslint-disable-next-line no-cond-assign + while (matches = pattern.exec(pem)) { + const base64 = matches[1] + .replace(/\r/g, "") + .replace(/\n/g, ""); + res.push(Buffer.from(base64, 'base64')); + } + + return res; +} + + + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function decodeSinglePEM>(pem: T, pemType: InferPEMType): InferPEMBuffer; +export function decodeSinglePEM(pem: string, pemType?: ValidPEMType): Buffer; +export function decodeSinglePEM(pem: string, pemType?: ValidPEMType): Buffer { + const res = decodePEM(pem, pemType); + if (res.length != 1) { + throw new Error("invalid pem"); + } + return res[0]; +} \ No newline at end of file diff --git a/@sammo/crypto/tsconfig.jest.json b/@sammo/crypto/tsconfig.jest.json new file mode 100644 index 0000000..50b79d4 --- /dev/null +++ b/@sammo/crypto/tsconfig.jest.json @@ -0,0 +1,6 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "verbatimModuleSyntax": false, + } +} \ No newline at end of file diff --git a/@sammo/crypto/tsconfig.json b/@sammo/crypto/tsconfig.json new file mode 100644 index 0000000..dd1920c --- /dev/null +++ b/@sammo/crypto/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist", + }, + "references": [ + { + "path": "../util" + } + ] +} diff --git a/@sammo/game_logic/package.json b/@sammo/game_logic/package.json new file mode 100644 index 0000000..3030291 --- /dev/null +++ b/@sammo/game_logic/package.json @@ -0,0 +1,23 @@ +{ + "name": "@sammo/game_logic", + "version": "1.0.0", + "description": "", + "main": "dist/index.js", + "scripts": { + "build": "tsc --build" + }, + "author": "", + "type": "module", + "license": "MIT", + "dependencies": { + "@sammo/api_def": "workspace:^", + "@sammo/server_util": "workspace:^", + "@sammo/util": "workspace:^", + "@strpc/express": "workspace:^", + "dotenv": "^16.3.1", + "mongoose": "^7.4.3" + }, + "devDependencies": { + "@types/node": "^20.6.3" + } +} diff --git a/@sammo/game_logic/src/generalStats.ts b/@sammo/game_logic/src/generalStats.ts new file mode 100644 index 0000000..1615b33 --- /dev/null +++ b/@sammo/game_logic/src/generalStats.ts @@ -0,0 +1,140 @@ +interface Stats { min: number, max: number, total: number }; + +export function abilityRand(stats: Stats): [number, number, number] { + let leadership = Math.random() * 65 + 10; + let strength = Math.random() * 65 + 10; + let intel = Math.random() * 65 + 10; + const rate = leadership + strength + intel; + + leadership = Math.floor((leadership / rate) * stats.total); + strength = Math.floor((strength / rate) * stats.total); + intel = Math.floor((intel / rate) * stats.total); + + while (leadership + strength + intel < stats.total) { + leadership += 1; + } + + if ( + leadership > stats.max || + strength > stats.max || + intel > stats.max || + leadership < stats.min || + strength < stats.min || + intel < stats.min + ) { + return abilityRand(stats); + } + + return [leadership, strength, intel]; +} + +export function abilityLeadpow(stats: Stats): [number, number, number] { + let leadership = Math.random() * 6; + let strength = Math.random() * 6; + let intel = Math.random() * 1; + const rate = leadership + strength + intel; + + leadership = Math.floor((leadership / rate) * stats.total); + strength = Math.floor((strength / rate) * stats.total); + intel = Math.floor((intel / rate) * stats.total); + + while (leadership + strength + intel < stats.total) { + strength += 1; + } + + if (intel < stats.min) { + leadership -= stats.min - intel; + intel = stats.min; + } + + if (leadership > stats.max) { + strength += leadership - stats.max; + leadership = stats.max; + } + + if (strength > stats.max) { + leadership += strength - stats.max; + strength = stats.max; + } + + if (leadership > stats.max) { + intel += leadership - stats.max; + leadership = stats.max; + } + + return [leadership, strength, intel]; +} + +export function abilityLeadint(stats: Stats): [number, number, number] { + let leadership = Math.random() * 6; + let strength = Math.random() * 1; + let intel = Math.random() * 6; + const rate = leadership + strength + intel; + + leadership = Math.floor((leadership / rate) * stats.total); + strength = Math.floor((strength / rate) * stats.total); + intel = Math.floor((intel / rate) * stats.total); + + while (leadership + strength + intel < stats.total) { + intel += 1; + } + + if (strength < stats.min) { + leadership -= stats.min - strength; + strength = stats.min; + } + + if (leadership > stats.max) { + intel += leadership - stats.max; + leadership = stats.max; + } + + if (intel > stats.max) { + leadership += intel - stats.max; + intel = stats.max; + } + + if (leadership > stats.max) { + strength += leadership - stats.max; + leadership = stats.max; + } + + return [leadership, strength, intel]; +} + +export function abilityPowint(stats: Stats): [number, number, number] { + let leadership = Math.random() * 1; + let strength = Math.random() * 6; + let intel = Math.random() * 6; + const rate = leadership + strength + intel; + + leadership = Math.floor((leadership / rate) * stats.total); + strength = Math.floor((strength / rate) * stats.total); + intel = Math.floor((intel / rate) * stats.total); + + while (leadership + strength + intel < stats.total) { + intel += 1; + } + + if (leadership < stats.min) { + strength -= stats.min - leadership; + leadership = stats.min; + } + + if (strength > stats.max) { + intel += strength - stats.max; + strength = stats.max; + } + + if (intel > stats.max) { + strength += intel - stats.max; + intel = stats.max; + } + + if (strength > stats.max) { + leadership += strength - stats.max; + strength = stats.max; + } + + return [leadership, strength, intel]; +} \ No newline at end of file diff --git a/@sammo/game_logic/src/index.ts b/@sammo/game_logic/src/index.ts new file mode 100644 index 0000000..7212077 --- /dev/null +++ b/@sammo/game_logic/src/index.ts @@ -0,0 +1 @@ +export * from "./generalStats.js"; \ No newline at end of file diff --git a/@sammo/game_logic/tsconfig.json b/@sammo/game_logic/tsconfig.json new file mode 100644 index 0000000..ebff90d --- /dev/null +++ b/@sammo/game_logic/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist", + }, + "references": [ + { + "path": "../../@strpc/express" + }, + { + "path": "../util" + }, + { + "path": "../crypto" + }, + { + "path": "../server_util" + }, + ] +} diff --git a/@sammo/gateway_client/env.d.ts b/@sammo/gateway_client/env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/@sammo/gateway_client/env.d.ts @@ -0,0 +1 @@ +/// diff --git a/@sammo/gateway_client/index.html b/@sammo/gateway_client/index.html new file mode 100644 index 0000000..a888544 --- /dev/null +++ b/@sammo/gateway_client/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite App + + +
+ + + diff --git a/@sammo/gateway_client/package.json b/@sammo/gateway_client/package.json new file mode 100644 index 0000000..7707322 --- /dev/null +++ b/@sammo/gateway_client/package.json @@ -0,0 +1,51 @@ +{ + "name": "@sammo/gateway_client", + "version": "1.0.1", + "description": "", + "main": "dist/index.js", + "scripts": { + "dev": "vite", + "build": "run-p type-check build-only", + "preview": "vite preview", + "build-only": "vite build", + "type-check": "vue-tsc --noEmit -p tsconfig.app.json --composite false", + "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore", + "format": "prettier --write src/" + }, + "author": "", + "type": "module", + "license": "MIT", + "dependencies": { + "@popperjs/core": "^2.11.8", + "@sammo/util": "workspace:^", + "@strpc/def": "workspace:^", + "bootstrap": "^5.3.1", + "bootstrap-vue-next": "^0.9.26", + "bson": "^5.4.0", + "date-fns": "^2.30.0", + "ky": "^1.0.1", + "lodash-es": "^4.17.21", + "pinia": "^2.1.4", + "vue": "^3.3.4", + "vue-router": "^4.2.4" + }, + "devDependencies": { + "@tsconfig/node20": "^20.1.2", + "@types/lodash-es": "^4.17.9", + "@types/node": "^20.6.3", + "@vue/eslint-config-prettier": "^8.0.0", + "@vue/eslint-config-typescript": "^11.0.3", + "@vue/tsconfig": "^0.4.0", + "eslint": "^8.50.0", + "eslint-plugin-vue": "^9.15.1", + "prettier": "^3.0.0", + "ts-node": "^10.9.1", + "tslib": "^2.6.2", + "vite": "^4.4.6", + "vue-tsc": "^1.8.6", + "zod": "^3.22.2" + }, + "peerDependencies": { + "zod": "^3.22.2" + } +} \ No newline at end of file diff --git a/@sammo/gateway_client/public/favicon.ico b/@sammo/gateway_client/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..df36fcfb72584e00488330b560ebcf34a41c64c2 GIT binary patch literal 4286 zcmds*O-Phc6o&64GDVCEQHxsW(p4>LW*W<827=Unuo8sGpRux(DN@jWP-e29Wl%wj zY84_aq9}^Am9-cWTD5GGEo#+5Fi2wX_P*bo+xO!)p*7B;iKlbFd(U~_d(U?#hLj56 zPhFkj-|A6~Qk#@g^#D^U0XT1cu=c-vu1+SElX9NR;kzAUV(q0|dl0|%h|dI$%VICy zJnu2^L*Te9JrJMGh%-P79CL0}dq92RGU6gI{v2~|)p}sG5x0U*z<8U;Ij*hB9z?ei z@g6Xq-pDoPl=MANPiR7%172VA%r)kevtV-_5H*QJKFmd;8yA$98zCxBZYXTNZ#QFk2(TX0;Y2dt&WitL#$96|gJY=3xX zpCoi|YNzgO3R`f@IiEeSmKrPSf#h#Qd<$%Ej^RIeeYfsxhPMOG`S`Pz8q``=511zm zAm)MX5AV^5xIWPyEu7u>qYs?pn$I4nL9J!=K=SGlKLXpE<5x+2cDTXq?brj?n6sp= zphe9;_JHf40^9~}9i08r{XM$7HB!`{Ys~TK0kx<}ZQng`UPvH*11|q7&l9?@FQz;8 zx!=3<4seY*%=OlbCbcae?5^V_}*K>Uo6ZWV8mTyE^B=DKy7-sdLYkR5Z?paTgK-zyIkKjIcpyO z{+uIt&YSa_$QnN_@t~L014dyK(fOOo+W*MIxbA6Ndgr=Y!f#Tokqv}n<7-9qfHkc3 z=>a|HWqcX8fzQCT=dqVbogRq!-S>H%yA{1w#2Pn;=e>JiEj7Hl;zdt-2f+j2%DeVD zsW0Ab)ZK@0cIW%W7z}H{&~yGhn~D;aiP4=;m-HCo`BEI+Kd6 z={Xwx{TKxD#iCLfl2vQGDitKtN>z|-AdCN|$jTFDg0m3O`WLD4_s#$S literal 0 HcmV?d00001 diff --git a/@sammo/gateway_client/src/App.vue b/@sammo/gateway_client/src/App.vue new file mode 100644 index 0000000..7905b05 --- /dev/null +++ b/@sammo/gateway_client/src/App.vue @@ -0,0 +1,85 @@ + + + + + diff --git a/@sammo/gateway_client/src/assets/base.css b/@sammo/gateway_client/src/assets/base.css new file mode 100644 index 0000000..8816868 --- /dev/null +++ b/@sammo/gateway_client/src/assets/base.css @@ -0,0 +1,86 @@ +/* color palette from */ +:root { + --vt-c-white: #ffffff; + --vt-c-white-soft: #f8f8f8; + --vt-c-white-mute: #f2f2f2; + + --vt-c-black: #181818; + --vt-c-black-soft: #222222; + --vt-c-black-mute: #282828; + + --vt-c-indigo: #2c3e50; + + --vt-c-divider-light-1: rgba(60, 60, 60, 0.29); + --vt-c-divider-light-2: rgba(60, 60, 60, 0.12); + --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65); + --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48); + + --vt-c-text-light-1: var(--vt-c-indigo); + --vt-c-text-light-2: rgba(60, 60, 60, 0.66); + --vt-c-text-dark-1: var(--vt-c-white); + --vt-c-text-dark-2: rgba(235, 235, 235, 0.64); +} + +/* semantic color variables for this project */ +:root { + --color-background: var(--vt-c-white); + --color-background-soft: var(--vt-c-white-soft); + --color-background-mute: var(--vt-c-white-mute); + + --color-border: var(--vt-c-divider-light-2); + --color-border-hover: var(--vt-c-divider-light-1); + + --color-heading: var(--vt-c-text-light-1); + --color-text: var(--vt-c-text-light-1); + + --section-gap: 160px; +} + +@media (prefers-color-scheme: dark) { + :root { + --color-background: var(--vt-c-black); + --color-background-soft: var(--vt-c-black-soft); + --color-background-mute: var(--vt-c-black-mute); + + --color-border: var(--vt-c-divider-dark-2); + --color-border-hover: var(--vt-c-divider-dark-1); + + --color-heading: var(--vt-c-text-dark-1); + --color-text: var(--vt-c-text-dark-2); + } +} + +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; + font-weight: normal; +} + +body { + min-height: 100vh; + color: var(--color-text); + background: var(--color-background); + transition: + color 0.5s, + background-color 0.5s; + line-height: 1.6; + font-family: + Inter, + -apple-system, + BlinkMacSystemFont, + 'Segoe UI', + Roboto, + Oxygen, + Ubuntu, + Cantarell, + 'Fira Sans', + 'Droid Sans', + 'Helvetica Neue', + sans-serif; + font-size: 15px; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} diff --git a/@sammo/gateway_client/src/assets/logo.svg b/@sammo/gateway_client/src/assets/logo.svg new file mode 100644 index 0000000..7565660 --- /dev/null +++ b/@sammo/gateway_client/src/assets/logo.svg @@ -0,0 +1 @@ + diff --git a/@sammo/gateway_client/src/assets/main.css b/@sammo/gateway_client/src/assets/main.css new file mode 100644 index 0000000..e8667cd --- /dev/null +++ b/@sammo/gateway_client/src/assets/main.css @@ -0,0 +1,35 @@ +@import './base.css'; + +#app { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + + font-weight: normal; +} + +a, +.green { + text-decoration: none; + color: hsla(160, 100%, 37%, 1); + transition: 0.4s; +} + +@media (hover: hover) { + a:hover { + background-color: hsla(160, 100%, 37%, 0.2); + } +} + +@media (min-width: 1024px) { + body { + display: flex; + place-items: center; + } + + #app { + display: grid; + grid-template-columns: 1fr 1fr; + padding: 0 2rem; + } +} diff --git a/@sammo/gateway_client/src/components/HelloWorld.vue b/@sammo/gateway_client/src/components/HelloWorld.vue new file mode 100644 index 0000000..38d821e --- /dev/null +++ b/@sammo/gateway_client/src/components/HelloWorld.vue @@ -0,0 +1,41 @@ + + + + + diff --git a/@sammo/gateway_client/src/components/TheWelcome.vue b/@sammo/gateway_client/src/components/TheWelcome.vue new file mode 100644 index 0000000..a70765c --- /dev/null +++ b/@sammo/gateway_client/src/components/TheWelcome.vue @@ -0,0 +1,86 @@ + + + diff --git a/@sammo/gateway_client/src/components/WelcomeItem.vue b/@sammo/gateway_client/src/components/WelcomeItem.vue new file mode 100644 index 0000000..6d7086a --- /dev/null +++ b/@sammo/gateway_client/src/components/WelcomeItem.vue @@ -0,0 +1,87 @@ + + + diff --git a/@sammo/gateway_client/src/components/icons/IconCommunity.vue b/@sammo/gateway_client/src/components/icons/IconCommunity.vue new file mode 100644 index 0000000..2dc8b05 --- /dev/null +++ b/@sammo/gateway_client/src/components/icons/IconCommunity.vue @@ -0,0 +1,7 @@ + diff --git a/@sammo/gateway_client/src/components/icons/IconDocumentation.vue b/@sammo/gateway_client/src/components/icons/IconDocumentation.vue new file mode 100644 index 0000000..6d4791c --- /dev/null +++ b/@sammo/gateway_client/src/components/icons/IconDocumentation.vue @@ -0,0 +1,7 @@ + diff --git a/@sammo/gateway_client/src/components/icons/IconEcosystem.vue b/@sammo/gateway_client/src/components/icons/IconEcosystem.vue new file mode 100644 index 0000000..c3a4f07 --- /dev/null +++ b/@sammo/gateway_client/src/components/icons/IconEcosystem.vue @@ -0,0 +1,7 @@ + diff --git a/@sammo/gateway_client/src/components/icons/IconSupport.vue b/@sammo/gateway_client/src/components/icons/IconSupport.vue new file mode 100644 index 0000000..7452834 --- /dev/null +++ b/@sammo/gateway_client/src/components/icons/IconSupport.vue @@ -0,0 +1,7 @@ + diff --git a/@sammo/gateway_client/src/components/icons/IconTooling.vue b/@sammo/gateway_client/src/components/icons/IconTooling.vue new file mode 100644 index 0000000..660598d --- /dev/null +++ b/@sammo/gateway_client/src/components/icons/IconTooling.vue @@ -0,0 +1,19 @@ + + diff --git a/@sammo/gateway_client/src/main.ts b/@sammo/gateway_client/src/main.ts new file mode 100644 index 0000000..24c9c4b --- /dev/null +++ b/@sammo/gateway_client/src/main.ts @@ -0,0 +1,14 @@ +import './assets/main.css' + +import { createApp } from 'vue' +import { createPinia } from 'pinia' + +import App from './App.vue' +import router from './router/index.js' + +const app = createApp(App) + +app.use(createPinia()) +app.use(router) + +app.mount('#app') diff --git a/@sammo/gateway_client/src/router/index.ts b/@sammo/gateway_client/src/router/index.ts new file mode 100644 index 0000000..a49ae50 --- /dev/null +++ b/@sammo/gateway_client/src/router/index.ts @@ -0,0 +1,23 @@ +import { createRouter, createWebHistory } from 'vue-router' +import HomeView from '../views/HomeView.vue' + +const router = createRouter({ + history: createWebHistory(import.meta.env.BASE_URL), + routes: [ + { + path: '/', + name: 'home', + component: HomeView + }, + { + path: '/about', + name: 'about', + // route level code-splitting + // this generates a separate chunk (About.[hash].js) for this route + // which is lazy-loaded when the route is visited. + component: () => import('../views/AboutView.vue') + } + ] +}) + +export default router diff --git a/@sammo/gateway_client/src/stores/counter.ts b/@sammo/gateway_client/src/stores/counter.ts new file mode 100644 index 0000000..b6757ba --- /dev/null +++ b/@sammo/gateway_client/src/stores/counter.ts @@ -0,0 +1,12 @@ +import { ref, computed } from 'vue' +import { defineStore } from 'pinia' + +export const useCounterStore = defineStore('counter', () => { + const count = ref(0) + const doubleCount = computed(() => count.value * 2) + function increment() { + count.value++ + } + + return { count, doubleCount, increment } +}) diff --git a/@sammo/gateway_client/src/views/AboutView.vue b/@sammo/gateway_client/src/views/AboutView.vue new file mode 100644 index 0000000..756ad2a --- /dev/null +++ b/@sammo/gateway_client/src/views/AboutView.vue @@ -0,0 +1,15 @@ + + + diff --git a/@sammo/gateway_client/src/views/HomeView.vue b/@sammo/gateway_client/src/views/HomeView.vue new file mode 100644 index 0000000..d5c0217 --- /dev/null +++ b/@sammo/gateway_client/src/views/HomeView.vue @@ -0,0 +1,9 @@ + + + diff --git a/@sammo/gateway_client/tsconfig.app.json b/@sammo/gateway_client/tsconfig.app.json new file mode 100644 index 0000000..3af40b0 --- /dev/null +++ b/@sammo/gateway_client/tsconfig.app.json @@ -0,0 +1,12 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], + "exclude": ["src/**/__tests__/*"], + "compilerOptions": { + "composite": true, + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + } + } \ No newline at end of file diff --git a/@sammo/gateway_client/tsconfig.json b/@sammo/gateway_client/tsconfig.json new file mode 100644 index 0000000..7087b3f --- /dev/null +++ b/@sammo/gateway_client/tsconfig.json @@ -0,0 +1,28 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist", + }, + "exclude": [ + + ], + "references": [ + { + + "path": "../util" + }, + { + "path": "../secure_token" + }, + { + "path": "../../@strpc/def" + }, + { + "path": "./tsconfig.node.json" + }, + { + "path": "./tsconfig.app.json" + }, + ] + } diff --git a/@sammo/gateway_client/tsconfig.node.json b/@sammo/gateway_client/tsconfig.node.json new file mode 100644 index 0000000..9ccb58a --- /dev/null +++ b/@sammo/gateway_client/tsconfig.node.json @@ -0,0 +1,18 @@ +{ + "extends": "@tsconfig/node20/tsconfig.json", + "include": [ + "vite.config.*", + "vitest.config.*", + "cypress.config.*", + "nightwatch.conf.*", + "playwright.config.*" + ], + "compilerOptions": { + "composite": true, + "module": "ESNext", + "moduleResolution": "Bundler", + "types": ["node"], + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + } +} diff --git a/@sammo/gateway_client/vite.config.ts b/@sammo/gateway_client/vite.config.ts new file mode 100644 index 0000000..e22c48f --- /dev/null +++ b/@sammo/gateway_client/vite.config.ts @@ -0,0 +1,17 @@ +import { fileURLToPath, URL } from 'node:url' + +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [ + vue(), + ], + resolve: { + alias: { + '@': fileURLToPath(new URL('./src', import.meta.url)), + '@util': fileURLToPath(new URL('./server/util', import.meta.url)), + } + } +}) diff --git a/@sammo/gateway_server/package.json b/@sammo/gateway_server/package.json new file mode 100644 index 0000000..2476260 --- /dev/null +++ b/@sammo/gateway_server/package.json @@ -0,0 +1,37 @@ +{ + "name": "@sammo/gateway_server", + "version": "1.0.0", + "description": "", + "main": "dist/index.js", + "scripts": { + "build": "tsc --build" + }, + "exports": { + ".": "./dist/index.js", + "./exports": "./dist/exports.js" + }, + "author": "", + "type": "module", + "license": "MIT", + "dependencies": { + "@sammo/api_def": "workspace:^", + "@sammo/crypto": "workspace:^", + "@sammo/server_util": "workspace:^", + "@sammo/util": "workspace:^", + "@strpc/express": "workspace:^", + "date-fns": "^2.30.0", + "dotenv": "^16.3.1", + "express": "^4.18.2", + "express-session": "^1.17.3", + "lodash-es": "^4.17.21", + "mongoose": "^7.4.3", + "reflect-metadata": "^0.1.13", + "tslib": "^2.6.2", + "zod": "^3.22.2" + }, + "devDependencies": { + "@types/express": "^4.17.17", + "@types/express-session": "^1.17.7", + "@types/node": "^20.6.3" + } +} diff --git a/@sammo/gateway_server/src/MongoSequence.ts b/@sammo/gateway_server/src/MongoSequence.ts new file mode 100644 index 0000000..008d4a0 --- /dev/null +++ b/@sammo/gateway_server/src/MongoSequence.ts @@ -0,0 +1,25 @@ +import type { StateIncrementer } from '@sammo/server_util'; +import SchemaSequence from './schema/SchemaSequence.js'; +import { InvalidArgument } from '@sammo/util'; + +export function MongoSequenceFactory(collectionName: string): StateIncrementer{ + + return async (increase: number) => { + if(increase <= 0){ + throw new InvalidArgument('increase must be > 0'); + } + increase = Math.ceil(increase); + + const result = await SchemaSequence.findOneAndUpdate({ + collectionName, + }, { + $inc: { + nextSeq: increase, + }, + }, { + upsert: true, + new: true, + }); + return result.nextSeq; + } +} \ No newline at end of file diff --git a/@sammo/gateway_server/src/api/GetGameLoginToken.ts b/@sammo/gateway_server/src/api/GetGameLoginToken.ts new file mode 100644 index 0000000..024e235 --- /dev/null +++ b/@sammo/gateway_server/src/api/GetGameLoginToken.ts @@ -0,0 +1,22 @@ +import type { structure } from "@sammo/api_def/gateway"; +import { StartSession } from "@sammo/server_util"; +import { GET, type APIReturnType } from "@strpc/express"; +import { declProcDecorators } from "@strpc/express/proc_decorator"; +import { ReqGatewayLogin } from "../procDecorator/ReqGatewayLogin.js"; + +type BaseAPI = typeof structure.GetGameLoginToken; +type RType = APIReturnType; + +export const GameLoginTokenSessionKey = "GameLoginToken"; + +export const GetGameLoginToken = GET()(declProcDecorators( + StartSession, + ReqGatewayLogin, +))( + async (query, ctx): RType => { + return { + result: false, + reason: 'NotYetImplemented', + }; + } +); \ No newline at end of file diff --git a/@sammo/gateway_server/src/api/Install/index.ts b/@sammo/gateway_server/src/api/Install/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/@sammo/gateway_server/src/api/Install/initAdmin.ts b/@sammo/gateway_server/src/api/Install/initAdmin.ts new file mode 100644 index 0000000..e69de29 diff --git a/@sammo/gateway_server/src/api/Login/ChangePassword.ts b/@sammo/gateway_server/src/api/Login/ChangePassword.ts new file mode 100644 index 0000000..894c5c0 --- /dev/null +++ b/@sammo/gateway_server/src/api/Login/ChangePassword.ts @@ -0,0 +1,18 @@ +import type { structure } from "@sammo/api_def/gateway"; +import { StartSession } from "@sammo/server_util"; +import { GET, type APIReturnType } from "@strpc/express"; +import { declProcDecorators } from "@strpc/express/proc_decorator"; +import { ReqGatewayLogin } from "../../procDecorator/ReqGatewayLogin.js"; + +type BaseAPI = typeof structure.Login.ReqNonce; +type RType = APIReturnType; +const argValidator = undefined; + +export const ReqNonce = GET(argValidator)(declProcDecorators( + StartSession, + ReqGatewayLogin, +))( + (query, ctx): RType => { + throw new Error("Method not implemented."); + } +); \ No newline at end of file diff --git a/@sammo/gateway_server/src/api/Login/LoginByID.ts b/@sammo/gateway_server/src/api/Login/LoginByID.ts new file mode 100644 index 0000000..dd1f1e2 --- /dev/null +++ b/@sammo/gateway_server/src/api/Login/LoginByID.ts @@ -0,0 +1,62 @@ +import type { structure } from "@sammo/api_def/gateway"; +import { StartSession } from "@sammo/server_util"; +import { POST, type APIReturnType } from "@strpc/express"; +import { declProcDecorators } from "@strpc/express/proc_decorator"; +import { z } from "zod"; +import { loginCtxSessionKey, type GatewayLoginCtx } from "@/procDecorator/ReqGatewayLogin.js"; +import { delay } from "@sammo/util"; + +type BaseAPI = typeof structure.Login.LoginByID; +type RType = APIReturnType; +const LoginByIDReq = z.object({ + id: z.string(), + password: z.string(), +}); + +export const LoginByID = POST(LoginByIDReq)(declProcDecorators( + StartSession, +))( + async (query, ctx, req, res): RType => { + const id = query.id; + const password = query.password; + + //TODO: DB에서 뭔가 가져와야 함 + await delay(1); + + if (Math.random() < 0.3) { + return { + result: false, + reason: "로그인 실패", + reqOTP: false, + } + } + + if (Math.random() < 0.5) { + return { + result: false, + reason: "OTP 인증 필요", + reqOTP: true, + } + } + + const userID = 1; + const userName = "test"; + const userLevel = 1; + const nextToken: [number, string] = [1, "1234567890"]; + const loginCtx: GatewayLoginCtx = { + userID, + userName, + userLevel, + allowServerAction: new Map(), + allowGatewayAction: new Set(), + loginDate: new Date(), + } + + ctx.session.setItem(loginCtxSessionKey, loginCtx); + + + return { + result: true, + nextToken, + } + }); \ No newline at end of file diff --git a/@sammo/gateway_server/src/api/Login/LoginByToken.ts b/@sammo/gateway_server/src/api/Login/LoginByToken.ts new file mode 100644 index 0000000..3b9fa9a --- /dev/null +++ b/@sammo/gateway_server/src/api/Login/LoginByToken.ts @@ -0,0 +1,50 @@ +import type { structure } from "@sammo/api_def/gateway"; +import { StartSession } from "@sammo/server_util"; +import { POST, type APIReturnType } from "@strpc/express"; +import { declProcDecorators } from "@strpc/express/proc_decorator"; +import { z } from "zod"; +import { loginCtxSessionKey, type GatewayLoginCtx } from "@/procDecorator/ReqGatewayLogin.js"; +import { delay } from "@sammo/util"; + +type BaseAPI = typeof structure.Login.LoginByToken; +type RType = APIReturnType; + +const LoginByTokenReq = z.object({ + token_id: z.number(), + hashedToken: z.string(), +}); + +export const LoginByToken = POST(LoginByTokenReq)(declProcDecorators( + StartSession, +)) + (async (query, ctx): RType => { + query.hashedToken; + ctx.session.clear(); + + await delay(1); + //무언가 로그인 + //TODO: DB는 어디서 들고옴? + + const userID = 1; + const userName = "test"; + const userLevel = 1; + const nextToken: [number, string] = [1, "1234567890"]; + const loginCtx: GatewayLoginCtx = { + userID, + userName, + userLevel, + allowServerAction: new Map(), + allowGatewayAction: new Set(), + loginDate: new Date(), + } + + ctx.session.setItem(loginCtxSessionKey, loginCtx); + + + //throw new Error("Method not implemented."); + return { + result: true, + nextToken, + } + + }); \ No newline at end of file diff --git a/@sammo/gateway_server/src/api/Login/ReqNonce.ts b/@sammo/gateway_server/src/api/Login/ReqNonce.ts new file mode 100644 index 0000000..100e22d --- /dev/null +++ b/@sammo/gateway_server/src/api/Login/ReqNonce.ts @@ -0,0 +1,30 @@ +import type { structure } from "@sammo/api_def/gateway"; +import { StartSession } from "@sammo/server_util"; +import { GET, type APIReturnType } from "@strpc/express"; +import { declProcDecorators } from "@strpc/express/proc_decorator"; + +type BaseAPI = typeof structure.Login.ReqNonce; +type RType = APIReturnType; + +export const ReqNonceSessionKey = 'loginNonce'; + +export const ReqNonce = GET(undefined)(declProcDecorators( + StartSession, +))( + async (query, ctx): RType => { + const nonce = ctx.session.getItem(ReqNonceSessionKey); + if (nonce !== undefined) { + return { + loginNonce: nonce, + result: true, + } + } + + const newNonce = "1234567890"; + ctx.session.setItem(ReqNonceSessionKey, newNonce); + return { + loginNonce: newNonce, + result: true, + } + } +) \ No newline at end of file diff --git a/@sammo/gateway_server/src/api/Login/index.ts b/@sammo/gateway_server/src/api/Login/index.ts new file mode 100644 index 0000000..226a311 --- /dev/null +++ b/@sammo/gateway_server/src/api/Login/index.ts @@ -0,0 +1,11 @@ +import type { structure } from "@sammo/api_def/gateway"; +import type { APINamespaceType } from "@strpc/express"; +import { LoginByID } from "./LoginByID.js"; +import { LoginByToken } from "./LoginByToken.js"; +import { ReqNonce } from "./ReqNonce.js"; + +export const Login = { + LoginByID, + LoginByToken, + ReqNonce, +} satisfies APINamespaceType; \ No newline at end of file diff --git a/@sammo/gateway_server/src/api/index.ts b/@sammo/gateway_server/src/api/index.ts new file mode 100644 index 0000000..24869d8 --- /dev/null +++ b/@sammo/gateway_server/src/api/index.ts @@ -0,0 +1,9 @@ +import type { structure } from "@sammo/api_def/gateway"; +import { GetGameLoginToken } from "./GetGameLoginToken.js"; +import { Login } from "./Login/index.js"; +import type { APINamespaceType } from "@strpc/express"; + +export const sammoGatewayAPI = { + Login, + GetGameLoginToken +} satisfies APINamespaceType; \ No newline at end of file diff --git a/@sammo/gateway_server/src/connectDB.ts b/@sammo/gateway_server/src/connectDB.ts new file mode 100644 index 0000000..499cbe2 --- /dev/null +++ b/@sammo/gateway_server/src/connectDB.ts @@ -0,0 +1,22 @@ +import './dotenv.js'; +import { connect, Mongoose } from "mongoose"; +import { unwrap } from '@sammo/util'; + +const dbConfig = { + host: unwrap(process.env.GATEWAY_DB_HOST), + port: Number(unwrap(process.env.GATEWAY_DB_PORT)), + user: unwrap(process.env.GATEWAY_DB_USER), + password: unwrap(process.env.GATEWAY_DB_PASSWORD), + database: unwrap(process.env.GATEWAY_DB_DATABASE), +} + +const db: Promise = (async () => { + return await connect(`mongodb://${dbConfig.host}:${dbConfig.port}/${dbConfig.database}`, { + auth:{ + username: dbConfig.user, + password: dbConfig.password, + } + }); +})(); + +export default db; \ No newline at end of file diff --git a/@sammo/gateway_server/src/constPath.ts b/@sammo/gateway_server/src/constPath.ts new file mode 100644 index 0000000..f00e15f --- /dev/null +++ b/@sammo/gateway_server/src/constPath.ts @@ -0,0 +1,3 @@ +import { resolve } from "node:path"; + +export const rootPath = resolve(resolve(), '../..'); \ No newline at end of file diff --git a/@sammo/gateway_server/src/dotenv.ts b/@sammo/gateway_server/src/dotenv.ts new file mode 100644 index 0000000..3273dc1 --- /dev/null +++ b/@sammo/gateway_server/src/dotenv.ts @@ -0,0 +1,47 @@ +import dotenv from 'dotenv'; +import { rootPath } from './constPath.js'; +import { unwrap } from '@sammo/util'; + +let init = false; +const dirPath = rootPath +console.log(rootPath); + +function initDotEnv() { + if (process.env['NODE_ENV'] == 'production') { + dotenv.config({ path: `${dirPath}/.env.production.local` }); + dotenv.config({ path: `${dirPath}/.env.local` }); + dotenv.config({ path: `${dirPath}/.env.production` }); + } + else { + dotenv.config({ path: `${dirPath}/.env.development.local` }); + dotenv.config({ path: `${dirPath}/.env.local` }); + dotenv.config({ path: `${dirPath}/.env.development` }); + } + dotenv.config(); + init = true; +} + +if (!init) { + initDotEnv(); +} + +let _ownConfig: ReturnType|undefined = undefined; + +function generateConfig() { + return { + port: parseInt(process.env['SERVER_PORT'] ?? "3001"), + sessionSecret: unwrap(process.env['SESSION_SECRET']), + apiRootPath: process.env['API_ROOT_PATH'] ?? '/api', + } as const; +} + +export function ownConfig() { + if(_ownConfig !== undefined){ + return _ownConfig; + } + if(!init){ + initDotEnv(); + } + _ownConfig = generateConfig(); + return _ownConfig; +} diff --git a/@sammo/gateway_server/src/exports.ts b/@sammo/gateway_server/src/exports.ts new file mode 100644 index 0000000..0a30fcf --- /dev/null +++ b/@sammo/gateway_server/src/exports.ts @@ -0,0 +1,9 @@ +export type { + ServerActionType, + UserIDType, + IUser, +} from "./schema/User.js"; + +export type { + ILoginToken +} from "./schema/LoginToken.js"; \ No newline at end of file diff --git a/@sammo/gateway_server/src/index.ts b/@sammo/gateway_server/src/index.ts new file mode 100644 index 0000000..687aa12 --- /dev/null +++ b/@sammo/gateway_server/src/index.ts @@ -0,0 +1,34 @@ +import './dotenv.js' +import { ownConfig } from './dotenv.js'; +import 'reflect-metadata'; +import gatewayDB from './connectDB.js'; +import express, { type Request, type Response } from "express" +import session from "express-session"; +import { buildAPISystem } from '@strpc/express/generator'; +import { sammoGatewayAPI } from './api/index.js'; +import { unwrap } from '@sammo/util'; + + +const gatewayConfig = ownConfig(); + +gatewayDB.then(async (gatewayDB) => { + // create express app + const app = express() + app.use(express.json()); + app.use(session({ + secret: unwrap(gatewayConfig.sessionSecret), + resave: false, + saveUninitialized: false, + })) + //app.set('etag', false); + + app.use('/gateway_api', buildAPISystem(sammoGatewayAPI)); + + // start express server + app.listen(gatewayConfig.port) + + console.log(`Gateway server has started on port ${gatewayConfig.port}`) + +}).catch(error => console.log(error)); + +export default {}; \ No newline at end of file diff --git a/@sammo/gateway_server/src/procDecorator/ReqGatewayLogin.ts b/@sammo/gateway_server/src/procDecorator/ReqGatewayLogin.ts new file mode 100644 index 0000000..27cadef --- /dev/null +++ b/@sammo/gateway_server/src/procDecorator/ReqGatewayLogin.ts @@ -0,0 +1,33 @@ +import type { SessionCtx } from "@sammo/server_util"; +import type { GatewayActionType, ServerActionType } from "../schema/User.js"; +import type { ProcDecorator } from "@strpc/express/proc_decorator"; + +export type GatewayLoginCtx = { + userID: number; + userName: string; + userLevel: number; + allowServerAction: Map>; + allowGatewayAction: Set; + loginDate: Date; +} +export const loginCtxSessionKey = 'loginCtx'; + +export function ReqGatewayLogin(): ProcDecorator { + return (ctx) => { + const loginCtx = ctx.session.getItem(loginCtxSessionKey); + if(!loginCtx){ + return [{ + result: false, + type: 'Required Login', + info: 'ReqLogin' + }, ctx]; + } + + return [{ + result: true, + },{ + ...loginCtx, + ...ctx, + }]; + } +} \ No newline at end of file diff --git a/@sammo/gateway_server/src/schema/LoginToken.ts b/@sammo/gateway_server/src/schema/LoginToken.ts new file mode 100644 index 0000000..27c5e46 --- /dev/null +++ b/@sammo/gateway_server/src/schema/LoginToken.ts @@ -0,0 +1,23 @@ +import { type UserIDType } from "./User.js"; +import { Mongoose, Schema, model } from "mongoose"; + +export interface ILoginToken { + userID: UserIDType; + token: string; + ip: string; + regDate: Date; + validUntil: Date; +} + +export const LoginToken = new Schema({ + userID: { type: Number, required: true }, + token: { type: String, required: true }, + ip: { type: String, required: true }, + regDate: { type: Date, required: true }, + validUntil: { type: Date, required: true }, +}, { autoIndex: false, autoCreate: false, }) + .index({ userID: 1, token: 1 }) + .index({ validUntil: 1 }, { expireAfterSeconds: 1 }) + ; + +export default (conn: Mongoose)=>conn.model('LoginToken', LoginToken); \ No newline at end of file diff --git a/@sammo/gateway_server/src/schema/SchemaSequence.ts b/@sammo/gateway_server/src/schema/SchemaSequence.ts new file mode 100644 index 0000000..2c6e2e2 --- /dev/null +++ b/@sammo/gateway_server/src/schema/SchemaSequence.ts @@ -0,0 +1,23 @@ +import { Schema, model, Types } from 'mongoose'; + +interface ISchemaSequence { + _id: Types.ObjectId; + + collectionName: string; + nextSeq: number; +} + +export const SchemaSequence = new Schema({ + collectionName: { type: String, required: true }, + nextSeq: { + type: Number, required: true, + get: (v: number) => Math.ceil(v), + set: (v: number) => Math.ceil(v), + default: 0, + }, + +}, { autoIndex: true, autoCreate: true }) + .index({ collectionName: 1 }, { unique: true }) + ; + +export default model('SchemaSequence', SchemaSequence); \ No newline at end of file diff --git a/@sammo/gateway_server/src/schema/ServerVersion.ts b/@sammo/gateway_server/src/schema/ServerVersion.ts new file mode 100644 index 0000000..ac34dd7 --- /dev/null +++ b/@sammo/gateway_server/src/schema/ServerVersion.ts @@ -0,0 +1,19 @@ +import { Schema, model } from "mongoose"; + +export interface IServerVersion { + serverKey: string; + branch: string; + version: string; + updateDate: Date; +} + +export const ServerVersion = new Schema({ + serverKey: { type: String, required: true }, + branch: { type: String, required: true }, + version: { type: String, required: true }, + updateDate: { type: Date, required: true }, +}, { autoIndex: false, autoCreate: false, }) + .index({ serverKey: 1 }, { unique: true }) + ; + +export default model('ServerVersion', ServerVersion); \ No newline at end of file diff --git a/@sammo/gateway_server/src/schema/User.ts b/@sammo/gateway_server/src/schema/User.ts new file mode 100644 index 0000000..8b06972 --- /dev/null +++ b/@sammo/gateway_server/src/schema/User.ts @@ -0,0 +1,90 @@ +import { Schema, model } from 'mongoose'; + +export type UserIDType = number; + +const validOAuthTypeList = ['KAKAO', 'NONE'] as const; +export type validOAuthType = typeof validOAuthTypeList[number]; + +const validServerActionTypeList = [ + 'Update', 'UpdateByGitPath', 'ShowErrorLog', + 'CloseServer', 'OpenServer', 'StopAndResumeServer', 'OpenVote', +] as const; +export type ServerActionType = typeof validServerActionTypeList[number]; + +const validGatewayActionTypeList = [ + 'Update', 'UpdateByGitPath', 'ShowErrorLog', 'ResetUserPassword', 'ChangeGatewayState', 'DeleteUser', +] as const; + +export type GatewayActionType = typeof validGatewayActionTypeList[number]; + +export interface IUser { + _id: UserIDType; + + oauthID?: bigint; + id: string; + email: string; + + oauthType: validOAuthType; + oauthInfo?: object; + tokenValidUntil?: Date; + + userSalt: string; + hashedPassword: string; + + allowThirdPartyUse: boolean; + + userName: string; + allowServerAction?: Map; + allowGatewayAction?: ServerActionType[]; + penalty?: Map; + + picture?: string; + useImgSvr?: boolean; + + regDate: Date; + deleteAfter?: Date; +} + +export const User = new Schema({ + _id: { type: Number, required: true }, + + oauthID: { type: BigInt, required: false }, + id: { type: String, required: true }, + email: { type: String, required: true }, + + oauthType: { type: String, required: true, enum: validOAuthTypeList }, + oauthInfo: { type: Object, required: false }, + tokenValidUntil: { type: Date, required: false }, + + userSalt: { type: String, required: true }, + hashedPassword: { type: String, required: true }, + + allowThirdPartyUse: { type: Boolean, required: true }, + + userName: { type: String, required: true }, + allowServerAction: { + type: Map, required: false, of: { + type: Array, + of: { type: String, enum: validServerActionTypeList } + } + }, + allowGatewayAction: { + type: Array, required: false, of: { + type: String, enum: validGatewayActionTypeList + } + }, + penalty: { type: Map, required: false, of: Date }, + + picture: { type: String, required: false }, + useImgSvr: { type: Boolean, required: false }, + + regDate: { type: Date, required: true }, + deleteAfter: { type: Date, required: false }, +}, { autoIndex: false, autoCreate: false }) + .index({ id: 1 }, { unique: true }) + .index({ email: 1 }, { unique: true }) + .index({ oauthID: 1 }, { unique: true, sparse: true }) + .index({ deleteAfter: 1 }) // 자동 삭제 아님! + ; + +export default model('User', User); \ No newline at end of file diff --git a/@sammo/gateway_server/src/schema/UserLog.ts b/@sammo/gateway_server/src/schema/UserLog.ts new file mode 100644 index 0000000..2742802 --- /dev/null +++ b/@sammo/gateway_server/src/schema/UserLog.ts @@ -0,0 +1,30 @@ +import { Schema, model, } from 'mongoose'; +import { type UserIDType } from './User.js'; + +export type LogType = 'register' + | 'login_pw' | 'login_token' | 'login_oauth' | 'logout' + | 'change_pw' | 'reset_pw'; +const LogTypeList: LogType[] = [ + 'register', + 'login_pw', 'login_token', 'login_oauth', 'logout', + 'change_pw', 'reset_pw', +]; + +interface IUserLog { + userID: UserIDType; + logDate: Date; + logType: LogType; + action: object; +} + +export const UserLog = new Schema({ + userID: { type: Number, required: true }, + logDate: { type: Date, required: true }, + logType: { type: String, required: true, enum: LogTypeList }, + action: { type: Object, required: true }, +}, { autoIndex: false, autoCreate: false, }) + .index({ userID: 1, logDate: 1 }) + .index({ logDate: 1 }, { expireAfterSeconds: 60 * 60 * 24 * 365 * 3 }) + ; + +export default model('UserLog', UserLog); \ No newline at end of file diff --git a/@sammo/gateway_server/tsconfig.json b/@sammo/gateway_server/tsconfig.json new file mode 100644 index 0000000..9654247 --- /dev/null +++ b/@sammo/gateway_server/tsconfig.json @@ -0,0 +1,27 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist", + "paths": { + "@/*": ["./src/*"] + } + }, + "references": [ + { + "path": "../../@strpc/express" + }, + { + "path": "../api_def" + }, + { + "path": "../util" + }, + { + "path": "../crypto" + }, + { + "path": "../server_util" + }, + ] +} diff --git a/@sammo/secure_token/package.json b/@sammo/secure_token/package.json new file mode 100644 index 0000000..2137c71 --- /dev/null +++ b/@sammo/secure_token/package.json @@ -0,0 +1,26 @@ +{ + "name": "@sammo/secure_token", + "version": "1.0.0", + "description": "", + "main": "dist/index.js", + "scripts": { + "build": "tsc --build" + }, + "author": "", + "type": "module", + "license": "MIT", + "dependencies": { + "@sammo/crypto": "workspace:^", + "@sammo/util": "workspace:^" + }, + "devDependencies": { + "bson": "^5.4.0", + "buffer": "^6.0.3", + "zod": "^3.22.2" + }, + "peerDependencies": { + "bson": "^5.4.0", + "buffer": "^6.0.3", + "zod": "^3.22.2" + } +} diff --git a/@sammo/secure_token/src/EncryptedSimple.ts b/@sammo/secure_token/src/EncryptedSimple.ts new file mode 100644 index 0000000..b7d646b --- /dev/null +++ b/@sammo/secure_token/src/EncryptedSimple.ts @@ -0,0 +1,79 @@ +import { sha512 } from "@sammo/crypto/SHA2"; +import { BSON } from "bson"; +import type { PlainBson } from '@sammo/util'; +import { calcBase64Len } from "@sammo/util"; +import { AES_GCM_Decrypt, AES_GCM_Encrypt } from "@sammo/crypto/AES"; +import { z } from "zod"; + +const nonceLen = 16; +const tagLen = 16; + +export type EncryptedSimpleItem = { + nonce: string; + ct: string; +} + +export const zodEncryptedSimpleItem = z.object({ + nonce: z.string().length(calcBase64Len(nonceLen)), + ct: z.string().min(calcBase64Len(tagLen)), +}); + +export type DecryptedSimpleItem> = T extends EncryptedSimpleItem ? U : never; + +const staticPresharedTokenSecret: string | undefined = process.env.PRESHARED_SECURE_TOKEN_SECRET; + +export async function encryptSimpleItem(data: T, presharedTokenSecret?: string): Promise> { + if (!presharedTokenSecret) { + if (!staticPresharedTokenSecret) { + throw new Error("PRESHARED_SECURE_TOKEN_SECRET is not set"); + } + presharedTokenSecret = staticPresharedTokenSecret; + } + + const secretLength = Buffer.byteLength(presharedTokenSecret, 'utf8'); + const secretBuffer = Buffer.alloc(secretLength + nonceLen); + secretBuffer.write(presharedTokenSecret, 0, secretLength, 'utf8'); + + //secretBuffer에서 Buffer를 바로 준비해도 되지만, 혹시모를 안전상의 이유로 별도로 할당하고 복사 + const nonce = Buffer.from(crypto.getRandomValues(new Uint8Array(nonceLen))); + secretBuffer.set(nonce, secretLength); + + const keyBuffer = Buffer.from(await sha512(secretBuffer)); + + const key = new Uint8Array(keyBuffer.buffer, 0, 32); + const iv = new Uint8Array(keyBuffer.buffer, 32, 12); + + const payload = BSON.serialize(data); + + const ciphertext = Buffer.from(await AES_GCM_Encrypt(key, iv, payload)); + + return { + nonce: nonce.toString('base64'), + ct: ciphertext.toString('base64'), + }; +} + +export async function decryptSimpleItem(data: EncryptedSimpleItem, presharedTokenSecret?: string): Promise { + if (!presharedTokenSecret) { + if (!staticPresharedTokenSecret) { + throw new Error("PRESHARED_SECURE_TOKEN_SECRET is not set"); + } + presharedTokenSecret = staticPresharedTokenSecret; + } + + const secretLength = Buffer.byteLength(presharedTokenSecret, 'utf8'); + const secretBuffer = Buffer.alloc(secretLength + 16); + secretBuffer.write(presharedTokenSecret, 0, secretLength, 'utf8'); + + const nonce = Buffer.from(data.nonce, 'base64'); + secretBuffer.set(nonce, secretLength); + + const keyBuffer = Buffer.from(await sha512(secretBuffer)); + const key = new Uint8Array(keyBuffer.buffer, 0, 32); + const iv = new Uint8Array(keyBuffer.buffer, 32, 12); + + const ct = Buffer.from(data.ct, 'base64'); + + const payload = BSON.deserialize(Buffer.from(await AES_GCM_Decrypt(key, iv, ct))) as T satisfies DecryptedSimpleItem>; + return payload; +} \ No newline at end of file diff --git a/@sammo/secure_token/src/SecureToken.ts b/@sammo/secure_token/src/SecureToken.ts new file mode 100644 index 0000000..6845f61 --- /dev/null +++ b/@sammo/secure_token/src/SecureToken.ts @@ -0,0 +1,225 @@ +import { AES_GCM_Decrypt, AES_GCM_Encrypt } from "@sammo/crypto/AES"; +import { Buffer } from "buffer"; +import { sha512 } from "@sammo/crypto/SHA2"; +import { BSON } from "bson"; +import { type Bsonifiable, bsonify, type JsonifiableObj } from '@sammo/util'; +import { type Jsonifiable, jsonify } from '@sammo/util'; + +const crypto = globalThis.crypto; + +/** + * Preshared Token Secret을 이용한 AES256-GCM 토큰 + * key, iv = SHA512(presharedSecret + nonce) 으로 생성 + */ + +export type SecureEncryptedToken = { + nonce: string; // [key, iv] = SHA512(presharedSecret + nonce) + encrypted: 1; + type: string; // aad[0] + validUntil: string; // aad[1] + payload: string; //BASE64(AES(BSON(aad),BSON(payload))) +} + +export type SecurePlaintextToken = { + nonce: string; // [key, iv] = SHA512(presharedSecret + nonce) + encrypted: 0; + type: string; // aad[0] + validUntil: string; // aad[1] + payload: string; // JSON => aad[2] + tag: string; //BASE64(AES(BSON(aad),null))) +} + +export type SecureToken = SecureEncryptedToken | SecurePlaintextToken; + +const staticPresharedTokenSecret: string | undefined = process.env.PRESHARED_SECURE_TOKEN_SECRET; + +type secureTokenAAD = { + type: string; + validUntilText: string; +} +type plaintextTokenAAD = { + type: string; + validUntilText: string; + jsonPayload: string; +} + +export async function generateSecureEncryptedToken(validUntil: Date, type: string, payload: T, presharedTokenSecret?: string): Promise { + if (!presharedTokenSecret) { + if (!staticPresharedTokenSecret) { + throw new Error("PRESHARED_SECURE_TOKEN_SECRET is not set"); + } + presharedTokenSecret = staticPresharedTokenSecret; + } + + const secretLength = Buffer.byteLength(presharedTokenSecret, 'utf8'); + const secretBuffer = Buffer.alloc(secretLength + 16); + secretBuffer.write(presharedTokenSecret, 0, secretLength, 'utf8'); + + //secretBuffer에서 Buffer를 바로 준비해도 되지만, 혹시모를 안전상의 이유로 별도로 할당하고 복사 + const nonce = Buffer.from(crypto.getRandomValues(new Uint8Array(16))); + secretBuffer.set(nonce, secretLength); + + const keyBuffer = Buffer.from(await sha512(secretBuffer)); + + const key = new Uint8Array(keyBuffer.buffer, 0, 32); + const iv = new Uint8Array(keyBuffer.buffer, 32, 12); + + const validUntilText = validUntil.toISOString(); + + const aad: secureTokenAAD = { + type, validUntilText + }; + + const aadRaw = BSON.serialize(aad); + const payloadRaw = BSON.serialize(bsonify(payload as Record)); + + const ciphertext = Buffer.from(await AES_GCM_Encrypt(key, iv, payloadRaw, aadRaw)); + + return { + nonce: nonce.toString('base64'), + encrypted: 1, + type, + validUntil: validUntilText, + payload: ciphertext.toString('base64'), + } +} + +export async function parseSecureEncryptedToken(secureToken: SecureEncryptedToken, presharedTokenSecret?: string): Promise { + const now = new Date(); + const validUntil = new Date(secureToken.validUntil); + if (now > validUntil) { + throw new Error("token expired"); + } + + if (!secureToken.encrypted) { + throw new Error("token is not encrypted"); + } + + if (!presharedTokenSecret) { + if (!staticPresharedTokenSecret) { + throw new Error("PRESHARED_SECURE_TOKEN_SECRET is not set"); + } + presharedTokenSecret = staticPresharedTokenSecret; + } + + const secretLength = Buffer.byteLength(presharedTokenSecret, 'utf8'); + const secretBuffer = Buffer.alloc(secretLength + 16); + secretBuffer.write(presharedTokenSecret, 0, secretLength, 'utf8'); + + const nonce = Buffer.from(secureToken.nonce, 'base64'); + secretBuffer.set(nonce, secretLength); + + const keyBuffer = Buffer.from(await sha512(secretBuffer)); + const key = new Uint8Array(keyBuffer.buffer, 0, 32); + const iv = new Uint8Array(keyBuffer.buffer, 32, 12); + + const aad: secureTokenAAD = { type: secureToken.type, validUntilText: secureToken.validUntil }; + + const aadRaw = BSON.serialize(aad); + const payloadCiphertext = Buffer.from(secureToken.payload, 'base64'); + + const payloadRaw = new Uint8Array(await AES_GCM_Decrypt(key, iv, payloadCiphertext, aadRaw)); + const payload = BSON.deserialize(payloadRaw); + + return payload as T; +} + +export async function generateSecurePlaintextToken(validUntil: Date, type: string, payload: T, presharedTokenSecret?: string): Promise { + if (!presharedTokenSecret) { + if (!staticPresharedTokenSecret) { + throw new Error("PRESHARED_SECURE_TOKEN_SECRET is not set"); + } + presharedTokenSecret = staticPresharedTokenSecret; + } + + const secretLength = Buffer.byteLength(presharedTokenSecret, 'utf8'); + const secretBuffer = Buffer.alloc(secretLength + 16); + secretBuffer.write(presharedTokenSecret, 0, secretLength, 'utf8'); + + //secretBuffer에서 Buffer를 바로 준비해도 되지만, 혹시모를 안전상의 이유로 별도로 할당하고 복사 + const nonce = Buffer.from(crypto.getRandomValues(new Uint8Array(16))); + secretBuffer.set(nonce, secretLength); + + const keyBuffer = Buffer.from(await sha512(secretBuffer)); + + const key = new Uint8Array(keyBuffer.buffer, 0, 32); + const iv = new Uint8Array(keyBuffer.buffer, 32, 12); + + const validUntilText = validUntil.toISOString(); + const jsonPayload = JSON.stringify(jsonify(payload as Record)); + + const aad: plaintextTokenAAD = { type, validUntilText, jsonPayload }; + const aadRaw = BSON.serialize(aad); + + const dummyPayload = new ArrayBuffer(0); + + const tag = Buffer.from(await AES_GCM_Encrypt(key, iv, dummyPayload, aadRaw)); + + return { + nonce: nonce.toString('base64'), + encrypted: 0, + type, + validUntil: validUntilText, + payload: jsonPayload, + tag: tag.toString('base64'), + } +} + +export async function parseSecurePlaintextToken(secureToken: SecurePlaintextToken, presharedTokenSecret?: string): Promise { + const now = new Date(); + const validUntil = new Date(secureToken.validUntil); + if (now > validUntil) { + throw new Error("token expired"); + } + + if (!presharedTokenSecret) { + if (!staticPresharedTokenSecret) { + throw new Error("PRESHARED_SECURE_TOKEN_SECRET is not set"); + } + presharedTokenSecret = staticPresharedTokenSecret; + } + + if (secureToken.encrypted) { + throw new Error("token is encrypted"); + } + + const secretLength = Buffer.byteLength(presharedTokenSecret, 'utf8'); + const secretBuffer = Buffer.alloc(secretLength + 16); + secretBuffer.write(presharedTokenSecret, 0, secretLength, 'utf8'); + + const nonce = Buffer.from(secureToken.nonce, 'base64'); + secretBuffer.set(nonce, secretLength); + + const keyBuffer = Buffer.from(await sha512(secretBuffer)); + const key = new Uint8Array(keyBuffer.buffer, 0, 32); + const iv = new Uint8Array(keyBuffer.buffer, 32, 12); + + const aad: plaintextTokenAAD = { + type: secureToken.type, + validUntilText: secureToken.validUntil, + jsonPayload: secureToken.payload + }; + const aadRaw = BSON.serialize(aad); + + const tag = Buffer.from(secureToken.tag, 'base64'); + + await AES_GCM_Decrypt(key, iv, tag, aadRaw); + + return JSON.parse(secureToken.payload); +} + +export async function generateSecureToken(encrypted: boolean, validUntil: Date, type: string, payload: T, presharedTokenSecret?: string): Promise { + if (encrypted) { + return await generateSecureEncryptedToken(validUntil, type, payload, presharedTokenSecret); + } else { + return await generateSecurePlaintextToken(validUntil, type, payload, presharedTokenSecret); + } +} + +export async function parseSecureToken(secureToken: SecureToken, presharedTokenSecret?: string): Promise { + if (secureToken.encrypted) { + return await parseSecureEncryptedToken(secureToken, presharedTokenSecret); + } else { + return await parseSecurePlaintextToken(secureToken, presharedTokenSecret); + } +} \ No newline at end of file diff --git a/@sammo/secure_token/src/index.ts b/@sammo/secure_token/src/index.ts new file mode 100644 index 0000000..15020f0 --- /dev/null +++ b/@sammo/secure_token/src/index.ts @@ -0,0 +1,4 @@ +export * from "./SecureToken.js" +export * from "./zodSecureToken.js" + +export * from "./EncryptedSimple.js" \ No newline at end of file diff --git a/@sammo/secure_token/src/zodSecureToken.ts b/@sammo/secure_token/src/zodSecureToken.ts new file mode 100644 index 0000000..5f29a99 --- /dev/null +++ b/@sammo/secure_token/src/zodSecureToken.ts @@ -0,0 +1,52 @@ +import { z } from "zod"; +import type { SecureEncryptedToken, SecurePlaintextToken } from "./SecureToken.js"; + +export function zodEncryptedSecureToken(type?: string) { + const obj = z.object({ + nonce: z.string(), + encrypted: z.literal(1), + type: z.string(), + validUntil: z.string().datetime(), + payload: z.string(), + }).refine((v) => { + const validUntil = new Date(v.validUntil); + const now = new Date(); + return validUntil > now; + + }, "token expired" + // eslint-disable-next-line @typescript-eslint/no-explicit-any + ) satisfies z.ZodType; + + if (type) { + return obj.refine((v) => { + return v.type === type; + }, "token type mismatch") + } + + return obj; +} + +export function zodPlaintextSecureToken(type: string) { + const obj = z.object({ + nonce: z.string(), + encrypted: z.literal(0), + type: z.string(), + validUntil: z.string().datetime(), + payload: z.string(), + tag: z.string(), + }).refine((v) => { + const validUntil = new Date(v.validUntil); + const now = new Date(); + return validUntil > now; + }, "token expired" + // eslint-disable-next-line @typescript-eslint/no-explicit-any + ) satisfies z.ZodType; + + if (type) { + return obj.refine((v) => { + return v.type === type; + }, "token type mismatch") + } + + return obj; +} \ No newline at end of file diff --git a/@sammo/secure_token/tsconfig.json b/@sammo/secure_token/tsconfig.json new file mode 100644 index 0000000..12c3359 --- /dev/null +++ b/@sammo/secure_token/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist", + }, + "references": [ + { + "path": "../util" + }, + { + "path": "../crypto" + }, + ] +} diff --git a/@sammo/server/package.json b/@sammo/server/package.json new file mode 100644 index 0000000..7da8f67 --- /dev/null +++ b/@sammo/server/package.json @@ -0,0 +1,37 @@ +{ + "name": "@sammo/server", + "version": "1.0.0", + "description": "", + "main": "dist/index.js", + "scripts": { + "build": "tsc --build" + }, + "author": "", + "type": "module", + "license": "MIT", + "dependencies": { + "@esfx/async-readerwriterlock": "^1.0.0", + "@sammo/api_def": "workspace:^", + "@sammo/game_logic": "workspace:^", + "@sammo/server_util": "workspace:^", + "@sammo/util": "workspace:^", + "@strpc/express": "workspace:^", + "date-fns": "^2.30.0", + "dotenv": "^16.3.1", + "eventemitter3": "^5.0.1", + "express": "^4.18.2", + "express-session": "^1.17.3", + "ky": "^1.0.1", + "lodash-es": "^4.17.21", + "mongoose": "^7.4.3", + "reflect-metadata": "^0.1.13", + "tslib": "^2.6.2", + "zod": "^3.22.2" + }, + "devDependencies": { + "@types/express": "^4.17.17", + "@types/express-session": "^1.17.7", + "@sammo/gateway_server": "workspace:^", + "@types/node": "^20.6.3" + } +} diff --git a/@sammo/server/src/MongoSequence.ts b/@sammo/server/src/MongoSequence.ts new file mode 100644 index 0000000..008d4a0 --- /dev/null +++ b/@sammo/server/src/MongoSequence.ts @@ -0,0 +1,25 @@ +import type { StateIncrementer } from '@sammo/server_util'; +import SchemaSequence from './schema/SchemaSequence.js'; +import { InvalidArgument } from '@sammo/util'; + +export function MongoSequenceFactory(collectionName: string): StateIncrementer{ + + return async (increase: number) => { + if(increase <= 0){ + throw new InvalidArgument('increase must be > 0'); + } + increase = Math.ceil(increase); + + const result = await SchemaSequence.findOneAndUpdate({ + collectionName, + }, { + $inc: { + nextSeq: increase, + }, + }, { + upsert: true, + new: true, + }); + return result.nextSeq; + } +} \ No newline at end of file diff --git a/@sammo/server/src/api/index.ts b/@sammo/server/src/api/index.ts new file mode 100644 index 0000000..c0fead8 --- /dev/null +++ b/@sammo/server/src/api/index.ts @@ -0,0 +1,5 @@ +import type { structure } from "@sammo/api_def"; +import type { APINamespaceType } from "@strpc/express"; + +export const sammoAPI = { +} satisfies APINamespaceType; \ No newline at end of file diff --git a/@sammo/server/src/connectDB.ts b/@sammo/server/src/connectDB.ts new file mode 100644 index 0000000..ab33459 --- /dev/null +++ b/@sammo/server/src/connectDB.ts @@ -0,0 +1,22 @@ +import 'dotenv/config'; +import { connect, Mongoose } from "mongoose"; +import { unwrap } from '@sammo/util'; + +const dbConfig = { + host: unwrap(process.env.GAME_DB_HOST), + port: Number(unwrap(process.env.GAME_DB_PORT)), + user: unwrap(process.env.GAME_DB_USER), + password: unwrap(process.env.GAME_DB_PASSWORD), + database: unwrap(process.env.GAME_DB_DATABASE), +} + +const db: Promise = (async () => { + return await connect(`mongodb://${dbConfig.host}:${dbConfig.port}/${dbConfig.database}`, { + auth:{ + username: dbConfig.user, + password: dbConfig.password, + } + }); +})(); + +export default db; \ No newline at end of file diff --git a/@sammo/server/src/constPath.ts b/@sammo/server/src/constPath.ts new file mode 100644 index 0000000..f00e15f --- /dev/null +++ b/@sammo/server/src/constPath.ts @@ -0,0 +1,3 @@ +import { resolve } from "node:path"; + +export const rootPath = resolve(resolve(), '../..'); \ No newline at end of file diff --git a/@sammo/server/src/dotenv.d.ts b/@sammo/server/src/dotenv.d.ts new file mode 100644 index 0000000..1ccbc5a --- /dev/null +++ b/@sammo/server/src/dotenv.d.ts @@ -0,0 +1,32 @@ +declare namespace NodeJS { + interface ProcessEnv { + NODE_ENV: 'development' | 'production'; + + //Docker 환경이라면 GAME_DB 또는 GATEWAY_DB 둘중에 하나만 설정되어 있을 것이다. + GAME_DB_HOST?: string; + GAME_DB_DATABASE?: string; + GAME_DB_PORT?: string; + GAME_DB_USER?: string; + GAME_DB_PASSWORD?: string; + + GATEWAY_DB_HOST?: string; + GATEWAY_DB_DATABASE?: string; + GATEWAY_DB_PORT?: string; + GATEWAY_DB_USER?: string; + GATEWAY_DB_PASSWORD?: string; + + //Gateway RPC용 + GATEWAY_HOST?: string; + GATEWAY_PORT?: string; + //gateway.ts용 + GATEWAY_SESSION_SECRET?: string; + + SERVER_PORT?: string; //숫자 + SESSION_SECRET?: string; //길게 + + API_ROOT_PATH?: string; + VITE_API_ROOT_PATH?: string; + + PRESHARED_SECURE_TOKEN_SECRET?: string; //길게 + } +} \ No newline at end of file diff --git a/@sammo/server/src/dotenv.ts b/@sammo/server/src/dotenv.ts new file mode 100644 index 0000000..ccebd03 --- /dev/null +++ b/@sammo/server/src/dotenv.ts @@ -0,0 +1,49 @@ +import dotenv from 'dotenv'; +import { rootPath } from './constPath.js'; +import { unwrap } from '@sammo/util'; + +let init = false; +const dirPath = rootPath +console.log(rootPath); + +function initDotEnv() { + if (process.env['NODE_ENV'] == 'production') { + dotenv.config({ path: `${dirPath}/.env.production.local` }); + dotenv.config({ path: `${dirPath}/.env.local` }); + dotenv.config({ path: `${dirPath}/.env.production` }); + } + else { + dotenv.config({ path: `${dirPath}/.env.development.local` }); + dotenv.config({ path: `${dirPath}/.env.local` }); + dotenv.config({ path: `${dirPath}/.env.development` }); + } + dotenv.config(); + init = true; +} + +if (!init) { + initDotEnv(); +} + +let _ownConfig: ReturnType|undefined = undefined; + +function generateConfig() { + return { + port: parseInt(process.env['SERVER_PORT'] ?? "3001"), + sessionSecret: unwrap(process.env['SESSION_SECRET']), + gatewayHost: unwrap(process.env.GATEWAY_HOST), + gatewayPort: Number(unwrap(process.env.GATEWAY_PORT)), + apiRootPath: process.env['API_ROOT_PATH'] ?? '/api', + } as const; +} + +export function serverConfig() { + if(_ownConfig !== undefined){ + return _ownConfig; + } + if(!init){ + initDotEnv(); + } + _ownConfig = generateConfig(); + return _ownConfig; +} diff --git a/@sammo/server/src/index.ts b/@sammo/server/src/index.ts new file mode 100644 index 0000000..0bca319 --- /dev/null +++ b/@sammo/server/src/index.ts @@ -0,0 +1,31 @@ +import './dotenv.js' +import 'reflect-metadata'; +import connectDB from './connectDB.js'; +import express, { type Request, type Response } from "express" +import session from "express-session"; +import { buildAPISystem } from '@strpc/express/generator'; +import { sammoAPI } from './api/index.js'; +import { unwrap } from '@sammo/util';; +import { serverConfig } from './serverConfig.js'; + +connectDB.then(async (db) => { + // create express app + const app = express() + app.use(express.json()); + app.use(session({ + secret: unwrap(serverConfig.sessionSecret), + resave: false, + saveUninitialized: false, + })) + //app.set('etag', false); + + app.use('/api', buildAPISystem(sammoAPI)); + + // start express server + app.listen(serverConfig.port) + + console.log(`Express server has started on port ${serverConfig.port}`) + +}).catch(error => console.log(error)); + +export default {}; \ No newline at end of file diff --git a/@sammo/server/src/procDecorator/ReqGameLogin.ts b/@sammo/server/src/procDecorator/ReqGameLogin.ts new file mode 100644 index 0000000..850ee1a --- /dev/null +++ b/@sammo/server/src/procDecorator/ReqGameLogin.ts @@ -0,0 +1,36 @@ +import type { SessionCtx } from "@sammo/server_util"; +import type { LoginCtx } from "./ReqLogin.js"; +import type { ProcDecoratorGenerator } from "@strpc/express/proc_decorator"; + +export type GameLoginCtx = { + generalID: number; + generalName: string; + gameLoginDate: Date; +} + +export function ReqGameLogin(): ProcDecoratorGenerator { + return async (ctx) => { + //NOTE: 게임 서버별로 gameLoginCtx를 따로 가져야 하는가? + let gameLoginCtx = ctx.session.getItem(`gameLoginCtx`); + if (gameLoginCtx) { + if (gameLoginCtx.gameLoginDate >= ctx.loginDate) { + return [{ + result: true, + }, { + ...gameLoginCtx, + ...ctx, + }]; + } + gameLoginCtx = undefined; + } + + //TODO: DB에서 generalID를 가져오는 로직 + return [{ + result: false, + type: 'Required GameLogin', + info: 'NotYetImplemented' + }, { + ...ctx + }]; + } +} \ No newline at end of file diff --git a/@sammo/server/src/procDecorator/ReqLogin.ts b/@sammo/server/src/procDecorator/ReqLogin.ts new file mode 100644 index 0000000..c3f3c84 --- /dev/null +++ b/@sammo/server/src/procDecorator/ReqLogin.ts @@ -0,0 +1,32 @@ +import type { SessionCtx } from "@sammo/server_util"; +import type { ProcDecorator } from "@strpc/express/proc_decorator"; +import type { ServerActionType } from "@sammo/gateway_server/exports" + +export type LoginCtx = { + userID: number; + userName: string; + userLevel: number; + allowServerAction?: Set; + loginDate: Date; +} +export const loginCtxSessionKey = 'loginCtx'; + +export function ReqLogin(): ProcDecorator { + return (ctx) => { + const loginCtx = ctx.session.getItem(loginCtxSessionKey); + if(!loginCtx){ + return [{ + result: false, + type: 'Required Login', + info: 'ReqLogin' + }, ctx]; + } + + return [{ + result: true, + },{ + ...loginCtx, + ...ctx, + }]; + } +} \ No newline at end of file diff --git a/@sammo/server/src/schema/SchemaSequence.ts b/@sammo/server/src/schema/SchemaSequence.ts new file mode 100644 index 0000000..2c6e2e2 --- /dev/null +++ b/@sammo/server/src/schema/SchemaSequence.ts @@ -0,0 +1,23 @@ +import { Schema, model, Types } from 'mongoose'; + +interface ISchemaSequence { + _id: Types.ObjectId; + + collectionName: string; + nextSeq: number; +} + +export const SchemaSequence = new Schema({ + collectionName: { type: String, required: true }, + nextSeq: { + type: Number, required: true, + get: (v: number) => Math.ceil(v), + set: (v: number) => Math.ceil(v), + default: 0, + }, + +}, { autoIndex: true, autoCreate: true }) + .index({ collectionName: 1 }, { unique: true }) + ; + +export default model('SchemaSequence', SchemaSequence); \ No newline at end of file diff --git a/@sammo/server/src/serverConfig.ts b/@sammo/server/src/serverConfig.ts new file mode 100644 index 0000000..269afc6 --- /dev/null +++ b/@sammo/server/src/serverConfig.ts @@ -0,0 +1,9 @@ +import 'dotenv/config'; +import { unwrap } from '@sammo/util'; + +export const serverConfig = { + sessionSecret: unwrap(process.env.SESSION_SECRET), + port: Number(unwrap(process.env.SERVER_PORT)), + gatewayHost: unwrap(process.env.GATEWAY_HOST), + gatewayPort: Number(unwrap(process.env.GATEWAY_PORT)), +}; diff --git a/@sammo/server/tsconfig.json b/@sammo/server/tsconfig.json new file mode 100644 index 0000000..4183b97 --- /dev/null +++ b/@sammo/server/tsconfig.json @@ -0,0 +1,30 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist", + "paths": { + "@/*": ["./src/*"] + } + }, + "references": [ + { + "path": "../../@strpc/express" + }, + { + "path": "../util" + }, + { + "path": "../crypto" + }, + { + "path": "../server_util" + }, + { + "path": "../api_def" + }, + { + "path": "../gateway_server" + } + ] +} diff --git a/@sammo/server_util/package.json b/@sammo/server_util/package.json new file mode 100644 index 0000000..3131d02 --- /dev/null +++ b/@sammo/server_util/package.json @@ -0,0 +1,25 @@ +{ + "name": "@sammo/server_util", + "version": "1.0.0", + "description": "", + "main": "dist/index.js", + "scripts": { + "build": "tsc --build" + }, + "type": "module", + "keywords": [], + "author": "", + "license": "MIT", + "dependencies": { + "@sammo/api_def": "workspace:^", + "@sammo/util": "workspace:^", + "@strpc/express": "workspace:^" + }, + "devDependencies": { + "@types/express-session": "^1.17.7", + "lodash-es": "^4.17.21" + }, + "peerDependencies": { + "lodash-es": "^4.17.21" + } +} \ No newline at end of file diff --git a/@sammo/server_util/src/StartSession.ts b/@sammo/server_util/src/StartSession.ts new file mode 100644 index 0000000..ae23a35 --- /dev/null +++ b/@sammo/server_util/src/StartSession.ts @@ -0,0 +1,58 @@ +import type { Empty, ProcDecoratorGenerator } from "@strpc/express/proc_decorator"; +import type { Session, SessionData } from "express-session"; + +export type SessionCtx = { + session: { + clear: () => Promise; + removeItem: (key: string) => boolean; + getItem: (key: string) => T | undefined; + setItem: (key: string, value: unknown) => void; + raw: Session & Partial & Record; + } +} + +export function StartSession(): ProcDecoratorGenerator { + return (inCtx, req) => { + if (!req.session) { + throw 'Express-session required'; + } + const sessionObj = { + raw: req.session + } as SessionCtx['session']; + sessionObj.clear = () => { + return new Promise((resolve) => { + sessionObj.raw = req.session.regenerate(resolve) as SessionCtx['session']['raw']; + }) + } + sessionObj.removeItem = (key: string): boolean => { + if (key in sessionObj.raw) { + delete sessionObj.raw[key]; + return true; + } + return false; + } + sessionObj.getItem = (key: string): T | undefined => { + if (!(key in sessionObj.raw)) { + return undefined; + } + return sessionObj.raw[key] as T; + } + sessionObj.setItem = (key: string, value: T | undefined): void => { + if (value === undefined) { + sessionObj.removeItem(key); + return; + } + sessionObj.raw[key] = value; + } + + return [ + { + result: true, + }, + { + session: sessionObj, + ...inCtx, + } + ] + } +} \ No newline at end of file diff --git a/@sammo/server_util/src/UniqueNumberAllocator.ts b/@sammo/server_util/src/UniqueNumberAllocator.ts new file mode 100644 index 0000000..d1c1165 --- /dev/null +++ b/@sammo/server_util/src/UniqueNumberAllocator.ts @@ -0,0 +1,198 @@ +export interface StateIncrementer { + (increase: number): Promise; +} + +export type NumberGroup = { + start: number; + remain: number; +} + +const AllocatorGroupBucketSize = 100; +const AllocatorPreserveThreshold = 50; + +export function* numberGenerator(numberGroups: NumberGroup[]): Generator { + for (const numberGroup of numberGroups) { + for (let i = 0; i < numberGroup.remain; i++) { + yield numberGroup.start + i; + } + } + return null; +} + +export class UniqueNumberAllocator { + private preservedNumbers: NumberGroup[]; + private incrementer: StateIncrementer; + private totalRemain: number; + private promisedCnt: number; + private promise: Promise; + + public constructor(incrementer: StateIncrementer, initialState?: NumberGroup) { + this.incrementer = incrementer; + if (!initialState) { + this.preservedNumbers = []; + this.totalRemain = 0; + } + else { + if (initialState.remain < 1) { + throw new Error('initialState.remain must be greater than 0'); + } + this.preservedNumbers = [initialState]; + this.totalRemain = initialState.remain; + } + this.promisedCnt = 0; + this.promise = Promise.resolve(); + this.preserveNext(); + } + + public static async generate(incrementer: StateIncrementer): Promise { + const initialStateEnd = await incrementer(AllocatorGroupBucketSize); + const initialState: NumberGroup = { + start: initialStateEnd - AllocatorGroupBucketSize + 1, + remain: AllocatorGroupBucketSize, + } + return new UniqueNumberAllocator(incrementer, initialState); + } + + private preserveNext(): void { + if (this.promisedCnt + this.totalRemain >= AllocatorGroupBucketSize) { + return; + } + + if (this.totalRemain >= AllocatorPreserveThreshold) { + return; + } + + const waiter = this.promise; + + this.promise = (async () => { + this.promisedCnt += AllocatorGroupBucketSize; + const nextP = this.incrementer(AllocatorGroupBucketSize); + await waiter; + const next = await nextP; + if (this.preservedNumbers.length > 0) { + const last = this.preservedNumbers[this.preservedNumbers.length - 1]; + if (last.start + last.remain === next - AllocatorGroupBucketSize + 1) { + // 마지막 그룹과 연속됨 + last.remain += AllocatorGroupBucketSize; + this.totalRemain += AllocatorGroupBucketSize; + this.promisedCnt -= AllocatorGroupBucketSize; + return; + } + } + const nextGroup: NumberGroup = { + start: next - AllocatorGroupBucketSize + 1, + remain: AllocatorGroupBucketSize, + } + this.preservedNumbers.push(nextGroup); + this.totalRemain += AllocatorGroupBucketSize; + this.promisedCnt -= AllocatorGroupBucketSize; + })(); + } + + public async allocateOne(): Promise { + if (this.totalRemain > 0) { + const head = this.preservedNumbers[0]; + if (head.remain > 1) { + const next = head.start; + head.start++; + head.remain--; + this.totalRemain--; + this.preserveNext(); + return next; + } + else { + this.preservedNumbers.shift(); + this.totalRemain--; + this.preserveNext(); + return head.start; + } + } + + const next = (await this.allocate(1)).next().value; + if (next === null) { + throw new Error('incrementer failed to allocate enough numbers'); + } + return next; + } + + public async allocate(n: number): Promise> { + n = Math.ceil(n); + if (n < 1) { + throw new Error('n must be greater than 0'); + } + + if (n > this.totalRemain + this.promisedCnt) { + const endP = this.incrementer(n); + this.preserveNext(); + const end = await endP; + + return numberGenerator([{ + start: end - n + 1, + remain: n, + }]); + } + + const result: NumberGroup[] = []; + + if (this.totalRemain > 0) { + const head = this.preservedNumbers[0]; + const headRemain = head.remain; + + if (n < headRemain) { + result.push({ + start: head.start, + remain: n, + }); + head.start += n; + head.remain -= n; + this.totalRemain -= n; + this.preserveNext(); + return numberGenerator(result); + } + if (n === headRemain) { + this.preservedNumbers.shift(); + result.push(head); + this.totalRemain -= n; + this.preserveNext(); + return numberGenerator(result); + } + + } + + //assert n <= this.totalRemain + this.promisedRemain + + if (n > this.totalRemain) { + await this.promise; + if (n > this.totalRemain) { + throw new Error('incrementer failed to allocate enough numbers'); + } + } + + this.totalRemain -= n; + this.preserveNext(); + + let remain = n; + let idx = 0; + while (remain > 0) { + const head = this.preservedNumbers[idx]; + if (head.remain <= remain) { + remain -= head.remain; + result.push(head); + idx++; + continue; + } + + result.push({ + start: head.start, + remain: remain, + }); + head.start += remain; + head.remain -= remain; + remain = 0; + break; + } + this.preservedNumbers = this.preservedNumbers.slice(idx); + + return numberGenerator(result); + } +} \ No newline at end of file diff --git a/@sammo/server_util/src/index.ts b/@sammo/server_util/src/index.ts new file mode 100644 index 0000000..8c59361 --- /dev/null +++ b/@sammo/server_util/src/index.ts @@ -0,0 +1,2 @@ +export { UniqueNumberAllocator, type StateIncrementer } from './UniqueNumberAllocator.js'; +export * from './StartSession.js'; \ No newline at end of file diff --git a/@sammo/server_util/tsconfig.json b/@sammo/server_util/tsconfig.json new file mode 100644 index 0000000..14f4d10 --- /dev/null +++ b/@sammo/server_util/tsconfig.json @@ -0,0 +1,36 @@ +{ + "compilerOptions": { + "target": "ESNext", + "module": "node16", + "moduleResolution": "node16", + "resolveJsonModule": true, + "declaration": true, + "declarationMap": true, + "importHelpers": true, + "isolatedModules": true, + "verbatimModuleSyntax": true, + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "noImplicitOverride": true, + "skipLibCheck": true, + "incremental": true, + "rootDir": "./src", + "outDir": "./dist", + "composite": true + }, + "references": [ + { + "path": "../../@strpc/express" + }, + { + "path": "../util" + }, + { + "path": "../crypto" + }, + ] +} diff --git a/@sammo/util/package.json b/@sammo/util/package.json new file mode 100644 index 0000000..59ee5b9 --- /dev/null +++ b/@sammo/util/package.json @@ -0,0 +1,28 @@ +{ + "name": "@sammo/util", + "version": "1.0.0", + "description": "", + "main": "dist/index.js", + "scripts": { + "build": "tsc --build" + }, + "exports": { + ".": "./dist/index.js", + "./converter": "./dist/converter/index.js", + "./datetime": "./dist/datetime/index.js", + "./korean": "./dist/korean/index.js", + "./josa_util": "./dist/korean/josa_util.js", + "./string": "./dist/string/index.js" + }, + "type": "module", + "keywords": [], + "author": "", + "license": "MIT", + "devDependencies": { + "@types/node": "^20.6.3", + "lodash-es": "^4.17.21" + }, + "peerDependencies": { + "lodash-es": "^4.17.21" + } +} diff --git a/@sammo/util/src/bsonify.ts b/@sammo/util/src/bsonify.ts new file mode 100644 index 0000000..7215c39 --- /dev/null +++ b/@sammo/util/src/bsonify.ts @@ -0,0 +1,263 @@ +import { every, isString } from "lodash-es"; +import type { JsonifiableClassObj, PlainJson, PlainJsonObj } from "./jsonify.js"; + +type BsonifiableLite = string | number | boolean | bigint | null | undefined; + +export type PlainBsonItem = + string | number | boolean | null | undefined | + Date | ArrayBuffer | SharedArrayBuffer | ArrayBufferView | + PlainBsonItem[] | + { [key: string]: PlainBsonItem }; + +export type PlainBson = + { [key: string]: PlainBsonItem }; + +export type BsonifiableItem = + BsonifiableLite | + Date | ArrayBuffer | SharedArrayBuffer | ArrayBufferView | + Array | + Map | + Set | + BsonifiableClassObj | + JsonifiableClassObj | + { [key: string]: BsonifiableItem } | + ReadonlyArray; + +export type Bsonifiable = + Map | + BsonifiableClassObj | + JsonifiableClassObj | + { [key: string]: BsonifiableItem }; + + +export interface BsonifiableClassObj { + bsonify(): T; +} + +type MaybeBsonifiedItem = T extends BsonifiableItem ? BsonifiedItem : never; +type MaybeBsonified = T extends Bsonifiable ? Bsonified : never; + +export type BsonifiedItem = + T extends string ? T : + T extends number ? T : + T extends boolean ? T : + T extends bigint ? ReturnType : + T extends null ? T : + T extends undefined ? T : + T extends Date ? T : + T extends ArrayBuffer ? T : + T extends SharedArrayBuffer ? T : + T extends ArrayBufferView ? T : + T extends Map ? { [key in K]: MaybeBsonified } : + T extends Map ? [MaybeBsonified, MaybeBsonified][] : + T extends Set ? MaybeBsonified[] : + T extends BsonifiableClassObj ? ReturnType : + T extends JsonifiableClassObj ? ReturnType : + T extends object ? { [key in keyof T]: MaybeBsonified } : + T extends unknown ? unknown : + never; + +export type Bsonified = + T extends Map ? { [key in K]: MaybeBsonifiedItem } : + T extends BsonifiableClassObj ? ReturnType : + T extends JsonifiableClassObj ? ReturnType : + T extends object ? { [key in keyof T]: MaybeBsonifiedItem } : + T extends unknown ? unknown : + never; + +/** + * Convert any object to BSON-safe object + */ +export function bsonifyItem(item: T): BsonifiedItem { + if (typeof item === 'string' || typeof item === 'number' || typeof item === 'boolean') { + return item as BsonifiedItem; + } + + if (typeof item === 'bigint') { + return item.toString() as BsonifiedItem; + } + + if (typeof item === 'undefined') { + return item as BsonifiedItem; + } + + if (item === null) { + return item as BsonifiedItem; + } + + if (item instanceof Date) { + return item as BsonifiedItem; + } + + if (item instanceof ArrayBuffer) { + return item as BsonifiedItem; + } + + if ('SharedArrayBuffer' in globalThis && item instanceof SharedArrayBuffer) { + return item as BsonifiedItem; + } + + if (ArrayBuffer.isView(item)) { + return item as BsonifiedItem; + } + + //HACK: depth hack, escape ts(2589) + if (item instanceof Map) { + const onlyStringKey = every(item.keys, isString); + if (onlyStringKey) { + const result: { [key: string]: string } = {}; + for (const [k, v] of item.entries()) { + result[k as string] = bsonifyItem(v as string); + } + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return result as any; + } + + const result: [string, string][] = []; + for (const [k, v] of item.entries()) { + result.push([bsonifyItem(k as string), bsonifyItem(v as string)]); + } + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return result as any; + } + + if (item instanceof Set) { + const result: string[] = []; + for (const v of item.values()) { + result.push(bsonifyItem(v as string)); + } + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return result as any; + } + + if (Array.isArray(item)) { + const result: string[] = []; + for (const v of item) { + result.push(bsonifyItem(v as string)); + } + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return result as any; + } + + if (typeof item !== 'object') { + throw new Error(`jsonify: invalid type ${typeof item}`); + } + + if ('bsonify' in item && typeof item.bsonify === 'function') { + return item.bsonify() as BsonifiedItem; + } + + if ('jsonify' in item && typeof item.jsonify === 'function') { + return item.jsonify() as BsonifiedItem; + } + + const result: { [key: string]: unknown } = {}; + for (const [k, v] of Object.entries(item)) { + if (typeof k !== 'string') { + continue; + } + if (k === 'prototype') { + continue; + } + if (k === '__proto__ ') { + continue; + } + if (typeof v === 'function') { + continue; + } + result[k] = bsonifyItem(v as BsonifiableItem); + } + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return result as any; +} + +/** + * Convert any object to BSON-document object + */ +export function bsonify(item: T): Bsonified { + if (typeof item === 'string' || typeof item === 'number' || typeof item === 'boolean') { + throw new Error(`bsonify: invalid type ${typeof item}`); + } + + if (typeof item === 'bigint') { + throw new Error(`bsonify: invalid type ${typeof item}`); + } + + if (typeof item === 'undefined') { + throw new Error(`bsonify: invalid type ${typeof item}`); + } + + if (item === null) { + throw new Error(`bsonify: invalid type ${typeof item}`); + } + + if (item instanceof Date) { + throw new Error(`bsonify: invalid type ${typeof item}`); + } + + if (item instanceof ArrayBuffer) { + throw new Error(`bsonify: invalid type ${typeof item}`); + } + + if ('SharedArrayBuffer' in globalThis && item instanceof SharedArrayBuffer) { + throw new Error(`bsonify: invalid type ${typeof item}`); + } + + if (ArrayBuffer.isView(item)) { + throw new Error(`bsonify: invalid type ${typeof item}`); + } + + //HACK: depth hack, escape ts(2589) + if (item instanceof Map) { + const onlyStringKey = every(item.keys, isString); + if (onlyStringKey) { + const result: { [key: string]: unknown } = {}; + for (const [k, v] of item.entries()) { + result[k as string] = bsonifyItem(v as string); + } + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return result as any; + } + + throw new Error(`bsonify: invalid type ${typeof item}`); + } + + if (item instanceof Set) { + throw new Error(`bsonify: invalid type ${typeof item}`); + } + + if (Array.isArray(item)) { + throw new Error(`bsonify: invalid type ${typeof item}`); + } + + if (typeof item !== 'object') { + throw new Error(`jsonify: invalid type ${typeof item}`); + } + + if ('bsonify' in item && typeof item.bsonify === 'function') { + return item.bsonify() as Bsonified; + } + + if ('jsonify' in item && typeof item.jsonify === 'function') { + return item.jsonify() as Bsonified; + } + + const result: { [key: string]: unknown } = {}; + for (const [k, v] of Object.entries(item)) { + if (typeof k !== 'string') { + continue; + } + if (k === 'prototype') { + continue; + } + if (k === '__proto__ ') { + continue; + } + if (typeof v === 'function') { + continue; + } + result[k] = bsonifyItem(v); + } + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return result as any; +} \ No newline at end of file diff --git a/@sammo/util/src/converter/combineArray.ts b/@sammo/util/src/converter/combineArray.ts new file mode 100644 index 0000000..9facda0 --- /dev/null +++ b/@sammo/util/src/converter/combineArray.ts @@ -0,0 +1,11 @@ +import { combineObject } from "./combineObject.js"; + + +export function combineArray(array: V[][], columnList: K[]): Record[] { + const result: Record[] = []; + for (const key of array.keys()) { + const item = array[key]; + result[key] = combineObject(item, columnList); + } + return result; +} diff --git a/@sammo/util/src/converter/combineObject.ts b/@sammo/util/src/converter/combineObject.ts new file mode 100644 index 0000000..624dc18 --- /dev/null +++ b/@sammo/util/src/converter/combineObject.ts @@ -0,0 +1,8 @@ +export function combineObject(item: V[], columnList: K[]): Record { + const newItem: Record = {}; + for (const columnIdx in columnList) { + const columnName = columnList[columnIdx]; + newItem[columnName] = item[columnIdx]; + } + return newItem; +} \ No newline at end of file diff --git a/@sammo/util/src/converter/convertBytesLikeToUint8Array.ts b/@sammo/util/src/converter/convertBytesLikeToUint8Array.ts new file mode 100644 index 0000000..9e3ae06 --- /dev/null +++ b/@sammo/util/src/converter/convertBytesLikeToUint8Array.ts @@ -0,0 +1,28 @@ +import type { BytesLike, BufferSource } from "../types.js"; + +export function convertBytesLikeToUint8Array(data: string, encodeUTF8: boolean): Uint8Array; +export function convertBytesLikeToUint8Array(data: BufferSource | string): Uint8Array; +export function convertBytesLikeToUint8Array(data: BytesLike, encodeUTF8 = true): Uint8Array { + if (data instanceof Uint8Array) { + return data; + } + if (data instanceof ArrayBuffer) { + return new Uint8Array(data); + } + if (data instanceof SharedArrayBuffer) { + return new Uint8Array(data); + } + if (data instanceof Uint8Array) { + return data; + } + if (ArrayBuffer.isView(data)) { + return new Uint8Array(data.buffer, data.byteOffset, data.byteLength); + } + if (typeof (data) === 'string') { + if(encodeUTF8){ + return (new TextEncoder()).encode(data); + } + return new Uint8Array(data.split('').map(s=>s.codePointAt(0) as number)); + } + throw new Error(`Unknown data type ${typeof (data)}`); +} \ No newline at end of file diff --git a/@sammo/util/src/converter/convertIDArray.ts b/@sammo/util/src/converter/convertIDArray.ts new file mode 100644 index 0000000..df8b42b --- /dev/null +++ b/@sammo/util/src/converter/convertIDArray.ts @@ -0,0 +1,9 @@ +import type { IDItem } from "../types.js"; + +export function convertIDArray(array: Iterable): IDItem[] { + const result: IDItem[] = []; + for (const id of array) { + result.push({ id }); + } + return result; +} diff --git a/@sammo/util/src/converter/convertIterableToMap.ts b/@sammo/util/src/converter/convertIterableToMap.ts new file mode 100644 index 0000000..ad98f75 --- /dev/null +++ b/@sammo/util/src/converter/convertIterableToMap.ts @@ -0,0 +1,10 @@ +export function convertIterableToMap( + values: Iterable, + key: K +): Map { + const result = new Map(); + for (const obj of values) { + result.set(obj[key] as V, obj); + } + return result; +} diff --git a/@sammo/util/src/converter/entriesWithType.ts b/@sammo/util/src/converter/entriesWithType.ts new file mode 100644 index 0000000..66fb096 --- /dev/null +++ b/@sammo/util/src/converter/entriesWithType.ts @@ -0,0 +1,7 @@ +type Entries = { + [K in keyof T]: [K, T[K]]; +}[keyof T][]; + +export function entriesWithType(value: T): Entries{ + return Object.entries(value) as unknown as Entries; +} \ No newline at end of file diff --git a/@sammo/util/src/converter/index.ts b/@sammo/util/src/converter/index.ts new file mode 100644 index 0000000..d826ee1 --- /dev/null +++ b/@sammo/util/src/converter/index.ts @@ -0,0 +1,5 @@ +export * from "./combineObject.js"; +export * from "./combineArray.js"; +export * from "./convertBytesLikeToUint8Array.js"; +export * from "./convertIDArray.js"; +export * from "./convertIterableToMap.js" \ No newline at end of file diff --git a/@sammo/util/src/converter/merge2DArrToObjectArr.ts b/@sammo/util/src/converter/merge2DArrToObjectArr.ts new file mode 100644 index 0000000..c9f276d --- /dev/null +++ b/@sammo/util/src/converter/merge2DArrToObjectArr.ts @@ -0,0 +1,20 @@ + +import type { ValuesOf } from "../types.js"; +import { zip } from "lodash-es"; + +export function merge2DArrToObjectArr>(column: (keyof T)[], list: ValuesOf[][]): T[]{ + const result: T[] = []; + for(const rawItem of list){ + const item: Record = {}; + + if(column.length != rawItem.length){ + throw `column과 item의 길이가 같지 않습니다: ${column.length} != ${list.length}, ${JSON.stringify(item)}`; + } + + for(const [key, value] of zip(column, rawItem)){ + item[key as string] = value; + } + result.push(item as T); + } + return result; +} \ No newline at end of file diff --git a/@sammo/util/src/converter/mergeKVArray.ts b/@sammo/util/src/converter/mergeKVArray.ts new file mode 100644 index 0000000..92c19d1 --- /dev/null +++ b/@sammo/util/src/converter/mergeKVArray.ts @@ -0,0 +1,35 @@ +import { isString } from "lodash-es"; + +interface NameValuePair { + name: string, + value: string +} + +export function mergeKVArray(array : NameValuePair[]):Record{ + const result:Record = {}; + + for(const {name, value} of array){ + if(!isString(name)){ + throw new TypeError(`${name} is not string`); + } + if(!isString(value)){ + throw new TypeError(`${value} is not string`); + } + + if(name === '' || name === '[]'){ + continue; + } + if(name.length > 2 && name.slice(-2) == '[]'){ + const keyHead = name.slice(0, -2); + if(!(keyHead in result)){ + result[keyHead] = [value]; + } + else{ + (result[keyHead] as string[]).push(value); + } + continue; + } + result[name] = value; + } + return result; +} \ No newline at end of file diff --git a/@sammo/util/src/datetime/formatTime.ts b/@sammo/util/src/datetime/formatTime.ts new file mode 100644 index 0000000..3a3d0d5 --- /dev/null +++ b/@sammo/util/src/datetime/formatTime.ts @@ -0,0 +1,18 @@ +import { format, formatISO9075 } from 'date-fns'; +//const DATE_TIME_FORMAT = 'yyyy-MM-dd HH:mm:ss'; +const DATE_TIME_FORMAT_WITH_FRACTION = 'yyyy-MM-dd HH:mm:ss.SSS'; + +export function formatTime(time: Date, withFraction?:boolean): string; +export function formatTime(time: Date, format:string): string; + +export function formatTime(time: Date, withFractionOrFormat:string|boolean = false): string { + if (typeof withFractionOrFormat === "string") { + return format(time, withFractionOrFormat); + } + else if(withFractionOrFormat){ + return format(time, DATE_TIME_FORMAT_WITH_FRACTION); + } + else { + return formatISO9075(time); + } +} \ No newline at end of file diff --git a/@sammo/util/src/datetime/getDateTimeNow.ts b/@sammo/util/src/datetime/getDateTimeNow.ts new file mode 100644 index 0000000..442d6e7 --- /dev/null +++ b/@sammo/util/src/datetime/getDateTimeNow.ts @@ -0,0 +1,4 @@ +import { formatTime } from './formatTime.js'; +export function getDateTimeNow(withFraction = false): string { + return formatTime(new Date(), withFraction); +} \ No newline at end of file diff --git a/@sammo/util/src/datetime/index.ts b/@sammo/util/src/datetime/index.ts new file mode 100644 index 0000000..da6aacc --- /dev/null +++ b/@sammo/util/src/datetime/index.ts @@ -0,0 +1,3 @@ +export * from "./formatTime.js"; +export * from "./parseTime.js"; +export * from "./parseYearMonth.js"; \ No newline at end of file diff --git a/@sammo/util/src/datetime/joinYearMonth.ts b/@sammo/util/src/datetime/joinYearMonth.ts new file mode 100644 index 0000000..f06a954 --- /dev/null +++ b/@sammo/util/src/datetime/joinYearMonth.ts @@ -0,0 +1,3 @@ +export function joinYearMonth(year: number, month: number): number { + return year * 12 + month - 1; +} \ No newline at end of file diff --git a/@sammo/util/src/datetime/parseTime.ts b/@sammo/util/src/datetime/parseTime.ts new file mode 100644 index 0000000..e90f9ce --- /dev/null +++ b/@sammo/util/src/datetime/parseTime.ts @@ -0,0 +1,5 @@ +import {parseISO} from 'date-fns'; + +export function parseTime(dateString: string): Date{ + return parseISO(dateString); +} \ No newline at end of file diff --git a/@sammo/util/src/datetime/parseYearMonth.ts b/@sammo/util/src/datetime/parseYearMonth.ts new file mode 100644 index 0000000..a174a98 --- /dev/null +++ b/@sammo/util/src/datetime/parseYearMonth.ts @@ -0,0 +1,3 @@ +export function parseYearMonth(yearMonth: number): [number, number] { + return [(yearMonth / 12) | 0, yearMonth % 12 + 1]; +} \ No newline at end of file diff --git a/@sammo/util/src/error.ts b/@sammo/util/src/error.ts new file mode 100644 index 0000000..a445b98 --- /dev/null +++ b/@sammo/util/src/error.ts @@ -0,0 +1,43 @@ +export class NotNullExpected extends TypeError { + public override name = 'NotNullExpected'; +} + +export class RuntimeError extends Error { + public override name = 'RuntimeError'; + constructor(public override message: string = '') { + super(message); + } + override toString(): string { + if (this.message) { + return this.name + ': ' + this.message; + } + else { + return this.name; + } + } +} + +export class NotYetImplemented extends Error { + public override name = 'NotYetImplemented'; + override toString(): string { + if (this.message) { + return this.name + ': ' + this.message; + } + else { + return this.name; + } + + } +} + +export class InvalidArgument extends Error { + public override name = 'InvalidArgument'; + override toString(): string { + if (this.message) { + return this.name + ': ' + this.message; + } + else { + return this.name; + } + } +} diff --git a/@sammo/util/src/index.ts b/@sammo/util/src/index.ts new file mode 100644 index 0000000..207a2e4 --- /dev/null +++ b/@sammo/util/src/index.ts @@ -0,0 +1,44 @@ +export * from "./bsonify.js" +export * from "./jsonify.js" +export * from "./error.js" +export * from "./unwrap.js" +export * from "./types.js" +export * from "./web.js" + +export * from "./strongType.js" + +export * as converter from "./converter/index.js" +export * as datetime from "./datetime/index.js"; +export * as korean from "./korean/index.js"; +export * as string from "./string/index.js"; + +export function calcBase64Len(length: number) { + return ((4 * length / 3) + 3) & ~3; +} + +export function delay(time: number): Promise; +export function delay(time: number, result: T): Promise; +export function delay(time: number, result?: T): Promise { + return new Promise(resolve => + setTimeout(() => { + resolve(result); + }, time) + ); +} + +export function isBufferSource(obj: unknown): obj is BufferSource { + if (obj instanceof ArrayBuffer){ + return true; + } + if('SharedArrayBuffer' in globalThis && obj instanceof SharedArrayBuffer){ + return true; + } + if (ArrayBuffer.isView(obj)){ + return true; + } + return false; +} + +export function isNotNull(value: T|null|undefined):value is T{ + return value !== null && value !== undefined; +} \ No newline at end of file diff --git a/@sammo/util/src/jsonify.ts b/@sammo/util/src/jsonify.ts new file mode 100644 index 0000000..5e4fa13 --- /dev/null +++ b/@sammo/util/src/jsonify.ts @@ -0,0 +1,238 @@ +import { every, isString } from "lodash-es"; +import type { BsonifiableClassObj, PlainBson } from "./bsonify.js"; + +export type PlainJson = + string | number | boolean | null | PlainJson[] | { [key: string]: PlainJson }; + +//엄밀히는 PlainJsonItem 스스로가 PlainJson이어야 하지만, Bson의 document와 호환을 맞추기 위해 object만 허용 +export type PlainJsonObj = + { [key: string]: PlainJson }; + +type JsonifiableLite = + string | number | boolean | bigint | null | undefined; + +export type Jsonifiable = + JsonifiableLite | + Date | ArrayBuffer | SharedArrayBuffer | ArrayBufferView | + Array | + Map | + Set | + JsonifiableClassObj | + BsonifiableClassObj | + { [key: string]: Jsonifiable } | + ReadonlyArray; + +export type JsonifiableObj = + Map | + JsonifiableClassObj | + BsonifiableClassObj | + { [key: string]: Jsonifiable }; + +export interface JsonifiableClassObj { + jsonify(): T; +} + +type MaybeJsonified = T extends Jsonifiable ? Jsonified : never; +type MaybeJsonifiedObj = T extends JsonifiableObj ? JsonifiedObj : never; + +export type Jsonified = + T extends string ? T : + T extends number ? T : + T extends boolean ? T : + T extends bigint ? ReturnType : + T extends null ? T : + T extends undefined ? T : + T extends Date ? string : + T extends ArrayBuffer ? string : + T extends SharedArrayBuffer ? string : + T extends ArrayBufferView ? string : + T extends Map ? { [key in K]: MaybeJsonified } : + T extends Map ? [MaybeJsonified, MaybeJsonified][] : + T extends Set ? MaybeJsonified[] : + T extends JsonifiableClassObj ? ReturnType : + T extends BsonifiableClassObj ? Jsonified> : + T extends object ? { [key in keyof T]: MaybeJsonified } : + T extends unknown ? unknown : + never; + +export type JsonifiedObj = + T extends Map ? { [key in K]: MaybeJsonifiedObj } : + T extends JsonifiableClassObj ? ReturnType : + T extends BsonifiableClassObj ? Jsonified> : + T extends object ? { [key in keyof T]: MaybeJsonified } : + T extends unknown ? unknown : + never; + +/** + * Convert any object to JSON-safe object + */ +export function jsonify(item: T): Jsonified { + if (typeof item === 'string' || typeof item === 'number' || typeof item === 'boolean') { + return item as Jsonified; + } + + if (typeof item === 'bigint') { + return item.toString() as Jsonified; + } + + if (typeof item === 'undefined') { + return item as Jsonified; + } + + if (item === null) { + return item as Jsonified; + } + + if (item instanceof Date) { + return item.toISOString() as Jsonified; + } + + if (item instanceof ArrayBuffer) { + return Buffer.from(item).toString('base64') as Jsonified; + } + + if ('SharedArrayBuffer' in globalThis && item instanceof SharedArrayBuffer) { + return Buffer.from(item).toString('base64') as Jsonified; + } + + if (ArrayBuffer.isView(item)) { + return Buffer.from(item.buffer, item.byteOffset, item.byteLength).toString('base64') as Jsonified; + } + + //HACK: depth hack, escape ts(2589) + if (item instanceof Map) { + const onlyStringKey = every(item.keys, isString); + if (onlyStringKey) { + const result: { [key: string]: string } = {}; + for (const [k, v] of item.entries()) { + result[k as string] = jsonify(v as string); + } + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return result as any; + } + + const result: [string, string][] = []; + for (const [k, v] of item.entries()) { + result.push([jsonify(k as string), jsonify(v as string)]); + } + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return result as any; + } + + if (item instanceof Set) { + const result: string[] = []; + for (const v of item.values()) { + result.push(jsonify(v as string)); + } + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return result as any; + } + + if (Array.isArray(item)) { + const result: string[] = []; + for (const v of item) { + result.push(jsonify(v as string)); + } + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return result as any; + } + + if (typeof item !== 'object') { + throw new Error(`jsonify: invalid type ${typeof item}`); + } + + if ('jsonify' in item && typeof item.jsonify === 'function') { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return item.jsonify() as any; + } + + if ('bsonify' in item && typeof item.bsonify === 'function') { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return jsonify(item.bsonify() as Record) as any; + } + + const result: { [key: string]: string } = {}; + for (const [k, v] of Object.entries(item)) { + if (typeof k !== 'string') { + continue; + } + if (k === 'prototype') { + continue; + } + if (k === '__proto__ ') { + continue; + } + if (typeof v === 'function') { + continue; + } + result[k] = jsonify(v as string); + } + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return result as any; +} + +export function jsonifyObj(item: T): JsonifiedObj { + if (item === null) { + throw new Error(`jsonifyObj: invalid type ${typeof item}`); + } + + if (item === undefined) { + throw new Error(`jsonifyObj: invalid type ${typeof item}`); + } + + //HACK: depth hack, escape ts(2589) + if (item instanceof Map) { + const onlyStringKey = every(item.keys, isString); + if (onlyStringKey) { + const result: { [key: string]: unknown } = {}; + for (const [k, v] of item.entries()) { + result[k as string] = jsonify(v as Record); + } + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return result as any; + } + + throw new Error(`jsonifyObj: invalid type ${typeof item}`); + } + + if (Array.isArray(item)) { + throw new Error(`jsonifyObj: invalid type ${typeof item}`); + } + + if (item instanceof Set) { + throw new Error(`jsonifyObj: invalid type ${typeof item}`); + } + + if (typeof item !== 'object') { + throw new Error(`jsonify: invalid type ${typeof item}`); + } + + if ('jsonify' in item && typeof item.jsonify === 'function') { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return item.jsonify() as any; + } + + if ('bsonify' in item && typeof item.bsonify === 'function') { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return jsonify(item.bsonify() as Record) as any; + } + + const result: { [key: string]: unknown } = {}; + for (const [k, v] of Object.entries(item)) { + if (typeof k !== 'string') { + continue; + } + if (k === 'prototype') { + continue; + } + if (k === '__proto__ ') { + continue; + } + if (typeof v === 'function') { + continue; + } + result[k] = jsonify(v as Record); + } + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return result as any; +} \ No newline at end of file diff --git a/@sammo/util/src/korean/JosaUtil.ts b/@sammo/util/src/korean/JosaUtil.ts new file mode 100644 index 0000000..70b3db6 --- /dev/null +++ b/@sammo/util/src/korean/JosaUtil.ts @@ -0,0 +1,586 @@ +import { unwrap_err } from "../unwrap.js"; + +// https://github.com/coxcore/postposition 의 php 버전을 다시 typescript로 재 작성 +const KO_START_CODE = 44032; +const KO_FINISH_CODE = 55203; +const HANJA_START_CODE = 0x4e00; +const HANJA_FINISH_CODE = 0xfa0b; +const REG_INVALID_CHAR_W_HANJA = /[^a-zA-Z0-9ㄱ-ㅎ가-힣一-廓\s]+/u; +const REG_INVALID_CHAR = /[^a-zA-Z0-9ㄱ-ㅎ가-힣\s]+/u; +const REG_TARGET_CHAR = /^[\s\S]*?(\S*)\s*$/u; + +const PRE_REG_NORMAL_FIXED = [ + "check|[hm]ook|limit", +]; +const PRE_REG_SPECIAL_CHAR = [ + "[ㄱ-ㄷㅁ-ㅎ]", + "^[036]", + "[^a-zA-Z][036]", + "[a-zA-Z]9", + "^[mn]", + "\\S[mn]e?", + "\\S(?:[aeiom]|lu)b", + "(?:u|\\S[aei]|[^o]o)p", + "(?:^i|[^auh]i|\\Su|[^ei][ae]|[^oi]o)t", + "(?:\\S[iou]|[^e][ae])c?k", + "\\S[aeiou](?:c|ng)", + "foot|go+d|b[ai]g|private", + "^(?:app|kor)", +]; +const PRE_REG_SPECIAL_RO = [ + "[178ㄹ]", + "^[lr]", + "^\\Sr", + "\\Sle?", +]; + +const DEFAULT_POSTPOSITION = { + "은": "는", + "이": "가", + "과": "와", + "이나": "나", + "을": "를", + "으로": "로", + "이라": "라", + "이랑": "랑", +}; + +const JONGSUNG_HANJA = [ + 0x523b, 0x5374, 0x5404, 0x606a, 0x6164, 0x6bbc, 0x73cf, 0x811a, + 0x89ba, 0x89d2, 0x95a3, 0x4f83, 0x520a, 0x58be, 0x5978, 0x59e6, + 0x5e72, 0x5e79, 0x61c7, 0x63c0, 0x6746, 0x67ec, 0x687f, 0x6f97, + 0x764e, 0x770b, 0x78f5, 0x7a08, 0x7aff, 0x7c21, 0x809d, 0x826e, + 0x8271, 0x8aeb, 0x9593, 0x4e6b, 0x559d, 0x66f7, 0x6e34, 0x78a3, + 0x7aed, 0x845b, 0x8910, 0x874e, 0x97a8, 0x52d8, 0x574e, 0x582a, + 0x5d4c, 0x611f, 0x61be, 0x6221, 0x6562, 0x67d1, 0x6a44, 0x6e1b, + 0x7518, 0x75b3, 0x76e3, 0x77b0, 0x7d3a, 0x90af, 0x9451, 0x9452, + 0x9f95, 0x5323, 0x5cac, 0x7532, 0x80db, 0x9240, 0x9598, 0x525b, + 0x5808, 0x59dc, 0x5ca1, 0x5d17, 0x5eb7, 0x5f3a, 0x5f4a, 0x6177, + 0x6c5f, 0x757a, 0x7586, 0x7ce0, 0x7d73, 0x7db1, 0x7f8c, 0x8154, + 0x8221, 0x8591, 0x8941, 0x8b1b, 0x92fc, 0x964d, 0x9c47, 0x5580, + 0x5ba2, 0x5751, 0xf901, 0x7cb3, 0x7fb9, 0x91b5, 0x4e7e, 0x4ef6, + 0x5065, 0x5dfe, 0x5efa, 0x6106, 0x6957, 0x8171, 0x8654, 0x8e47, + 0x9375, 0x9a2b, 0x4e5e, 0x5091, 0x6770, 0x6840, 0x5109, 0x528d, + 0x5292, 0x6aa2, 0x77bc, 0x9210, 0x9ed4, 0x52ab, 0x602f, 0x8ff2, + 0x64ca, 0x683c, 0x6a84, 0x6fc0, 0x8188, 0x89a1, 0x9694, 0x5805, + 0x727d, 0x72ac, 0x7504, 0x7d79, 0x7e6d, 0x80a9, 0x898b, 0x8b74, + 0x9063, 0x9d51, 0x6289, 0x6c7a, 0x6f54, 0x7d50, 0x7f3a, 0x8a23, + 0x517c, 0x614a, 0x7b9d, 0x8b19, 0x9257, 0x938c, 0x4eac, 0x4fd3, + 0x501e, 0x50be, 0x5106, 0x52c1, 0x52cd, 0x537f, 0x5770, 0x5883, + 0x5e9a, 0x5f91, 0x6176, 0x61ac, 0x64ce, 0x656c, 0x666f, 0x66bb, + 0x66f4, 0x6897, 0x6d87, 0x7085, 0x70f1, 0x749f, 0x74a5, 0x74ca, + 0x75d9, 0x786c, 0x78ec, 0x7adf, 0x7af6, 0x7d45, 0x7d93, 0x8015, + 0x803f, 0x811b, 0x8396, 0x8b66, 0x8f15, 0x9015, 0x93e1, 0x9803, + 0x9838, 0x9a5a, 0x9be8, 0x54ed, 0x659b, 0x66f2, 0x688f, 0x7a40, + 0x8c37, 0x9d60, 0x56f0, 0x5764, 0x5d11, 0x6606, 0x68b1, 0x68cd, + 0x6efe, 0x7428, 0x889e, 0x9be4, 0x6c68, 0xf904, 0x9aa8, 0x4f9b, + 0x516c, 0x5171, 0x529f, 0x5b54, 0x5de5, 0x6050, 0x606d, 0x62f1, + 0x63a7, 0x653b, 0x73d9, 0x7a7a, 0x86a3, 0x8ca2, 0x978f, 0x4e32, + 0x5ed3, 0x69e8, 0x85ff, 0x90ed, 0xf905, 0x51a0, 0x5b98, 0x5bec, + 0x6163, 0x68fa, 0x6b3e, 0x704c, 0x742f, 0x74d8, 0x7ba1, 0x7f50, + 0x83c5, 0x89c0, 0x8cab, 0x95dc, 0x9928, 0x522e, 0x605d, 0x62ec, + 0x9002, 0x4f8a, 0x5149, 0x5321, 0x58d9, 0x5ee3, 0x66e0, 0x6d38, + 0x709a, 0x72c2, 0x73d6, 0x7b50, 0x80f1, 0x945b, 0x5b8f, 0x7d18, + 0x80b1, 0x8f5f, 0x570b, 0x5c40, 0x83ca, 0x97a0, 0x97ab, 0x9eb4, + 0x541b, 0x7a98, 0x7fa4, 0x88d9, 0x8ecd, 0x90e1, 0x5800, 0x5c48, + 0x6398, 0x7a9f, 0x5bae, 0x5f13, 0x7a79, 0x7aae, 0x828e, 0x8eac, + 0x5026, 0x5238, 0x52f8, 0x5377, 0x5708, 0x62f3, 0x6372, 0x6b0a, + 0x6dc3, 0x7737, 0x53a5, 0x7357, 0x8568, 0x8e76, 0x95d5, 0x52fb, + 0x5747, 0x7547, 0x7b60, 0x83cc, 0x921e, 0xf908, 0x6a58, 0x514b, + 0x524b, 0x5287, 0x621f, 0x68d8, 0x6975, 0x9699, 0x50c5, 0x52a4, + 0x52e4, 0x61c3, 0x65a4, 0x6839, 0x69ff, 0x747e, 0x7b4b, 0x82b9, + 0x83eb, 0x89b2, 0x8b39, 0x8fd1, 0x9949, 0xf909, 0x4eca, 0x5997, + 0x64d2, 0x6611, 0x6a8e, 0x7434, 0x7981, 0x79bd, 0x82a9, 0x887e, + 0x887f, 0x895f, 0xf90a, 0x9326, 0x4f0b, 0x53ca, 0x6025, 0x6271, + 0x6c72, 0x7d1a, 0x7d66, 0x4e98, 0x5162, 0x77dc, 0x80af, 0x7dca, + 0x4f76, 0x5409, 0x62ee, 0x6854, 0x91d1, 0x55ab, 0xf914, 0xf915, + 0xf916, 0xf917, 0xf918, 0x8afe, 0xf919, 0xf91a, 0xf91b, 0xf91c, + 0x6696, 0xf91d, 0x7156, 0xf91e, 0xf91f, 0x96e3, 0xf920, 0x634f, + 0x637a, 0x5357, 0xf921, 0x678f, 0x6960, 0x6e73, 0xf922, 0x7537, + 0xf923, 0xf924, 0xf925, 0x7d0d, 0xf926, 0xf927, 0x8872, 0x56ca, + 0x5a18, 0xf928, 0xf929, 0xf92a, 0xf92b, 0xf92c, 0xf92e, 0x5e74, + 0x649a, 0x79ca, 0x5ff5, 0x606c, 0x62c8, 0x637b, 0x5be7, 0x5bd7, + 0xf93b, 0xf93c, 0xf93d, 0xf93e, 0xf93f, 0xf940, 0xf941, 0xf942, + 0xf943, 0x6fc3, 0xf944, 0xf945, 0x81bf, 0x8fb2, 0x5ae9, 0x8a25, + 0xf952, 0xf953, 0xf954, 0xf955, 0xf956, 0xf957, 0x80fd, 0xf958, + 0xf959, 0x533f, 0x6eba, 0x4e39, 0x4eb6, 0x4f46, 0x55ae, 0x5718, + 0x58c7, 0x5f56, 0x65b7, 0x65e6, 0x6a80, 0x6bb5, 0x6e4d, 0x77ed, + 0x7aef, 0x7c1e, 0x7dde, 0x86cb, 0x8892, 0x9132, 0x935b, 0x64bb, + 0x6fbe, 0x737a, 0x75b8, 0x9054, 0x5556, 0x574d, 0x61ba, 0x64d4, + 0x66c7, 0x6de1, 0x6e5b, 0x6f6d, 0x6fb9, 0x75f0, 0x8043, 0x81bd, + 0x8541, 0x8983, 0x8ac7, 0x8b5a, 0x931f, 0x6c93, 0x7553, 0x7b54, + 0x8e0f, 0x905d, 0x5510, 0x5802, 0x5858, 0x5e62, 0x6207, 0x649e, + 0x68e0, 0x7576, 0x7cd6, 0x87b3, 0x9ee8, 0x5b85, 0x5fb7, 0x60b3, + 0x6bd2, 0x7006, 0x7258, 0x72a2, 0x7368, 0x7763, 0x79bf, 0x7be4, + 0x7e9b, 0x8b80, 0x58a9, 0x60c7, 0x6566, 0x65fd, 0x66be, 0x6c8c, + 0x711e, 0x71c9, 0x8c5a, 0x9813, 0x4e6d, 0x7a81, 0x4edd, 0x51ac, + 0x51cd, 0x52d5, 0x540c, 0x61a7, 0x6771, 0x6850, 0x68df, 0x6d1e, + 0x6f7c, 0x75bc, 0x77b3, 0x7ae5, 0x80f4, 0x8463, 0x9285, 0x5c6f, + 0x81c0, 0x829a, 0x9041, 0x906f, 0x920d, 0x5f97, 0x5d9d, 0x6a59, + 0x71c8, 0x767b, 0x7b49, 0x85e4, 0x8b04, 0x9127, 0x9a30, 0xf95c, + 0x6d1b, 0x70d9, 0x73de, 0x7d61, 0x843d, 0xf95d, 0x916a, 0x99f1, + 0xf95e, 0x4e82, 0x5375, 0x6b04, 0x6b12, 0x703e, 0x721b, 0x862d, + 0x9e1e, 0x524c, 0x8fa3, 0x5d50, 0x64e5, 0x652c, 0x6b16, 0x6feb, + 0x7c43, 0x7e9c, 0x85cd, 0x8964, 0x89bd, 0x62c9, 0x81d8, 0x881f, + 0x5eca, 0x6717, 0x6d6a, 0x72fc, 0x7405, 0x746f, 0x8782, 0x90de, + 0x51b7, 0x63a0, 0x7565, 0x4eae, 0x5006, 0x5169, 0x51c9, 0x6881, + 0x6a11, 0x7cae, 0x7cb1, 0x7ce7, 0x826f, 0x8ad2, 0x8f1b, 0x91cf, + 0x529b, 0x66c6, 0x6b77, 0x701d, 0x792b, 0x8f62, 0x9742, 0x6190, + 0x6200, 0x6523, 0x6f23, 0x7149, 0x7489, 0x7df4, 0x806f, 0x84ee, + 0x8f26, 0x9023, 0x934a, 0x51bd, 0x5217, 0x52a3, 0x6d0c, 0x70c8, + 0x88c2, 0x5ec9, 0x6582, 0x6bae, 0x6fc2, 0x7c3e, 0x7375, 0x4ee4, + 0x4f36, 0x56f9, 0xf95f, 0x5cba, 0x5dba, 0x601c, 0x73b2, 0x7b2d, + 0x7f9a, 0x7fce, 0x8046, 0x901e, 0x9234, 0x96f6, 0x9748, 0x9818, + 0x9f61, 0x788c, 0x797f, 0x7da0, 0x83c9, 0x9304, 0x9e7f, 0x9e93, + 0x8ad6, 0x58df, 0x5f04, 0x6727, 0x7027, 0x74cf, 0x7c60, 0x807e, + 0x9f8d, 0x516d, 0x622e, 0x9678, 0x4f96, 0x502b, 0x5d19, 0x6dea, + 0x7db8, 0x8f2a, 0x5f8b, 0x6144, 0x6817, 0xf961, 0x9686, 0x52d2, + 0x808b, 0x51dc, 0x51cc, 0x695e, 0x7a1c, 0x7dbe, 0x83f1, 0x9675, + 0x541d, 0x6f7e, 0x71d0, 0x7498, 0x85fa, 0x8eaa, 0x96a3, 0x9c57, + 0x9e9f, 0x6797, 0x6dcb, 0x7433, 0x81e8, 0x9716, 0x782c, 0x7acb, + 0x7b20, 0x7c92, 0x5bde, 0x5e55, 0x6f20, 0x819c, 0x83ab, 0x9088, + 0x4e07, 0x534d, 0x5a29, 0x5dd2, 0x5f4e, 0x6162, 0x633d, 0x6669, + 0x66fc, 0x6eff, 0x6f2b, 0x7063, 0x779e, 0x842c, 0x8513, 0x883b, + 0x8f13, 0x9945, 0x9c3b, 0x551c, 0x62b9, 0x672b, 0x6cab, 0x8309, + 0x896a, 0x977a, 0x4ea1, 0x5984, 0x5fd8, 0x5fd9, 0x671b, 0x7db2, + 0x7f54, 0x8292, 0x832b, 0x83bd, 0x8f1e, 0x9099, 0x8108, 0x8c8a, + 0x964c, 0x9a40, 0x9ea5, 0x5b5f, 0x6c13, 0x731b, 0x76f2, 0x76df, + 0x840c, 0x51aa, 0x8993, 0x514d, 0x5195, 0x52c9, 0x68c9, 0x6c94, + 0x7704, 0x7720, 0x7dbf, 0x7dec, 0x9762, 0x9eb5, 0x6ec5, 0x8511, + 0x51a5, 0x540d, 0x547d, 0x660e, 0x669d, 0x6927, 0x6e9f, 0x76bf, + 0x7791, 0x8317, 0x84c2, 0x879f, 0x9169, 0x9298, 0x9cf4, 0x6728, + 0x6c90, 0x7267, 0x76ee, 0x7766, 0x7a46, 0x9da9, 0x6b7f, 0x6c92, + 0x5922, 0x6726, 0x8499, 0x58a8, 0x9ed8, 0x5011, 0x520e, 0x543b, + 0x554f, 0x6587, 0x6c76, 0x7d0a, 0x7d0b, 0x805e, 0x868a, 0x9580, + 0x96ef, 0x52ff, 0x6c95, 0x7269, 0x5cb7, 0x60b6, 0x610d, 0x61ab, + 0x654f, 0x65fb, 0x65fc, 0x6c11, 0x6cef, 0x739f, 0x73c9, 0x7de1, + 0x9594, 0x5bc6, 0x871c, 0x8b10, 0x525d, 0x535a, 0x62cd, 0x640f, + 0x64b2, 0x6734, 0x6a38, 0x6cca, 0x73c0, 0x749e, 0x7b94, 0x7c95, + 0x7e1b, 0x818a, 0x8236, 0x8584, 0x8feb, 0x96f9, 0x99c1, 0x4f34, + 0x534a, 0x53cd, 0x53db, 0x62cc, 0x642c, 0x6500, 0x6591, 0x69c3, + 0x6cee, 0x6f58, 0x73ed, 0x7554, 0x7622, 0x76e4, 0x76fc, 0x78d0, + 0x78fb, 0x792c, 0x7d46, 0x822c, 0x87e0, 0x8fd4, 0x9812, 0x98ef, + 0x52c3, 0x62d4, 0x64a5, 0x6e24, 0x6f51, 0x767c, 0x8dcb, 0x91b1, + 0x9262, 0x9aee, 0x9b43, 0x5023, 0x508d, 0x574a, 0x59a8, 0x5c28, + 0x5e47, 0x5f77, 0x623f, 0x653e, 0x65b9, 0x65c1, 0x6609, 0x678b, + 0x699c, 0x6ec2, 0x78c5, 0x7d21, 0x80aa, 0x8180, 0x822b, 0x82b3, + 0x84a1, 0x868c, 0x8a2a, 0x8b17, 0x90a6, 0x9632, 0x9f90, 0x4f2f, + 0x4f70, 0x5e1b, 0x67cf, 0x6822, 0x767d, 0x767e, 0x9b44, 0x5e61, + 0x6a0a, 0x7169, 0x71d4, 0x756a, 0xf964, 0x7e41, 0x8543, 0x85e9, + 0x98dc, 0x4f10, 0x7b4f, 0x7f70, 0x95a5, 0x51e1, 0x5e06, 0x68b5, + 0x6c3e, 0x6c4e, 0x6cdb, 0x72af, 0x7bc4, 0x8303, 0x6cd5, 0x743a, + 0x50fb, 0x5288, 0x58c1, 0x64d8, 0x6a97, 0x74a7, 0x7656, 0x78a7, + 0x8617, 0x95e2, 0x9739, 0xf965, 0x535e, 0x5f01, 0x8b8a, 0x8fa8, + 0x8faf, 0x908a, 0x5225, 0x77a5, 0x9c49, 0x9f08, 0x4e19, 0x5002, + 0x5175, 0x5c5b, 0x5e77, 0x661e, 0x663a, 0x67c4, 0x68c5, 0x70b3, + 0x7501, 0x75c5, 0x79c9, 0x7add, 0x8f27, 0x9920, 0x9a08, 0x4f0f, + 0x50d5, 0x5310, 0x535c, 0x5b93, 0x5fa9, 0x670d, 0x798f, 0x8179, + 0x832f, 0x8514, 0x8907, 0x8986, 0x8f39, 0x8f3b, 0x99a5, 0x9c12, + 0x672c, 0x4e76, 0x4ff8, 0x5949, 0x5c01, 0x5cef, 0x5cf0, 0x6367, + 0x68d2, 0x70fd, 0x71a2, 0x742b, 0x7e2b, 0x84ec, 0x8702, 0x9022, + 0x92d2, 0x9cf3, 0x5317, 0x5206, 0x5429, 0x5674, 0x58b3, 0x5954, + 0x596e, 0x5fff, 0x61a4, 0x626e, 0x6610, 0x6c7e, 0x711a, 0x76c6, + 0x7c89, 0x7cde, 0x7d1b, 0x82ac, 0x8cc1, 0x96f0, 0xf967, 0x4f5b, + 0x5f17, 0x5f7f, 0x62c2, 0x5d29, 0x670b, 0x68da, 0x787c, 0x7e43, + 0x9d6c, 0x56ac, 0x5b2a, 0x5f6c, 0x658c, 0x6ab3, 0x6baf, 0x6d5c, + 0x6ff1, 0x7015, 0x725d, 0x73ad, 0x8ca7, 0x8cd3, 0x983b, 0x6191, + 0x6c37, 0x8058, 0x9a01, 0x524a, 0xf969, 0x6714, 0xf96a, 0x5098, + 0x522a, 0x5c71, 0x6563, 0x6c55, 0x73ca, 0x7523, 0x759d, 0x7b97, + 0x849c, 0x9178, 0x9730, 0x4e77, 0x6492, 0x6bba, 0x715e, 0x85a9, + 0x4e09, 0xf96b, 0x6749, 0x68ee, 0x6e17, 0x829f, 0x8518, 0x886b, + 0x63f7, 0x6f81, 0x9212, 0x98af, 0x4e0a, 0x50b7, 0x50cf, 0x511f, + 0x5546, 0x55aa, 0x5617, 0x5b40, 0x5c19, 0x5ce0, 0x5e38, 0x5e8a, + 0x5ea0, 0x5ec2, 0x60f3, 0x6851, 0x6a61, 0x6e58, 0x723d, 0x7240, + 0x72c0, 0x76f8, 0x7965, 0x7bb1, 0x7fd4, 0x88f3, 0x89f4, 0x8a73, + 0x8c61, 0x8cde, 0x971c, 0x55c7, 0xf96c, 0x7a61, 0x7d22, 0x8272, + 0x7272, 0x751f, 0x7525, 0xf96d, 0x7b19, 0x5915, 0x596d, 0x5e2d, + 0x60dc, 0x6614, 0x6673, 0x6790, 0x6c50, 0x6dc5, 0x6f5f, 0x77f3, + 0x78a9, 0x84c6, 0x91cb, 0x932b, 0x4ed9, 0x50ca, 0x5148, 0x5584, + 0x5b0b, 0x5ba3, 0x6247, 0x657e, 0x65cb, 0x6e32, 0x717d, 0x7401, + 0x7444, 0x7487, 0x74bf, 0x766c, 0x79aa, 0x7dda, 0x7e55, 0x7fa8, + 0x817a, 0x81b3, 0x8239, 0x861a, 0x87ec, 0x8a75, 0x8de3, 0x9078, + 0x9291, 0x9425, 0x994d, 0x9bae, 0x5368, 0x5c51, 0x6954, 0x6cc4, + 0x6d29, 0x6e2b, 0x820c, 0x859b, 0x893b, 0x8a2d, 0x8aaa, 0x96ea, + 0x9f67, 0x5261, 0x66b9, 0x6bb2, 0x7e96, 0x87fe, 0x8d0d, 0x9583, + 0x965d, 0x651d, 0x6d89, 0x71ee, 0xf96e, 0x57ce, 0x59d3, 0x5bac, + 0x6027, 0x60fa, 0x6210, 0x661f, 0x665f, 0x7329, 0x73f9, 0x76db, + 0x7701, 0x7b6c, 0x8056, 0x8072, 0x8165, 0x8aa0, 0x9192, 0x4fd7, + 0x5c6c, 0x675f, 0x6d91, 0x7c9f, 0x7e8c, 0x8b16, 0x8d16, 0x901f, + 0x5b6b, 0x5dfd, 0x640d, 0x84c0, 0x905c, 0x98e1, 0x7387, 0x5b8b, + 0x609a, 0x677e, 0x6dde, 0x8a1f, 0x8aa6, 0x9001, 0x980c, 0x53d4, + 0x587e, 0x5919, 0x5b70, 0x5bbf, 0x6dd1, 0x6f5a, 0x719f, 0x7421, + 0x74b9, 0x8085, 0x83fd, 0x5de1, 0x5f87, 0x5faa, 0x6042, 0x65ec, + 0x6812, 0x696f, 0x6a53, 0x6b89, 0x6d35, 0x6df3, 0x73e3, 0x76fe, + 0x77ac, 0x7b4d, 0x7d14, 0x8123, 0x821c, 0x8340, 0x84f4, 0x8563, + 0x8a62, 0x8ac4, 0x9187, 0x931e, 0x9806, 0x99b4, 0x620c, 0x8853, + 0x8ff0, 0x9265, 0x5d07, 0x5d27, 0x5d69, 0x745f, 0x819d, 0x8768, + 0x6fd5, 0x62fe, 0x7fd2, 0x8936, 0x8972, 0x4e1e, 0x4e58, 0x50e7, + 0x52dd, 0x5347, 0x627f, 0x6607, 0x7e69, 0x8805, 0x965e, 0x57f4, + 0x5bd4, 0x5f0f, 0x606f, 0x62ed, 0x690d, 0x6b96, 0x6e5c, 0x7184, + 0x7bd2, 0x8755, 0x8b58, 0x8efe, 0x98df, 0x98fe, 0x4f38, 0x4f81, + 0x4fe1, 0x547b, 0x5a20, 0x5bb8, 0x613c, 0x65b0, 0x6668, 0x71fc, + 0x7533, 0x795e, 0x7d33, 0x814e, 0x81e3, 0x8398, 0x85aa, 0x85ce, + 0x8703, 0x8a0a, 0x8eab, 0x8f9b, 0xf971, 0x8fc5, 0x5931, 0x5ba4, + 0x5be6, 0x6089, 0x5be9, 0x5c0b, 0x5fc3, 0x6c81, 0xf972, 0x6df1, + 0x700b, 0x751a, 0x82af, 0x8af6, 0x4ec0, 0x5341, 0xf973, 0x96d9, + 0x580a, 0x5cb3, 0x5dbd, 0x5e44, 0x60e1, 0x6115, 0x63e1, 0x6a02, + 0x6e25, 0x9102, 0x9354, 0x984e, 0x9c10, 0x9f77, 0x5b89, 0x5cb8, + 0x6309, 0x664f, 0x6848, 0x773c, 0x96c1, 0x978d, 0x9854, 0x9b9f, + 0x65a1, 0x8b01, 0x8ecb, 0x95bc, 0x5535, 0x5ca9, 0x5dd6, 0x5eb5, + 0x6697, 0x764c, 0x83f4, 0x95c7, 0x58d3, 0x62bc, 0x72ce, 0x9d28, + 0x4ef0, 0x592e, 0x600f, 0x663b, 0x6b83, 0x79e7, 0x9d26, 0x5384, + 0x627c, 0x6396, 0x6db2, 0x7e0a, 0x814b, 0x984d, 0x6afb, 0x7f4c, + 0x9daf, 0x9e1a, 0x5f31, 0xf975, 0xf976, 0x7d04, 0x82e5, 0x846f, + 0x84bb, 0x85e5, 0x8e8d, 0xf977, 0x4f6f, 0xf978, 0xf979, 0x58e4, + 0x5b43, 0x6059, 0x63da, 0x6518, 0x656d, 0x6698, 0xf97a, 0x694a, + 0x6a23, 0x6d0b, 0x7001, 0x716c, 0x75d2, 0x760d, 0x79b3, 0x7a70, + 0xf97b, 0x7f8a, 0xf97c, 0x8944, 0xf97d, 0x8b93, 0x91c0, 0x967d, + 0xf97e, 0x990a, 0x5104, 0x61b6, 0x6291, 0x6a8d, 0x81c6, 0x5043, + 0x5830, 0x5f66, 0x7109, 0x8a00, 0x8afa, 0x5b7c, 0x8616, 0x4ffa, + 0x513c, 0x56b4, 0x5944, 0x63a9, 0x6df9, 0x5daa, 0x696d, 0x5186, + 0x4ea6, 0xf98a, 0x57df, 0x5f79, 0x6613, 0xf98b, 0xf98c, 0x75ab, + 0x7e79, 0x8b6f, 0xf98d, 0x9006, 0x9a5b, 0x56a5, 0x5827, 0x59f8, + 0x5a1f, 0x5bb4, 0xf98e, 0x5ef6, 0xf98f, 0xf990, 0x6350, 0x633b, + 0xf991, 0x693d, 0x6c87, 0x6cbf, 0x6d8e, 0x6d93, 0x6df5, 0x6f14, + 0xf992, 0x70df, 0x7136, 0x7159, 0xf993, 0x71c3, 0x71d5, 0xf994, + 0x784f, 0x786f, 0xf995, 0x7b75, 0x7de3, 0xf996, 0x7e2f, 0xf997, + 0x884d, 0x8edf, 0xf998, 0xf999, 0xf99a, 0x925b, 0xf99b, 0x9cf6, + 0xf99c, 0xf99d, 0xf99e, 0x6085, 0x6d85, 0xf99f, 0x71b1, 0xf9a0, + 0xf9a1, 0x95b1, 0x53ad, 0xf9a2, 0xf9a3, 0xf9a4, 0x67d3, 0xf9a5, + 0x708e, 0x7130, 0x7430, 0x8276, 0x82d2, 0xf9a6, 0x95bb, 0x9ae5, + 0x9e7d, 0x66c4, 0xf9a7, 0x71c1, 0x8449, 0xf9a8, 0xf9a9, 0x584b, + 0xf9aa, 0xf9ab, 0x5db8, 0x5f71, 0xf9ac, 0x6620, 0x668e, 0x6979, + 0x69ae, 0x6c38, 0x6cf3, 0x6e36, 0x6f41, 0x6fda, 0x701b, 0x702f, + 0x7150, 0x71df, 0x7370, 0xf9ad, 0x745b, 0xf9ae, 0x74d4, 0x76c8, + 0x7a4e, 0x7e93, 0xf9af, 0xf9b0, 0x82f1, 0x8a60, 0x8fce, 0xf9b1, + 0x9348, 0xf9b2, 0x9719, 0xf9b3, 0xf9b4, 0x5c4b, 0x6c83, 0x7344, + 0x7389, 0x923a, 0x6eab, 0x7465, 0x761f, 0x7a69, 0x7e15, 0x860a, + 0x5140, 0x58c5, 0x64c1, 0x74ee, 0x7515, 0x7670, 0x7fc1, 0x9095, + 0x96cd, 0x9954, 0x5a49, 0x5b8c, 0x5b9b, 0x68a1, 0x6900, 0x6d63, + 0x73a9, 0x7413, 0x742c, 0x7897, 0x7de9, 0x7feb, 0x8118, 0x8155, + 0x839e, 0x8c4c, 0x962e, 0x9811, 0x66f0, 0x5f80, 0x65fa, 0x6789, + 0x6c6a, 0x738b, 0x617e, 0x6b32, 0x6d74, 0x7e1f, 0x8925, 0x8fb1, + 0x4fd1, 0x50ad, 0x5197, 0x52c7, 0x57c7, 0x5889, 0x5bb9, 0x5eb8, + 0x6142, 0x6995, 0x6d8c, 0x6e67, 0x6eb6, 0x7194, 0x7462, 0x7528, + 0x752c, 0x8073, 0x8338, 0x84c9, 0x8e0a, 0x9394, 0x93de, 0xf9c4, + 0x52d6, 0x5f67, 0x65ed, 0x6631, 0x682f, 0x715c, 0x7a36, 0x90c1, + 0x980a, 0x4e91, 0xf9c5, 0x6a52, 0x6b9e, 0x6f90, 0x7189, 0x8018, + 0x82b8, 0x8553, 0x904b, 0x9695, 0x96f2, 0x97fb, 0x851a, 0x9b31, + 0x4e90, 0x718a, 0x96c4, 0x5143, 0x539f, 0x54e1, 0x5713, 0x5712, + 0x57a3, 0x5a9b, 0x5ac4, 0x5bc3, 0x6028, 0x613f, 0x63f4, 0x6c85, + 0x6d39, 0x6e72, 0x6e90, 0x7230, 0x733f, 0x7457, 0x82d1, 0x8881, + 0x8f45, 0x9060, 0xf9c6, 0x9662, 0x9858, 0x9d1b, 0x6708, 0x8d8a, + 0x925e, 0xf9d1, 0x5809, 0xf9d2, 0x6bd3, 0x8089, 0x80b2, 0xf9d3, + 0xf9d4, 0x5141, 0x596b, 0x5c39, 0xf9d5, 0xf9d6, 0x6f64, 0x73a7, + 0x80e4, 0x8d07, 0xf9d7, 0x9217, 0x958f, 0xf9d8, 0xf9d9, 0xf9da, + 0xf9db, 0x807f, 0x620e, 0x701c, 0x7d68, 0x878d, 0xf9dc, 0x57a0, + 0x6069, 0x6147, 0x6bb7, 0x8abe, 0x9280, 0x96b1, 0x4e59, 0x541f, + 0x6deb, 0x852d, 0x9670, 0x97f3, 0x98ee, 0x63d6, 0x6ce3, 0x9091, + 0x51dd, 0x61c9, 0x81ba, 0x9df9, 0xf9eb, 0xf9ec, 0x7037, 0x76ca, + 0x7fca, 0x7fcc, 0x7ffc, 0x8b1a, 0x4eba, 0x4ec1, 0x5203, 0x5370, + 0xf9ed, 0x54bd, 0x56e0, 0x59fb, 0x5bc5, 0x5f15, 0x5fcd, 0x6e6e, + 0xf9ee, 0xf9ef, 0x7d6a, 0x8335, 0xf9f0, 0x8693, 0x8a8d, 0xf9f1, + 0x976d, 0x9777, 0xf9f2, 0xf9f3, 0x4e00, 0x4f5a, 0x4f7e, 0x58f9, + 0x65e5, 0x6ea2, 0x9038, 0x93b0, 0x99b9, 0x4efb, 0x58ec, 0x598a, + 0x59d9, 0x6041, 0xf9f4, 0xf9f5, 0x7a14, 0xf9f6, 0x834f, 0x8cc3, + 0x5165, 0x5344, 0xf9f7, 0xf9f8, 0xf9f9, 0x4ecd, 0x5269, 0x5b55, + 0x82bf, 0x4f5c, 0x52fa, 0x56bc, 0x65ab, 0x6628, 0x707c, 0x70b8, + 0x7235, 0x7dbd, 0x828d, 0x914c, 0x96c0, 0x9d72, 0x5b71, 0x68e7, + 0x6b98, 0x6f7a, 0x76de, 0x5c91, 0x66ab, 0x6f5b, 0x7bb4, 0x7c2a, + 0x8836, 0x96dc, 0x4e08, 0x4ed7, 0x5320, 0x5834, 0x58bb, 0x58ef, + 0x596c, 0x5c07, 0x5e33, 0x5e84, 0x5f35, 0x638c, 0x66b2, 0x6756, + 0x6a1f, 0x6aa3, 0x6b0c, 0x6f3f, 0x7246, 0xf9fa, 0x7350, 0x748b, + 0x7ae0, 0x7ca7, 0x8178, 0x81df, 0x81e7, 0x838a, 0x846c, 0x8523, + 0x8594, 0x85cf, 0x88dd, 0x8d13, 0x91ac, 0x9577, 0x969c, 0x722d, + 0x7b8f, 0x8acd, 0x931a, 0x52e3, 0x540a, 0x5ae1, 0x5bc2, 0x6458, + 0x6575, 0x6ef4, 0x72c4, 0xf9fb, 0x7684, 0x7a4d, 0x7b1b, 0x7c4d, + 0x7e3e, 0x7fdf, 0x837b, 0x8b2b, 0x8cca, 0x8d64, 0x8de1, 0x8e5f, + 0x8fea, 0x8ff9, 0x9069, 0x93d1, 0x4f43, 0x4f7a, 0x50b3, 0x5168, + 0x5178, 0x524d, 0x526a, 0x5861, 0x587c, 0x5960, 0x5c08, 0x5c55, + 0x5edb, 0x609b, 0x6230, 0x6813, 0x6bbf, 0x6c08, 0x6fb1, 0x714e, + 0x7420, 0x7530, 0x7538, 0x7551, 0x7672, 0x7b4c, 0x7b8b, 0x7bad, + 0x7bc6, 0x7e8f, 0x8a6e, 0x8f3e, 0x8f49, 0x923f, 0x9293, 0x9322, + 0x942b, 0x96fb, 0x985a, 0x986b, 0x991e, 0x5207, 0x622a, 0x6298, + 0x6d59, 0x7664, 0x7aca, 0x7bc0, 0x7d76, 0x5360, 0x5cbe, 0x5e97, + 0x6f38, 0x70b9, 0x7c98, 0x9711, 0x9b8e, 0x9ede, 0x63a5, 0x647a, + 0x8776, 0x4e01, 0x4e95, 0x4ead, 0x505c, 0x5075, 0x5448, 0x59c3, + 0x5b9a, 0x5e40, 0x5ead, 0x5ef7, 0x5f81, 0x60c5, 0x633a, 0x653f, + 0x6574, 0x65cc, 0x6676, 0x6678, 0x67fe, 0x6968, 0x6a89, 0x6b63, + 0x6c40, 0x6dc0, 0x6de8, 0x6e1f, 0x6e5e, 0x701e, 0x70a1, 0x738e, + 0x73fd, 0x753a, 0x775b, 0x7887, 0x798e, 0x7a0b, 0x7a7d, 0x7cbe, + 0x7d8e, 0x8247, 0x8a02, 0x8aea, 0x8c9e, 0x912d, 0x914a, 0x91d8, + 0x9266, 0x92cc, 0x9320, 0x9706, 0x9756, 0x975c, 0x9802, 0x9f0e, + 0x65cf, 0x7c07, 0x8db3, 0x93c3, 0x5b58, 0x5c0a, 0x5352, 0x62d9, + 0x731d, 0x5027, 0x5b97, 0x5f9e, 0x60b0, 0x616b, 0x68d5, 0x6dd9, + 0x742e, 0x7a2e, 0x7d42, 0x7d9c, 0x7e31, 0x816b, 0x8e2a, 0x8e35, + 0x937e, 0x9418, 0x7af9, 0x7ca5, 0x4fca, 0x5101, 0x51c6, 0x57c8, + 0x5bef, 0x5cfb, 0x6659, 0x6a3d, 0x6d5a, 0x6e96, 0x6fec, 0x710c, + 0x756f, 0x7ae3, 0x8822, 0x9021, 0x9075, 0x96cb, 0x99ff, 0x8301, + 0x4e2d, 0x4ef2, 0x8846, 0x91cd, 0x537d, 0x6adb, 0x696b, 0x6c41, + 0x847a, 0x589e, 0x618e, 0x66fe, 0x62ef, 0x70dd, 0x7511, 0x75c7, + 0x7e52, 0x84b8, 0x8b49, 0x8d08, 0x76f4, 0x7a19, 0x7a37, 0x7e54, + 0x8077, 0x5507, 0x55d4, 0x5875, 0x632f, 0x6422, 0x6649, 0x664b, + 0x686d, 0x699b, 0x6b84, 0x6d25, 0x6eb1, 0x73cd, 0x7468, 0x74a1, + 0x755b, 0x75b9, 0x76e1, 0x771e, 0x778b, 0x79e6, 0x7e09, 0x7e1d, + 0x81fb, 0x852f, 0x8897, 0x8a3a, 0x8cd1, 0x8eeb, 0x8fb0, 0x9032, + 0x93ad, 0x9663, 0x9673, 0x9707, 0x4f84, 0x53f1, 0x59ea, 0x5ac9, + 0x5e19, 0x684e, 0x74c6, 0x75be, 0x79e9, 0x7a92, 0x81a3, 0x86ed, + 0x8cea, 0x8dcc, 0x8fed, 0x659f, 0x6715, 0xf9fd, 0x57f7, 0x6f57, + 0x7ddd, 0x8f2f, 0x93f6, 0x96c6, 0x5fb5, 0x61f2, 0x6f84, 0x6349, + 0x643e, 0x7740, 0x7a84, 0x932f, 0x947f, 0x9f6a, 0x64b0, 0x6faf, + 0x71e6, 0x74a8, 0x74da, 0x7ac4, 0x7c12, 0x7e82, 0x7cb2, 0x7e98, + 0x8b9a, 0x8d0a, 0x947d, 0x9910, 0x994c, 0x5239, 0x5bdf, 0x64e6, + 0x672d, 0x7d2e, 0x50ed, 0x53c3, 0x5879, 0x6158, 0x6159, 0x61fa, + 0x65ac, 0x7ad9, 0x8b92, 0x8b96, 0x5009, 0x5021, 0x5275, 0x5531, + 0x5a3c, 0x5ee0, 0x5f70, 0x6134, 0x655e, 0x660c, 0x6636, 0x66a2, + 0x69cd, 0x6ec4, 0x6f32, 0x7316, 0x7621, 0x7a93, 0x8139, 0x8259, + 0x83d6, 0x84bc, 0x518a, 0x67f5, 0x7b56, 0x8cac, 0x501c, 0xf9ff, + 0x5254, 0x5c3a, 0x617d, 0x621a, 0x62d3, 0x64f2, 0x65a5, 0x6ecc, + 0x7620, 0x810a, 0x8e60, 0x965f, 0x96bb, 0x4edf, 0x5343, 0x5598, + 0x5929, 0x5ddd, 0x64c5, 0x6cc9, 0x6dfa, 0x7394, 0x7a7f, 0x821b, + 0x85a6, 0x8ce4, 0x8e10, 0x9077, 0x91e7, 0x95e1, 0x9621, 0x97c6, + 0x51f8, 0x54f2, 0x5586, 0x5fb9, 0x64a4, 0x6f88, 0x7db4, 0x8f1f, + 0x8f4d, 0x9435, 0x50c9, 0x5c16, 0x6cbe, 0x6dfb, 0x751b, 0x77bb, + 0x7c3d, 0x7c64, 0x8a79, 0x8ac2, 0x581e, 0x59be, 0x5e16, 0x6377, + 0x7252, 0x758a, 0x776b, 0x8adc, 0x8cbc, 0x8f12, 0x5ef3, 0x6674, + 0x6df8, 0x807d, 0x83c1, 0x8acb, 0x9751, 0x9bd6, 0x4fc3, 0x56d1, + 0x71ed, 0x77d7, 0x8700, 0x89f8, 0x5bf8, 0x5fd6, 0x6751, 0x90a8, + 0x53e2, 0x585a, 0x5bf5, 0x60a4, 0x6181, 0x6460, 0x7e3d, 0x8070, + 0x8525, 0x9283, 0x64ae, 0x4e11, 0x755c, 0x795d, 0x7afa, 0x7b51, + 0x7bc9, 0x7e2e, 0x84c4, 0x8e59, 0x8e74, 0x8ef8, 0x9010, 0x6625, + 0x693f, 0x7443, 0x51fa, 0x672e, 0x9edc, 0x5145, 0x5fe0, 0x6c96, + 0x87f2, 0x885d, 0x8877, 0x5074, 0x4ec4, 0x53a0, 0x60fb, 0x6e2c, + 0x5c64, 0x5247, 0x52c5, 0x98ed, 0x89aa, 0x4e03, 0x67d2, 0x6f06, + 0x4fb5, 0x5be2, 0x6795, 0x6c88, 0x6d78, 0x741b, 0x7827, 0x91dd, + 0x937c, 0x87c4, 0x79e4, 0x7a31, 0x502c, 0x5353, 0x5544, 0x577c, + 0xfa01, 0x6258, 0xfa02, 0x64e2, 0x666b, 0x67dd, 0x6fc1, 0x6fef, + 0x7422, 0x7438, 0x8a17, 0x9438, 0x5451, 0x5606, 0x5766, 0x5f48, + 0x619a, 0x6b4e, 0x7058, 0x70ad, 0x7dbb, 0x8a95, 0x596a, 0x812b, + 0x63a2, 0x7708, 0x803d, 0x8caa, 0x5854, 0x642d, 0x69bb, 0x5b95, + 0x5e11, 0x6e6f, 0xfa03, 0x8569, 0xfa04, 0x64c7, 0x6fa4, 0x6491, + 0x615f, 0x6876, 0xfa05, 0x75db, 0x7b52, 0x7d71, 0x901a, 0x615d, + 0x7279, 0x95d6, 0x5224, 0x5742, 0x677f, 0x7248, 0x74e3, 0x8ca9, + 0x8fa6, 0x9211, 0x962a, 0x516b, 0x53ed, 0x634c, 0x5f6d, 0x6f8e, + 0x70f9, 0x81a8, 0x610e, 0x4fbf, 0x504f, 0x6241, 0x7247, 0x7bc7, + 0x7de8, 0x7fe9, 0x904d, 0x97ad, 0x9a19, 0x8cb6, 0x576a, 0x5e73, + 0x67b0, 0x840d, 0x8a55, 0x5e45, 0x66b4, 0x66dd, 0x7011, 0x7206, + 0xfa07, 0x54c1, 0x7a1f, 0x6953, 0x8af7, 0x8c4a, 0x98a8, 0x99ae, + 0x5339, 0x5f3c, 0x5fc5, 0x6ccc, 0x73cc, 0x7562, 0x758b, 0x7b46, + 0x82fe, 0x999d, 0x4e4f, 0x903c, 0x58d1, 0x5b78, 0x8650, 0x8b14, + 0x9db4, 0x5bd2, 0x6068, 0x608d, 0x65f1, 0x6c57, 0x6f22, 0x6fa3, + 0x701a, 0x7f55, 0x7ff0, 0x9591, 0x9592, 0x9650, 0x97d3, 0x5272, + 0x8f44, 0x51fd, 0x542b, 0x54b8, 0x5563, 0x558a, 0x6abb, 0x6db5, + 0x7dd8, 0x8266, 0x929c, 0x9677, 0x9e79, 0x5408, 0x54c8, 0x76d2, + 0x86e4, 0x95a4, 0x95d4, 0x965c, 0x4ea2, 0x4f09, 0x59ee, 0x5ae6, + 0x5df7, 0x6052, 0x6297, 0x676d, 0x6841, 0x6c86, 0x6e2f, 0x7f38, + 0x809b, 0x822a, 0xfa08, 0xfa09, 0x9805, 0x52be, 0x6838, 0x5016, + 0x5e78, 0x674f, 0x8347, 0x884c, 0x4eab, 0x5411, 0x56ae, 0x73e6, + 0x9115, 0x97ff, 0x9909, 0x9957, 0x9999, 0x61b2, 0x6af6, 0x737b, + 0x8ed2, 0x6b47, 0x96aa, 0x9a57, 0x5955, 0x7200, 0x8d6b, 0x9769, + 0x4fd4, 0x5cf4, 0x5f26, 0x61f8, 0x665b, 0x6ceb, 0x70ab, 0x7384, + 0x73b9, 0x73fe, 0x7729, 0x774d, 0x7d43, 0x7d62, 0x7e23, 0x8237, + 0x8852, 0xfa0a, 0x8ce2, 0x9249, 0x986f, 0x5b51, 0x7a74, 0x8840, + 0x9801, 0x5acc, 0x4fe0, 0x5354, 0x593e, 0x5cfd, 0x633e, 0x6d79, + 0x72f9, 0x8105, 0x8107, 0x83a2, 0x92cf, 0x9830, 0x4ea8, 0x5144, + 0x5211, 0x578b, 0x5f62, 0x6cc2, 0x6ece, 0x7005, 0x7050, 0x70af, + 0x7192, 0x73e9, 0x7469, 0x834a, 0x87a2, 0x8861, 0x9008, 0x90a2, + 0x93a3, 0x99a8, 0x60d1, 0x6216, 0x9177, 0x5a5a, 0x660f, 0x6df7, + 0x6e3e, 0x743f, 0x9b42, 0x5ffd, 0x60da, 0x7b0f, 0x54c4, 0x5f18, + 0x6c5e, 0x6cd3, 0x6d2a, 0x70d8, 0x7d05, 0x8679, 0x8a0c, 0x9d3b, + 0xfa0b, 0x64f4, 0x652b, 0x78ba, 0x78bb, 0x7a6b, 0x4e38, 0x559a, + 0x5950, 0x5ba6, 0x5e7b, 0x60a3, 0x63db, 0x6b61, 0x6665, 0x6853, + 0x6e19, 0x7165, 0x74b0, 0x7d08, 0x9084, 0x9a69, 0x9c25, 0x6d3b, + 0x6ed1, 0x733e, 0x8c41, 0x95ca, 0x51f0, 0x5e4c, 0x5fa8, 0x604d, + 0x60f6, 0x6130, 0x614c, 0x6643, 0x6644, 0x69a5, 0x6cc1, 0x6e5f, + 0x6ec9, 0x6f62, 0x714c, 0x749c, 0x7687, 0x7bc1, 0x7c27, 0x8352, + 0x8757, 0x9051, 0x968d, 0x9ec3, 0x5283, 0x7372, 0x5b96, 0x6a6b, + 0x9404, 0x52db, 0x52f3, 0x5864, 0x58ce, 0x7104, 0x718f, 0x71fb, + 0x85b0, 0x8a13, 0x6688, 0x85a8, 0x55a7, 0x6684, 0x714a, 0x8431, + 0x6064, 0x8b4e, 0x9df8, 0x5147, 0x51f6, 0x5308, 0x6d36, 0x80f8, + 0x9ed1, 0x6615, 0x6b23, 0x7098, 0x75d5, 0x5403, 0x5c79, 0x7d07, + 0x8a16, 0x6b20, 0x6b3d, 0x6b46, 0x5438, 0x6070, 0x6d3d, 0x7fd5, + 0x8208, 0x8a70, 0xfa0b +]; + +const RO_HANJA = [ + 0x4e6b, 0x559d, 0x66f7, 0x6e34, 0x78a3, 0x7aed, 0x845b, 0x8910, + 0x874e, 0x97a8, 0x4e5e, 0x5091, 0x6770, 0x6840, 0x6289, 0x6c7a, + 0x6f54, 0x7d50, 0x7f3a, 0x8a23, 0x6c68, 0xf904, 0x9aa8, 0x522e, + 0x605d, 0x62ec, 0x9002, 0x5800, 0x5c48, 0x6398, 0x7a9f, 0x53a5, + 0x7357, 0x8568, 0x8e76, 0x95d5, 0x6a58, 0xf909, 0x4f76, 0x5409, + 0x62ee, 0x6854, 0x634f, 0x637a, 0x8a25, 0x64bb, 0x6fbe, 0x737a, + 0x75b8, 0x9054, 0x4e6d, 0x7a81, 0x524c, 0x8fa3, 0x51bd, 0x5217, + 0x52a3, 0x6d0c, 0x70c8, 0x88c2, 0x5f8b, 0x6144, 0x6817, 0xf961, + 0x551c, 0x62b9, 0x672b, 0x6cab, 0x8309, 0x896a, 0x977a, 0x6ec5, + 0x8511, 0x6b7f, 0x6c92, 0x52ff, 0x6c95, 0x7269, 0x5bc6, 0x871c, + 0x8b10, 0x52c3, 0x62d4, 0x64a5, 0x6e24, 0x6f51, 0x767c, 0x8dcb, + 0x91b1, 0x9262, 0x9aee, 0x9b43, 0x4f10, 0x7b4f, 0x7f70, 0x95a5, + 0x5225, 0x77a5, 0x9c49, 0x9f08, 0x4e76, 0xf967, 0x4f5b, 0x5f17, + 0x5f7f, 0x62c2, 0x4e77, 0x6492, 0x6bba, 0x715e, 0x85a9, 0x5368, + 0x5c51, 0x6954, 0x6cc4, 0x6d29, 0x6e2b, 0x820c, 0x859b, 0x893b, + 0x8a2d, 0x8aaa, 0x96ea, 0x9f67, 0x7387, 0x620c, 0x8853, 0x8ff0, + 0x9265, 0x745f, 0x819d, 0x8768, 0x5931, 0x5ba4, 0x5be6, 0x6089, + 0x65a1, 0x8b01, 0x8ecb, 0x95bc, 0x5b7c, 0x8616, 0xf99c, 0xf99d, + 0xf99e, 0x6085, 0x6d85, 0xf99f, 0x71b1, 0xf9a0, 0xf9a1, 0x95b1, + 0x5140, 0x66f0, 0x851a, 0x9b31, 0x4e90, 0x6708, 0x8d8a, 0x925e, + 0xf9d8, 0xf9d9, 0xf9da, 0xf9db, 0x807f, 0x4e59, 0x4e00, 0x4f5a, + 0x4f7e, 0x58f9, 0x65e5, 0x6ea2, 0x9038, 0x93b0, 0x99b9, 0x5207, + 0x622a, 0x6298, 0x6d59, 0x7664, 0x7aca, 0x7bc0, 0x7d76, 0x5352, + 0x62d9, 0x731d, 0x8301, 0x6adb, 0x4f84, 0x53f1, 0x59ea, 0x5ac9, + 0x5e19, 0x684e, 0x74c6, 0x75be, 0x79e9, 0x7a92, 0x81a3, 0x86ed, + 0x8cea, 0x8dcc, 0x8fed, 0x5239, 0x5bdf, 0x64e6, 0x672d, 0x7d2e, + 0x51f8, 0x54f2, 0x5586, 0x5fb9, 0x64a4, 0x6f88, 0x7db4, 0x8f1f, + 0x8f4d, 0x9435, 0x64ae, 0x51fa, 0x672e, 0x9edc, 0x4e03, 0x67d2, + 0x6f06, 0x596a, 0x812b, 0x516b, 0x53ed, 0x634c, 0x5339, 0x5f3c, + 0x5fc5, 0x6ccc, 0x73cc, 0x7562, 0x758b, 0x7b46, 0x82fe, 0x999d, + 0x5272, 0x8f44, 0x6b47, 0x5b51, 0x7a74, 0x8840, 0x9801, 0x5ffd, + 0x60da, 0x7b0f, 0x6d3b, 0x6ed1, 0x733e, 0x8c41, 0x95ca, 0x6064, + 0x8b4e, 0x9df8, 0x5403, 0x5c79, 0x7d07, 0x8a16, 0x8a70, +]; + +const regNormalFixed = new RegExp(`/(?:${PRE_REG_NORMAL_FIXED.join('|')})$/iu`); +const regSpecialChar = new RegExp(`/(?:${PRE_REG_SPECIAL_CHAR.join('|')})$/iu`); +const regSpecialRo = new RegExp(`/(?:${PRE_REG_SPECIAL_RO.join('|')})$/iu`); + +const jongsungHanja = new Set(); +for (const hanjaCode of JONGSUNG_HANJA) { + jongsungHanja.add(hanjaCode); +} +const roHanja = new Set(); +for (const hanjaCode of RO_HANJA) { + roHanja.add(hanjaCode); +} +const mapPostPosition = new Map(); +for (const [key, val] of Object.entries(DEFAULT_POSTPOSITION)) { + mapPostPosition.set(`(${key})${val}`, key); + mapPostPosition.set(key, key); + mapPostPosition.set(val, key); +} + +function checkText(text: string, isRo: boolean): boolean { + if (regNormalFixed.test(text)) { + return false; + } + + if (regSpecialChar.test(text)) { + return true; + } + + if (!isRo && regSpecialRo.test(text)) { + return true; + } + + return false; +} + +function checkCode(code: number, isRo: boolean): boolean { + const jongsung = (code - KO_START_CODE) % 28; + if (jongsung === 0) { + return false; + } + + if (isRo && jongsung === 8) { + return false; + } + + return true; +} + +export function check(text: string, type: string): boolean { + + const htarget = text.replace(REG_INVALID_CHAR_W_HANJA, ' ').replace(REG_TARGET_CHAR, '$1'); + if (!htarget) { + return false; + } + const hcode = htarget.charAt(htarget.length - 1).charCodeAt(0); + const isRo = type === '로' || type === '으로'; + + if (HANJA_START_CODE <= hcode && hcode <= HANJA_FINISH_CODE) { + if (isRo && roHanja.has(hcode)) { + return false; + } + if (jongsungHanja.has(hcode)) { + return true; + } + if (hcode < KO_START_CODE || KO_FINISH_CODE < hcode) { + return false; + } + } + + const target = text.replace(REG_INVALID_CHAR, ' ').replace(REG_TARGET_CHAR, '$1'); + const code = target.charAt(target.length - 1).charCodeAt(0); + + const isKorean = KO_START_CODE <= code && code <= KO_FINISH_CODE; + + return isKorean ? checkCode(code, isRo) : checkText(target, isRo); +} + +export function pick(text: string|number, wJongsung: string, woJongsung = ''): string { + /* NOTE:원본 코드와 인자 순서가 다름. + * 원본은 pick('바람', '랑', '이랑'); 이었다면 pick('바람', '이랑', '랑'); 으로 바뀜. + * pick('바람', '은', '는'); JosaUtil.pick('바람', '이', '가');처럼 쓰기 위해서임. + */ + if (!text) { + text = ''; + } else if(typeof text === 'number'){ + text = String(text); + } + + if(!woJongsung){ + if(!mapPostPosition.has(wJongsung)){ + throw `올바르지 않은 조사 지정: ${wJongsung}`; + } + wJongsung = unwrap_err(mapPostPosition.get(wJongsung), Error, `올바르지 않은 조사 지정: ${wJongsung}`); + woJongsung = DEFAULT_POSTPOSITION[wJongsung as keyof typeof DEFAULT_POSTPOSITION]; + } + + return check(text, wJongsung) ? wJongsung : woJongsung; +} + +export function put(text: string, wJongsung: string, woJongsung = ''): string{ + return `${text}${pick(text, wJongsung, woJongsung)}`; +} + +export function fix(wJongsung: string, woJongsung = ''){ + if(!woJongsung){ + if(!mapPostPosition.has(wJongsung)){ + throw `올바르지 않은 조사 지정: ${wJongsung}`; + } + wJongsung = unwrap_err(mapPostPosition.get(wJongsung), Error, `올바르지 않은 조사 지정: ${wJongsung}`); + woJongsung = DEFAULT_POSTPOSITION[wJongsung as keyof typeof DEFAULT_POSTPOSITION]; + } + return function(text: string){ + return put(text, wJongsung, woJongsung); + } +} + +export function batch(text: string, decorator = ';'){ + const regExp = new RegExp(`${decorator}([^${decorator}]+)${decorator}([^${decorator}]*)${decorator}([^${decorator}]+)${decorator}`, 'g'); + + let matchRes; + let lastIndex = 0; + + const result: string[] = []; + + while ((matchRes = regExp.exec(text)) !== null) { + const { + 0: partAll, + 1: body, + 2: filler, + 3: wJongsung, + index, + } = matchRes; + if(lastIndex != index){ + result.push(text.slice(lastIndex, index)); + } + + result.push(body, filler, pick(body, wJongsung)); + + lastIndex = index + partAll.length; + } + if(lastIndex != text.length){ + result.push(text.slice(lastIndex)); + } + + return result.join(''); +} \ No newline at end of file diff --git a/@sammo/util/src/korean/automata초성.ts b/@sammo/util/src/korean/automata초성.ts new file mode 100644 index 0000000..b6eb499 --- /dev/null +++ b/@sammo/util/src/korean/automata초성.ts @@ -0,0 +1,101 @@ +const convListLevel1: Record> = { + 'ㄱ': { + 'ㅅ': 'ㄳ', + }, + 'ㄴ': { + 'ㅈ': 'ㄵ', + 'ㅎ': 'ㄶ', + }, + 'ㄹ': { + 'ㅂ': 'ㄼ', + 'ㄱ': 'ㄺ', + 'ㅅ': 'ㄽ', + 'ㅁ': 'ㄻ', + 'ㅎ': 'ㅀ', + 'ㅌ': 'ㄾ', + 'ㅍ': 'ㄿ', + }, + 'ㅂ': { + 'ㅅ': 'ㅄ', + }, +} + +const convListLevel2: Record> = { + 'ㄱ': { + 'ㄱ': 'ㄲ', + 'ㅅ': 'ㄳ', + }, + 'ㄴ': { + 'ㅈ': 'ㄵ', + 'ㅎ': 'ㄶ', + }, + 'ㄷ': { + 'ㄷ': 'ㄸ', + }, + 'ㄹ': { + 'ㅂ': 'ㄼ', + 'ㄱ': 'ㄺ', + 'ㅅ': 'ㄽ', + 'ㅁ': 'ㄻ', + 'ㅎ': 'ㅀ', + 'ㅌ': 'ㄾ', + 'ㅍ': 'ㄿ', + }, + 'ㅂ': { + 'ㅂ': 'ㅃ', + 'ㅅ': 'ㅄ', + }, + 'ㅅ': { + 'ㅅ': 'ㅆ', + }, + 'ㅈ': { + 'ㅈ': 'ㅉ', + } +} + +function automata초성(text: string, convList: Record>): string{ + const result: string[] = []; + let head: undefined | string = undefined; + for (const ch of text) { + if (head === undefined) { + if(!(ch in convList)){ + result.push(ch); + continue; + } + head = ch; + continue; + } + + const nextConv = convList[head]; + if(ch in nextConv){ + result.push(nextConv[ch]); + head = undefined; + continue; + } + + result.push(head); + if(!(ch in convList)){ + result.push(ch); + head = undefined; + continue; + } + head = ch; + } + if(head !== undefined){ + result.push(head); + head = undefined; + } + return result.join(''); +} + +export function automata초성All(text: string): [string, string]{ + return [automata초성(text, convListLevel1), automata초성(text, convListLevel2)]; +} + +export function automata초성Level1(text: string): string{ + return automata초성(text, convListLevel1); +} + +export function automata초성Level2(text: string): string { + return automata초성(text, convListLevel2); +} \ No newline at end of file diff --git a/@sammo/util/src/korean/convertSearch초성.ts b/@sammo/util/src/korean/convertSearch초성.ts new file mode 100644 index 0000000..13ff32a --- /dev/null +++ b/@sammo/util/src/korean/convertSearch초성.ts @@ -0,0 +1,9 @@ +import { automata초성All } from "./automata초성.js"; +import { filter초성withAlphabet } from "./filter초성withAlphabet.js"; + +export function convertSearch초성(text: string): string[]{ + const [filteredTextH, filteredTextA] = filter초성withAlphabet(text.replace(/\s+/g, "")); + const [filteredTextHL1, filteredTextHL2] = automata초성All(filteredTextH); + + return [text, filteredTextA, filteredTextH, filteredTextHL1, filteredTextHL2]; +} \ No newline at end of file diff --git a/@sammo/util/src/korean/filter초성.ts b/@sammo/util/src/korean/filter초성.ts new file mode 100644 index 0000000..a4c1045 --- /dev/null +++ b/@sammo/util/src/korean/filter초성.ts @@ -0,0 +1,17 @@ +export function filter초성(text: string): string { + const 초성 = [ + "ㄱ", "ㄲ", "ㄴ", "ㄷ", "ㄸ", "ㄹ", "ㅁ", "ㅂ", "ㅃ", + "ㅅ", "ㅆ", "ㅇ", "ㅈ", "ㅉ", "ㅊ", "ㅋ", "ㅌ", "ㅍ", "ㅎ" + ]; + const result: string[] = []; + for (const char of text) { + const code = (char.codePointAt(0) ?? 0) - 44032; + if (0 <= code && code < 11172) { + result.push(초성[~~(code / 588)]); + } + else { + result.push(char); + } + } + return result.join(''); +} \ No newline at end of file diff --git a/@sammo/util/src/korean/filter초성withAlphabet.ts b/@sammo/util/src/korean/filter초성withAlphabet.ts new file mode 100644 index 0000000..a071b51 --- /dev/null +++ b/@sammo/util/src/korean/filter초성withAlphabet.ts @@ -0,0 +1,24 @@ +export function filter초성withAlphabet(text: string): [string, string] { + const 초성 = [ + "ㄱ", "ㄲ", "ㄴ", "ㄷ", "ㄸ", "ㄹ", "ㅁ", "ㅂ", "ㅃ", + "ㅅ", "ㅆ", "ㅇ", "ㅈ", "ㅉ", "ㅊ", "ㅋ", "ㅌ", "ㅍ", "ㅎ" + ]; + const alphabets = [ + "r", "R", "s", "e", "E", "f", "a", "q", "Q", + "t", "T", "d", "w", "W", "c", "z", "x", "v", "g" + ]; + const resultH: string[] = []; + const resultA: string[] = []; + for (const char of text) { + const code = (char.codePointAt(0) ?? 0) - 44032; + if (0 <= code && code < 11172) { + resultH.push(초성[~~(code / 588)]); + resultA.push(alphabets[~~(code / 588)]); + } + else { + resultH.push(char); + resultA.push(char); + } + } + return [resultH.join(''), resultA.join('')]; +} \ No newline at end of file diff --git a/@sammo/util/src/korean/index.ts b/@sammo/util/src/korean/index.ts new file mode 100644 index 0000000..2b78bcd --- /dev/null +++ b/@sammo/util/src/korean/index.ts @@ -0,0 +1,5 @@ +export * from "./automata초성.js"; +export * from "./convertSearch초성.js" +export * from "./filter초성.js"; +export * from "./filter초성withAlphabet.js"; +export * as JosaUtil from "./JosaUtil.js"; \ No newline at end of file diff --git a/@sammo/util/src/simpleSerialize.ts b/@sammo/util/src/simpleSerialize.ts new file mode 100644 index 0000000..f421fdd --- /dev/null +++ b/@sammo/util/src/simpleSerialize.ts @@ -0,0 +1,18 @@ +import { isInteger, isString } from "lodash-es"; + +export function simpleSerialize(...values : (string|number)[]): string{ + const result: string[] = []; + for(const value of values){ + if(isString(value)){ + result.push(`str(${value.length},${value})`); + continue; + } + if(isInteger(value)){ + result.push(`int(${value})`); + continue; + } + const float6 = value.toLocaleString("en-US", {maximumFractionDigits: 6}); + result.push(`float(${float6})`); + } + return result.join('|'); +} \ No newline at end of file diff --git a/@sammo/util/src/string/index.ts b/@sammo/util/src/string/index.ts new file mode 100644 index 0000000..761e58b --- /dev/null +++ b/@sammo/util/src/string/index.ts @@ -0,0 +1,5 @@ +export * from "./mb_strimwidth.js" +export * from "./mb_strwidth.js" +export * from "./nl2br.js" +export * from "./numberWithCommas.js" +export * from "./randStr.js"; \ No newline at end of file diff --git a/@sammo/util/src/string/mb_strimwidth.ts b/@sammo/util/src/string/mb_strimwidth.ts new file mode 100644 index 0000000..f096c5e --- /dev/null +++ b/@sammo/util/src/string/mb_strimwidth.ts @@ -0,0 +1,31 @@ +import { mb_strwidth } from ".//mb_strwidth.js"; + +/** + * mb_strimwidth + * @param String + * @param int + * @param int + * @param String + * @return String + * @see http://www.php.net/manual/function.mb-strimwidth.php + */ +export function mb_strimwidth(str: string, start: number, width: number, trimmarker = ''): string { + const trimmakerWidth = mb_strwidth(trimmarker); + const l = str.length; + let trimmedLength = 0; + const trimmedStr: string[] = []; + for (let i = start; i < l; i++) { + const c = str.charAt(i); + const charWidth = mb_strwidth(c); + const next = str.charAt(i + 1); + const nextWidth = mb_strwidth(next); + + trimmedLength += charWidth; + trimmedStr.push(c); + if (trimmedLength + trimmakerWidth + nextWidth > width) { + trimmedStr.push(trimmarker); + break; + } + } + return trimmedStr.join(''); +} diff --git a/@sammo/util/src/string/mb_strwidth.ts b/@sammo/util/src/string/mb_strwidth.ts new file mode 100644 index 0000000..37ef5b8 --- /dev/null +++ b/@sammo/util/src/string/mb_strwidth.ts @@ -0,0 +1,24 @@ +//https://gist.github.com/demouth/3217440 +/** + * mb_strwidth + * @see http://php.net/manual/function.mb-strwidth.php + */ +export function mb_strwidth(str: string): number { + const l = str.length; + let length = 0; + for (let i = 0; i < l; i++) { + const c = str.charCodeAt(i); + if (0x0000 <= c && c <= 0x0019) { + length += 0; + } else if (0x0020 <= c && c <= 0x1FFF) { + length += 1; + } else if (0x2000 <= c && c <= 0xFF60) { + length += 2; + } else if (0xFF61 <= c && c <= 0xFF9F) { + length += 1; + } else if (0xFFA0 <= c) { + length += 2; + } + } + return length; +} diff --git a/@sammo/util/src/string/nl2br.ts b/@sammo/util/src/string/nl2br.ts new file mode 100644 index 0000000..555c703 --- /dev/null +++ b/@sammo/util/src/string/nl2br.ts @@ -0,0 +1,4 @@ + +export function nl2br(text: string): string { + return text.replace(/\n/g, "
"); +} diff --git a/@sammo/util/src/string/numberWithCommas.ts b/@sammo/util/src/string/numberWithCommas.ts new file mode 100644 index 0000000..971045f --- /dev/null +++ b/@sammo/util/src/string/numberWithCommas.ts @@ -0,0 +1,5 @@ + + +export function numberWithCommas(x: number): string { + return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); +} diff --git a/@sammo/util/src/string/randStr.ts b/@sammo/util/src/string/randStr.ts new file mode 100644 index 0000000..d462532 --- /dev/null +++ b/@sammo/util/src/string/randStr.ts @@ -0,0 +1,25 @@ +const charList = [ + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', + 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', + 'u', 'v', 'w', 'x', 'y', 'z', +] as const; + +export function randStr(len: number): string { + const result: string[] = []; + const charListLen = charList.length; + let isStart = true; + + while(len > 0){ + const randChrIdx = Math.floor(Math.random() * charListLen); + if(isStart){ + if(randChrIdx == 0){ + continue; + } + isStart = false; + } + result.push(charList[randChrIdx]); + len -= 1; + } + return result.join(''); +} \ No newline at end of file diff --git a/@sammo/util/src/strongType.ts b/@sammo/util/src/strongType.ts new file mode 100644 index 0000000..6d513a2 --- /dev/null +++ b/@sammo/util/src/strongType.ts @@ -0,0 +1,51 @@ + + +/** Buffer이지만 ts에서 타입 구분 편의를 제공 */ +export interface WrappedBuffer extends Buffer { + /** 타입구분자. 항상 undefined일 것이다 */ + _w_type?: string; +} + + +/** ArrayBuffer,Uint8Array,Buffer를 WrappedBuffer로 변환 + */ +export function wrapBuffer(buffer: BufferSource): T { + /** + * Buffer라면 wrapBuffer없이 그대로 대입 가능 + * ArrayBuffer, Uint8Array 등이라면 Buffer.from을 사용 가능 + * DataView 등인 경우는 ArrayBufferView 활용 + * 그냥 써도 되지만, 위 방법보다 아무렇게나 쓰기 좋다는 장점은 있음 + */ + if (buffer instanceof Buffer) { + return buffer as T; + } + if (buffer instanceof ArrayBuffer) { + return Buffer.from(buffer) as T; + } + if (buffer instanceof SharedArrayBuffer) { + return Buffer.from(buffer) as T; + } + return Buffer.from(buffer.buffer, buffer.byteOffset, buffer.byteLength) as T; +} + +/** 호출할 필요 없이 바로 Buffer에 대입해도 되지만, 누군가 찾을 수 있어서. */ +export function unwrapBuffer(buffer: T): Buffer { + return buffer; +} + +/** + * base64 string에 내부 타입으로 WrappedBuffer를 보관한 형태 + */ +// eslint-disable-next-line @typescript-eslint/ban-types +export type Base64String = string & { + /** 타입구분자. 항상 undefined일 것이다 */ + _b_type?: T; +} + +export function base64FromWrappedBuffer(buffer: T | ArrayBuffer | Uint8Array): Base64String { + return Buffer.from(buffer).toString('base64'); +} + +export function wrappedBufferFromBase64(base64: Base64String): T { + return Buffer.from(base64, 'base64') as T; +} diff --git a/@sammo/util/src/types.ts b/@sammo/util/src/types.ts new file mode 100644 index 0000000..4d46c37 --- /dev/null +++ b/@sammo/util/src/types.ts @@ -0,0 +1,15 @@ +export type Nullable = T | null | undefined; + +export declare type ValuesOf = T[keyof T]; + +export type IDItem = { + id: T; +}; + +export type Entries = { + [K in keyof T]: [K, T[K]]; + }[keyof T][]; + + +export type BufferSource = ArrayBufferView | ArrayBuffer | SharedArrayBuffer; +export type BytesLike = BufferSource | string; diff --git a/@sammo/util/src/unwrap.ts b/@sammo/util/src/unwrap.ts new file mode 100644 index 0000000..9778b02 --- /dev/null +++ b/@sammo/util/src/unwrap.ts @@ -0,0 +1,25 @@ +import type { Nullable } from './types.js'; +import { NotNullExpected } from "./error.js"; + +export function unwrap(result: Nullable): T { + if (result === null || result === undefined) { + throw new NotNullExpected(); + } + return result; +} + +export function unwrap_any(result: Nullable): T { + if (result === null || result === undefined) { + throw new NotNullExpected(); + } + return result as T; +} + +type ErrType = { new(msg?: string): T } + +export function unwrap_err(result: Nullable, errType: ErrType, errMsg?: string): T { + if (result === null || result === undefined) { + throw new errType(errMsg); + } + return result; +} \ No newline at end of file diff --git a/@sammo/util/src/web.ts b/@sammo/util/src/web.ts new file mode 100644 index 0000000..4835494 --- /dev/null +++ b/@sammo/util/src/web.ts @@ -0,0 +1,34 @@ +import { unwrap } from "./unwrap.js"; + +export function isEmail(addr: string): boolean { + return String(addr) + .toLowerCase() + .match( + /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|.(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ + ) !== null; +} + +export function isIPAddr4(addr: string): boolean { + if (/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(addr)) { + return (true) + } + return false; +} + +export function hexToRgb(hex: string): { r: number; g: number; b: number; } | null { + const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); + return result ? { + r: parseInt(result[1], 16), + g: parseInt(result[2], 16), + b: parseInt(result[3], 16) + } : null; +} + +export function isBrightColor(color: string): boolean { + const cv = unwrap(hexToRgb(color)); + if ((cv.r * 0.299 + cv.g * 0.587 + cv.b * 0.114) > 140) { + return true; + } else { + return false; + } +} diff --git a/@sammo/util/tsconfig.json b/@sammo/util/tsconfig.json new file mode 100644 index 0000000..283da74 --- /dev/null +++ b/@sammo/util/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "ESNext", + "module": "node16", + "moduleResolution": "node16", + "resolveJsonModule": true, + "declaration": true, + "declarationMap": true, + "importHelpers": true, + "isolatedModules": true, + "verbatimModuleSyntax": true, + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "noImplicitOverride": true, + "skipLibCheck": true, + "incremental": true, + "rootDir": "./src", + "outDir": "./dist", + "composite": true + } +} diff --git a/@strpc/client_ky/package.json b/@strpc/client_ky/package.json new file mode 100644 index 0000000..98379e5 --- /dev/null +++ b/@strpc/client_ky/package.json @@ -0,0 +1,27 @@ +{ + "name": "@strpc/client_ky", + "version": "1.0.0", + "description": "", + "main": "dist/index.js", + "exports": { + ".": "./dist/index.js", + "./types": "./dist/types.js" + }, + "dependencies": { + "@strpc/def": "workspace:^" + }, + "devDependencies": { + "ky": "^1.0.1", + "lodash-es": "^4.17.21" + }, + "scripts": { + "build": "tsc --build" + }, + "type": "module", + "author": "", + "license": "MIT", + "peerDependencies": { + "ky": "^1.0.1", + "lodash-es": "^4.17.21" + } +} diff --git a/@strpc/client_ky/src/callClientAPI.ts b/@strpc/client_ky/src/callClientAPI.ts new file mode 100644 index 0000000..400c877 --- /dev/null +++ b/@strpc/client_ky/src/callClientAPI.ts @@ -0,0 +1,158 @@ +import { isArray, isEmpty } from "lodash-es"; +import ky from "ky"; +import type { HttpMethod, InvalidResponse, RawArgType, ValidResponse, recoveryMethod } from "@strpc/def"; + + +export type globalRecoveryFunction = (method: HttpMethod, path: string, args: RawArgType, recovery: recoveryMethod, result: InvalidResponse) => Promise<{ + justRetryAPI?: boolean; +} | void>; + +export class APIFailed extends Error { + constructor(public readonly reason: string, public readonly detail: unknown, public readonly recovery?: recoveryMethod) { + super(reason); + } +} + +export async function callClientAPI( + method: HttpMethod, + apiRoot: string, + path: string | string[], + args: RawArgType, + globalRecovery: globalRecoveryFunction | undefined +): Promise; +export async function callClientAPI( + method: HttpMethod, + apiRoot: string, + path: string | string[], + args: RawArgType, + globalRecovery: globalRecoveryFunction | undefined, + returnError: undefined +): Promise; +export async function callClientAPI( + method: HttpMethod, + apiRoot: string, + path: string | string[], + args: RawArgType, + globalRecovery: globalRecoveryFunction | undefined, + returnError: false +): Promise; +export async function callClientAPI( + method: HttpMethod, + apiRoot: string, + path: string | string[], + args: RawArgType, + globalRecovery: globalRecoveryFunction | undefined, + returnError: true +): Promise; +export async function callClientAPI( + method: HttpMethod, + apiRoot: string, + path: string | string[], + args: RawArgType, + globalRecovery: globalRecoveryFunction | undefined, + returnError?: boolean +): Promise { + if (isArray(path)) { + path = [apiRoot, ...path].join("/"); + } + else if (path.startsWith("/")) { + path = `${apiRoot}${path}`; + } + else { + path = `${apiRoot}/${path}`; + } + + if (args && isEmpty(args)) { + args = undefined; + } + + try { + let trialRemain = 3; + let lastErr: ErrorType | undefined = undefined; + // eslint-disable-next-line no-constant-condition + while(trialRemain > 0){ + const result = (await (() => { + if (method == "get") { + //TODO: args가 복합 object일 경우의 처리 + return ky(path, { + searchParams: args === undefined ? undefined : { + ...(args as Record), + }, + method, + headers: { + "content-type": "application/json", + }, + timeout: 30000, + retry: 0, + }); + } + return ky(path, { + method, + json: args, + headers: { + "content-type": "application/json", + }, + timeout: 30000, + retry: 0, + }); + })().json()) as ErrorType | ResultType; + + if (!result.result) { + lastErr = result; + if(result.recovery && globalRecovery){ + const recoveryResult = await globalRecovery(method, path, args, result.recovery, result); + if(recoveryResult !== undefined && recoveryResult.justRetryAPI){ + trialRemain--; + continue; + } + } + + if (returnError) { + return result; + } + throw new APIFailed( + result.reason, + result.detail, + result.recovery + ); + } + return result; + } + + if(lastErr === undefined){ + throw new Error('lastErr is undefined'); + } + + if (returnError) { + return lastErr; + } + throw lastErr.reason; + + } + catch(err) { + if(!returnError){ + throw err; + } + + let infoText = '' + + if(err instanceof APIFailed){ + infoText = err.reason; + } + else if(err instanceof Error){ + infoText = err.toString(); + } + else if(typeof err == 'string'){ + infoText = err; + } + else{ + infoText = JSON.stringify(err); + } + + return { + result: false, + reason: `failed to fetch(${path}): ${err}`, + detail: err, + } as ErrorType; + } +} \ No newline at end of file diff --git a/@strpc/client_ky/src/index.ts b/@strpc/client_ky/src/index.ts new file mode 100644 index 0000000..b4ebd3c --- /dev/null +++ b/@strpc/client_ky/src/index.ts @@ -0,0 +1,15 @@ +import { clientAPIPathGen, type APITail, type DefAPINamespace, type RawArgType } from "@strpc/def"; +import { callClientAPI, type globalRecoveryFunction } from "./callClientAPI.js"; +export { callClientAPI, type globalRecoveryFunction } from "./callClientAPI.js"; + +export function buildClientAPI(structure: T, apiRoot = '/api', globalRecovery?: globalRecoveryFunction){ + return clientAPIPathGen(structure, (path: string[], tail: APITail) => { + const method = tail.reqType; + return (args?: RawArgType, returnError?: boolean) => { + if (returnError) { + return callClientAPI(method, apiRoot, path.join('/'), args, globalRecovery, returnError); + } + return callClientAPI(method, apiRoot, path.join('/'), args, globalRecovery); + }; + }); +} \ No newline at end of file diff --git a/@strpc/client_ky/tsconfig.json b/@strpc/client_ky/tsconfig.json new file mode 100644 index 0000000..ac5ecf2 --- /dev/null +++ b/@strpc/client_ky/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist", + }, + "references": [ + { + "path": "../def" + }, + ] +} diff --git a/@strpc/def/package.json b/@strpc/def/package.json new file mode 100644 index 0000000..95bd123 --- /dev/null +++ b/@strpc/def/package.json @@ -0,0 +1,17 @@ +{ + "name": "@strpc/def", + "version": "1.0.0", + "description": "", + "main": "dist/index.js", + "exports": { + ".": "./dist/index.js", + "./types": "./dist/types.js" + }, + "devDependencies": {}, + "scripts": { + "build": "tsc --build" + }, + "type": "module", + "author": "", + "license": "MIT" +} diff --git a/@strpc/def/src/clientAPIPathGen.ts b/@strpc/def/src/clientAPIPathGen.ts new file mode 100644 index 0000000..c2549d3 --- /dev/null +++ b/@strpc/def/src/clientAPIPathGen.ts @@ -0,0 +1,38 @@ +export function clientAPIPathGen( + obj: T, + callback: (path: string[], tail: V) => unknown, + path: string[] = [], +): T { + const map = new Map(); + return new Proxy(obj, { + get(target, key) { + if(typeof key === 'symbol'){ + throw new Error('Symbol is not supported'); + } + + const cachedResult = map.get(key); + if(cachedResult !== undefined){ + return cachedResult; + } + + const nextPath = [...path, key]; + + let next; + if (key in target) { + next = target[key as keyof typeof target]; + } + else { + throw `${nextPath} is not exists`; + } + + if (typeof (next) === 'function') { + const result = callback(nextPath, next as V); + map.set(key, result); + return result; + } + const result = clientAPIPathGen(next as object, callback, nextPath); + map.set(key, result); + return result; + } + }) as T; +} \ No newline at end of file diff --git a/@strpc/def/src/index.ts b/@strpc/def/src/index.ts new file mode 100644 index 0000000..8819516 --- /dev/null +++ b/@strpc/def/src/index.ts @@ -0,0 +1,23 @@ +export type { + HttpMethod, + RawArgType, + DefAPINamespace, + APICompatType, + ValidResponse, + InvalidResponse, + recoveryMethod, + InferResponse, + InferError, + InferQuery, +} from './types.js'; + +export { + type APITail, + GET, + POST, + PUT, + DELETE, + PATCH, + HEAD, +} from './tail.js'; +export { clientAPIPathGen } from './clientAPIPathGen.js'; \ No newline at end of file diff --git a/@strpc/def/src/tail.ts b/@strpc/def/src/tail.ts new file mode 100644 index 0000000..46f72e3 --- /dev/null +++ b/@strpc/def/src/tail.ts @@ -0,0 +1,177 @@ +import type { ArgDeleteAPI, ArgGetAPI, ArgHeadAPI, ArgPatchAPI, ArgPostAPI, ArgPutAPI, EmptyDeleteAPI, EmptyGetAPI, EmptyHeadAPI, EmptyPatchAPI, EmptyPostAPI, EmptyPutAPI, InvalidResponse, RawArgType, ValidResponse } from "./types.js"; + +export type APITail = ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType; + +export function GET(): EmptyGetAPI; +export function GET< + ResultType extends ValidResponse = ValidResponse, + ErrorType extends InvalidResponse = InvalidResponse, +>(): EmptyGetAPI; +export function GET< + ArgType extends RawArgType, + ResultType extends ValidResponse = ValidResponse, + ErrorType extends InvalidResponse = InvalidResponse, +>(): ArgGetAPI; +export function GET< + ArgType extends RawArgType, + ResultType extends ValidResponse = ValidResponse, + ErrorType extends InvalidResponse = InvalidResponse, +>(): ArgGetAPI | EmptyGetAPI { + return Object.assign( + fakeGET, + { reqType: 'get' } as const + ) +} + +export function POST(): EmptyPostAPI; +export function POST< + ResultType extends ValidResponse = ValidResponse, + ErrorType extends InvalidResponse = InvalidResponse, +>(): EmptyPostAPI; +export function POST< + ArgType extends RawArgType, + ResultType extends ValidResponse = ValidResponse, + ErrorType extends InvalidResponse = InvalidResponse, +>(): ArgPostAPI; +export function POST< + ArgType extends RawArgType, + ResultType extends ValidResponse = ValidResponse, + ErrorType extends InvalidResponse = InvalidResponse, +>(): ArgPostAPI | EmptyPostAPI { + return Object.assign( + fakePOST, + { reqType: 'post' } as const + ) +} + +export function PUT(): EmptyPutAPI; +export function PUT< + ResultType extends ValidResponse = ValidResponse, + ErrorType extends InvalidResponse = InvalidResponse, +>(): EmptyPutAPI; +export function PUT< + ArgType extends RawArgType, + ResultType extends ValidResponse = ValidResponse, + ErrorType extends InvalidResponse = InvalidResponse, +>(): ArgPutAPI; +export function PUT< + ArgType extends RawArgType, + ResultType extends ValidResponse = ValidResponse, + ErrorType extends InvalidResponse = InvalidResponse, +>(): ArgPutAPI | EmptyPutAPI { + return Object.assign( + fakePUT, + { reqType: 'put' } as const + ) +} + +export function DELETE(): EmptyDeleteAPI; +export function DELETE< + ResultType extends ValidResponse = ValidResponse, + ErrorType extends InvalidResponse = InvalidResponse, +>(): EmptyDeleteAPI; +export function DELETE< + ArgType extends RawArgType, + ResultType extends ValidResponse = ValidResponse, + ErrorType extends InvalidResponse = InvalidResponse, +>(): ArgDeleteAPI; +export function DELETE< + ArgType extends RawArgType, + ResultType extends ValidResponse = ValidResponse, + ErrorType extends InvalidResponse = InvalidResponse, +>(): ArgDeleteAPI | EmptyDeleteAPI { + return Object.assign( + fakeDELETE, + { reqType: 'delete' } as const + ) +} + +export function PATCH(): EmptyPatchAPI; +export function PATCH< + ResultType extends ValidResponse = ValidResponse, + ErrorType extends InvalidResponse = InvalidResponse, +>(): EmptyPatchAPI; +export function PATCH< + ArgType extends RawArgType, + ResultType extends ValidResponse = ValidResponse, + ErrorType extends InvalidResponse = InvalidResponse, +>(): ArgPatchAPI; +export function PATCH< + ArgType extends RawArgType, + ResultType extends ValidResponse = ValidResponse, + ErrorType extends InvalidResponse = InvalidResponse, +>(): ArgPatchAPI | EmptyPatchAPI { + return Object.assign( + fakePATCH, + { reqType: 'patch' } as const + ) +} + +export function HEAD(): EmptyHeadAPI; +export function HEAD< + ResultType extends ValidResponse = ValidResponse, + ErrorType extends InvalidResponse = InvalidResponse, +>(): EmptyHeadAPI; +export function HEAD< + ArgType extends RawArgType, + ResultType extends ValidResponse = ValidResponse, + ErrorType extends InvalidResponse = InvalidResponse, +>(): ArgHeadAPI; +export function HEAD< + ArgType extends RawArgType, + ResultType extends ValidResponse = ValidResponse, + ErrorType extends InvalidResponse = InvalidResponse, +>(): ArgHeadAPI | EmptyHeadAPI { + return Object.assign( + fakeHEAD, + { reqType: 'head' } as const + ) +} + +async function fakeGET< + ResultType extends ValidResponse, + ErrorType extends InvalidResponse, + ArgType extends undefined = undefined +>(args?: ArgType, returnError = false): Promise { + throw `Can't directly call GET. ${args}, ${returnError}. Use auto-generated path API.` +} + +async function fakePOST< + ResultType extends ValidResponse, + ErrorType extends InvalidResponse, + ArgType extends RawArgType = undefined +>(args: ArgType, returnError = false): Promise { + throw `Can't directly call POST. ${args}, ${returnError}. Use auto-generated path API.` +} + +async function fakePUT< + ResultType extends ValidResponse, + ErrorType extends InvalidResponse, + ArgType extends RawArgType = undefined +>(args: ArgType, returnError = false): Promise { + throw `Can't directly call PUT. ${args}, ${returnError}. Use auto-generated path API.`; +} + +async function fakeDELETE< + ResultType extends ValidResponse, + ErrorType extends InvalidResponse, + ArgType extends RawArgType = undefined +>(args: ArgType, returnError = false): Promise { + throw `Can't directly call DELETE. ${args}, ${returnError}. Use auto-generated path API.`; +} + +async function fakePATCH< + ResultType extends ValidResponse, + ErrorType extends InvalidResponse, + ArgType extends RawArgType = undefined +>(args: ArgType, returnError = false): Promise { + throw `Can't directly call PATCH. ${args}, ${returnError}. Use auto-generated path API.` +} + +async function fakeHEAD< + ResultType extends ValidResponse, + ErrorType extends InvalidResponse, + ArgType extends RawArgType = undefined +>(args?: ArgType, returnError = false): Promise { + throw `Can't directly call HEAD. ${args}, ${returnError}. Use auto-generated path API.`; +} diff --git a/@strpc/def/src/types.ts b/@strpc/def/src/types.ts new file mode 100644 index 0000000..708b423 --- /dev/null +++ b/@strpc/def/src/types.ts @@ -0,0 +1,191 @@ +export type HttpMethod = 'get' | 'post' | 'put' | 'delete' | 'patch' | 'head'; +export type RawArgType = { + [key: string]: unknown; +} | undefined; + + +export interface ArgAnyAPI< + ArgType extends RawArgType, + ResultType extends ValidResponse, + ErrorType extends InvalidResponse, + Method extends HttpMethod +> { + (args: ArgType): Promise; + (args: ArgType, returnError: false): Promise; + (args: ArgType, returnError: true): Promise; + readonly reqType: Method; +} + +export type ArgGetAPI< + ArgType extends RawArgType, + ResultType extends ValidResponse, + ErrorType extends InvalidResponse +> = ArgAnyAPI; + +export type ArgPostAPI< + ArgType extends RawArgType, + ResultType extends ValidResponse, + ErrorType extends InvalidResponse +> = ArgAnyAPI; + +export type ArgPutAPI< + ArgType extends RawArgType, + ResultType extends ValidResponse, + ErrorType extends InvalidResponse +> = ArgAnyAPI; + +export type ArgDeleteAPI< + ArgType extends RawArgType, + ResultType extends ValidResponse, + ErrorType extends InvalidResponse +> = ArgAnyAPI; + +export type ArgPatchAPI< + ArgType extends RawArgType, + ResultType extends ValidResponse, + ErrorType extends InvalidResponse +> = ArgAnyAPI; + +export type ArgHeadAPI< + ArgType extends RawArgType, + ResultType extends ValidResponse, + ErrorType extends InvalidResponse +> = ArgAnyAPI; + +export interface EmptyAnyAPI { + (): Promise; + (args?: undefined): Promise; + (args: undefined, returnError: false): Promise; + (args: undefined, returnError: true): Promise; + readonly reqType: Method; +} + +export type EmptyGetAPI< + ResultType extends ValidResponse, + ErrorType extends InvalidResponse +> = EmptyAnyAPI; + +export type EmptyPostAPI< + ResultType extends ValidResponse, + ErrorType extends InvalidResponse +> = EmptyAnyAPI; + +export type EmptyPutAPI< + ResultType extends ValidResponse, + ErrorType extends InvalidResponse +> = EmptyAnyAPI; + +export type EmptyDeleteAPI< + ResultType extends ValidResponse, + ErrorType extends InvalidResponse +> = EmptyAnyAPI; + +export type EmptyPatchAPI< + ResultType extends ValidResponse, + ErrorType extends InvalidResponse +> = EmptyAnyAPI; + +export type EmptyHeadAPI< + ResultType extends ValidResponse, + ErrorType extends InvalidResponse +> = EmptyAnyAPI; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export type ArgTypeOf = T extends AnyAPI ? A : never; + + +export type AnyAPI< + ArgType extends RawArgType, + ResultType extends ValidResponse = ValidResponse, + ErrorType extends InvalidResponse = InvalidResponse +> = ArgType extends undefined ? EmptyAnyAPI : ArgAnyAPI; + +export type GetAPI< + ArgType extends RawArgType, + ResultType extends ValidResponse = ValidResponse, + ErrorType extends InvalidResponse = InvalidResponse +> = ArgType extends undefined ? EmptyGetAPI : ArgGetAPI; + +export type PostAPI< + ArgType extends RawArgType, + ResultType extends ValidResponse = ValidResponse, + ErrorType extends InvalidResponse = InvalidResponse +> = ArgType extends undefined ? EmptyPostAPI : ArgPostAPI; + +export type PutAPI< + ArgType extends RawArgType, + ResultType extends ValidResponse = ValidResponse, + ErrorType extends InvalidResponse = InvalidResponse +> = ArgType extends undefined ? EmptyPutAPI : ArgPutAPI; + +export type DeleteAPI< + ArgType extends RawArgType, + ResultType extends ValidResponse = ValidResponse, + ErrorType extends InvalidResponse = InvalidResponse +> = ArgType extends undefined ? EmptyDeleteAPI : ArgDeleteAPI; + +export type PatchAPI< + ArgType extends RawArgType, + ResultType extends ValidResponse = ValidResponse, + ErrorType extends InvalidResponse = InvalidResponse +> = ArgType extends undefined ? EmptyPatchAPI : ArgPatchAPI; + +export type HeadAPI< + ArgType extends RawArgType, + ResultType extends ValidResponse = ValidResponse, + ErrorType extends InvalidResponse = InvalidResponse +> = ArgType extends undefined ? EmptyHeadAPI : ArgHeadAPI; + +export interface ValidResponse { + result: true; +} + +export type recoveryMethod = 'hardRefresh' | 'refreshEntireProcess' | 'retryAPI' | 'login'; +export interface InvalidResponse { + result: false; + reason: string; + recovery?: recoveryMethod; + detail?: string | string[] | Record; +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export type Callable = (...args: any) => any; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export type InferQuery> = T extends EmptyAnyAPI ? undefined : T extends ArgAnyAPI ? Q : never; +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export type InferResponse> = T extends EmptyAnyAPI ? R : T extends ArgAnyAPI ? R : never; +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export type InferError> = T extends EmptyAnyAPI ? E : T extends ArgAnyAPI ? E : never; + + +export type DefAPINamespace = { + [key: string]: DefAPINamespace + // eslint-disable-next-line @typescript-eslint/no-explicit-any + | ArgGetAPI + // eslint-disable-next-line @typescript-eslint/no-explicit-any + | ArgPostAPI + // eslint-disable-next-line @typescript-eslint/no-explicit-any + | ArgPutAPI + // eslint-disable-next-line @typescript-eslint/no-explicit-any + | ArgDeleteAPI + // eslint-disable-next-line @typescript-eslint/no-explicit-any + | ArgPatchAPI + // eslint-disable-next-line @typescript-eslint/no-explicit-any + | ArgHeadAPI + // eslint-disable-next-line @typescript-eslint/no-explicit-any + | EmptyGetAPI + // eslint-disable-next-line @typescript-eslint/no-explicit-any + | EmptyPostAPI + // eslint-disable-next-line @typescript-eslint/no-explicit-any + | EmptyPutAPI + // eslint-disable-next-line @typescript-eslint/no-explicit-any + | EmptyDeleteAPI + // eslint-disable-next-line @typescript-eslint/no-explicit-any + | EmptyPatchAPI + // eslint-disable-next-line @typescript-eslint/no-explicit-any + | EmptyHeadAPI + ; +} + +export type APICompatType = T extends AnyAPI ? AnyAPI : never; diff --git a/@strpc/def/tsconfig.json b/@strpc/def/tsconfig.json new file mode 100644 index 0000000..d6e53f3 --- /dev/null +++ b/@strpc/def/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist", + }, + "references": [ + ] +} diff --git a/@strpc/express/package.json b/@strpc/express/package.json new file mode 100644 index 0000000..3dd1a05 --- /dev/null +++ b/@strpc/express/package.json @@ -0,0 +1,33 @@ +{ + "name": "@strpc/express", + "version": "1.0.0", + "description": "", + "main": "dist/index.js", + "scripts": { + "build": "tsc --build" + }, + "exports": { + ".": "./dist/index.js", + "./generator": "./dist/generator.js", + "./proc_decorator": "./dist/proc_decorator.js" + }, + "type": "module", + "author": "", + "license": "MIT", + "dependencies": { + "@strpc/def": "workspace:^" + }, + "devDependencies": { + "@types/express": "^4.17.17", + "express": "^4.18.2", + "express-session": "^1.17.3", + "lodash-es": "^4.17.21", + "zod": "^3.22.2" + }, + "peerDependencies": { + "express": "^4.18.2", + "express-session": "^1.17.3", + "lodash-es": "^4.17.21", + "zod": "^3.22.2" + } +} diff --git a/@strpc/express/src/defs.ts b/@strpc/express/src/defs.ts new file mode 100644 index 0000000..9dd5a35 --- /dev/null +++ b/@strpc/express/src/defs.ts @@ -0,0 +1,213 @@ + +import type { Request, Response } from 'express'; +import type { AnyAPI, Callable, DefAPINamespace, DeleteAPI, GetAPI, HeadAPI, HttpMethod, InferError, InferQuery, InferResponse, InvalidResponse, PatchAPI, PostAPI, PutAPI, recoveryMethod } from '@strpc/def/types'; +import type { Empty, PostProcDecoratorRunner, ProcDecoratorRunner } from './proc_decorator.js'; +import type { ZodType } from 'zod'; + +export type APINamespace = { + [key: string]: APINamespace + // eslint-disable-next-line @typescript-eslint/no-explicit-any + | iAPI_GET + // eslint-disable-next-line @typescript-eslint/no-explicit-any + | iAPI_POST + // eslint-disable-next-line @typescript-eslint/no-explicit-any + | iAPI_PUT + // eslint-disable-next-line @typescript-eslint/no-explicit-any + | iAPI_DELETE + // eslint-disable-next-line @typescript-eslint/no-explicit-any + | iAPI_PATCH + // eslint-disable-next-line @typescript-eslint/no-explicit-any + | iAPI_HEAD + ; +} + + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export type AnyAPIExecuter = APIExecuter; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type AnyAnyAPI = AnyAPI; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +interface APIExecuter { + (query: InferQuery, ctx: CTX, expressReq: Request, expressRes: Response): Promise | InferError | true>; + httpMethod: HttpMethod; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + argValidator?: ZodType>; + preDecorator: ProcDecoratorRunner; + postDecorator: PostProcDecoratorRunner; +} + +export interface iAPI_GET extends APIExecuter { + httpMethod: 'get'; +} + +export interface iAPI_POST extends APIExecuter { + httpMethod: 'post'; +} + +export interface iAPI_PUT extends APIExecuter { + httpMethod: 'put'; +} + +export interface iAPI_DELETE extends APIExecuter { + httpMethod: 'delete'; +} + +export interface iAPI_PATCH extends APIExecuter { + httpMethod: 'patch'; +} + +export interface iAPI_HEAD extends APIExecuter { + httpMethod: 'head'; +} + + +/** API의 반환형. ValidResponse | InvalidResponse | true */ +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export type APIReturnType = Promise | InferError | true>; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function generateAPI(httpMethod: HttpMethod, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + argValidator: ZodType> | undefined, + preDecorator: ProcDecoratorRunner, + postDecorator: PostProcDecoratorRunner, + callback: (query: InferQuery, ctx: CTX, expressReq: Request, expressRes: Response) => Promise | InferError | true>, +): APIExecuter { + return Object.assign( + callback, + { + httpMethod, + argValidator, + preDecorator, + postDecorator, + } + ); +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function GET>(argValidator?: ZodType>) { + return ([preDecorator, postDecorator]: readonly [ProcDecoratorRunner, PostProcDecoratorRunner]) => { + return (callback: (query: InferQuery, ctx: CTX, expressReq: Request, expressRes: Response) => Promise | InferError | true>) => { + return generateAPI( + 'get', + argValidator, + preDecorator, + postDecorator, + callback, + ) as iAPI_GET; + } + } +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function POST>(argValidator?: ZodType>) { + return ([preDecorator, postDecorator]: readonly [ProcDecoratorRunner, PostProcDecoratorRunner]) => { + return (callback: (query: InferQuery, ctx: CTX, expressReq: Request, expressRes: Response) => Promise | InferError | true>) => { + return generateAPI( + 'post', + argValidator, + preDecorator, + postDecorator, + callback, + ) as iAPI_POST; + } + } +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function PUT>(argValidator?: ZodType>) { + return ([preDecorator, postDecorator]: readonly [ProcDecoratorRunner, PostProcDecoratorRunner]) => { + return (callback: (query: InferQuery, ctx: CTX, expressReq: Request, expressRes: Response) => Promise | InferError | true>) => { + return generateAPI( + 'put', + argValidator, + preDecorator, + postDecorator, + callback, + ) as iAPI_PUT; + } + } +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function DELETE, Z extends ZodType>>(argValidator?: Z) { + return ([preDecorator, postDecorator]: readonly [ProcDecoratorRunner, PostProcDecoratorRunner]) => { + return (callback: (query: InferQuery, ctx: CTX, expressReq: Request, expressRes: Response) => Promise | InferError | true>) => { + return generateAPI( + 'delete', + argValidator, + preDecorator, + postDecorator, + callback, + ) as iAPI_DELETE; + } + } +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function PATCH>(argValidator?: ZodType>) { + return ([preDecorator, postDecorator]: readonly [ProcDecoratorRunner, PostProcDecoratorRunner]) => { + return (callback: (query: InferQuery, ctx: CTX, expressReq: Request, expressRes: Response) => Promise | InferError | true>) => { + return generateAPI( + 'patch', + argValidator, + preDecorator, + postDecorator, + callback, + ) as iAPI_PATCH; + } + } +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function HEAD>(argValidator?: ZodType>) { + return ([preDecorator, postDecorator]: readonly [ProcDecoratorRunner, PostProcDecoratorRunner]) => { + return (callback: (query: InferQuery, ctx: CTX, expressReq: Request, expressRes: Response) => Promise | InferError | true>) => { + return generateAPI( + 'head', + argValidator, + preDecorator, + postDecorator, + callback, + ) as iAPI_HEAD; + } + } +} + +export function raiseError(reason: string, recovery?: recoveryMethod): InvalidResponse { + if (recovery) { + return { + result: false, + reason, + recovery, + }; + } + return { + result: false, + reason, + }; +} + +export type APIServerType = + // eslint-disable-next-line @typescript-eslint/no-explicit-any + T extends GetAPI ? iAPI_GET, any> : + // eslint-disable-next-line @typescript-eslint/no-explicit-any + T extends PostAPI ? iAPI_POST, any> : + // eslint-disable-next-line @typescript-eslint/no-explicit-any + T extends PutAPI ? iAPI_PUT, any> : + // eslint-disable-next-line @typescript-eslint/no-explicit-any + T extends DeleteAPI ? iAPI_DELETE, any> : + // eslint-disable-next-line @typescript-eslint/no-explicit-any + T extends PatchAPI ? iAPI_PATCH, any> : + // eslint-disable-next-line @typescript-eslint/no-explicit-any + T extends HeadAPI ? iAPI_HEAD, any> : + + never; +export type APINamespaceType = { + [K in keyof T]: + T[K] extends Callable ? APIServerType : + T[K] extends DefAPINamespace ? APINamespaceType : + never; +}; \ No newline at end of file diff --git a/@strpc/express/src/generator.ts b/@strpc/express/src/generator.ts new file mode 100644 index 0000000..54fd46c --- /dev/null +++ b/@strpc/express/src/generator.ts @@ -0,0 +1,161 @@ +import { Router, type Request, type Response } from 'express'; +import type { AnyAPIExecuter, APINamespace } from './defs.js'; +import type { RawArgType } from '@strpc/def'; +import type { SafeParseReturnType, ZodType } from 'zod'; +import { flatten } from 'lodash-es'; + +const PRINT_API_CALL = true; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +async function parseParam(req: Request, argValidator?: ZodType): Promise> { + if (!argValidator) { + return { + success: true, + data: req.query as Q + } + } + + const query = req.query; + return await argValidator.safeParseAsync(query); +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +async function parseBody(req: Request, argValidator?: ZodType): Promise> { + if (!argValidator) { + return { + success: true, + data: req.body as Q + } + } + + const query = req.body; + return await argValidator.safeParseAsync(query); +} + +async function apiRun(query: Q, req: Request, res: Response, api: AnyAPIExecuter): Promise { + const [preResult, ctx] = await api.preDecorator({}, req, res); + if (!preResult.every((v) => v.result)) { + const lastErr = preResult.pop() as typeof preResult[0]; + + const [postResult,] = await api.postDecorator(ctx, preResult, req, res, false); + const postErrors = postResult.filter((obj) => !obj.result); + if (postErrors.length) { + //회수조차 불가능? + if (PRINT_API_CALL) { + console.log(JSON.stringify([(new Date).toISOString(), req.ip, req.path, false, 'preDecorator', lastErr.type, lastErr.info])); + } + res.json({ + result: false, + path: req.path, + reason: lastErr.info, + recovery: lastErr.recovery, + detail: { + type: 'decorator', + preDecorator: [lastErr.type, lastErr.info], + postDecorator: flatten(postErrors.map((obj) => [obj.type, obj.info])), + }, + }); + return; + } + + if (PRINT_API_CALL) { + console.log(JSON.stringify([(new Date).toISOString(), req.ip, req.path, false, 'preDecorator', lastErr.type, lastErr.info])); + } + res.json({ + result: false, + path: req.path, + reason: lastErr.info, + recovery: lastErr.recovery, + detail: { + type: 'decorator', + preDecorator: [lastErr.type, lastErr.info], + }, + }) + return; + } + const result = await api(query, ctx, req, res); + const [postResult,] = await api.postDecorator(ctx, preResult, req, res, true); + const postErrors = postResult.filter((obj) => !obj.result); + if (postErrors.length) { + const lastErr = postErrors.pop() as typeof postErrors[0]; + if (PRINT_API_CALL) { + console.log(JSON.stringify([(new Date).toISOString(), req.ip, req.path, false, 'postDecorator', lastErr.type, lastErr.info])); + } + if (result === true) { + //NOTE: 이미 api에서 response를 보낸 특이 케이스. + return; + } + res.json({ + result: false, + path: req.path, + reason: lastErr?.info, + recovery: lastErr?.recovery, + detail: { + type: 'decorator', + preDecorator: flatten(postErrors.map((obj) => [obj.type, obj.info])), + }, + originalResult: result, + }); + return; + } + + if (PRINT_API_CALL) { + if(result === true){ + console.log(JSON.stringify([(new Date).toISOString(), req.ip, req.path, true, 'passThrough'])); + } + else{ + let tmp_result = true; + let tmp_reason = undefined; + if('result' in result){ + tmp_result = result.result; + } + if('reason' in result){ + tmp_reason = result.reason; + } + console.log(JSON.stringify([(new Date).toISOString(), req.ip, req.path, tmp_result, tmp_reason])); + } + + } + + if (result !== true) { + res.json(result); + } +} + +export function buildAPISystem(api: N | Q): Router { + const router = Router(); + + if (typeof api === 'function') { + throw 'root api cannot be function'; + } + + for (const [key, value] of Object.entries(api)) { + const rkey = `/${key}`; + if (typeof value !== 'function') { + router.use(rkey, buildAPISystem(value)); + + continue; + } + const executer = value; + + if (!executer.httpMethod) { + throw new Error('APIExecuter.reqType is not defined'); + } + + const parser = executer.httpMethod === 'get' ? parseParam : parseBody; + router[executer.httpMethod](rkey, async (req, res) => { + const queryResult = await parser(req, executer.argValidator); + if (!queryResult.success) { + res.json({ + result: false, + reason: `invalid parameter: ${queryResult.error.message}`, + error: queryResult.error + }); + return; + } + + await apiRun(queryResult.data, req, res, executer); + }); + } + return router; +} \ No newline at end of file diff --git a/@strpc/express/src/index.ts b/@strpc/express/src/index.ts new file mode 100644 index 0000000..0545755 --- /dev/null +++ b/@strpc/express/src/index.ts @@ -0,0 +1,3 @@ +export * from './defs.js'; +export * as generator from './generator.js'; +export * as proc_decorator from './proc_decorator.js'; \ No newline at end of file diff --git a/@strpc/express/src/proc_decorator.ts b/@strpc/express/src/proc_decorator.ts new file mode 100644 index 0000000..da17d98 --- /dev/null +++ b/@strpc/express/src/proc_decorator.ts @@ -0,0 +1,186 @@ +import type { recoveryMethod } from "@strpc/def"; +import type { Request, Response } from "express"; + +type MayBePromise = T | Promise; + +export type Empty = Record; +export type DecoratorResultTrue = { + result: true; + type?: string; + info?: string; + recovery?: recoveryMethod; +}; +export type DecoratorResultFalse = { + result: false; + type: string; + info: string; + recovery?: recoveryMethod; +} +export type DecoratorResult = DecoratorResultTrue | DecoratorResultFalse; +export type DecoratorStack = DecoratorResult[]; + +export interface ProcDecorator { + (inCtx: In & Partial, req: Request, res: Response) + : MayBePromise<[DecoratorResultTrue, Out] | [DecoratorResultFalse, In & Partial]>; +} + +export interface PostProcDecorator { + (ctx: T, preResult: DecoratorResult, req: Request, res: Response, isValidRoute: boolean): MayBePromise<[DecoratorResult, T]>; +} + +export interface ProcDecoratorRunner { + (inCtx: In & Partial, req: Request, res: Response): MayBePromise<[DecoratorStack, Out]>; +} + +export interface PostProcDecoratorRunner { + (ctx: T, preResult: DecoratorStack, req: Request, res: Response, isValidRoute: boolean): MayBePromise<[DecoratorStack, T]>; +} + + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type PlainDecorator = ProcDecorator; +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type PlainPostDecorator = PostProcDecorator; + + +export type ProcDecoratorGenerator = ProcDecorator; +export type ProcDecoratorPrePostGenerator = [ProcDecorator, PostProcDecorator]; + +export type ProcDecoratorChain = readonly ((() => PlainDecorator) | (() => [PlainDecorator, PlainPostDecorator]))[]; + +export type ResolveChain = T extends undefined ? Empty : T extends ProcDecoratorChain ? Resolve> : never; + + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export type ParseInType = T extends ProcDecorator ? object extends A ? A : never : never; +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export type ParseOutType = T extends ProcDecorator ? B : never; + +export const EmptyProcDecorator: readonly [ProcDecoratorRunner, PostProcDecoratorRunner] = [ + async (ctx) => [[], ctx], async (ctx, stack) => [stack, ctx] +]; + +export function declProcDecorators(...decorators: T) { + type OutType = ParseOutType>; + + const preDecorator: PlainDecorator[] = []; + const postDecorator: (PlainPostDecorator | undefined)[] = []; + if (decorators) { + for (const procGen of decorators) { + const proc = procGen(); + if (Array.isArray(proc)) { + preDecorator.push(proc[0]); + postDecorator.push(proc[1]); + } + else { + preDecorator.push(proc); + postDecorator.push(undefined); + } + } + } + + const packedDecorators: readonly [ProcDecoratorRunner, PostProcDecoratorRunner] = [ + async (ctx, req, res) => { + let rctx = ctx as unknown as OutType; + const decoratorStack: DecoratorStack = []; + if (!preDecorator) { + return [decoratorStack, rctx]; + } + + for (const [idx, proc] of preDecorator.entries()) { + try { + const [stackResult, newCtx] = await proc(rctx, req, res); + decoratorStack.push(stackResult); + + if (stackResult.result) { + rctx = newCtx; + continue; + } + + return [decoratorStack, newCtx]; + } + catch (e) { + while (decoratorStack.length > idx) { + decoratorStack.pop(); + } + decoratorStack.push({ + result: false, + type: 'PreThrow', + info: `internal error: ${e}`, + }); + + return [decoratorStack, rctx]; + } + } + + return [decoratorStack, rctx]; + }, + async (ctx, stack, req, res) => { + if (!postDecorator.length) { + return [stack, ctx]; + } + let isValidRoute = stack.length === postDecorator.length && stack.every(v => v.result); + for (let idx = stack.length - 1; idx >= 0; idx--) { + const preStackResult = stack[idx] as DecoratorResult; + if (!preStackResult.result) { + continue; + } + + const proc = postDecorator[idx]; + + if (!proc) { + if (isValidRoute) { + stack.pop(); + } + continue; + } + + try { + const [postStackResult, nextCtx] = await proc(ctx, preStackResult, req, res, isValidRoute); + if (postStackResult.result) { + if (isValidRoute) { + stack.pop(); + } + ctx = nextCtx; + continue; + } + + isValidRoute = false; + stack[idx] = postStackResult; + + ctx = nextCtx; + } + catch (e) { + isValidRoute = false; + stack[idx] = { + result: false, + type: 'PostThrow', + info: `internal error: ${e}`, + }; + } + + } + return [stack, ctx]; + }, + ] as const; + + return packedDecorators; +} + +type Compose2 = B extends C ? ProcDecorator : never; + +type PD1 = () => ProcDecorator; +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type PD2 = () => [ProcDecorator, PostProcDecorator]; + +export type PackChain = + T extends readonly [] ? ProcDecorator : + T extends readonly [PD1] ? ProcDecorator : + T extends readonly [PD2] ? ProcDecorator : + T extends readonly [PD1, PD1, ... infer R] ? PackChain<[() => Compose2, ...R]> : + T extends readonly [PD2, PD1, ... infer R] ? PackChain<[() => Compose2, ...R]> : + T extends readonly [PD1, PD2, ... infer R] ? PackChain<[() => Compose2, ...R]> : + T extends readonly [PD2, PD2, ... infer R] ? PackChain<[() => Compose2, ...R]> : + never; + +type Resolve = T extends ProcDecorator ? Empty extends A ? B : never : never; \ No newline at end of file diff --git a/@strpc/express/tsconfig.json b/@strpc/express/tsconfig.json new file mode 100644 index 0000000..0f5425e --- /dev/null +++ b/@strpc/express/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist", + }, + "references": [ + { + "path": "../def" + }, + ] +} \ No newline at end of file diff --git a/LICENSE b/LICENSE index 6a3aa52..02cc200 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2023 devsam +Copyright (c) 2023 hide_d Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: diff --git a/README.md b/README.md deleted file mode 100644 index 12bfd72..0000000 --- a/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# ts_test - diff --git a/package.json b/package.json new file mode 100644 index 0000000..c6d9a9e --- /dev/null +++ b/package.json @@ -0,0 +1,47 @@ +{ + "name": "sam_hidche", + "version": "0.0.0", + "private": true, + "scripts": { + "dev": "run-p dev:client dev:server dev:gateway_server dev:gateway_client", + "build": "run-s build:ts build:vite", + "build:ts": "run-p build:server build:gateway_server", + "build:vite": "run-s build:client build:gateway_client", + "type-check": "run-p type-check:server type-check:client type-check:gateway_server type-check:gateway_client", + + "dev:server": "pnpm --filter @sammo/server dev", + "dev:client": "pnpm --filter @sammo/client dev", + "dev:gateway_server": "pnpm --filter @sammo/gateway_server dev", + "dev:gateway_client": "pnpm --filter @sammo/gateway_client dev", + + "build:def": "pnpm --filter @sammo/api_def build --force", + "build:server": "pnpm --filter @sammo/server build", + "build:client": "pnpm --filter @sammo/client build", + "build:gateway_server": "pnpm --filter @sammo/gateway_server build", + "build:gateway_client": "pnpm --filter @sammo/gateway_client build", + + "type-check:server": "pnpm --filter @sammo/server type-check", + "type-check:client": "pnpm --filter @sammo/client type-check", + "type-check:gateway_server": "pnpm --filter @sammo/gateway_server type-check", + "type-check:gateway_client": "pnpm --filter @sammo/gateway_client type-check", + + "lint": "lint", + "test": "jest" + }, + "devDependencies": { + "@rushstack/eslint-patch": "^1.3.2", + "@types/lodash-es": "^4.17.8", + "@types/node": "^18.17.0", + "@vitejs/plugin-vue": "^4.2.3", + "@vue/eslint-config-prettier": "^8.0.0", + "@vue/eslint-config-typescript": "^11.0.3", + "@vue/tsconfig": "^0.4.0", + "eslint": "^8.45.0", + "eslint-plugin-vue": "^9.15.1", + "npm-run-all": "^4.1.5", + "prettier": "^3.0.0", + "ts-node": "^10.9.1", + "tsc-watch": "^6.0.4", + "typescript": "~5.1.6" + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..24e3709 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,6441 @@ +lockfileVersion: '6.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + devDependencies: + '@rushstack/eslint-patch': + specifier: ^1.3.2 + version: 1.3.2 + '@types/lodash-es': + specifier: ^4.17.8 + version: 4.17.8 + '@types/node': + specifier: ^18.17.0 + version: 18.17.0 + '@vitejs/plugin-vue': + specifier: ^4.2.3 + version: 4.2.3(vite@4.4.6)(vue@3.3.4) + '@vue/eslint-config-prettier': + specifier: ^8.0.0 + version: 8.0.0(eslint@8.45.0)(prettier@3.0.0) + '@vue/eslint-config-typescript': + specifier: ^11.0.3 + version: 11.0.3(eslint-plugin-vue@9.15.1)(eslint@8.45.0)(typescript@5.1.6) + '@vue/tsconfig': + specifier: ^0.4.0 + version: 0.4.0 + eslint: + specifier: ^8.45.0 + version: 8.45.0 + eslint-plugin-vue: + specifier: ^9.15.1 + version: 9.15.1(eslint@8.45.0) + npm-run-all: + specifier: ^4.1.5 + version: 4.1.5 + prettier: + specifier: ^3.0.0 + version: 3.0.0 + ts-node: + specifier: ^10.9.1 + version: 10.9.1(@types/node@18.17.0)(typescript@5.1.6) + tsc-watch: + specifier: ^6.0.4 + version: 6.0.4(typescript@5.1.6) + typescript: + specifier: ~5.1.6 + version: 5.1.6 + + '@sammo/api_def': + dependencies: + '@sammo/crypto': + specifier: workspace:^ + version: link:../crypto + '@sammo/secure_token': + specifier: workspace:^ + version: link:../secure_token + '@sammo/util': + specifier: workspace:^ + version: link:../util + '@strpc/def': + specifier: workspace:^ + version: link:../../@strpc/def + devDependencies: + zod: + specifier: ^3.22.2 + version: 3.22.2 + + '@sammo/client': + dependencies: + '@popperjs/core': + specifier: ^2.11.8 + version: 2.11.8 + '@sammo/game_logic': + specifier: workspace:^ + version: link:../game_logic + '@sammo/util': + specifier: workspace:^ + version: link:../util + '@strpc/def': + specifier: workspace:^ + version: link:../../@strpc/def + bootstrap: + specifier: ^5.3.1 + version: 5.3.1(@popperjs/core@2.11.8) + bootstrap-vue-next: + specifier: ^0.9.26 + version: 0.9.26(vue@3.3.4) + bson: + specifier: ^5.4.0 + version: 5.4.0 + date-fns: + specifier: ^2.30.0 + version: 2.30.0 + ky: + specifier: ^1.0.1 + version: 1.0.1 + lodash-es: + specifier: ^4.17.21 + version: 4.17.21 + pinia: + specifier: ^2.1.4 + version: 2.1.4(typescript@5.2.2)(vue@3.3.4) + vue: + specifier: ^3.3.4 + version: 3.3.4 + vue-router: + specifier: ^4.2.4 + version: 4.2.4(vue@3.3.4) + devDependencies: + '@tsconfig/node20': + specifier: ^20.1.2 + version: 20.1.2 + '@types/lodash-es': + specifier: ^4.17.9 + version: 4.17.9 + '@types/node': + specifier: ^20.6.3 + version: 20.6.3 + '@vue/eslint-config-prettier': + specifier: ^8.0.0 + version: 8.0.0(eslint@8.50.0)(prettier@3.0.0) + '@vue/eslint-config-typescript': + specifier: ^11.0.3 + version: 11.0.3(eslint-plugin-vue@9.15.1)(eslint@8.50.0)(typescript@5.2.2) + '@vue/tsconfig': + specifier: ^0.4.0 + version: 0.4.0 + eslint: + specifier: ^8.50.0 + version: 8.50.0 + eslint-plugin-vue: + specifier: ^9.15.1 + version: 9.15.1(eslint@8.50.0) + prettier: + specifier: ^3.0.0 + version: 3.0.0 + ts-node: + specifier: ^10.9.1 + version: 10.9.1(@types/node@20.6.3)(typescript@5.2.2) + tslib: + specifier: ^2.6.2 + version: 2.6.2 + vite: + specifier: ^4.4.6 + version: 4.4.6(@types/node@20.6.3) + vue-tsc: + specifier: ^1.8.6 + version: 1.8.6(typescript@5.2.2) + zod: + specifier: ^3.22.2 + version: 3.22.2 + + '@sammo/crypto': + dependencies: + '@sammo/util': + specifier: workspace:^ + version: link:../util + devDependencies: + '@types/jest': + specifier: ^29.5.4 + version: 29.5.5 + '@types/lodash': + specifier: ^4.14.198 + version: 4.14.198 + '@types/lodash-es': + specifier: ^4.17.9 + version: 4.17.9 + '@types/node': + specifier: ^20.6.0 + version: 20.6.3 + '@typescript-eslint/eslint-plugin': + specifier: ^6.7.0 + version: 6.7.2(@typescript-eslint/parser@6.7.2)(eslint@8.49.0)(typescript@5.2.2) + '@typescript-eslint/parser': + specifier: ^6.7.0 + version: 6.7.2(eslint@8.49.0)(typescript@5.2.2) + bson: + specifier: ^5.4.0 + version: 5.4.0 + buffer: + specifier: ^6.0.3 + version: 6.0.3 + eslint: + specifier: ^8.49.0 + version: 8.49.0 + jest: + specifier: ^29.7.0 + version: 29.7.0(@types/node@20.6.3)(ts-node@10.9.1) + lodash-es: + specifier: ^4.17.21 + version: 4.17.21 + ts-jest: + specifier: ^29.1.1 + version: 29.1.1(@babel/core@7.22.20)(jest@29.7.0)(typescript@5.2.2) + tslib: + specifier: ^2.6.2 + version: 2.6.2 + typescript: + specifier: ^5.2.2 + version: 5.2.2 + + '@sammo/game_logic': + dependencies: + '@sammo/api_def': + specifier: workspace:^ + version: link:../api_def + '@sammo/server_util': + specifier: workspace:^ + version: link:../server_util + '@sammo/util': + specifier: workspace:^ + version: link:../util + '@strpc/express': + specifier: workspace:^ + version: link:../../@strpc/express + dotenv: + specifier: ^16.3.1 + version: 16.3.1 + mongoose: + specifier: ^7.4.3 + version: 7.4.3 + devDependencies: + '@types/node': + specifier: ^20.6.3 + version: 20.6.3 + + '@sammo/gateway_client': + dependencies: + '@popperjs/core': + specifier: ^2.11.8 + version: 2.11.8 + '@sammo/util': + specifier: workspace:^ + version: link:../util + '@strpc/def': + specifier: workspace:^ + version: link:../../@strpc/def + bootstrap: + specifier: ^5.3.1 + version: 5.3.1(@popperjs/core@2.11.8) + bootstrap-vue-next: + specifier: ^0.9.26 + version: 0.9.26(vue@3.3.4) + bson: + specifier: ^5.4.0 + version: 5.4.0 + date-fns: + specifier: ^2.30.0 + version: 2.30.0 + ky: + specifier: ^1.0.1 + version: 1.0.1 + lodash-es: + specifier: ^4.17.21 + version: 4.17.21 + pinia: + specifier: ^2.1.4 + version: 2.1.4(typescript@5.2.2)(vue@3.3.4) + vue: + specifier: ^3.3.4 + version: 3.3.4 + vue-router: + specifier: ^4.2.4 + version: 4.2.4(vue@3.3.4) + devDependencies: + '@tsconfig/node20': + specifier: ^20.1.2 + version: 20.1.2 + '@types/lodash-es': + specifier: ^4.17.9 + version: 4.17.9 + '@types/node': + specifier: ^20.6.3 + version: 20.6.3 + '@vue/eslint-config-prettier': + specifier: ^8.0.0 + version: 8.0.0(eslint@8.50.0)(prettier@3.0.0) + '@vue/eslint-config-typescript': + specifier: ^11.0.3 + version: 11.0.3(eslint-plugin-vue@9.15.1)(eslint@8.50.0)(typescript@5.2.2) + '@vue/tsconfig': + specifier: ^0.4.0 + version: 0.4.0 + eslint: + specifier: ^8.50.0 + version: 8.50.0 + eslint-plugin-vue: + specifier: ^9.15.1 + version: 9.15.1(eslint@8.50.0) + prettier: + specifier: ^3.0.0 + version: 3.0.0 + ts-node: + specifier: ^10.9.1 + version: 10.9.1(@types/node@20.6.3)(typescript@5.2.2) + tslib: + specifier: ^2.6.2 + version: 2.6.2 + vite: + specifier: ^4.4.6 + version: 4.4.6(@types/node@20.6.3) + vue-tsc: + specifier: ^1.8.6 + version: 1.8.6(typescript@5.2.2) + zod: + specifier: ^3.22.2 + version: 3.22.2 + + '@sammo/gateway_server': + dependencies: + '@sammo/api_def': + specifier: workspace:^ + version: link:../api_def + '@sammo/crypto': + specifier: workspace:^ + version: link:../crypto + '@sammo/server_util': + specifier: workspace:^ + version: link:../server_util + '@sammo/util': + specifier: workspace:^ + version: link:../util + '@strpc/express': + specifier: workspace:^ + version: link:../../@strpc/express + date-fns: + specifier: ^2.30.0 + version: 2.30.0 + dotenv: + specifier: ^16.3.1 + version: 16.3.1 + express: + specifier: ^4.18.2 + version: 4.18.2 + express-session: + specifier: ^1.17.3 + version: 1.17.3 + lodash-es: + specifier: ^4.17.21 + version: 4.17.21 + mongoose: + specifier: ^7.4.3 + version: 7.4.3 + reflect-metadata: + specifier: ^0.1.13 + version: 0.1.13 + tslib: + specifier: ^2.6.2 + version: 2.6.2 + zod: + specifier: ^3.22.2 + version: 3.22.2 + devDependencies: + '@types/express': + specifier: ^4.17.17 + version: 4.17.17 + '@types/express-session': + specifier: ^1.17.7 + version: 1.17.7 + '@types/node': + specifier: ^20.6.3 + version: 20.6.3 + + '@sammo/secure_token': + dependencies: + '@sammo/crypto': + specifier: workspace:^ + version: link:../crypto + '@sammo/util': + specifier: workspace:^ + version: link:../util + devDependencies: + bson: + specifier: ^5.4.0 + version: 5.4.0 + buffer: + specifier: ^6.0.3 + version: 6.0.3 + zod: + specifier: ^3.22.2 + version: 3.22.2 + + '@sammo/server': + dependencies: + '@esfx/async-readerwriterlock': + specifier: ^1.0.0 + version: 1.0.0 + '@sammo/api_def': + specifier: workspace:^ + version: link:../api_def + '@sammo/game_logic': + specifier: workspace:^ + version: link:../game_logic + '@sammo/server_util': + specifier: workspace:^ + version: link:../server_util + '@sammo/util': + specifier: workspace:^ + version: link:../util + '@strpc/express': + specifier: workspace:^ + version: link:../../@strpc/express + date-fns: + specifier: ^2.30.0 + version: 2.30.0 + dotenv: + specifier: ^16.3.1 + version: 16.3.1 + eventemitter3: + specifier: ^5.0.1 + version: 5.0.1 + express: + specifier: ^4.18.2 + version: 4.18.2 + express-session: + specifier: ^1.17.3 + version: 1.17.3 + ky: + specifier: ^1.0.1 + version: 1.0.1 + lodash-es: + specifier: ^4.17.21 + version: 4.17.21 + mongoose: + specifier: ^7.4.3 + version: 7.4.3 + reflect-metadata: + specifier: ^0.1.13 + version: 0.1.13 + tslib: + specifier: ^2.6.2 + version: 2.6.2 + zod: + specifier: ^3.22.2 + version: 3.22.2 + devDependencies: + '@sammo/gateway_server': + specifier: workspace:^ + version: link:../gateway_server + '@types/express': + specifier: ^4.17.17 + version: 4.17.17 + '@types/express-session': + specifier: ^1.17.7 + version: 1.17.7 + '@types/node': + specifier: ^20.6.3 + version: 20.6.3 + + '@sammo/server_util': + dependencies: + '@sammo/api_def': + specifier: workspace:^ + version: link:../api_def + '@sammo/util': + specifier: workspace:^ + version: link:../util + '@strpc/express': + specifier: workspace:^ + version: link:../../@strpc/express + devDependencies: + '@types/express-session': + specifier: ^1.17.7 + version: 1.17.7 + lodash-es: + specifier: ^4.17.21 + version: 4.17.21 + + '@sammo/util': + devDependencies: + '@types/node': + specifier: ^20.6.3 + version: 20.6.3 + lodash-es: + specifier: ^4.17.21 + version: 4.17.21 + + '@strpc/client_ky': + dependencies: + '@strpc/def': + specifier: workspace:^ + version: link:../def + devDependencies: + ky: + specifier: ^1.0.1 + version: 1.0.1 + lodash-es: + specifier: ^4.17.21 + version: 4.17.21 + + '@strpc/def': {} + + '@strpc/express': + dependencies: + '@strpc/def': + specifier: workspace:^ + version: link:../def + devDependencies: + '@types/express': + specifier: ^4.17.17 + version: 4.17.17 + express: + specifier: ^4.18.2 + version: 4.18.2 + express-session: + specifier: ^1.17.3 + version: 1.17.3 + lodash-es: + specifier: ^4.17.21 + version: 4.17.21 + zod: + specifier: ^3.22.2 + version: 3.22.2 + +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.19 + dev: true + + /@babel/code-frame@7.22.13: + resolution: {integrity: sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/highlight': 7.22.20 + chalk: 2.4.2 + dev: true + + /@babel/compat-data@7.22.20: + resolution: {integrity: sha512-BQYjKbpXjoXwFW5jGqiizJQQT/aC7pFm9Ok1OWssonuguICi264lbgMzRp2ZMmRSlfkX6DsWDDcsrctK8Rwfiw==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/core@7.22.20: + resolution: {integrity: sha512-Y6jd1ahLubuYweD/zJH+vvOY141v4f9igNQAQ+MBgq9JlHS2iTsZKn1aMsb3vGccZsXI16VzTBw52Xx0DWmtnA==} + engines: {node: '>=6.9.0'} + dependencies: + '@ampproject/remapping': 2.2.1 + '@babel/code-frame': 7.22.13 + '@babel/generator': 7.22.15 + '@babel/helper-compilation-targets': 7.22.15 + '@babel/helper-module-transforms': 7.22.20(@babel/core@7.22.20) + '@babel/helpers': 7.22.15 + '@babel/parser': 7.22.16 + '@babel/template': 7.22.15 + '@babel/traverse': 7.22.20 + '@babel/types': 7.22.19 + convert-source-map: 1.9.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.22.15: + resolution: {integrity: sha512-Zu9oWARBqeVOW0dZOjXc3JObrzuqothQ3y/n1kUtrjCoCPLkXUwMvOo/F/TCfoHMbWIFlWwpZtkZVb9ga4U2pA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.22.19 + '@jridgewell/gen-mapping': 0.3.3 + '@jridgewell/trace-mapping': 0.3.19 + 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.22.20 + '@babel/helper-validator-option': 7.22.15 + browserslist: 4.21.11 + 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.22.5: + resolution: {integrity: sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.22.15 + '@babel/types': 7.22.19 + dev: true + + /@babel/helper-hoist-variables@7.22.5: + resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.22.19 + 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.22.19 + dev: true + + /@babel/helper-module-transforms@7.22.20(@babel/core@7.22.20): + resolution: {integrity: sha512-dLT7JVWIUUxKOs1UnJUBR3S70YK+pKX6AbJgB2vMIvEkZkrfJDbYDJesnPshtKV4LhDOR3Oc5YULeDizRek+5A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.22.20 + '@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.22.19 + 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.22.19 + dev: true + + /@babel/helper-string-parser@7.22.5: + resolution: {integrity: sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==} + engines: {node: '>=6.9.0'} + + /@babel/helper-validator-identifier@7.22.20: + resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} + engines: {node: '>=6.9.0'} + + /@babel/helper-validator-identifier@7.22.5: + resolution: {integrity: sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==} + 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.22.15: + resolution: {integrity: sha512-7pAjK0aSdxOwR+CcYAqgWOGy5dcfvzsTIfFTb2odQqW47MDfv14UaJDY6eng8ylM2EaeKXdxaSWESbkmaQHTmw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.22.15 + '@babel/traverse': 7.22.20 + '@babel/types': 7.22.19 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/highlight@7.22.20: + resolution: {integrity: sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==} + 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.22.16: + resolution: {integrity: sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.22.19 + + /@babel/parser@7.22.7: + resolution: {integrity: sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.22.5 + dev: true + + /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.22.20): + resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.20 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.22.20): + resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.20 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.22.20): + resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.20 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.22.20): + resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.20 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.22.20): + resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.20 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-jsx@7.22.5(@babel/core@7.22.20): + resolution: {integrity: sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.20 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.22.20): + resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.20 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.22.20): + resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.20 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.22.20): + resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.20 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.22.20): + resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.20 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.22.20): + resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.20 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.22.20): + resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.20 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.22.20): + resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.20 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-typescript@7.22.5(@babel/core@7.22.20): + resolution: {integrity: sha512-1mS2o03i7t1c6VzH6fdQ3OA8tcEIxwG18zIPRp+UY1Ihv6W+XZzBCVxExF9upussPXJ0xE9XRHwMoNs1ep/nRQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.20 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/runtime@7.22.6: + resolution: {integrity: sha512-wDb5pWm4WDdF6LFUde3Jl8WzPA+3ZbxYqkC6xAXuD3irdEHN1k0NfTRrJD8ZD378SJ61miMLCqIOXYhd8x+AJQ==} + engines: {node: '>=6.9.0'} + dependencies: + regenerator-runtime: 0.13.11 + dev: false + + /@babel/template@7.22.15: + resolution: {integrity: sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.22.13 + '@babel/parser': 7.22.16 + '@babel/types': 7.22.19 + dev: true + + /@babel/traverse@7.22.20: + resolution: {integrity: sha512-eU260mPZbU7mZ0N+X10pxXhQFMGTeLb9eFS0mxehS8HZp9o1uSnFeWQuG1UPrlxgA7QoUzFhOnilHDp0AXCyHw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.22.13 + '@babel/generator': 7.22.15 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-function-name': 7.22.5 + '@babel/helper-hoist-variables': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/parser': 7.22.16 + '@babel/types': 7.22.19 + debug: 4.3.4 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/types@7.22.19: + resolution: {integrity: sha512-P7LAw/LbojPzkgp5oznjE6tQEIWbp4PkkfrZDINTro9zgBRtI324/EYsiSI7lhPbpIQ+DCeR2NNmMWANGGfZsg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': 7.22.5 + '@babel/helper-validator-identifier': 7.22.20 + to-fast-properties: 2.0.0 + + /@babel/types@7.22.5: + resolution: {integrity: sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': 7.22.5 + '@babel/helper-validator-identifier': 7.22.5 + to-fast-properties: 2.0.0 + dev: true + + /@bcoe/v8-coverage@0.2.3: + resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + dev: true + + /@cspotcode/source-map-support@0.8.1: + resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} + engines: {node: '>=12'} + dependencies: + '@jridgewell/trace-mapping': 0.3.9 + dev: true + + /@esbuild/android-arm64@0.18.17: + resolution: {integrity: sha512-9np+YYdNDed5+Jgr1TdWBsozZ85U1Oa3xW0c7TWqH0y2aGghXtZsuT8nYRbzOMcl0bXZXjOGbksoTtVOlWrRZg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm@0.18.17: + resolution: {integrity: sha512-wHsmJG/dnL3OkpAcwbgoBTTMHVi4Uyou3F5mf58ZtmUyIKfcdA7TROav/6tCzET4A3QW2Q2FC+eFneMU+iyOxg==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-x64@0.18.17: + resolution: {integrity: sha512-O+FeWB/+xya0aLg23hHEM2E3hbfwZzjqumKMSIqcHbNvDa+dza2D0yLuymRBQQnC34CWrsJUXyH2MG5VnLd6uw==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-arm64@0.18.17: + resolution: {integrity: sha512-M9uJ9VSB1oli2BE/dJs3zVr9kcCBBsE883prage1NWz6pBS++1oNn/7soPNS3+1DGj0FrkSvnED4Bmlu1VAE9g==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-x64@0.18.17: + resolution: {integrity: sha512-XDre+J5YeIJDMfp3n0279DFNrGCXlxOuGsWIkRb1NThMZ0BsrWXoTg23Jer7fEXQ9Ye5QjrvXpxnhzl3bHtk0g==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-arm64@0.18.17: + resolution: {integrity: sha512-cjTzGa3QlNfERa0+ptykyxs5A6FEUQQF0MuilYXYBGdBxD3vxJcKnzDlhDCa1VAJCmAxed6mYhA2KaJIbtiNuQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-x64@0.18.17: + resolution: {integrity: sha512-sOxEvR8d7V7Kw8QqzxWc7bFfnWnGdaFBut1dRUYtu+EIRXefBc/eIsiUiShnW0hM3FmQ5Zf27suDuHsKgZ5QrA==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm64@0.18.17: + resolution: {integrity: sha512-c9w3tE7qA3CYWjT+M3BMbwMt+0JYOp3vCMKgVBrCl1nwjAlOMYzEo+gG7QaZ9AtqZFj5MbUc885wuBBmu6aADQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm@0.18.17: + resolution: {integrity: sha512-2d3Lw6wkwgSLC2fIvXKoMNGVaeY8qdN0IC3rfuVxJp89CRfA3e3VqWifGDfuakPmp90+ZirmTfye1n4ncjv2lg==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ia32@0.18.17: + resolution: {integrity: sha512-1DS9F966pn5pPnqXYz16dQqWIB0dmDfAQZd6jSSpiT9eX1NzKh07J6VKR3AoXXXEk6CqZMojiVDSZi1SlmKVdg==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-loong64@0.18.17: + resolution: {integrity: sha512-EvLsxCk6ZF0fpCB6w6eOI2Fc8KW5N6sHlIovNe8uOFObL2O+Mr0bflPHyHwLT6rwMg9r77WOAWb2FqCQrVnwFg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-mips64el@0.18.17: + resolution: {integrity: sha512-e0bIdHA5p6l+lwqTE36NAW5hHtw2tNRmHlGBygZC14QObsA3bD4C6sXLJjvnDIjSKhW1/0S3eDy+QmX/uZWEYQ==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ppc64@0.18.17: + resolution: {integrity: sha512-BAAilJ0M5O2uMxHYGjFKn4nJKF6fNCdP1E0o5t5fvMYYzeIqy2JdAP88Az5LHt9qBoUa4tDaRpfWt21ep5/WqQ==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-riscv64@0.18.17: + resolution: {integrity: sha512-Wh/HW2MPnC3b8BqRSIme/9Zhab36PPH+3zam5pqGRH4pE+4xTrVLx2+XdGp6fVS3L2x+DrsIcsbMleex8fbE6g==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-s390x@0.18.17: + resolution: {integrity: sha512-j/34jAl3ul3PNcK3pfI0NSlBANduT2UO5kZ7FCaK33XFv3chDhICLY8wJJWIhiQ+YNdQ9dxqQctRg2bvrMlYgg==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-x64@0.18.17: + resolution: {integrity: sha512-QM50vJ/y+8I60qEmFxMoxIx4de03pGo2HwxdBeFd4nMh364X6TIBZ6VQ5UQmPbQWUVWHWws5MmJXlHAXvJEmpQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/netbsd-x64@0.18.17: + resolution: {integrity: sha512-/jGlhWR7Sj9JPZHzXyyMZ1RFMkNPjC6QIAan0sDOtIo2TYk3tZn5UDrkE0XgsTQCxWTTOcMPf9p6Rh2hXtl5TQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/openbsd-x64@0.18.17: + resolution: {integrity: sha512-rSEeYaGgyGGf4qZM2NonMhMOP/5EHp4u9ehFiBrg7stH6BYEEjlkVREuDEcQ0LfIl53OXLxNbfuIj7mr5m29TA==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/sunos-x64@0.18.17: + resolution: {integrity: sha512-Y7ZBbkLqlSgn4+zot4KUNYst0bFoO68tRgI6mY2FIM+b7ZbyNVtNbDP5y8qlu4/knZZ73fgJDlXID+ohY5zt5g==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-arm64@0.18.17: + resolution: {integrity: sha512-bwPmTJsEQcbZk26oYpc4c/8PvTY3J5/QK8jM19DVlEsAB41M39aWovWoHtNm78sd6ip6prilxeHosPADXtEJFw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-ia32@0.18.17: + resolution: {integrity: sha512-H/XaPtPKli2MhW+3CQueo6Ni3Avggi6hP/YvgkEe1aSaxw+AeO8MFjq8DlgfTd9Iz4Yih3QCZI6YLMoyccnPRg==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-x64@0.18.17: + resolution: {integrity: sha512-fGEb8f2BSA3CW7riJVurug65ACLuQAzKq0SSqkY2b2yHHH0MzDfbLyKIGzHwOI/gkHcxM/leuSW6D5w/LMNitA==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esfx/async-lockable@1.0.0: + resolution: {integrity: sha512-MQoJKY9ityrO3W0DImrZn7jUJZ5mQBXUWsMH+baHz0YwdGXF36i1KPuxb5v1NG0gZkER3Sxr4jXQKeGDQNX6Xw==} + dependencies: + '@esfx/cancelable': 1.0.0 + '@esfx/disposable': 1.0.0 + dev: false + + /@esfx/async-readerwriterlock@1.0.0: + resolution: {integrity: sha512-YFT9lYUfBMbXB7e7NT5iyatQXmOexuAXGy9MeonmvZBxPZyBPT4rWOyNkloeZRDC73ygGQL4P4nX31/LVTCjkA==} + dependencies: + '@esfx/async-lockable': 1.0.0 + '@esfx/async-waitqueue': 1.0.0 + '@esfx/cancelable': 1.0.0 + '@esfx/disposable': 1.0.0 + dev: false + + /@esfx/async-waitqueue@1.0.0: + resolution: {integrity: sha512-LrPP501g1hhEq5wlW59A7WHl/43JQvm19HYhAMVUB7YoS+UQVHY/Rg9nEnyFhverTU24tXOWXlPKp0arju5B8Q==} + dependencies: + '@esfx/cancelable': 1.0.0 + dev: false + + /@esfx/cancelable@1.0.0: + resolution: {integrity: sha512-2dry/TuOT9ydpw86f396v09cyi/gLeGPIZSH4Gx+V/qKQaS/OXCRurCY+Cn8zkBfTAgFsjk9NE15d+LPo2kt9A==} + dependencies: + '@esfx/disposable': 1.0.0 + dev: false + + /@esfx/disposable@1.0.0: + resolution: {integrity: sha512-hu7EI+YxlEWEKrb2himbS13HNaq5mlUePASf99KeQqkiNeqiAZbKqG4w59uDcLZs8JrV3qJqS/NYib5ZMhbfTQ==} + dev: false + + /@eslint-community/eslint-utils@4.4.0(eslint@8.45.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.45.0 + eslint-visitor-keys: 3.4.2 + dev: true + + /@eslint-community/eslint-utils@4.4.0(eslint@8.49.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.49.0 + eslint-visitor-keys: 3.4.2 + dev: true + + /@eslint-community/eslint-utils@4.4.0(eslint@8.50.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.50.0 + eslint-visitor-keys: 3.4.2 + dev: true + + /@eslint-community/regexpp@4.6.2: + resolution: {integrity: sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + dev: true + + /@eslint/eslintrc@2.1.1: + resolution: {integrity: sha512-9t7ZA7NGGK8ckelF0PQCfcxIUzs1Md5rrO6U/c+FIQNanea5UZC0wqKXH4vHBccmu4ZJgZ2idtPeW7+Q2npOEA==} + 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.20.0 + ignore: 5.2.4 + 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/eslintrc@2.1.2: + resolution: {integrity: sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==} + 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.20.0 + ignore: 5.2.4 + 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.44.0: + resolution: {integrity: sha512-Ag+9YM4ocKQx9AarydN0KY2j0ErMHNIocPDrVo8zAE44xLTjEtz81OdR68/cydGtk6m6jDb5Za3r2useMzYmSw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + /@eslint/js@8.49.0: + resolution: {integrity: sha512-1S8uAY/MTJqVx0SC4epBq+N2yhuwtNwLbJYNZyhL2pO1ZVKn5HFXav5T41Ryzy9K9V7ZId2JB2oy/W4aCd9/2w==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + /@eslint/js@8.50.0: + resolution: {integrity: sha512-NCC3zz2+nvYd+Ckfh87rA47zfu2QsQpvc6k1yzTk+b9KzRj0wkGa8LSoGOXN6Zv4lRf/EIoZ80biDh9HOI+RNQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + /@floating-ui/core@1.4.1: + resolution: {integrity: sha512-jk3WqquEJRlcyu7997NtR5PibI+y5bi+LS3hPmguVClypenMsCY3CBa3LAQnozRCtCrYWSEtAdiskpamuJRFOQ==} + dependencies: + '@floating-ui/utils': 0.1.1 + dev: false + + /@floating-ui/dom@1.5.1: + resolution: {integrity: sha512-KwvVcPSXg6mQygvA1TjbN/gh///36kKtllIF8SUm0qpFj8+rvYrpvlYdL1JoA71SHpDqgSSdGOSoQ0Mp3uY5aw==} + dependencies: + '@floating-ui/core': 1.4.1 + '@floating-ui/utils': 0.1.1 + dev: false + + /@floating-ui/utils@0.1.1: + resolution: {integrity: sha512-m0G6wlnhm/AX0H12IOWtK8gASEMffnX08RtKkCgTdHb9JpHKGloI7icFfLg9ZmQeavcvR0PKmzxClyuFPSjKWw==} + dev: false + + /@floating-ui/vue@1.0.2(vue@3.3.4): + resolution: {integrity: sha512-sImlAl9mAoCKZLNlwWz2P2ZMJIDlOEDXrRD6aD2sIHAka1LPC+nWtB+D3lPe7IE7FGWSbwBPTnlSdlABa3Fr0A==} + dependencies: + '@floating-ui/dom': 1.5.1 + vue-demi: 0.14.5(vue@3.3.4) + transitivePeerDependencies: + - '@vue/composition-api' + - vue + dev: false + + /@humanwhocodes/config-array@0.11.10: + resolution: {integrity: sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==} + engines: {node: '>=10.10.0'} + dependencies: + '@humanwhocodes/object-schema': 1.2.1 + debug: 4.3.4 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@humanwhocodes/config-array@0.11.11: + resolution: {integrity: sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==} + engines: {node: '>=10.10.0'} + dependencies: + '@humanwhocodes/object-schema': 1.2.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@1.2.1: + resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} + dev: true + + /@istanbuljs/load-nyc-config@1.1.0: + resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} + engines: {node: '>=8'} + dependencies: + camelcase: 5.3.1 + find-up: 4.1.0 + get-package-type: 0.1.0 + js-yaml: 3.14.1 + resolve-from: 5.0.0 + dev: true + + /@istanbuljs/schema@0.1.3: + resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} + engines: {node: '>=8'} + dev: true + + /@jest/console@29.7.0: + resolution: {integrity: sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/types': 29.6.3 + '@types/node': 20.6.3 + chalk: 4.1.2 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + slash: 3.0.0 + dev: true + + /@jest/core@29.7.0(ts-node@10.9.1): + resolution: {integrity: sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + dependencies: + '@jest/console': 29.7.0 + '@jest/reporters': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.6.3 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + ci-info: 3.8.0 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-changed-files: 29.7.0 + jest-config: 29.7.0(@types/node@20.6.3)(ts-node@10.9.1) + jest-haste-map: 29.7.0 + jest-message-util: 29.7.0 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-resolve-dependencies: 29.7.0 + jest-runner: 29.7.0 + jest-runtime: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + jest-watcher: 29.7.0 + micromatch: 4.0.5 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-ansi: 6.0.1 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + - ts-node + dev: true + + /@jest/environment@29.7.0: + resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/fake-timers': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.6.3 + jest-mock: 29.7.0 + dev: true + + /@jest/expect-utils@29.7.0: + resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + jest-get-type: 29.6.3 + dev: true + + /@jest/expect@29.7.0: + resolution: {integrity: sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + expect: 29.7.0 + jest-snapshot: 29.7.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@jest/fake-timers@29.7.0: + resolution: {integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/types': 29.6.3 + '@sinonjs/fake-timers': 10.3.0 + '@types/node': 20.6.3 + jest-message-util: 29.7.0 + jest-mock: 29.7.0 + jest-util: 29.7.0 + dev: true + + /@jest/globals@29.7.0: + resolution: {integrity: sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/environment': 29.7.0 + '@jest/expect': 29.7.0 + '@jest/types': 29.6.3 + jest-mock: 29.7.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@jest/reporters@29.7.0: + resolution: {integrity: sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + dependencies: + '@bcoe/v8-coverage': 0.2.3 + '@jest/console': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@jridgewell/trace-mapping': 0.3.19 + '@types/node': 20.6.3 + chalk: 4.1.2 + collect-v8-coverage: 1.0.2 + exit: 0.1.2 + glob: 7.2.3 + graceful-fs: 4.2.11 + istanbul-lib-coverage: 3.2.0 + istanbul-lib-instrument: 6.0.0 + istanbul-lib-report: 3.0.1 + istanbul-lib-source-maps: 4.0.1 + istanbul-reports: 3.1.6 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + jest-worker: 29.7.0 + slash: 3.0.0 + string-length: 4.0.2 + strip-ansi: 6.0.1 + v8-to-istanbul: 9.1.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@jest/schemas@29.6.3: + resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@sinclair/typebox': 0.27.8 + dev: true + + /@jest/source-map@29.6.3: + resolution: {integrity: sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jridgewell/trace-mapping': 0.3.19 + callsites: 3.1.0 + graceful-fs: 4.2.11 + dev: true + + /@jest/test-result@29.7.0: + resolution: {integrity: sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/console': 29.7.0 + '@jest/types': 29.6.3 + '@types/istanbul-lib-coverage': 2.0.4 + collect-v8-coverage: 1.0.2 + dev: true + + /@jest/test-sequencer@29.7.0: + resolution: {integrity: sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/test-result': 29.7.0 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + slash: 3.0.0 + dev: true + + /@jest/transform@29.7.0: + resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@babel/core': 7.22.20 + '@jest/types': 29.6.3 + '@jridgewell/trace-mapping': 0.3.19 + babel-plugin-istanbul: 6.1.1 + chalk: 4.1.2 + convert-source-map: 2.0.0 + fast-json-stable-stringify: 2.1.0 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + jest-regex-util: 29.6.3 + jest-util: 29.7.0 + micromatch: 4.0.5 + pirates: 4.0.6 + slash: 3.0.0 + write-file-atomic: 4.0.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@jest/types@29.6.3: + resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/schemas': 29.6.3 + '@types/istanbul-lib-coverage': 2.0.4 + '@types/istanbul-reports': 3.0.1 + '@types/node': 20.6.3 + '@types/yargs': 17.0.24 + chalk: 4.1.2 + 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.19 + 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==} + + /@jridgewell/trace-mapping@0.3.19: + resolution: {integrity: sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==} + dependencies: + '@jridgewell/resolve-uri': 3.1.1 + '@jridgewell/sourcemap-codec': 1.4.15 + dev: true + + /@jridgewell/trace-mapping@0.3.9: + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + 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 + + /@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.1 + is-glob: 4.0.3 + open: 9.1.0 + picocolors: 1.0.0 + tslib: 2.6.2 + dev: true + + /@popperjs/core@2.11.8: + resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} + dev: false + + /@rushstack/eslint-patch@1.3.2: + resolution: {integrity: sha512-V+MvGwaHH03hYhY+k6Ef/xKd6RYlc4q8WBx+2ANmipHJcKuktNcI/NgEsJgdSUF6Lw32njT6OnrRsKYCdgHjYw==} + dev: true + + /@sinclair/typebox@0.27.8: + resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} + dev: true + + /@sinonjs/commons@3.0.0: + resolution: {integrity: sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==} + dependencies: + type-detect: 4.0.8 + dev: true + + /@sinonjs/fake-timers@10.3.0: + resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} + dependencies: + '@sinonjs/commons': 3.0.0 + dev: true + + /@tsconfig/node10@1.0.9: + resolution: {integrity: sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==} + dev: true + + /@tsconfig/node12@1.0.11: + resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} + dev: true + + /@tsconfig/node14@1.0.3: + resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} + dev: true + + /@tsconfig/node16@1.0.4: + resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} + dev: true + + /@tsconfig/node20@20.1.2: + resolution: {integrity: sha512-madaWq2k+LYMEhmcp0fs+OGaLFk0OenpHa4gmI4VEmCKX4PJntQ6fnnGADVFrVkBj0wIdAlQnK/MrlYTHsa1gQ==} + dev: true + + /@types/babel__core@7.20.2: + resolution: {integrity: sha512-pNpr1T1xLUc2l3xJKuPtsEky3ybxN3m4fJkknfIpTCTfIZCDW57oAg+EfCgIIp2rvCe0Wn++/FfodDS4YXxBwA==} + dependencies: + '@babel/parser': 7.22.7 + '@babel/types': 7.22.5 + '@types/babel__generator': 7.6.5 + '@types/babel__template': 7.4.2 + '@types/babel__traverse': 7.20.2 + dev: true + + /@types/babel__generator@7.6.5: + resolution: {integrity: sha512-h9yIuWbJKdOPLJTbmSpPzkF67e659PbQDba7ifWm5BJ8xTv+sDmS7rFmywkWOvXedGTivCdeGSIIX8WLcRTz8w==} + dependencies: + '@babel/types': 7.22.5 + dev: true + + /@types/babel__template@7.4.2: + resolution: {integrity: sha512-/AVzPICMhMOMYoSx9MoKpGDKdBRsIXMNByh1PXSZoa+v6ZoLa8xxtsT/uLQ/NJm0XVAWl/BvId4MlDeXJaeIZQ==} + dependencies: + '@babel/parser': 7.22.7 + '@babel/types': 7.22.5 + dev: true + + /@types/babel__traverse@7.20.2: + resolution: {integrity: sha512-ojlGK1Hsfce93J0+kn3H5R73elidKUaZonirN33GSmgTUMpzI/MIFfSpF3haANe3G1bEBS9/9/QEqwTzwqFsKw==} + dependencies: + '@babel/types': 7.22.5 + dev: true + + /@types/body-parser@1.19.3: + resolution: {integrity: sha512-oyl4jvAfTGX9Bt6Or4H9ni1Z447/tQuxnZsytsCaExKlmJiU8sFgnIBRzJUpKwB5eWn9HuBYlUlVA74q/yN0eQ==} + dependencies: + '@types/connect': 3.4.36 + '@types/node': 20.6.3 + dev: true + + /@types/connect@3.4.36: + resolution: {integrity: sha512-P63Zd/JUGq+PdrM1lv0Wv5SBYeA2+CORvbrXbngriYY0jzLUWfQMQQxOhjONEz/wlHOAxOdY7CY65rgQdTjq2w==} + dependencies: + '@types/node': 20.6.3 + dev: true + + /@types/express-serve-static-core@4.17.36: + resolution: {integrity: sha512-zbivROJ0ZqLAtMzgzIUC4oNqDG9iF0lSsAqpOD9kbs5xcIM3dTiyuHvBc7R8MtWBp3AAWGaovJa+wzWPjLYW7Q==} + dependencies: + '@types/node': 20.6.3 + '@types/qs': 6.9.8 + '@types/range-parser': 1.2.4 + '@types/send': 0.17.1 + dev: true + + /@types/express-session@1.17.7: + resolution: {integrity: sha512-L25080PBYoRLu472HY/HNCxaXY8AaGgqGC8/p/8+BYMhG0RDOLQ1wpXOpAzr4Gi5TGozTKyJv5BVODM5UNyVMw==} + dependencies: + '@types/express': 4.17.17 + dev: true + + /@types/express@4.17.17: + resolution: {integrity: sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==} + dependencies: + '@types/body-parser': 1.19.3 + '@types/express-serve-static-core': 4.17.36 + '@types/qs': 6.9.8 + '@types/serve-static': 1.15.2 + dev: true + + /@types/graceful-fs@4.1.7: + resolution: {integrity: sha512-MhzcwU8aUygZroVwL2jeYk6JisJrPl/oov/gsgGCue9mkgl9wjGbzReYQClxiUgFDnib9FuHqTndccKeZKxTRw==} + dependencies: + '@types/node': 20.6.3 + dev: true + + /@types/http-errors@2.0.2: + resolution: {integrity: sha512-lPG6KlZs88gef6aD85z3HNkztpj7w2R7HmR3gygjfXCQmsLloWNARFkMuzKiiY8FGdh1XDpgBdrSf4aKDiA7Kg==} + dev: true + + /@types/istanbul-lib-coverage@2.0.4: + resolution: {integrity: sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==} + dev: true + + /@types/istanbul-lib-report@3.0.0: + resolution: {integrity: sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==} + dependencies: + '@types/istanbul-lib-coverage': 2.0.4 + dev: true + + /@types/istanbul-reports@3.0.1: + resolution: {integrity: sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==} + dependencies: + '@types/istanbul-lib-report': 3.0.0 + dev: true + + /@types/jest@29.5.5: + resolution: {integrity: sha512-ebylz2hnsWR9mYvmBFbXJXr+33UPc4+ZdxyDXh5w0FlPBTfCVN3wPL+kuOiQt3xvrK419v7XWeAs+AeOksafXg==} + dependencies: + expect: 29.7.0 + pretty-format: 29.7.0 + dev: true + + /@types/json-schema@7.0.12: + resolution: {integrity: sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==} + dev: true + + /@types/lodash-es@4.17.8: + resolution: {integrity: sha512-euY3XQcZmIzSy7YH5+Unb3b2X12Wtk54YWINBvvGQ5SmMvwb11JQskGsfkH/5HXK77Kr8GF0wkVDIxzAisWtog==} + dependencies: + '@types/lodash': 4.14.196 + dev: true + + /@types/lodash-es@4.17.9: + resolution: {integrity: sha512-ZTcmhiI3NNU7dEvWLZJkzG6ao49zOIjEgIE0RgV7wbPxU0f2xT3VSAHw2gmst8swH6V0YkLRGp4qPlX/6I90MQ==} + dependencies: + '@types/lodash': 4.14.198 + dev: true + + /@types/lodash@4.14.196: + resolution: {integrity: sha512-22y3o88f4a94mKljsZcanlNWPzO0uBsBdzLAngf2tp533LzZcQzb6+eZPJ+vCTt+bqF2XnvT9gejTLsAcJAJyQ==} + dev: true + + /@types/lodash@4.14.198: + resolution: {integrity: sha512-trNJ/vtMZYMLhfN45uLq4ShQSw0/S7xCTLLVM+WM1rmFpba/VS42jVUgaO3w/NOLiWR/09lnYk0yMaA/atdIsg==} + dev: true + + /@types/mime@1.3.2: + resolution: {integrity: sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==} + dev: true + + /@types/mime@3.0.1: + resolution: {integrity: sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==} + dev: true + + /@types/node@18.17.0: + resolution: {integrity: sha512-GXZxEtOxYGFchyUzxvKI14iff9KZ2DI+A6a37o6EQevtg6uO9t+aUZKcaC1Te5Ng1OnLM7K9NVVj+FbecD9cJg==} + dev: true + + /@types/node@20.6.3: + resolution: {integrity: sha512-HksnYH4Ljr4VQgEy2lTStbCKv/P590tmPe5HqOnv9Gprffgv5WXAY+Y5Gqniu0GGqeTCUdBnzC3QSrzPkBkAMA==} + + /@types/qs@6.9.8: + resolution: {integrity: sha512-u95svzDlTysU5xecFNTgfFG5RUWu1A9P0VzgpcIiGZA9iraHOdSzcxMxQ55DyeRaGCSxQi7LxXDI4rzq/MYfdg==} + dev: true + + /@types/range-parser@1.2.4: + resolution: {integrity: sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==} + dev: true + + /@types/semver@7.5.0: + resolution: {integrity: sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==} + dev: true + + /@types/send@0.17.1: + resolution: {integrity: sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q==} + dependencies: + '@types/mime': 1.3.2 + '@types/node': 20.6.3 + dev: true + + /@types/serve-static@1.15.2: + resolution: {integrity: sha512-J2LqtvFYCzaj8pVYKw8klQXrLLk7TBZmQ4ShlcdkELFKGwGMfevMLneMMRkMgZxotOD9wg497LpC7O8PcvAmfw==} + dependencies: + '@types/http-errors': 2.0.2 + '@types/mime': 3.0.1 + '@types/node': 20.6.3 + dev: true + + /@types/stack-utils@2.0.1: + resolution: {integrity: sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==} + dev: true + + /@types/web-bluetooth@0.0.17: + resolution: {integrity: sha512-4p9vcSmxAayx72yn70joFoL44c9MO/0+iVEBIQXe3v2h2SiAsEIo/G5v6ObFWvNKRFjbrVadNf9LqEEZeQPzdA==} + dev: false + + /@types/webidl-conversions@7.0.0: + resolution: {integrity: sha512-xTE1E+YF4aWPJJeUzaZI5DRntlkY3+BCVJi0axFptnjGmAoWxkyREIh/XMrfxVLejwQxMCfDXdICo0VLxThrog==} + dev: false + + /@types/whatwg-url@8.2.2: + resolution: {integrity: sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA==} + dependencies: + '@types/node': 20.6.3 + '@types/webidl-conversions': 7.0.0 + dev: false + + /@types/yargs-parser@21.0.0: + resolution: {integrity: sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==} + dev: true + + /@types/yargs@17.0.24: + resolution: {integrity: sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==} + dependencies: + '@types/yargs-parser': 21.0.0 + dev: true + + /@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0)(eslint@8.45.0)(typescript@5.1.6): + resolution: {integrity: sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + '@typescript-eslint/parser': ^5.0.0 + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@eslint-community/regexpp': 4.6.2 + '@typescript-eslint/parser': 5.62.0(eslint@8.45.0)(typescript@5.1.6) + '@typescript-eslint/scope-manager': 5.62.0 + '@typescript-eslint/type-utils': 5.62.0(eslint@8.45.0)(typescript@5.1.6) + '@typescript-eslint/utils': 5.62.0(eslint@8.45.0)(typescript@5.1.6) + debug: 4.3.4 + eslint: 8.45.0 + graphemer: 1.4.0 + ignore: 5.2.4 + natural-compare-lite: 1.4.0 + semver: 7.5.4 + tsutils: 3.21.0(typescript@5.1.6) + typescript: 5.1.6 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0)(eslint@8.50.0)(typescript@5.2.2): + resolution: {integrity: sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + '@typescript-eslint/parser': ^5.0.0 + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@eslint-community/regexpp': 4.6.2 + '@typescript-eslint/parser': 5.62.0(eslint@8.50.0)(typescript@5.2.2) + '@typescript-eslint/scope-manager': 5.62.0 + '@typescript-eslint/type-utils': 5.62.0(eslint@8.50.0)(typescript@5.2.2) + '@typescript-eslint/utils': 5.62.0(eslint@8.50.0)(typescript@5.2.2) + debug: 4.3.4 + eslint: 8.50.0 + graphemer: 1.4.0 + ignore: 5.2.4 + natural-compare-lite: 1.4.0 + semver: 7.5.4 + tsutils: 3.21.0(typescript@5.2.2) + typescript: 5.2.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/eslint-plugin@6.7.2(@typescript-eslint/parser@6.7.2)(eslint@8.49.0)(typescript@5.2.2): + resolution: {integrity: sha512-ooaHxlmSgZTM6CHYAFRlifqh1OAr3PAQEwi7lhYhaegbnXrnh7CDcHmc3+ihhbQC7H0i4JF0psI5ehzkF6Yl6Q==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha + eslint: ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@eslint-community/regexpp': 4.6.2 + '@typescript-eslint/parser': 6.7.2(eslint@8.49.0)(typescript@5.2.2) + '@typescript-eslint/scope-manager': 6.7.2 + '@typescript-eslint/type-utils': 6.7.2(eslint@8.49.0)(typescript@5.2.2) + '@typescript-eslint/utils': 6.7.2(eslint@8.49.0)(typescript@5.2.2) + '@typescript-eslint/visitor-keys': 6.7.2 + debug: 4.3.4 + eslint: 8.49.0 + graphemer: 1.4.0 + ignore: 5.2.4 + natural-compare: 1.4.0 + semver: 7.5.4 + ts-api-utils: 1.0.3(typescript@5.2.2) + typescript: 5.2.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/parser@5.62.0(eslint@8.45.0)(typescript@5.1.6): + resolution: {integrity: sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/scope-manager': 5.62.0 + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.1.6) + debug: 4.3.4 + eslint: 8.45.0 + typescript: 5.1.6 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/parser@5.62.0(eslint@8.50.0)(typescript@5.2.2): + resolution: {integrity: sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/scope-manager': 5.62.0 + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.2.2) + debug: 4.3.4 + eslint: 8.50.0 + typescript: 5.2.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/parser@6.7.2(eslint@8.49.0)(typescript@5.2.2): + resolution: {integrity: sha512-KA3E4ox0ws+SPyxQf9iSI25R6b4Ne78ORhNHeVKrPQnoYsb9UhieoiRoJgrzgEeKGOXhcY1i8YtOeCHHTDa6Fw==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/scope-manager': 6.7.2 + '@typescript-eslint/types': 6.7.2 + '@typescript-eslint/typescript-estree': 6.7.2(typescript@5.2.2) + '@typescript-eslint/visitor-keys': 6.7.2 + debug: 4.3.4 + eslint: 8.49.0 + typescript: 5.2.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/scope-manager@5.62.0: + resolution: {integrity: sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/visitor-keys': 5.62.0 + dev: true + + /@typescript-eslint/scope-manager@6.7.2: + resolution: {integrity: sha512-bgi6plgyZjEqapr7u2mhxGR6E8WCzKNUFWNh6fkpVe9+yzRZeYtDTbsIBzKbcxI+r1qVWt6VIoMSNZ4r2A+6Yw==} + engines: {node: ^16.0.0 || >=18.0.0} + dependencies: + '@typescript-eslint/types': 6.7.2 + '@typescript-eslint/visitor-keys': 6.7.2 + dev: true + + /@typescript-eslint/type-utils@5.62.0(eslint@8.45.0)(typescript@5.1.6): + resolution: {integrity: sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: '*' + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.1.6) + '@typescript-eslint/utils': 5.62.0(eslint@8.45.0)(typescript@5.1.6) + debug: 4.3.4 + eslint: 8.45.0 + tsutils: 3.21.0(typescript@5.1.6) + typescript: 5.1.6 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/type-utils@5.62.0(eslint@8.50.0)(typescript@5.2.2): + resolution: {integrity: sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: '*' + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.2.2) + '@typescript-eslint/utils': 5.62.0(eslint@8.50.0)(typescript@5.2.2) + debug: 4.3.4 + eslint: 8.50.0 + tsutils: 3.21.0(typescript@5.2.2) + typescript: 5.2.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/type-utils@6.7.2(eslint@8.49.0)(typescript@5.2.2): + resolution: {integrity: sha512-36F4fOYIROYRl0qj95dYKx6kybddLtsbmPIYNK0OBeXv2j9L5nZ17j9jmfy+bIDHKQgn2EZX+cofsqi8NPATBQ==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/typescript-estree': 6.7.2(typescript@5.2.2) + '@typescript-eslint/utils': 6.7.2(eslint@8.49.0)(typescript@5.2.2) + debug: 4.3.4 + eslint: 8.49.0 + ts-api-utils: 1.0.3(typescript@5.2.2) + typescript: 5.2.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/types@5.62.0: + resolution: {integrity: sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + /@typescript-eslint/types@6.7.2: + resolution: {integrity: sha512-flJYwMYgnUNDAN9/GAI3l8+wTmvTYdv64fcH8aoJK76Y+1FCZ08RtI5zDerM/FYT5DMkAc+19E4aLmd5KqdFyg==} + engines: {node: ^16.0.0 || >=18.0.0} + dev: true + + /@typescript-eslint/typescript-estree@5.62.0(typescript@5.1.6): + resolution: {integrity: sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/visitor-keys': 5.62.0 + debug: 4.3.4 + globby: 11.1.0 + is-glob: 4.0.3 + semver: 7.5.4 + tsutils: 3.21.0(typescript@5.1.6) + typescript: 5.1.6 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/typescript-estree@5.62.0(typescript@5.2.2): + resolution: {integrity: sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/visitor-keys': 5.62.0 + debug: 4.3.4 + globby: 11.1.0 + is-glob: 4.0.3 + semver: 7.5.4 + tsutils: 3.21.0(typescript@5.2.2) + typescript: 5.2.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/typescript-estree@6.7.2(typescript@5.2.2): + resolution: {integrity: sha512-kiJKVMLkoSciGyFU0TOY0fRxnp9qq1AzVOHNeN1+B9erKFCJ4Z8WdjAkKQPP+b1pWStGFqezMLltxO+308dJTQ==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/types': 6.7.2 + '@typescript-eslint/visitor-keys': 6.7.2 + debug: 4.3.4 + globby: 11.1.0 + is-glob: 4.0.3 + semver: 7.5.4 + ts-api-utils: 1.0.3(typescript@5.2.2) + typescript: 5.2.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/utils@5.62.0(eslint@8.45.0)(typescript@5.1.6): + resolution: {integrity: sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.45.0) + '@types/json-schema': 7.0.12 + '@types/semver': 7.5.0 + '@typescript-eslint/scope-manager': 5.62.0 + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.1.6) + eslint: 8.45.0 + eslint-scope: 5.1.1 + semver: 7.5.4 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /@typescript-eslint/utils@5.62.0(eslint@8.50.0)(typescript@5.2.2): + resolution: {integrity: sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.50.0) + '@types/json-schema': 7.0.12 + '@types/semver': 7.5.0 + '@typescript-eslint/scope-manager': 5.62.0 + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.2.2) + eslint: 8.50.0 + eslint-scope: 5.1.1 + semver: 7.5.4 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /@typescript-eslint/utils@6.7.2(eslint@8.49.0)(typescript@5.2.2): + resolution: {integrity: sha512-ZCcBJug/TS6fXRTsoTkgnsvyWSiXwMNiPzBUani7hDidBdj1779qwM1FIAmpH4lvlOZNF3EScsxxuGifjpLSWQ==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.49.0) + '@types/json-schema': 7.0.12 + '@types/semver': 7.5.0 + '@typescript-eslint/scope-manager': 6.7.2 + '@typescript-eslint/types': 6.7.2 + '@typescript-eslint/typescript-estree': 6.7.2(typescript@5.2.2) + eslint: 8.49.0 + semver: 7.5.4 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /@typescript-eslint/visitor-keys@5.62.0: + resolution: {integrity: sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + '@typescript-eslint/types': 5.62.0 + eslint-visitor-keys: 3.4.2 + dev: true + + /@typescript-eslint/visitor-keys@6.7.2: + resolution: {integrity: sha512-uVw9VIMFBUTz8rIeaUT3fFe8xIUx8r4ywAdlQv1ifH+6acn/XF8Y6rwJ7XNmkNMDrTW+7+vxFFPIF40nJCVsMQ==} + engines: {node: ^16.0.0 || >=18.0.0} + dependencies: + '@typescript-eslint/types': 6.7.2 + eslint-visitor-keys: 3.4.2 + dev: true + + /@vitejs/plugin-vue@4.2.3(vite@4.4.6)(vue@3.3.4): + resolution: {integrity: sha512-R6JDUfiZbJA9cMiguQ7jxALsgiprjBeHL5ikpXfJCH62pPHtI+JdJ5xWj6Ev73yXSlYl86+blXn1kZHQ7uElxw==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + vite: ^4.0.0 + vue: ^3.2.25 + dependencies: + vite: 4.4.6(@types/node@18.17.0) + vue: 3.3.4 + dev: true + + /@volar/language-core@1.9.2: + resolution: {integrity: sha512-9GTes/IUPOl0YoV5RQWhCP5a4EDFFfJZGwZn1xA5ug1FO0G6GOVoJI6tQatujtcQmDOQlOM5/0NewnlumygPkQ==} + dependencies: + '@volar/source-map': 1.9.2 + dev: true + + /@volar/source-map@1.9.2: + resolution: {integrity: sha512-rYTvV/HMf2CSRkd6oiVxcjX4rnSxEsVfJmw1KTmD4VTBXlz1+b16VIysQX4+1p/eZd2TyCeFblyylIxbZ+YOGg==} + dependencies: + muggle-string: 0.3.1 + dev: true + + /@volar/typescript@1.9.2: + resolution: {integrity: sha512-l4DA+S3ZVOWGACDdRNVSYZ41nuTWOH8OMS/yVeFV2fTmr/IuD37+3wzzGnjIPwCUa0w+fpg8vJPalzYetmlFTQ==} + dependencies: + '@volar/language-core': 1.9.2 + dev: true + + /@vue/compiler-core@3.3.4: + resolution: {integrity: sha512-cquyDNvZ6jTbf/+x+AgM2Arrp6G4Dzbb0R64jiG804HRMfRiFXWI6kqUVqZ6ZR0bQhIoQjB4+2bhNtVwndW15g==} + dependencies: + '@babel/parser': 7.22.16 + '@vue/shared': 3.3.4 + estree-walker: 2.0.2 + source-map-js: 1.0.2 + + /@vue/compiler-dom@3.3.4: + resolution: {integrity: sha512-wyM+OjOVpuUukIq6p5+nwHYtj9cFroz9cwkfmP9O1nzH68BenTTv0u7/ndggT8cIQlnBeOo6sUT/gvHcIkLA5w==} + dependencies: + '@vue/compiler-core': 3.3.4 + '@vue/shared': 3.3.4 + + /@vue/compiler-sfc@3.3.4: + resolution: {integrity: sha512-6y/d8uw+5TkCuzBkgLS0v3lSM3hJDntFEiUORM11pQ/hKvkhSKZrXW6i69UyXlJQisJxuUEJKAWEqWbWsLeNKQ==} + dependencies: + '@babel/parser': 7.22.16 + '@vue/compiler-core': 3.3.4 + '@vue/compiler-dom': 3.3.4 + '@vue/compiler-ssr': 3.3.4 + '@vue/reactivity-transform': 3.3.4 + '@vue/shared': 3.3.4 + estree-walker: 2.0.2 + magic-string: 0.30.2 + postcss: 8.4.27 + source-map-js: 1.0.2 + + /@vue/compiler-ssr@3.3.4: + resolution: {integrity: sha512-m0v6oKpup2nMSehwA6Uuu+j+wEwcy7QmwMkVNVfrV9P2qE5KshC6RwOCq8fjGS/Eak/uNb8AaWekfiXxbBB6gQ==} + dependencies: + '@vue/compiler-dom': 3.3.4 + '@vue/shared': 3.3.4 + + /@vue/devtools-api@6.5.0: + resolution: {integrity: sha512-o9KfBeaBmCKl10usN4crU53fYtC1r7jJwdGKjPT24t348rHxgfpZ0xL3Xm/gLUYnc0oTp8LAmrxOeLyu6tbk2Q==} + dev: false + + /@vue/eslint-config-prettier@8.0.0(eslint@8.45.0)(prettier@3.0.0): + resolution: {integrity: sha512-55dPqtC4PM/yBjhAr+yEw6+7KzzdkBuLmnhBrDfp4I48+wy+Giqqj9yUr5T2uD/BkBROjjmqnLZmXRdOx/VtQg==} + peerDependencies: + eslint: '>= 8.0.0' + prettier: '>= 3.0.0' + dependencies: + eslint: 8.45.0 + eslint-config-prettier: 8.10.0(eslint@8.45.0) + eslint-plugin-prettier: 5.0.0(eslint-config-prettier@8.10.0)(eslint@8.45.0)(prettier@3.0.0) + prettier: 3.0.0 + transitivePeerDependencies: + - '@types/eslint' + dev: true + + /@vue/eslint-config-prettier@8.0.0(eslint@8.50.0)(prettier@3.0.0): + resolution: {integrity: sha512-55dPqtC4PM/yBjhAr+yEw6+7KzzdkBuLmnhBrDfp4I48+wy+Giqqj9yUr5T2uD/BkBROjjmqnLZmXRdOx/VtQg==} + peerDependencies: + eslint: '>= 8.0.0' + prettier: '>= 3.0.0' + dependencies: + eslint: 8.50.0 + eslint-config-prettier: 8.10.0(eslint@8.50.0) + eslint-plugin-prettier: 5.0.0(eslint-config-prettier@8.10.0)(eslint@8.50.0)(prettier@3.0.0) + prettier: 3.0.0 + transitivePeerDependencies: + - '@types/eslint' + dev: true + + /@vue/eslint-config-typescript@11.0.3(eslint-plugin-vue@9.15.1)(eslint@8.45.0)(typescript@5.1.6): + resolution: {integrity: sha512-dkt6W0PX6H/4Xuxg/BlFj5xHvksjpSlVjtkQCpaYJBIEuKj2hOVU7r+TIe+ysCwRYFz/lGqvklntRkCAibsbPw==} + engines: {node: ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.2.0 || ^7.0.0 || ^8.0.0 + eslint-plugin-vue: ^9.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/eslint-plugin': 5.62.0(@typescript-eslint/parser@5.62.0)(eslint@8.45.0)(typescript@5.1.6) + '@typescript-eslint/parser': 5.62.0(eslint@8.45.0)(typescript@5.1.6) + eslint: 8.45.0 + eslint-plugin-vue: 9.15.1(eslint@8.45.0) + typescript: 5.1.6 + vue-eslint-parser: 9.3.1(eslint@8.45.0) + transitivePeerDependencies: + - supports-color + dev: true + + /@vue/eslint-config-typescript@11.0.3(eslint-plugin-vue@9.15.1)(eslint@8.50.0)(typescript@5.2.2): + resolution: {integrity: sha512-dkt6W0PX6H/4Xuxg/BlFj5xHvksjpSlVjtkQCpaYJBIEuKj2hOVU7r+TIe+ysCwRYFz/lGqvklntRkCAibsbPw==} + engines: {node: ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.2.0 || ^7.0.0 || ^8.0.0 + eslint-plugin-vue: ^9.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/eslint-plugin': 5.62.0(@typescript-eslint/parser@5.62.0)(eslint@8.50.0)(typescript@5.2.2) + '@typescript-eslint/parser': 5.62.0(eslint@8.50.0)(typescript@5.2.2) + eslint: 8.50.0 + eslint-plugin-vue: 9.15.1(eslint@8.50.0) + typescript: 5.2.2 + vue-eslint-parser: 9.3.1(eslint@8.50.0) + transitivePeerDependencies: + - supports-color + dev: true + + /@vue/language-core@1.8.6(typescript@5.2.2): + resolution: {integrity: sha512-PyYDMArbR7hnhqw9OEupr0s4ut0/ZfITp7WEjigF58cd2R0lRLNM1HPvzFMuULpy3ImBEOZI11KRIDirqOe+tQ==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@volar/language-core': 1.9.2 + '@volar/source-map': 1.9.2 + '@vue/compiler-dom': 3.3.4 + '@vue/reactivity': 3.3.4 + '@vue/shared': 3.3.4 + minimatch: 9.0.3 + muggle-string: 0.3.1 + typescript: 5.2.2 + vue-template-compiler: 2.7.14 + dev: true + + /@vue/reactivity-transform@3.3.4: + resolution: {integrity: sha512-MXgwjako4nu5WFLAjpBnCj/ieqcjE2aJBINUNQzkZQfzIZA4xn+0fV1tIYBJvvva3N3OvKGofRLvQIwEQPpaXw==} + dependencies: + '@babel/parser': 7.22.16 + '@vue/compiler-core': 3.3.4 + '@vue/shared': 3.3.4 + estree-walker: 2.0.2 + magic-string: 0.30.2 + + /@vue/reactivity@3.3.4: + resolution: {integrity: sha512-kLTDLwd0B1jG08NBF3R5rqULtv/f8x3rOFByTDz4J53ttIQEDmALqKqXY0J+XQeN0aV2FBxY8nJDf88yvOPAqQ==} + dependencies: + '@vue/shared': 3.3.4 + + /@vue/runtime-core@3.3.4: + resolution: {integrity: sha512-R+bqxMN6pWO7zGI4OMlmvePOdP2c93GsHFM/siJI7O2nxFRzj55pLwkpCedEY+bTMgp5miZ8CxfIZo3S+gFqvA==} + dependencies: + '@vue/reactivity': 3.3.4 + '@vue/shared': 3.3.4 + + /@vue/runtime-dom@3.3.4: + resolution: {integrity: sha512-Aj5bTJ3u5sFsUckRghsNjVTtxZQ1OyMWCr5dZRAPijF/0Vy4xEoRCwLyHXcj4D0UFbJ4lbx3gPTgg06K/GnPnQ==} + dependencies: + '@vue/runtime-core': 3.3.4 + '@vue/shared': 3.3.4 + csstype: 3.1.2 + + /@vue/server-renderer@3.3.4(vue@3.3.4): + resolution: {integrity: sha512-Q6jDDzR23ViIb67v+vM1Dqntu+HUexQcsWKhhQa4ARVzxOY2HbC7QRW/ggkDBd5BU+uM1sV6XOAP0b216o34JQ==} + peerDependencies: + vue: 3.3.4 + dependencies: + '@vue/compiler-ssr': 3.3.4 + '@vue/shared': 3.3.4 + vue: 3.3.4 + + /@vue/shared@3.3.4: + resolution: {integrity: sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ==} + + /@vue/tsconfig@0.4.0: + resolution: {integrity: sha512-CPuIReonid9+zOG/CGTT05FXrPYATEqoDGNrEaqS4hwcw5BUNM2FguC0mOwJD4Jr16UpRVl9N0pY3P+srIbqmg==} + dev: true + + /@vue/typescript@1.8.6(typescript@5.2.2): + resolution: {integrity: sha512-sDQ5tltrSVS3lAkE3JtMRGJo91CLIxcWPy7yms/DT+ssxXpwxbVRD5Gok68HenEZBA4Klq7nW99sG/nTRnpPuQ==} + dependencies: + '@volar/typescript': 1.9.2 + '@vue/language-core': 1.8.6(typescript@5.2.2) + transitivePeerDependencies: + - typescript + dev: true + + /@vueuse/core@10.3.0(vue@3.3.4): + resolution: {integrity: sha512-BEM5yxcFKb5btFjTSAFjTu5jmwoW66fyV9uJIP4wUXXU8aR5Hl44gndaaXp7dC5HSObmgbnR2RN+Un1p68Mf5Q==} + dependencies: + '@types/web-bluetooth': 0.0.17 + '@vueuse/metadata': 10.3.0 + '@vueuse/shared': 10.3.0(vue@3.3.4) + vue-demi: 0.14.5(vue@3.3.4) + transitivePeerDependencies: + - '@vue/composition-api' + - vue + dev: false + + /@vueuse/metadata@10.3.0: + resolution: {integrity: sha512-Ema3YhNOa4swDsV0V7CEY5JXvK19JI/o1szFO1iWxdFg3vhdFtCtSTP26PCvbUpnUtNHBY2wx5y3WDXND5Pvnw==} + dev: false + + /@vueuse/shared@10.3.0(vue@3.3.4): + resolution: {integrity: sha512-kGqCTEuFPMK4+fNWy6dUOiYmxGcUbtznMwBZLC1PubidF4VZY05B+Oht7Jh7/6x4VOWGpvu3R37WHi81cKpiqg==} + dependencies: + vue-demi: 0.14.5(vue@3.3.4) + transitivePeerDependencies: + - '@vue/composition-api' + - vue + dev: false + + /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 + + /acorn-jsx@5.3.2(acorn@8.10.0): + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + acorn: 8.10.0 + dev: true + + /acorn-walk@8.2.0: + resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==} + engines: {node: '>=0.4.0'} + dev: true + + /acorn@8.10.0: + resolution: {integrity: sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==} + 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-escapes@4.3.2: + resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} + engines: {node: '>=8'} + dependencies: + type-fest: 0.21.3 + 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 + + /ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + 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 + + /arg@4.1.3: + resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} + dev: true + + /argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + dependencies: + sprintf-js: 1.0.3 + dev: true + + /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.2 + is-array-buffer: 3.0.2 + dev: true + + /array-flatten@1.1.1: + resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} + + /array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + dev: true + + /arraybuffer.prototype.slice@1.0.1: + resolution: {integrity: sha512-09x0ZWFEjj4WD8PDbykUwo3t9arLn8NIzmmYEJFpYekOAQjpkGSyrQhNoRTcwwcFRu+ycWF78QZ63oWTqSjBcw==} + engines: {node: '>= 0.4'} + dependencies: + array-buffer-byte-length: 1.0.0 + call-bind: 1.0.2 + define-properties: 1.2.0 + get-intrinsic: 1.2.1 + is-array-buffer: 3.0.2 + is-shared-array-buffer: 1.0.2 + dev: true + + /available-typed-arrays@1.0.5: + resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==} + engines: {node: '>= 0.4'} + dev: true + + /babel-jest@29.7.0(@babel/core@7.22.20): + resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@babel/core': ^7.8.0 + dependencies: + '@babel/core': 7.22.20 + '@jest/transform': 29.7.0 + '@types/babel__core': 7.20.2 + babel-plugin-istanbul: 6.1.1 + babel-preset-jest: 29.6.3(@babel/core@7.22.20) + chalk: 4.1.2 + graceful-fs: 4.2.11 + slash: 3.0.0 + transitivePeerDependencies: + - supports-color + dev: true + + /babel-plugin-istanbul@6.1.1: + resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} + engines: {node: '>=8'} + dependencies: + '@babel/helper-plugin-utils': 7.22.5 + '@istanbuljs/load-nyc-config': 1.1.0 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-instrument: 5.2.1 + test-exclude: 6.0.0 + transitivePeerDependencies: + - supports-color + dev: true + + /babel-plugin-jest-hoist@29.6.3: + resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@babel/template': 7.22.15 + '@babel/types': 7.22.5 + '@types/babel__core': 7.20.2 + '@types/babel__traverse': 7.20.2 + dev: true + + /babel-preset-current-node-syntax@1.0.1(@babel/core@7.22.20): + resolution: {integrity: sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.22.20 + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.22.20) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.22.20) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.22.20) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.22.20) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.22.20) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.22.20) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.22.20) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.22.20) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.22.20) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.22.20) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.22.20) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.22.20) + dev: true + + /babel-preset-jest@29.6.3(@babel/core@7.22.20): + resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.22.20 + babel-plugin-jest-hoist: 29.6.3 + babel-preset-current-node-syntax: 1.0.1(@babel/core@7.22.20) + dev: true + + /balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + dev: true + + /base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + dev: true + + /big-integer@1.6.51: + resolution: {integrity: sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==} + engines: {node: '>=0.6'} + dev: true + + /body-parser@1.20.1: + resolution: {integrity: sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + http-errors: 2.0.0 + iconv-lite: 0.4.24 + on-finished: 2.4.1 + qs: 6.11.0 + raw-body: 2.5.1 + type-is: 1.6.18 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + + /boolbase@1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + dev: true + + /bootstrap-vue-next@0.9.26(vue@3.3.4): + resolution: {integrity: sha512-3kikLOCNfFPRZ5zdPVlXRK7tusQcgmipEwEM0cucAWbZcxnhIRf4u/0wy4T7OpF28SB0/Mfb6xCf+9Sfu9p9zA==} + peerDependencies: + vue: ^3.3.4 + dependencies: + '@floating-ui/vue': 1.0.2(vue@3.3.4) + '@vueuse/core': 10.3.0(vue@3.3.4) + vue: 3.3.4 + transitivePeerDependencies: + - '@vue/composition-api' + dev: false + + /bootstrap@5.3.1(@popperjs/core@2.11.8): + resolution: {integrity: sha512-jzwza3Yagduci2x0rr9MeFSORjcHpt0lRZukZPZQJT1Dth5qzV7XcgGqYzi39KGAVYR8QEDVoO0ubFKOxzMG+g==} + peerDependencies: + '@popperjs/core': ^2.11.8 + dependencies: + '@popperjs/core': 2.11.8 + dev: false + + /bplist-parser@0.2.0: + resolution: {integrity: sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==} + engines: {node: '>= 5.10.0'} + dependencies: + big-integer: 1.6.51 + 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 + + /brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + dependencies: + balanced-match: 1.0.2 + dev: true + + /braces@3.0.2: + resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} + engines: {node: '>=8'} + dependencies: + fill-range: 7.0.1 + dev: true + + /browserslist@4.21.11: + resolution: {integrity: sha512-xn1UXOKUz7DjdGlg9RrUr0GGiWzI97UQJnugHtH0OLDfJB7jMgoIkYvRIEO1l9EeEERVqeqLYOcFBW9ldjypbQ==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + dependencies: + caniuse-lite: 1.0.30001538 + electron-to-chromium: 1.4.527 + node-releases: 2.0.13 + update-browserslist-db: 1.0.13(browserslist@4.21.11) + dev: true + + /bs-logger@0.2.6: + resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==} + engines: {node: '>= 6'} + dependencies: + fast-json-stable-stringify: 2.1.0 + dev: true + + /bser@2.1.1: + resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} + dependencies: + node-int64: 0.4.0 + dev: true + + /bson@5.4.0: + resolution: {integrity: sha512-WRZ5SQI5GfUuKnPTNmAYPiKIof3ORXAF4IRU5UcgmivNIon01rWQlw5RUH954dpu8yGL8T59YShVddIPaU/gFA==} + engines: {node: '>=14.20.1'} + + /buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + dev: true + + /buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.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'} + + /call-bind@1.0.2: + resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} + dependencies: + function-bind: 1.1.1 + get-intrinsic: 1.2.1 + + /callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + dev: true + + /camelcase@5.3.1: + resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} + engines: {node: '>=6'} + dev: true + + /camelcase@6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + dev: true + + /caniuse-lite@1.0.30001538: + resolution: {integrity: sha512-HWJnhnID+0YMtGlzcp3T9drmBJUVDchPJ08tpUGFLs9CYlwWPH2uLgpHn8fND5pCgXVtnGS3H4QR9XLMHVNkHw==} + 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 + + /char-regex@1.0.2: + resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} + engines: {node: '>=10'} + dev: true + + /ci-info@3.8.0: + resolution: {integrity: sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==} + engines: {node: '>=8'} + dev: true + + /cjs-module-lexer@1.2.3: + resolution: {integrity: sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==} + dev: true + + /cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + dev: true + + /co@4.6.0: + resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} + engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} + dev: true + + /collect-v8-coverage@1.0.2: + resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==} + dev: true + + /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 + + /content-disposition@0.5.4: + resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} + engines: {node: '>= 0.6'} + dependencies: + safe-buffer: 5.2.1 + + /content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + + /convert-source-map@1.9.0: + resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} + dev: true + + /convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + dev: true + + /cookie-signature@1.0.6: + resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} + + /cookie@0.4.2: + resolution: {integrity: sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==} + engines: {node: '>= 0.6'} + + /cookie@0.5.0: + resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==} + engines: {node: '>= 0.6'} + + /create-jest@29.7.0(@types/node@20.6.3)(ts-node@10.9.1): + resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + dependencies: + '@jest/types': 29.6.3 + chalk: 4.1.2 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-config: 29.7.0(@types/node@20.6.3)(ts-node@10.9.1) + jest-util: 29.7.0 + prompts: 2.4.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + dev: true + + /create-require@1.1.1: + resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} + dev: true + + /cross-spawn@6.0.5: + resolution: {integrity: sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==} + engines: {node: '>=4.8'} + dependencies: + nice-try: 1.0.5 + path-key: 2.0.1 + semver: 5.7.2 + shebang-command: 1.2.0 + which: 1.3.1 + 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 + + /cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + dev: true + + /csstype@3.1.2: + resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==} + + /date-fns@2.30.0: + resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==} + engines: {node: '>=0.11'} + dependencies: + '@babel/runtime': 7.22.6 + dev: false + + /de-indent@1.0.2: + resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==} + 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 + + /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 + + /dedent@1.5.1: + resolution: {integrity: sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==} + peerDependencies: + babel-plugin-macros: ^3.1.0 + peerDependenciesMeta: + babel-plugin-macros: + optional: true + dev: true + + /deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + dev: true + + /deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + 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-lazy-prop@3.0.0: + resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} + engines: {node: '>=12'} + dev: true + + /define-properties@1.2.0: + resolution: {integrity: sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==} + engines: {node: '>= 0.4'} + dependencies: + has-property-descriptors: 1.0.0 + object-keys: 1.1.1 + dev: true + + /depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + + /destroy@1.2.0: + resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + + /detect-newline@3.1.0: + resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} + engines: {node: '>=8'} + dev: true + + /diff-sequences@29.6.3: + resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dev: true + + /diff@4.0.2: + resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} + engines: {node: '>=0.3.1'} + dev: true + + /dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + dependencies: + path-type: 4.0.0 + dev: true + + /doctrine@3.0.0: + resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} + engines: {node: '>=6.0.0'} + dependencies: + esutils: 2.0.3 + dev: true + + /dotenv@16.3.1: + resolution: {integrity: sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==} + engines: {node: '>=12'} + dev: false + + /duplexer@0.1.2: + resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} + dev: true + + /ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + + /electron-to-chromium@1.4.527: + resolution: {integrity: sha512-EafxEiEDzk2aLrdbtVczylHflHdHkNrpGNHIgDyA63sUQLQVS2ayj2hPw3RsVB42qkwURH+T2OxV7kGPUuYszA==} + dev: true + + /emittery@0.13.1: + resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} + engines: {node: '>=12'} + dev: true + + /emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + dev: true + + /encodeurl@1.0.2: + resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} + engines: {node: '>= 0.8'} + + /error-ex@1.3.2: + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + dependencies: + is-arrayish: 0.2.1 + dev: true + + /es-abstract@1.22.1: + resolution: {integrity: sha512-ioRRcXMO6OFyRpyzV3kE1IIBd4WG5/kltnzdxSCqoP8CMGs/Li+M1uF5o7lOkZVFjDs+NLesthnF66Pg/0q0Lw==} + engines: {node: '>= 0.4'} + dependencies: + array-buffer-byte-length: 1.0.0 + arraybuffer.prototype.slice: 1.0.1 + available-typed-arrays: 1.0.5 + call-bind: 1.0.2 + es-set-tostringtag: 2.0.1 + es-to-primitive: 1.2.1 + function.prototype.name: 1.1.5 + get-intrinsic: 1.2.1 + get-symbol-description: 1.0.0 + globalthis: 1.0.3 + gopd: 1.0.1 + has: 1.0.3 + has-property-descriptors: 1.0.0 + has-proto: 1.0.1 + has-symbols: 1.0.3 + internal-slot: 1.0.5 + 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.12.3 + object-keys: 1.1.1 + object.assign: 4.1.4 + regexp.prototype.flags: 1.5.0 + safe-array-concat: 1.0.0 + safe-regex-test: 1.0.0 + string.prototype.trim: 1.2.7 + string.prototype.trimend: 1.0.6 + string.prototype.trimstart: 1.0.6 + 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.11 + dev: true + + /es-set-tostringtag@2.0.1: + resolution: {integrity: sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.1 + has: 1.0.3 + has-tostringtag: 1.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.18.17: + resolution: {integrity: sha512-1GJtYnUxsJreHYA0Y+iQz2UEykonY66HNWOb0yXYZi9/kNrORUEHVg87eQsCtqh59PEJ5YVZJO98JHznMJSWjg==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/android-arm': 0.18.17 + '@esbuild/android-arm64': 0.18.17 + '@esbuild/android-x64': 0.18.17 + '@esbuild/darwin-arm64': 0.18.17 + '@esbuild/darwin-x64': 0.18.17 + '@esbuild/freebsd-arm64': 0.18.17 + '@esbuild/freebsd-x64': 0.18.17 + '@esbuild/linux-arm': 0.18.17 + '@esbuild/linux-arm64': 0.18.17 + '@esbuild/linux-ia32': 0.18.17 + '@esbuild/linux-loong64': 0.18.17 + '@esbuild/linux-mips64el': 0.18.17 + '@esbuild/linux-ppc64': 0.18.17 + '@esbuild/linux-riscv64': 0.18.17 + '@esbuild/linux-s390x': 0.18.17 + '@esbuild/linux-x64': 0.18.17 + '@esbuild/netbsd-x64': 0.18.17 + '@esbuild/openbsd-x64': 0.18.17 + '@esbuild/sunos-x64': 0.18.17 + '@esbuild/win32-arm64': 0.18.17 + '@esbuild/win32-ia32': 0.18.17 + '@esbuild/win32-x64': 0.18.17 + 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==} + + /escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + dev: true + + /escape-string-regexp@2.0.0: + resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} + engines: {node: '>=8'} + dev: true + + /escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + dev: true + + /eslint-config-prettier@8.10.0(eslint@8.45.0): + resolution: {integrity: sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==} + hasBin: true + peerDependencies: + eslint: '>=7.0.0' + dependencies: + eslint: 8.45.0 + dev: true + + /eslint-config-prettier@8.10.0(eslint@8.50.0): + resolution: {integrity: sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==} + hasBin: true + peerDependencies: + eslint: '>=7.0.0' + dependencies: + eslint: 8.50.0 + dev: true + + /eslint-plugin-prettier@5.0.0(eslint-config-prettier@8.10.0)(eslint@8.45.0)(prettier@3.0.0): + resolution: {integrity: sha512-AgaZCVuYDXHUGxj/ZGu1u8H8CYgDY3iG6w5kUFw4AzMVXzB7VvbKgYR4nATIN+OvUrghMbiDLeimVjVY5ilq3w==} + 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.45.0 + eslint-config-prettier: 8.10.0(eslint@8.45.0) + prettier: 3.0.0 + prettier-linter-helpers: 1.0.0 + synckit: 0.8.5 + dev: true + + /eslint-plugin-prettier@5.0.0(eslint-config-prettier@8.10.0)(eslint@8.50.0)(prettier@3.0.0): + resolution: {integrity: sha512-AgaZCVuYDXHUGxj/ZGu1u8H8CYgDY3iG6w5kUFw4AzMVXzB7VvbKgYR4nATIN+OvUrghMbiDLeimVjVY5ilq3w==} + 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.50.0 + eslint-config-prettier: 8.10.0(eslint@8.50.0) + prettier: 3.0.0 + prettier-linter-helpers: 1.0.0 + synckit: 0.8.5 + dev: true + + /eslint-plugin-vue@9.15.1(eslint@8.45.0): + resolution: {integrity: sha512-CJE/oZOslvmAR9hf8SClTdQ9JLweghT6JCBQNrT2Iel1uVw0W0OLJxzvPd6CxmABKCvLrtyDnqGV37O7KQv6+A==} + engines: {node: ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.2.0 || ^7.0.0 || ^8.0.0 + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.45.0) + eslint: 8.45.0 + natural-compare: 1.4.0 + nth-check: 2.1.1 + postcss-selector-parser: 6.0.13 + semver: 7.5.4 + vue-eslint-parser: 9.3.1(eslint@8.45.0) + xml-name-validator: 4.0.0 + transitivePeerDependencies: + - supports-color + dev: true + + /eslint-plugin-vue@9.15.1(eslint@8.50.0): + resolution: {integrity: sha512-CJE/oZOslvmAR9hf8SClTdQ9JLweghT6JCBQNrT2Iel1uVw0W0OLJxzvPd6CxmABKCvLrtyDnqGV37O7KQv6+A==} + engines: {node: ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.2.0 || ^7.0.0 || ^8.0.0 + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.50.0) + eslint: 8.50.0 + natural-compare: 1.4.0 + nth-check: 2.1.1 + postcss-selector-parser: 6.0.13 + semver: 7.5.4 + vue-eslint-parser: 9.3.1(eslint@8.50.0) + xml-name-validator: 4.0.0 + transitivePeerDependencies: + - supports-color + dev: true + + /eslint-scope@5.1.1: + resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} + engines: {node: '>=8.0.0'} + dependencies: + esrecurse: 4.3.0 + estraverse: 4.3.0 + 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.2: + resolution: {integrity: sha512-8drBzUEyZ2llkpCA67iYrgEssKDUu68V8ChqqOfFupIaG/LCVPUT+CoGJpT77zJprs4T/W7p07LP7zAIMuweVw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.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.45.0: + resolution: {integrity: sha512-pd8KSxiQpdYRfYa9Wufvdoct3ZPQQuVuU5O6scNgMuOMYuxvH0IGaYK0wUFjo4UYYQQCUndlXiMbnxopwvvTiw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + hasBin: true + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.45.0) + '@eslint-community/regexpp': 4.6.2 + '@eslint/eslintrc': 2.1.1 + '@eslint/js': 8.44.0 + '@humanwhocodes/config-array': 0.11.10 + '@humanwhocodes/module-importer': 1.0.1 + '@nodelib/fs.walk': 1.2.8 + 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.2 + 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.20.0 + graphemer: 1.4.0 + ignore: 5.2.4 + 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 + + /eslint@8.49.0: + resolution: {integrity: sha512-jw03ENfm6VJI0jA9U+8H5zfl5b+FvuU3YYvZRdZHOlU2ggJkxrlkJH4HcDrZpj6YwD8kuYqvQM8LyesoazrSOQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + hasBin: true + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.49.0) + '@eslint-community/regexpp': 4.6.2 + '@eslint/eslintrc': 2.1.2 + '@eslint/js': 8.49.0 + '@humanwhocodes/config-array': 0.11.11 + '@humanwhocodes/module-importer': 1.0.1 + '@nodelib/fs.walk': 1.2.8 + 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.20.0 + graphemer: 1.4.0 + ignore: 5.2.4 + 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 + + /eslint@8.50.0: + resolution: {integrity: sha512-FOnOGSuFuFLv/Sa+FDVRZl4GGVAAFFi8LecRsI5a1tMO5HIE8nCm4ivAlzt4dT3ol/PaaGC0rJEEXQmHJBGoOg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + hasBin: true + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.50.0) + '@eslint-community/regexpp': 4.6.2 + '@eslint/eslintrc': 2.1.2 + '@eslint/js': 8.50.0 + '@humanwhocodes/config-array': 0.11.11 + '@humanwhocodes/module-importer': 1.0.1 + '@nodelib/fs.walk': 1.2.8 + 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.20.0 + graphemer: 1.4.0 + ignore: 5.2.4 + 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.10.0 + acorn-jsx: 5.3.2(acorn@8.10.0) + eslint-visitor-keys: 3.4.3 + dev: true + + /esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + 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@4.3.0: + resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} + engines: {node: '>=4.0'} + dev: true + + /estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + dev: true + + /estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + + /esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + dev: true + + /etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + + /event-stream@3.3.4: + resolution: {integrity: sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g==} + dependencies: + duplexer: 0.1.2 + from: 0.1.7 + map-stream: 0.1.0 + pause-stream: 0.0.11 + split: 0.3.3 + stream-combiner: 0.0.4 + through: 2.3.8 + dev: true + + /eventemitter3@5.0.1: + resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + dev: false + + /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 + + /exit@0.1.2: + resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} + engines: {node: '>= 0.8.0'} + dev: true + + /expect@29.7.0: + resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/expect-utils': 29.7.0 + jest-get-type: 29.6.3 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + dev: true + + /express-session@1.17.3: + resolution: {integrity: sha512-4+otWXlShYlG1Ma+2Jnn+xgKUZTMJ5QD3YvfilX3AcocOAbIkVylSWEklzALe/+Pu4qV6TYBj5GwOBFfdKqLBw==} + engines: {node: '>= 0.8.0'} + dependencies: + cookie: 0.4.2 + cookie-signature: 1.0.6 + debug: 2.6.9 + depd: 2.0.0 + on-headers: 1.0.2 + parseurl: 1.3.3 + safe-buffer: 5.2.1 + uid-safe: 2.1.5 + transitivePeerDependencies: + - supports-color + + /express@4.18.2: + resolution: {integrity: sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==} + engines: {node: '>= 0.10.0'} + dependencies: + accepts: 1.3.8 + array-flatten: 1.1.1 + body-parser: 1.20.1 + content-disposition: 0.5.4 + content-type: 1.0.5 + cookie: 0.5.0 + cookie-signature: 1.0.6 + debug: 2.6.9 + depd: 2.0.0 + encodeurl: 1.0.2 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 1.2.0 + fresh: 0.5.2 + http-errors: 2.0.0 + merge-descriptors: 1.0.1 + methods: 1.1.2 + on-finished: 2.4.1 + parseurl: 1.3.3 + path-to-regexp: 0.1.7 + proxy-addr: 2.0.7 + qs: 6.11.0 + range-parser: 1.2.1 + safe-buffer: 5.2.1 + send: 0.18.0 + serve-static: 1.15.0 + setprototypeof: 1.2.0 + statuses: 2.0.1 + type-is: 1.6.18 + utils-merge: 1.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + + /fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + dev: true + + /fast-diff@1.3.0: + resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} + dev: true + + /fast-glob@3.3.1: + resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} + 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 + + /fb-watchman@2.0.2: + resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} + dependencies: + bser: 2.1.1 + 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.0.4 + dev: true + + /fill-range@7.0.1: + resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} + engines: {node: '>=8'} + dependencies: + to-regex-range: 5.0.1 + dev: true + + /finalhandler@1.2.0: + resolution: {integrity: sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==} + engines: {node: '>= 0.8'} + dependencies: + debug: 2.6.9 + encodeurl: 1.0.2 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.1 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + + /find-up@4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + 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.0.4: + resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==} + engines: {node: ^10.12.0 || >=12.0.0} + dependencies: + flatted: 3.2.7 + rimraf: 3.0.2 + dev: true + + /flatted@3.2.7: + resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} + dev: true + + /for-each@0.3.3: + resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} + dependencies: + is-callable: 1.2.7 + dev: true + + /forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} + + /fresh@0.5.2: + resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} + engines: {node: '>= 0.6'} + + /from@0.1.7: + resolution: {integrity: sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==} + dev: true + + /fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + dev: true + + /fsevents@2.3.2: + resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /function-bind@1.1.1: + resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} + + /function.prototype.name@1.1.5: + resolution: {integrity: sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.2.0 + es-abstract: 1.22.1 + 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-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + dev: true + + /get-intrinsic@1.2.1: + resolution: {integrity: sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==} + dependencies: + function-bind: 1.1.1 + has: 1.0.3 + has-proto: 1.0.1 + has-symbols: 1.0.3 + + /get-package-type@0.1.0: + resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} + engines: {node: '>=8.0.0'} + dev: true + + /get-stream@6.0.1: + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} + dev: true + + /get-symbol-description@1.0.0: + resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + get-intrinsic: 1.2.1 + 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@11.12.0: + resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} + engines: {node: '>=4'} + dev: true + + /globals@13.20.0: + resolution: {integrity: sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==} + 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.0 + dev: true + + /globby@11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} + engines: {node: '>=10'} + dependencies: + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.3.1 + ignore: 5.2.4 + merge2: 1.4.1 + slash: 3.0.0 + dev: true + + /gopd@1.0.1: + resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + dependencies: + get-intrinsic: 1.2.1 + dev: true + + /graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + 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.0: + resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==} + dependencies: + get-intrinsic: 1.2.1 + dev: true + + /has-proto@1.0.1: + resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} + engines: {node: '>= 0.4'} + + /has-symbols@1.0.3: + resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} + engines: {node: '>= 0.4'} + + /has-tostringtag@1.0.0: + resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==} + engines: {node: '>= 0.4'} + dependencies: + has-symbols: 1.0.3 + dev: true + + /has@1.0.3: + resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} + engines: {node: '>= 0.4.0'} + dependencies: + function-bind: 1.1.1 + + /he@1.2.0: + resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} + hasBin: true + dev: true + + /hosted-git-info@2.8.9: + resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} + dev: true + + /html-escaper@2.0.2: + resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + 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 + + /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 + + /iconv-lite@0.4.24: + resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} + engines: {node: '>=0.10.0'} + dependencies: + safer-buffer: 2.1.2 + + /ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + dev: true + + /ignore@5.2.4: + resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} + 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 + + /import-local@3.1.0: + resolution: {integrity: sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==} + engines: {node: '>=8'} + hasBin: true + dependencies: + pkg-dir: 4.2.0 + resolve-cwd: 3.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==} + + /internal-slot@1.0.5: + resolution: {integrity: sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.1 + has: 1.0.3 + side-channel: 1.0.4 + dev: true + + /ip@2.0.0: + resolution: {integrity: sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==} + dev: false + + /ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + + /is-array-buffer@3.0.2: + resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==} + dependencies: + call-bind: 1.0.2 + get-intrinsic: 1.2.1 + is-typed-array: 1.1.12 + dev: true + + /is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + dev: true + + /is-bigint@1.0.4: + resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} + dependencies: + has-bigints: 1.0.2 + dev: true + + /is-boolean-object@1.1.2: + resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + 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.12.1: + resolution: {integrity: sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==} + dependencies: + has: 1.0.3 + 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-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-fn@2.1.0: + resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} + engines: {node: '>=6'} + 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-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-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'} + dev: true + + /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.2 + has-tostringtag: 1.0.0 + dev: true + + /is-shared-array-buffer@1.0.2: + resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==} + dependencies: + call-bind: 1.0.2 + dev: true + + /is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + dev: true + + /is-stream@3.0.0: + resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + 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.11 + dev: true + + /is-weakref@1.0.2: + resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} + dependencies: + call-bind: 1.0.2 + dev: true + + /is-wsl@2.2.0: + resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} + engines: {node: '>=8'} + dependencies: + is-docker: 2.2.1 + 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 + + /istanbul-lib-coverage@3.2.0: + resolution: {integrity: sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==} + engines: {node: '>=8'} + dev: true + + /istanbul-lib-instrument@5.2.1: + resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} + engines: {node: '>=8'} + dependencies: + '@babel/core': 7.22.20 + '@babel/parser': 7.22.7 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-coverage: 3.2.0 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + dev: true + + /istanbul-lib-instrument@6.0.0: + resolution: {integrity: sha512-x58orMzEVfzPUKqlbLd1hXCnySCxKdDKa6Rjg97CwuLLRI4g3FHTdnExu1OqffVFay6zeMW+T6/DowFLndWnIw==} + engines: {node: '>=10'} + dependencies: + '@babel/core': 7.22.20 + '@babel/parser': 7.22.7 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-coverage: 3.2.0 + semver: 7.5.4 + transitivePeerDependencies: + - supports-color + dev: true + + /istanbul-lib-report@3.0.1: + resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} + engines: {node: '>=10'} + dependencies: + istanbul-lib-coverage: 3.2.0 + make-dir: 4.0.0 + supports-color: 7.2.0 + dev: true + + /istanbul-lib-source-maps@4.0.1: + resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} + engines: {node: '>=10'} + dependencies: + debug: 4.3.4 + istanbul-lib-coverage: 3.2.0 + source-map: 0.6.1 + transitivePeerDependencies: + - supports-color + dev: true + + /istanbul-reports@3.1.6: + resolution: {integrity: sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==} + engines: {node: '>=8'} + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.1 + dev: true + + /jest-changed-files@29.7.0: + resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + execa: 5.1.1 + jest-util: 29.7.0 + p-limit: 3.1.0 + dev: true + + /jest-circus@29.7.0: + resolution: {integrity: sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/environment': 29.7.0 + '@jest/expect': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.6.3 + chalk: 4.1.2 + co: 4.6.0 + dedent: 1.5.1 + is-generator-fn: 2.1.0 + jest-each: 29.7.0 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-runtime: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + p-limit: 3.1.0 + pretty-format: 29.7.0 + pure-rand: 6.0.3 + slash: 3.0.0 + stack-utils: 2.0.6 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + dev: true + + /jest-cli@29.7.0(@types/node@20.6.3)(ts-node@10.9.1): + resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + dependencies: + '@jest/core': 29.7.0(ts-node@10.9.1) + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + chalk: 4.1.2 + create-jest: 29.7.0(@types/node@20.6.3)(ts-node@10.9.1) + exit: 0.1.2 + import-local: 3.1.0 + jest-config: 29.7.0(@types/node@20.6.3)(ts-node@10.9.1) + jest-util: 29.7.0 + jest-validate: 29.7.0 + yargs: 17.7.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + dev: true + + /jest-config@29.7.0(@types/node@20.6.3)(ts-node@10.9.1): + resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@types/node': '*' + ts-node: '>=9.0.0' + peerDependenciesMeta: + '@types/node': + optional: true + ts-node: + optional: true + dependencies: + '@babel/core': 7.22.20 + '@jest/test-sequencer': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.6.3 + babel-jest: 29.7.0(@babel/core@7.22.20) + chalk: 4.1.2 + ci-info: 3.8.0 + deepmerge: 4.3.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-circus: 29.7.0 + jest-environment-node: 29.7.0 + jest-get-type: 29.6.3 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-runner: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + micromatch: 4.0.5 + parse-json: 5.2.0 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + ts-node: 10.9.1(@types/node@18.17.0)(typescript@5.1.6) + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + dev: true + + /jest-diff@29.7.0: + resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + chalk: 4.1.2 + diff-sequences: 29.6.3 + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + dev: true + + /jest-docblock@29.7.0: + resolution: {integrity: sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + detect-newline: 3.1.0 + dev: true + + /jest-each@29.7.0: + resolution: {integrity: sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/types': 29.6.3 + chalk: 4.1.2 + jest-get-type: 29.6.3 + jest-util: 29.7.0 + pretty-format: 29.7.0 + dev: true + + /jest-environment-node@29.7.0: + resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/environment': 29.7.0 + '@jest/fake-timers': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.6.3 + jest-mock: 29.7.0 + jest-util: 29.7.0 + dev: true + + /jest-get-type@29.6.3: + resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dev: true + + /jest-haste-map@29.7.0: + resolution: {integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/types': 29.6.3 + '@types/graceful-fs': 4.1.7 + '@types/node': 20.6.3 + anymatch: 3.1.3 + fb-watchman: 2.0.2 + graceful-fs: 4.2.11 + jest-regex-util: 29.6.3 + jest-util: 29.7.0 + jest-worker: 29.7.0 + micromatch: 4.0.5 + walker: 1.0.8 + optionalDependencies: + fsevents: 2.3.2 + dev: true + + /jest-leak-detector@29.7.0: + resolution: {integrity: sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + dev: true + + /jest-matcher-utils@29.7.0: + resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + chalk: 4.1.2 + jest-diff: 29.7.0 + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + dev: true + + /jest-message-util@29.7.0: + resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@babel/code-frame': 7.22.13 + '@jest/types': 29.6.3 + '@types/stack-utils': 2.0.1 + chalk: 4.1.2 + graceful-fs: 4.2.11 + micromatch: 4.0.5 + pretty-format: 29.7.0 + slash: 3.0.0 + stack-utils: 2.0.6 + dev: true + + /jest-mock@29.7.0: + resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/types': 29.6.3 + '@types/node': 20.6.3 + jest-util: 29.7.0 + dev: true + + /jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): + resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} + engines: {node: '>=6'} + peerDependencies: + jest-resolve: '*' + peerDependenciesMeta: + jest-resolve: + optional: true + dependencies: + jest-resolve: 29.7.0 + dev: true + + /jest-regex-util@29.6.3: + resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dev: true + + /jest-resolve-dependencies@29.7.0: + resolution: {integrity: sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + jest-regex-util: 29.6.3 + jest-snapshot: 29.7.0 + transitivePeerDependencies: + - supports-color + dev: true + + /jest-resolve@29.7.0: + resolution: {integrity: sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + chalk: 4.1.2 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + jest-pnp-resolver: 1.2.3(jest-resolve@29.7.0) + jest-util: 29.7.0 + jest-validate: 29.7.0 + resolve: 1.22.2 + resolve.exports: 2.0.2 + slash: 3.0.0 + dev: true + + /jest-runner@29.7.0: + resolution: {integrity: sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/console': 29.7.0 + '@jest/environment': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.6.3 + chalk: 4.1.2 + emittery: 0.13.1 + graceful-fs: 4.2.11 + jest-docblock: 29.7.0 + jest-environment-node: 29.7.0 + jest-haste-map: 29.7.0 + jest-leak-detector: 29.7.0 + jest-message-util: 29.7.0 + jest-resolve: 29.7.0 + jest-runtime: 29.7.0 + jest-util: 29.7.0 + jest-watcher: 29.7.0 + jest-worker: 29.7.0 + p-limit: 3.1.0 + source-map-support: 0.5.13 + transitivePeerDependencies: + - supports-color + dev: true + + /jest-runtime@29.7.0: + resolution: {integrity: sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/environment': 29.7.0 + '@jest/fake-timers': 29.7.0 + '@jest/globals': 29.7.0 + '@jest/source-map': 29.6.3 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.6.3 + chalk: 4.1.2 + cjs-module-lexer: 1.2.3 + collect-v8-coverage: 1.0.2 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + jest-message-util: 29.7.0 + jest-mock: 29.7.0 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + slash: 3.0.0 + strip-bom: 4.0.0 + transitivePeerDependencies: + - supports-color + dev: true + + /jest-snapshot@29.7.0: + resolution: {integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@babel/core': 7.22.20 + '@babel/generator': 7.22.15 + '@babel/plugin-syntax-jsx': 7.22.5(@babel/core@7.22.20) + '@babel/plugin-syntax-typescript': 7.22.5(@babel/core@7.22.20) + '@babel/types': 7.22.5 + '@jest/expect-utils': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + babel-preset-current-node-syntax: 1.0.1(@babel/core@7.22.20) + chalk: 4.1.2 + expect: 29.7.0 + graceful-fs: 4.2.11 + jest-diff: 29.7.0 + jest-get-type: 29.6.3 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + natural-compare: 1.4.0 + pretty-format: 29.7.0 + semver: 7.5.4 + transitivePeerDependencies: + - supports-color + dev: true + + /jest-util@29.7.0: + resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/types': 29.6.3 + '@types/node': 20.6.3 + chalk: 4.1.2 + ci-info: 3.8.0 + graceful-fs: 4.2.11 + picomatch: 2.3.1 + dev: true + + /jest-validate@29.7.0: + resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/types': 29.6.3 + camelcase: 6.3.0 + chalk: 4.1.2 + jest-get-type: 29.6.3 + leven: 3.1.0 + pretty-format: 29.7.0 + dev: true + + /jest-watcher@29.7.0: + resolution: {integrity: sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.6.3 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + emittery: 0.13.1 + jest-util: 29.7.0 + string-length: 4.0.2 + dev: true + + /jest-worker@29.7.0: + resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@types/node': 20.6.3 + jest-util: 29.7.0 + merge-stream: 2.0.0 + supports-color: 8.1.1 + dev: true + + /jest@29.7.0(@types/node@20.6.3)(ts-node@10.9.1): + resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + dependencies: + '@jest/core': 29.7.0(ts-node@10.9.1) + '@jest/types': 29.6.3 + import-local: 3.1.0 + jest-cli: 29.7.0(@types/node@20.6.3)(ts-node@10.9.1) + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + dev: true + + /js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + dev: true + + /js-yaml@3.14.1: + resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} + hasBin: true + dependencies: + argparse: 1.0.10 + esprima: 4.0.1 + dev: true + + /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-parse-better-errors@1.0.2: + resolution: {integrity: sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==} + dev: true + + /json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + 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 + + /kareem@2.5.1: + resolution: {integrity: sha512-7jFxRVm+jD+rkq3kY0iZDJfsO2/t4BBPeEb2qKn2lR/9KhuksYk5hxzfRYWMPV8P/x2d0kHD306YyWLzjjH+uA==} + engines: {node: '>=12.0.0'} + dev: false + + /kleur@3.0.3: + resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} + engines: {node: '>=6'} + dev: true + + /ky@1.0.1: + resolution: {integrity: sha512-UvcwpQO0LOuZwG0Ti3VDo6w57KYt+r4bWEYlNaMt82hgyFtse86QtOGum1RzsZni31FndXQl6NvtDArfunt2JQ==} + engines: {node: '>=18'} + + /leven@3.1.0: + resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} + engines: {node: '>=6'} + 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 + + /lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + dev: true + + /load-json-file@4.0.0: + resolution: {integrity: sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==} + engines: {node: '>=4'} + dependencies: + graceful-fs: 4.2.11 + parse-json: 4.0.0 + pify: 3.0.0 + strip-bom: 3.0.0 + dev: true + + /locate-path@5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + dependencies: + p-locate: 4.1.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-es@4.17.21: + resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} + + /lodash.memoize@4.1.2: + resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} + dev: true + + /lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + dev: true + + /lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + dev: true + + /lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + dependencies: + yallist: 3.1.1 + dev: true + + /lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + dependencies: + yallist: 4.0.0 + dev: true + + /magic-string@0.30.2: + resolution: {integrity: sha512-lNZdu7pewtq/ZvWUp9Wpf/x7WzMTsR26TWV03BRZrXFsv+BI6dy8RAiKgm1uM/kyR0rCfUcqvOlXKG66KhIGug==} + engines: {node: '>=12'} + dependencies: + '@jridgewell/sourcemap-codec': 1.4.15 + + /make-dir@4.0.0: + resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} + engines: {node: '>=10'} + dependencies: + semver: 7.5.4 + dev: true + + /make-error@1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + dev: true + + /makeerror@1.0.12: + resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} + dependencies: + tmpl: 1.0.5 + dev: true + + /map-stream@0.1.0: + resolution: {integrity: sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g==} + dev: true + + /media-typer@0.3.0: + resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} + engines: {node: '>= 0.6'} + + /memory-pager@1.5.0: + resolution: {integrity: sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==} + requiresBuild: true + dev: false + optional: true + + /memorystream@0.3.1: + resolution: {integrity: sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==} + engines: {node: '>= 0.10.0'} + dev: true + + /merge-descriptors@1.0.1: + resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==} + + /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'} + + /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 + + /mime@1.6.0: + resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} + engines: {node: '>=4'} + hasBin: true + + /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 + + /minimatch@9.0.3: + resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} + engines: {node: '>=16 || 14 >=14.17'} + dependencies: + brace-expansion: 2.0.1 + dev: true + + /mongodb-connection-string-url@2.6.0: + resolution: {integrity: sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==} + dependencies: + '@types/whatwg-url': 8.2.2 + whatwg-url: 11.0.0 + dev: false + + /mongodb@5.7.0: + resolution: {integrity: sha512-zm82Bq33QbqtxDf58fLWBwTjARK3NSvKYjyz997KSy6hpat0prjeX/kxjbPVyZY60XYPDNETaHkHJI2UCzSLuw==} + engines: {node: '>=14.20.1'} + peerDependencies: + '@aws-sdk/credential-providers': ^3.201.0 + '@mongodb-js/zstd': ^1.1.0 + kerberos: ^2.0.1 + mongodb-client-encryption: '>=2.3.0 <3' + snappy: ^7.2.2 + peerDependenciesMeta: + '@aws-sdk/credential-providers': + optional: true + '@mongodb-js/zstd': + optional: true + kerberos: + optional: true + mongodb-client-encryption: + optional: true + snappy: + optional: true + dependencies: + bson: 5.4.0 + mongodb-connection-string-url: 2.6.0 + socks: 2.7.1 + optionalDependencies: + saslprep: 1.0.3 + dev: false + + /mongoose@7.4.3: + resolution: {integrity: sha512-eok0lW6mZJHK2vVSWyJb9tUfPMUuRF3h7YC4pU2K2/YSZBlNDUwvKsHgftMOANbokP2Ry+4ylvzAdW4KjkRFjw==} + engines: {node: '>=14.20.1'} + dependencies: + bson: 5.4.0 + kareem: 2.5.1 + mongodb: 5.7.0 + mpath: 0.9.0 + mquery: 5.0.0 + ms: 2.1.3 + sift: 16.0.1 + transitivePeerDependencies: + - '@aws-sdk/credential-providers' + - '@mongodb-js/zstd' + - kerberos + - mongodb-client-encryption + - snappy + - supports-color + dev: false + + /mpath@0.9.0: + resolution: {integrity: sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==} + engines: {node: '>=4.0.0'} + dev: false + + /mquery@5.0.0: + resolution: {integrity: sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==} + engines: {node: '>=14.0.0'} + dependencies: + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: false + + /ms@2.0.0: + resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} + + /ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + + /ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + /muggle-string@0.3.1: + resolution: {integrity: sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg==} + dev: true + + /nanoid@3.3.6: + resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + /natural-compare-lite@1.4.0: + resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==} + dev: true + + /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'} + + /nice-try@1.0.5: + resolution: {integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==} + dev: true + + /node-cleanup@2.1.2: + resolution: {integrity: sha512-qN8v/s2PAJwGUtr1/hYTpNKlD6Y9rc4p8KSmJXyGdYGZsDGKXrGThikLFP9OCHFeLeEpQzPwiAtdIvBLqm//Hw==} + dev: true + + /node-int64@0.4.0: + resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} + dev: true + + /node-releases@2.0.13: + resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==} + dev: true + + /normalize-package-data@2.5.0: + resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} + dependencies: + hosted-git-info: 2.8.9 + resolve: 1.22.2 + semver: 5.7.2 + validate-npm-package-license: 3.0.4 + dev: true + + /normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + dev: true + + /npm-run-all@4.1.5: + resolution: {integrity: sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==} + engines: {node: '>= 4'} + hasBin: true + dependencies: + ansi-styles: 3.2.1 + chalk: 2.4.2 + cross-spawn: 6.0.5 + memorystream: 0.3.1 + minimatch: 3.1.2 + pidtree: 0.3.1 + read-pkg: 3.0.0 + shell-quote: 1.8.1 + string.prototype.padend: 3.1.4 + 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 + + /nth-check@2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + dependencies: + boolbase: 1.0.0 + dev: true + + /object-inspect@1.12.3: + resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==} + + /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.2 + define-properties: 1.2.0 + has-symbols: 1.0.3 + object-keys: 1.1.1 + dev: true + + /on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + dependencies: + ee-first: 1.1.1 + + /on-headers@1.0.2: + resolution: {integrity: sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==} + engines: {node: '>= 0.8'} + + /once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + dependencies: + wrappy: 1.0.2 + dev: true + + /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 + + /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@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + dependencies: + p-try: 2.2.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@4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + dependencies: + p-limit: 2.3.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 + + /p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + 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 + + /parse-json@4.0.0: + resolution: {integrity: sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==} + engines: {node: '>=4'} + dependencies: + error-ex: 1.3.2 + json-parse-better-errors: 1.0.2 + dev: true + + /parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + dependencies: + '@babel/code-frame': 7.22.13 + error-ex: 1.3.2 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + dev: true + + /parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + + /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@2.0.1: + resolution: {integrity: sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==} + engines: {node: '>=4'} + 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-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + dev: true + + /path-to-regexp@0.1.7: + resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==} + + /path-type@3.0.0: + resolution: {integrity: sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==} + engines: {node: '>=4'} + dependencies: + pify: 3.0.0 + dev: true + + /path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + dev: true + + /pause-stream@0.0.11: + resolution: {integrity: sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==} + dependencies: + through: 2.3.8 + dev: true + + /picocolors@1.0.0: + resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + + /picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + dev: true + + /pidtree@0.3.1: + resolution: {integrity: sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==} + engines: {node: '>=0.10'} + hasBin: true + dev: true + + /pify@3.0.0: + resolution: {integrity: sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==} + engines: {node: '>=4'} + dev: true + + /pinia@2.1.4(typescript@5.2.2)(vue@3.3.4): + resolution: {integrity: sha512-vYlnDu+Y/FXxv1ABo1vhjC+IbqvzUdiUC3sfDRrRyY2CQSrqqaa+iiHmqtARFxJVqWQMCJfXx1PBvFs9aJVLXQ==} + peerDependencies: + '@vue/composition-api': ^1.4.0 + typescript: '>=4.4.4' + vue: ^2.6.14 || ^3.3.0 + peerDependenciesMeta: + '@vue/composition-api': + optional: true + typescript: + optional: true + dependencies: + '@vue/devtools-api': 6.5.0 + typescript: 5.2.2 + vue: 3.3.4 + vue-demi: 0.14.5(vue@3.3.4) + dev: false + + /pirates@4.0.6: + resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} + engines: {node: '>= 6'} + dev: true + + /pkg-dir@4.2.0: + resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} + engines: {node: '>=8'} + dependencies: + find-up: 4.1.0 + dev: true + + /postcss-selector-parser@6.0.13: + resolution: {integrity: sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==} + engines: {node: '>=4'} + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + dev: true + + /postcss@8.4.27: + resolution: {integrity: sha512-gY/ACJtJPSmUFPDCHtX78+01fHa64FaU4zaaWfuh1MhGJISufJAH4cun6k/8fwsHYeK4UQmENQK+tRLCFJE8JQ==} + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.6 + picocolors: 1.0.0 + source-map-js: 1.0.2 + + /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.0.0: + resolution: {integrity: sha512-zBf5eHpwHOGPC47h0zrPyNn+eAEIdEzfywMoYn2XPi0P44Zp0tSq64rq0xAREh4auw2cJZHo9QUob+NqCQky4g==} + engines: {node: '>=14'} + hasBin: true + dev: true + + /pretty-format@29.7.0: + resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/schemas': 29.6.3 + ansi-styles: 5.2.0 + react-is: 18.2.0 + dev: true + + /prompts@2.4.2: + resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} + engines: {node: '>= 6'} + dependencies: + kleur: 3.0.3 + sisteransi: 1.0.5 + dev: true + + /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 + + /ps-tree@1.2.0: + resolution: {integrity: sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA==} + engines: {node: '>= 0.10'} + hasBin: true + dependencies: + event-stream: 3.3.4 + dev: true + + /punycode@2.3.0: + resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} + engines: {node: '>=6'} + + /pure-rand@6.0.3: + resolution: {integrity: sha512-KddyFewCsO0j3+np81IQ+SweXLDnDQTs5s67BOnrYmYe/yNmUhttQyGsYzy8yUnoljGAQ9sl38YB4vH8ur7Y+w==} + dev: true + + /qs@6.11.0: + resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==} + engines: {node: '>=0.6'} + dependencies: + side-channel: 1.0.4 + + /queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + dev: true + + /random-bytes@1.0.0: + resolution: {integrity: sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==} + engines: {node: '>= 0.8'} + + /range-parser@1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} + + /raw-body@2.5.1: + resolution: {integrity: sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==} + engines: {node: '>= 0.8'} + dependencies: + bytes: 3.1.2 + http-errors: 2.0.0 + iconv-lite: 0.4.24 + unpipe: 1.0.0 + + /react-is@18.2.0: + resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} + dev: true + + /read-pkg@3.0.0: + resolution: {integrity: sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==} + engines: {node: '>=4'} + dependencies: + load-json-file: 4.0.0 + normalize-package-data: 2.5.0 + path-type: 3.0.0 + dev: true + + /reflect-metadata@0.1.13: + resolution: {integrity: sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==} + dev: false + + /regenerator-runtime@0.13.11: + resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} + dev: false + + /regexp.prototype.flags@1.5.0: + resolution: {integrity: sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.2.0 + functions-have-names: 1.2.3 + dev: true + + /require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + dev: true + + /resolve-cwd@3.0.0: + resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} + engines: {node: '>=8'} + dependencies: + resolve-from: 5.0.0 + dev: true + + /resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + dev: true + + /resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + dev: true + + /resolve.exports@2.0.2: + resolution: {integrity: sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==} + engines: {node: '>=10'} + dev: true + + /resolve@1.22.2: + resolution: {integrity: sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==} + hasBin: true + dependencies: + is-core-module: 2.12.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@3.27.2: + resolution: {integrity: sha512-YGwmHf7h2oUHkVBT248x0yt6vZkYQ3/rvE5iQuVBh3WO8GcJ6BNeOkpoX1yMHIiBm18EMLjBPIoUDkhgnyxGOQ==} + engines: {node: '>=14.18.0', npm: '>=8.0.0'} + hasBin: true + optionalDependencies: + fsevents: 2.3.2 + 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-array-concat@1.0.0: + resolution: {integrity: sha512-9dVEFruWIsnie89yym+xWTAYASdpw3CJV7Li/6zBewGf9z2i1j31rP6jnY0pHEO4QZh6N0K11bFjWmdR8UGdPQ==} + engines: {node: '>=0.4'} + dependencies: + call-bind: 1.0.2 + get-intrinsic: 1.2.1 + has-symbols: 1.0.3 + isarray: 2.0.5 + dev: true + + /safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + /safe-regex-test@1.0.0: + resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==} + dependencies: + call-bind: 1.0.2 + get-intrinsic: 1.2.1 + is-regex: 1.1.4 + dev: true + + /safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + /saslprep@1.0.3: + resolution: {integrity: sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==} + engines: {node: '>=6'} + requiresBuild: true + dependencies: + sparse-bitfield: 3.0.3 + dev: false + optional: true + + /semver@5.7.2: + resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} + hasBin: true + dev: true + + /semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + dev: true + + /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 + dev: true + + /send@0.18.0: + resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==} + engines: {node: '>= 0.8.0'} + dependencies: + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + encodeurl: 1.0.2 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 0.5.2 + http-errors: 2.0.0 + mime: 1.6.0 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.1 + transitivePeerDependencies: + - supports-color + + /serve-static@1.15.0: + resolution: {integrity: sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==} + engines: {node: '>= 0.8.0'} + dependencies: + encodeurl: 1.0.2 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 0.18.0 + transitivePeerDependencies: + - supports-color + + /setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + + /shebang-command@1.2.0: + resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==} + engines: {node: '>=0.10.0'} + dependencies: + shebang-regex: 1.0.0 + 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@1.0.0: + resolution: {integrity: sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==} + engines: {node: '>=0.10.0'} + dev: true + + /shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + dev: true + + /shell-quote@1.8.1: + resolution: {integrity: sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==} + dev: true + + /side-channel@1.0.4: + resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} + dependencies: + call-bind: 1.0.2 + get-intrinsic: 1.2.1 + object-inspect: 1.12.3 + + /sift@16.0.1: + resolution: {integrity: sha512-Wv6BjQ5zbhW7VFefWusVP33T/EM0vYikCaQ2qR8yULbsilAT8/wQaXvuQ3ptGLpoKx+lihJE3y2UTgKDyyNHZQ==} + dev: false + + /signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + dev: true + + /sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + dev: true + + /slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + dev: true + + /smart-buffer@4.2.0: + resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} + engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} + dev: false + + /socks@2.7.1: + resolution: {integrity: sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==} + engines: {node: '>= 10.13.0', npm: '>= 3.0.0'} + dependencies: + ip: 2.0.0 + smart-buffer: 4.2.0 + dev: false + + /source-map-js@1.0.2: + resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} + engines: {node: '>=0.10.0'} + + /source-map-support@0.5.13: + resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + dev: true + + /source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + dev: true + + /sparse-bitfield@3.0.3: + resolution: {integrity: sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==} + requiresBuild: true + dependencies: + memory-pager: 1.5.0 + dev: false + optional: true + + /spdx-correct@3.2.0: + resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} + dependencies: + spdx-expression-parse: 3.0.1 + spdx-license-ids: 3.0.13 + dev: true + + /spdx-exceptions@2.3.0: + resolution: {integrity: sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==} + dev: true + + /spdx-expression-parse@3.0.1: + resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} + dependencies: + spdx-exceptions: 2.3.0 + spdx-license-ids: 3.0.13 + dev: true + + /spdx-license-ids@3.0.13: + resolution: {integrity: sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==} + dev: true + + /split@0.3.3: + resolution: {integrity: sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA==} + dependencies: + through: 2.3.8 + dev: true + + /sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + dev: true + + /stack-utils@2.0.6: + resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} + engines: {node: '>=10'} + dependencies: + escape-string-regexp: 2.0.0 + dev: true + + /statuses@2.0.1: + resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} + engines: {node: '>= 0.8'} + + /stream-combiner@0.0.4: + resolution: {integrity: sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw==} + dependencies: + duplexer: 0.1.2 + dev: true + + /string-argv@0.3.2: + resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} + engines: {node: '>=0.6.19'} + dev: true + + /string-length@4.0.2: + resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} + engines: {node: '>=10'} + dependencies: + char-regex: 1.0.2 + strip-ansi: 6.0.1 + 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.prototype.padend@3.1.4: + resolution: {integrity: sha512-67otBXoksdjsnXXRUq+KMVTdlVRZ2af422Y0aTyTjVaoQkGr3mxl2Bc5emi7dOQ3OGVVQQskmLEWwFXwommpNw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.2.0 + es-abstract: 1.22.1 + dev: true + + /string.prototype.trim@1.2.7: + resolution: {integrity: sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.2.0 + es-abstract: 1.22.1 + dev: true + + /string.prototype.trimend@1.0.6: + resolution: {integrity: sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==} + dependencies: + call-bind: 1.0.2 + define-properties: 1.2.0 + es-abstract: 1.22.1 + dev: true + + /string.prototype.trimstart@1.0.6: + resolution: {integrity: sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==} + dependencies: + call-bind: 1.0.2 + define-properties: 1.2.0 + es-abstract: 1.22.1 + dev: true + + /strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + dependencies: + ansi-regex: 5.0.1 + dev: true + + /strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + dev: true + + /strip-bom@4.0.0: + resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} + engines: {node: '>=8'} + 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 + 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-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + 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 + + /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 + + /test-exclude@6.0.0: + resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} + engines: {node: '>=8'} + dependencies: + '@istanbuljs/schema': 0.1.3 + glob: 7.2.3 + minimatch: 3.1.2 + dev: true + + /text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + dev: true + + /through@2.3.8: + resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + dev: true + + /titleize@3.0.0: + resolution: {integrity: sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==} + engines: {node: '>=12'} + dev: true + + /tmpl@1.0.5: + resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} + dev: true + + /to-fast-properties@2.0.0: + resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} + engines: {node: '>=4'} + + /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'} + + /tr46@3.0.0: + resolution: {integrity: sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==} + engines: {node: '>=12'} + dependencies: + punycode: 2.3.0 + dev: false + + /ts-api-utils@1.0.3(typescript@5.2.2): + resolution: {integrity: sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==} + engines: {node: '>=16.13.0'} + peerDependencies: + typescript: '>=4.2.0' + dependencies: + typescript: 5.2.2 + dev: true + + /ts-jest@29.1.1(@babel/core@7.22.20)(jest@29.7.0)(typescript@5.2.2): + resolution: {integrity: sha512-D6xjnnbP17cC85nliwGiL+tpoKN0StpgE0TeOjXQTU6MVCfsB4v7aW05CgQ/1OywGb0x/oy9hHFnN+sczTiRaA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + peerDependencies: + '@babel/core': '>=7.0.0-beta.0 <8' + '@jest/types': ^29.0.0 + babel-jest: ^29.0.0 + esbuild: '*' + jest: ^29.0.0 + typescript: '>=4.3 <6' + peerDependenciesMeta: + '@babel/core': + optional: true + '@jest/types': + optional: true + babel-jest: + optional: true + esbuild: + optional: true + dependencies: + '@babel/core': 7.22.20 + bs-logger: 0.2.6 + fast-json-stable-stringify: 2.1.0 + jest: 29.7.0(@types/node@20.6.3)(ts-node@10.9.1) + jest-util: 29.7.0 + json5: 2.2.3 + lodash.memoize: 4.1.2 + make-error: 1.3.6 + semver: 7.5.4 + typescript: 5.2.2 + yargs-parser: 21.1.1 + dev: true + + /ts-node@10.9.1(@types/node@18.17.0)(typescript@5.1.6): + resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} + hasBin: true + peerDependencies: + '@swc/core': '>=1.2.50' + '@swc/wasm': '>=1.2.50' + '@types/node': '*' + typescript: '>=2.7' + peerDependenciesMeta: + '@swc/core': + optional: true + '@swc/wasm': + optional: true + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.9 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 18.17.0 + acorn: 8.10.0 + acorn-walk: 8.2.0 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 5.1.6 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + dev: true + + /ts-node@10.9.1(@types/node@20.6.3)(typescript@5.2.2): + resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} + hasBin: true + peerDependencies: + '@swc/core': '>=1.2.50' + '@swc/wasm': '>=1.2.50' + '@types/node': '*' + typescript: '>=2.7' + peerDependenciesMeta: + '@swc/core': + optional: true + '@swc/wasm': + optional: true + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.9 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 20.6.3 + acorn: 8.10.0 + acorn-walk: 8.2.0 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 5.2.2 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + dev: true + + /tsc-watch@6.0.4(typescript@5.1.6): + resolution: {integrity: sha512-cHvbvhjO86w2aGlaHgSCeQRl+Aqw6X6XN4sQMPZKF88GoP30O+oTuh5lRIJr5pgFWrRpF1AgXnJJ2DoFEIPHyg==} + engines: {node: '>=12.12.0'} + hasBin: true + peerDependencies: + typescript: '*' + dependencies: + cross-spawn: 7.0.3 + node-cleanup: 2.1.2 + ps-tree: 1.2.0 + string-argv: 0.3.2 + typescript: 5.1.6 + dev: true + + /tslib@1.14.1: + resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + dev: true + + /tslib@2.6.2: + resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} + + /tsutils@3.21.0(typescript@5.1.6): + resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} + engines: {node: '>= 6'} + peerDependencies: + typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' + dependencies: + tslib: 1.14.1 + typescript: 5.1.6 + dev: true + + /tsutils@3.21.0(typescript@5.2.2): + resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} + engines: {node: '>= 6'} + peerDependencies: + typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' + dependencies: + tslib: 1.14.1 + typescript: 5.2.2 + 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-detect@4.0.8: + resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} + engines: {node: '>=4'} + dev: true + + /type-fest@0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} + dev: true + + /type-fest@0.21.3: + resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} + 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 + + /typed-array-buffer@1.0.0: + resolution: {integrity: sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + get-intrinsic: 1.2.1 + 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.2 + 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.2 + 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.2 + for-each: 0.3.3 + is-typed-array: 1.1.12 + dev: true + + /typescript@5.1.6: + resolution: {integrity: sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==} + engines: {node: '>=14.17'} + hasBin: true + dev: true + + /typescript@5.2.2: + resolution: {integrity: sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==} + engines: {node: '>=14.17'} + hasBin: true + + /uid-safe@2.1.5: + resolution: {integrity: sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==} + engines: {node: '>= 0.8'} + dependencies: + random-bytes: 1.0.0 + + /unbox-primitive@1.0.2: + resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} + dependencies: + call-bind: 1.0.2 + has-bigints: 1.0.2 + has-symbols: 1.0.3 + which-boxed-primitive: 1.0.2 + dev: true + + /unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + + /untildify@4.0.0: + resolution: {integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==} + engines: {node: '>=8'} + dev: true + + /update-browserslist-db@1.0.13(browserslist@4.21.11): + resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + dependencies: + browserslist: 4.21.11 + escalade: 3.1.1 + picocolors: 1.0.0 + dev: true + + /uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + dependencies: + punycode: 2.3.0 + dev: true + + /util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + dev: true + + /utils-merge@1.0.1: + resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} + engines: {node: '>= 0.4.0'} + + /v8-compile-cache-lib@3.0.1: + resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} + dev: true + + /v8-to-istanbul@9.1.0: + resolution: {integrity: sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==} + engines: {node: '>=10.12.0'} + dependencies: + '@jridgewell/trace-mapping': 0.3.19 + '@types/istanbul-lib-coverage': 2.0.4 + convert-source-map: 1.9.0 + dev: true + + /validate-npm-package-license@3.0.4: + resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} + dependencies: + spdx-correct: 3.2.0 + spdx-expression-parse: 3.0.1 + dev: true + + /vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + + /vite@4.4.6(@types/node@18.17.0): + resolution: {integrity: sha512-EY6Mm8vJ++S3D4tNAckaZfw3JwG3wa794Vt70M6cNJ6NxT87yhq7EC8Rcap3ahyHdo8AhCmV9PTk+vG1HiYn1A==} + engines: {node: ^14.18.0 || >=16.0.0} + hasBin: true + peerDependencies: + '@types/node': '>= 14' + 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: + '@types/node': 18.17.0 + esbuild: 0.18.17 + postcss: 8.4.27 + rollup: 3.27.2 + optionalDependencies: + fsevents: 2.3.2 + dev: true + + /vite@4.4.6(@types/node@20.6.3): + resolution: {integrity: sha512-EY6Mm8vJ++S3D4tNAckaZfw3JwG3wa794Vt70M6cNJ6NxT87yhq7EC8Rcap3ahyHdo8AhCmV9PTk+vG1HiYn1A==} + engines: {node: ^14.18.0 || >=16.0.0} + hasBin: true + peerDependencies: + '@types/node': '>= 14' + 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: + '@types/node': 20.6.3 + esbuild: 0.18.17 + postcss: 8.4.27 + rollup: 3.27.2 + optionalDependencies: + fsevents: 2.3.2 + dev: true + + /vue-demi@0.14.5(vue@3.3.4): + resolution: {integrity: sha512-o9NUVpl/YlsGJ7t+xuqJKx8EBGf1quRhCiT6D/J0pfwmk9zUwYkC7yrF4SZCe6fETvSM3UNL2edcbYrSyc4QHA==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + peerDependencies: + '@vue/composition-api': ^1.0.0-rc.1 + vue: ^3.0.0-0 || ^2.6.0 + peerDependenciesMeta: + '@vue/composition-api': + optional: true + dependencies: + vue: 3.3.4 + dev: false + + /vue-eslint-parser@9.3.1(eslint@8.45.0): + resolution: {integrity: sha512-Clr85iD2XFZ3lJ52/ppmUDG/spxQu6+MAeHXjjyI4I1NUYZ9xmenQp4N0oaHJhrA8OOxltCVxMRfANGa70vU0g==} + engines: {node: ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: '>=6.0.0' + dependencies: + debug: 4.3.4 + eslint: 8.45.0 + eslint-scope: 7.2.2 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 + esquery: 1.5.0 + lodash: 4.17.21 + semver: 7.5.4 + transitivePeerDependencies: + - supports-color + dev: true + + /vue-eslint-parser@9.3.1(eslint@8.50.0): + resolution: {integrity: sha512-Clr85iD2XFZ3lJ52/ppmUDG/spxQu6+MAeHXjjyI4I1NUYZ9xmenQp4N0oaHJhrA8OOxltCVxMRfANGa70vU0g==} + engines: {node: ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: '>=6.0.0' + dependencies: + debug: 4.3.4 + eslint: 8.50.0 + eslint-scope: 7.2.2 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 + esquery: 1.5.0 + lodash: 4.17.21 + semver: 7.5.4 + transitivePeerDependencies: + - supports-color + dev: true + + /vue-router@4.2.4(vue@3.3.4): + resolution: {integrity: sha512-9PISkmaCO02OzPVOMq2w82ilty6+xJmQrarYZDkjZBfl4RvYAlt4PKnEX21oW4KTtWfa9OuO/b3qk1Od3AEdCQ==} + peerDependencies: + vue: ^3.2.0 + dependencies: + '@vue/devtools-api': 6.5.0 + vue: 3.3.4 + dev: false + + /vue-template-compiler@2.7.14: + resolution: {integrity: sha512-zyA5Y3ArvVG0NacJDkkzJuPQDF8RFeRlzV2vLeSnhSpieO6LK2OVbdLPi5MPPs09Ii+gMO8nY4S3iKQxBxDmWQ==} + dependencies: + de-indent: 1.0.2 + he: 1.2.0 + dev: true + + /vue-tsc@1.8.6(typescript@5.2.2): + resolution: {integrity: sha512-8ffD4NGfwyATjw/s40Lw2EgB7L2/PAqnGlJBaVQLgblr3SU4EYdhJ67TNXXuDD8NMbDAFSM24V8i3ZIJgTs32Q==} + hasBin: true + peerDependencies: + typescript: '*' + dependencies: + '@vue/language-core': 1.8.6(typescript@5.2.2) + '@vue/typescript': 1.8.6(typescript@5.2.2) + semver: 7.5.4 + typescript: 5.2.2 + dev: true + + /vue@3.3.4: + resolution: {integrity: sha512-VTyEYn3yvIeY1Py0WaYGZsXnz3y5UnGi62GjVEqvEGPl6nxbOrCXbVOTQWBEJUqAyTUk2uJ5JLVnYJ6ZzGbrSw==} + dependencies: + '@vue/compiler-dom': 3.3.4 + '@vue/compiler-sfc': 3.3.4 + '@vue/runtime-dom': 3.3.4 + '@vue/server-renderer': 3.3.4(vue@3.3.4) + '@vue/shared': 3.3.4 + + /walker@1.0.8: + resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} + dependencies: + makeerror: 1.0.12 + dev: true + + /webidl-conversions@7.0.0: + resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} + engines: {node: '>=12'} + dev: false + + /whatwg-url@11.0.0: + resolution: {integrity: sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==} + engines: {node: '>=12'} + dependencies: + tr46: 3.0.0 + webidl-conversions: 7.0.0 + dev: false + + /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-typed-array@1.1.11: + resolution: {integrity: sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.5 + call-bind: 1.0.2 + for-each: 0.3.3 + gopd: 1.0.1 + has-tostringtag: 1.0.0 + dev: true + + /which@1.3.1: + resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} + hasBin: true + dependencies: + isexe: 2.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 + + /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==} + dev: true + + /write-file-atomic@4.0.2: + resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + dependencies: + imurmurhash: 0.1.4 + signal-exit: 3.0.7 + dev: true + + /xml-name-validator@4.0.0: + resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==} + engines: {node: '>=12'} + dev: true + + /y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + dev: true + + /yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + dev: true + + /yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + dev: true + + /yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + dev: true + + /yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + dependencies: + cliui: 8.0.1 + 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: 21.1.1 + dev: true + + /yn@3.1.1: + resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} + engines: {node: '>=6'} + dev: true + + /yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + dev: true + + /zod@3.22.2: + resolution: {integrity: sha512-wvWkphh5WQsJbVk1tbx1l1Ly4yg+XecD+Mq280uBGt9wa5BKSWf4Mhp6GmrkPixhMxmabYY7RbzlwVP32pbGCg==} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 0000000..432bec2 --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,4 @@ +packages: + - '@sammo/*' + - '@strpc/*' + - '!**/test/**' \ No newline at end of file diff --git a/schemats.d.ts b/schemats.d.ts new file mode 100644 index 0000000..68b0573 --- /dev/null +++ b/schemats.d.ts @@ -0,0 +1,1079 @@ +/* eslint-disable @typescript-eslint/no-namespace */ + + +/** + * AUTO-GENERATED FILE @ 2023-08-05 12:06:36 - DO NOT EDIT! + * + * This file was automatically generated by schemats v.3.0.3 + * $ schemats generate -c mysql://username:password@127.0.0.1/hidche_hwe -C -t board -t city -t comment -t diplomacy -t emperior -t event -t general -t general_access_log -t general_record -t general_turn -t hall -t message -t nation -t nation_env -t nation_turn -t ng_auction -t ng_auction_bid -t ng_betting -t ng_diplomacy -t ng_games -t ng_history -t ng_old_generals -t ng_old_nations -t plock -t rank_data -t reserved_open -t select_npc_token -t select_pool -t statistic -t storage -t tournament -t troop -t user_record -t vote -t vote_comment -t world_history -s hidche_hwe + * + */ + +export type EnumTarget = 'MONTH' | 'OCCUPY_CITY' | 'DESTROY_NATION' | 'PRE_MONTH' | 'UNITED'; +export type EnumAuctionType = 'buyRice' | 'sellRice' | 'uniqueItem'; +export type EnumReqResource = 'gold' | 'rice' | 'inheritPoint'; +export type EnumLogType = 'action' | 'battle_brief' | 'battle' | 'history'; +export type EnumMsgType = 'private' | 'national' | 'public' | 'diplomacy'; +export type EnumPermission = 'normal' | 'auditor' | 'ambassador'; +export type EnumType = 'GAME' | 'ETC' | 'TOURNAMENT'; +export type EnumState = 'proposed' | 'activated' | 'cancelled' | 'replaced'; + +export namespace BoardFields { + export type no = number; + export type nationNo = number; + export type isSecret = boolean; + export type date = Date; + export type generalNo = number; + export type author = string; + export type authorIcon = string | null; + export type title = string; + export type text = string; + +} + +export interface Board { + no: BoardFields.no; + nationNo: BoardFields.nationNo; + isSecret: BoardFields.isSecret; + date: BoardFields.date; + generalNo: BoardFields.generalNo; + author: BoardFields.author; + authorIcon: BoardFields.authorIcon; + title: BoardFields.title; + text: BoardFields.text; + +} + +export namespace CityFields { + export type city = number; + export type name = string; + export type level = number; + export type nation = number; + export type supply = number; + export type front = number; + export type pop = number; + export type popMax = number; + export type agri = number; + export type agriMax = number; + export type comm = number; + export type commMax = number; + export type secu = number; + export type secuMax = number; + export type trust = number; + export type trade = number | null; + export type dead = number; + export type def = number; + export type defMax = number; + export type wall = number; + export type wallMax = number; + export type officerSet = number; + export type state = number; + export type region = number; + export type term = number; + export type conflict = string; + +} + +export interface City { + city: CityFields.city; + name: CityFields.name; + level: CityFields.level; + nation: CityFields.nation; + supply: CityFields.supply; + front: CityFields.front; + pop: CityFields.pop; + popMax: CityFields.popMax; + agri: CityFields.agri; + agriMax: CityFields.agriMax; + comm: CityFields.comm; + commMax: CityFields.commMax; + secu: CityFields.secu; + secuMax: CityFields.secuMax; + trust: CityFields.trust; + trade: CityFields.trade; + dead: CityFields.dead; + def: CityFields.def; + defMax: CityFields.defMax; + wall: CityFields.wall; + wallMax: CityFields.wallMax; + officerSet: CityFields.officerSet; + state: CityFields.state; + region: CityFields.region; + term: CityFields.term; + conflict: CityFields.conflict; + +} + +export namespace CommentFields { + export type no = number; + export type nationNo = number; + export type isSecret = boolean; + export type date = Date; + export type documentNo = number; + export type generalNo = number; + export type author = string; + export type text = string; + +} + +export interface Comment { + no: CommentFields.no; + nationNo: CommentFields.nationNo; + isSecret: CommentFields.isSecret; + date: CommentFields.date; + documentNo: CommentFields.documentNo; + generalNo: CommentFields.generalNo; + author: CommentFields.author; + text: CommentFields.text; + +} + +export namespace DiplomacyFields { + export type no = number; + export type me = number; + export type you = number; + export type state = number | null; + export type term = number | null; + export type dead = number | null; + export type showing = Date | null; + +} + +export interface Diplomacy { + no: DiplomacyFields.no; + me: DiplomacyFields.me; + you: DiplomacyFields.you; + state: DiplomacyFields.state; + term: DiplomacyFields.term; + dead: DiplomacyFields.dead; + showing: DiplomacyFields.showing; + +} + +export namespace EmperiorFields { + export type no = number; + export type serverId = string | null; + export type phase = string | null; + export type nationCount = string | null; + export type nationName = string | null; + export type nationHist = string | null; + export type genCount = string | null; + export type personalHist = string | null; + export type specialHist = string | null; + export type name = string | null; + export type type = string | null; + export type color = string | null; + export type year = number | null; + export type month = number | null; + export type power = number | null; + export type gennum = number | null; + export type citynum = number | null; + export type pop = string | null; + export type poprate = string | null; + export type gold = number | null; + export type rice = number | null; + export type l12Name = string | null; + export type l12Pic = string | null; + export type l11Name = string | null; + export type l11Pic = string | null; + export type l10Name = string | null; + export type l10Pic = string | null; + export type l9Name = string | null; + export type l9Pic = string | null; + export type l8Name = string | null; + export type l8Pic = string | null; + export type l7Name = string | null; + export type l7Pic = string | null; + export type l6Name = string | null; + export type l6Pic = string | null; + export type l5Name = string | null; + export type l5Pic = string | null; + export type tiger = string | null; + export type eagle = string | null; + export type gen = string | null; + export type history = string | null; + export type aux = string | null; + +} + +export interface Emperior { + no: EmperiorFields.no; + serverId: EmperiorFields.serverId; + phase: EmperiorFields.phase; + nationCount: EmperiorFields.nationCount; + nationName: EmperiorFields.nationName; + nationHist: EmperiorFields.nationHist; + genCount: EmperiorFields.genCount; + personalHist: EmperiorFields.personalHist; + specialHist: EmperiorFields.specialHist; + name: EmperiorFields.name; + type: EmperiorFields.type; + color: EmperiorFields.color; + year: EmperiorFields.year; + month: EmperiorFields.month; + power: EmperiorFields.power; + gennum: EmperiorFields.gennum; + citynum: EmperiorFields.citynum; + pop: EmperiorFields.pop; + poprate: EmperiorFields.poprate; + gold: EmperiorFields.gold; + rice: EmperiorFields.rice; + l12Name: EmperiorFields.l12Name; + l12Pic: EmperiorFields.l12Pic; + l11Name: EmperiorFields.l11Name; + l11Pic: EmperiorFields.l11Pic; + l10Name: EmperiorFields.l10Name; + l10Pic: EmperiorFields.l10Pic; + l9Name: EmperiorFields.l9Name; + l9Pic: EmperiorFields.l9Pic; + l8Name: EmperiorFields.l8Name; + l8Pic: EmperiorFields.l8Pic; + l7Name: EmperiorFields.l7Name; + l7Pic: EmperiorFields.l7Pic; + l6Name: EmperiorFields.l6Name; + l6Pic: EmperiorFields.l6Pic; + l5Name: EmperiorFields.l5Name; + l5Pic: EmperiorFields.l5Pic; + tiger: EmperiorFields.tiger; + eagle: EmperiorFields.eagle; + gen: EmperiorFields.gen; + history: EmperiorFields.history; + aux: EmperiorFields.aux; + +} + +export namespace EventFields { + export type id = number; + export type target = EnumTarget; + export type priority = number; + export type condition = string; + export type action = string; + +} + +export interface Event { + id: EventFields.id; + target: EventFields.target; + priority: EventFields.priority; + condition: EventFields.condition; + action: EventFields.action; + +} + +export namespace GeneralFields { + export type no = number; + export type owner = number; + export type npcmsg = string | null; + export type npc = number; + export type npcOrg = number | null; + export type affinity = number | null; + export type bornyear = number | null; + export type deadyear = number | null; + export type newmsg = number | null; + export type picture = string; + export type imgsvr = number; + export type name = string; + export type ownerName = string | null; + export type nation = number; + export type city = number; + export type troop = number; + export type leadership = number; + export type leadershipExp = number; + export type strength = number; + export type strengthExp = number; + export type intel = number; + export type intelExp = number; + export type injury = number; + export type experience = number; + export type dedication = number; + export type dex1 = number; + export type dex2 = number; + export type dex3 = number; + export type dex4 = number; + export type dex5 = number; + export type officerLevel = number; + export type officerCity = number; + export type permission = EnumPermission | null; + export type gold = number; + export type rice = number; + export type crew = number; + export type crewtype = number; + export type train = number; + export type atmos = number; + export type weapon = string; + export type book = string; + export type horse = string; + export type item = string; + export type turntime = Date; + export type recentWar = Date | null; + export type makelimit = number | null; + export type killturn = number | null; + export type block = number | null; + export type dedlevel = number | null; + export type explevel = number | null; + export type age = number | null; + export type startage = number | null; + export type belong = number | null; + export type betray = number | null; + export type personal = string; + export type special = string; + export type specage = number | null; + export type special2 = string; + export type specage2 = number | null; + export type defenceTrain = number | null; + export type tnmt = number | null; + export type myset = number | null; + export type tournament = number | null; + export type newvote = number | null; + export type lastTurn = string; + export type aux = string; + export type penalty = string | null; + +} + +export interface General { + no: GeneralFields.no; + owner: GeneralFields.owner; + npcmsg: GeneralFields.npcmsg; + npc: GeneralFields.npc; + npcOrg: GeneralFields.npcOrg; + affinity: GeneralFields.affinity; + bornyear: GeneralFields.bornyear; + deadyear: GeneralFields.deadyear; + newmsg: GeneralFields.newmsg; + picture: GeneralFields.picture; + imgsvr: GeneralFields.imgsvr; + name: GeneralFields.name; + ownerName: GeneralFields.ownerName; + nation: GeneralFields.nation; + city: GeneralFields.city; + troop: GeneralFields.troop; + leadership: GeneralFields.leadership; + leadershipExp: GeneralFields.leadershipExp; + strength: GeneralFields.strength; + strengthExp: GeneralFields.strengthExp; + intel: GeneralFields.intel; + intelExp: GeneralFields.intelExp; + injury: GeneralFields.injury; + experience: GeneralFields.experience; + dedication: GeneralFields.dedication; + dex1: GeneralFields.dex1; + dex2: GeneralFields.dex2; + dex3: GeneralFields.dex3; + dex4: GeneralFields.dex4; + dex5: GeneralFields.dex5; + officerLevel: GeneralFields.officerLevel; + officerCity: GeneralFields.officerCity; + permission: GeneralFields.permission; + gold: GeneralFields.gold; + rice: GeneralFields.rice; + crew: GeneralFields.crew; + crewtype: GeneralFields.crewtype; + train: GeneralFields.train; + atmos: GeneralFields.atmos; + weapon: GeneralFields.weapon; + book: GeneralFields.book; + horse: GeneralFields.horse; + item: GeneralFields.item; + turntime: GeneralFields.turntime; + recentWar: GeneralFields.recentWar; + makelimit: GeneralFields.makelimit; + killturn: GeneralFields.killturn; + block: GeneralFields.block; + dedlevel: GeneralFields.dedlevel; + explevel: GeneralFields.explevel; + age: GeneralFields.age; + startage: GeneralFields.startage; + belong: GeneralFields.belong; + betray: GeneralFields.betray; + personal: GeneralFields.personal; + special: GeneralFields.special; + specage: GeneralFields.specage; + special2: GeneralFields.special2; + specage2: GeneralFields.specage2; + defenceTrain: GeneralFields.defenceTrain; + tnmt: GeneralFields.tnmt; + myset: GeneralFields.myset; + tournament: GeneralFields.tournament; + newvote: GeneralFields.newvote; + lastTurn: GeneralFields.lastTurn; + aux: GeneralFields.aux; + penalty: GeneralFields.penalty; + +} + +export namespace GeneralAccessLogFields { + export type id = number; + export type generalId = number; + export type userId = number | null; + export type lastRefresh = Date | null; + export type refresh = number; + export type refreshTotal = number; + export type refreshScore = number; + export type refreshScoreTotal = number; + +} + +export interface GeneralAccessLog { + id: GeneralAccessLogFields.id; + generalId: GeneralAccessLogFields.generalId; + userId: GeneralAccessLogFields.userId; + lastRefresh: GeneralAccessLogFields.lastRefresh; + refresh: GeneralAccessLogFields.refresh; + refreshTotal: GeneralAccessLogFields.refreshTotal; + refreshScore: GeneralAccessLogFields.refreshScore; + refreshScoreTotal: GeneralAccessLogFields.refreshScoreTotal; + +} + +export namespace GeneralRecordFields { + export type id = number; + export type generalId = number; + export type logType = EnumLogType; + export type year = number; + export type month = number; + export type text = string; + +} + +export interface GeneralRecord { + id: GeneralRecordFields.id; + generalId: GeneralRecordFields.generalId; + logType: GeneralRecordFields.logType; + year: GeneralRecordFields.year; + month: GeneralRecordFields.month; + text: GeneralRecordFields.text; + +} + +export namespace GeneralTurnFields { + export type id = number; + export type generalId = number; + export type turnIdx = number; + export type action = string; + export type arg = string | null; + export type brief = string | null; + +} + +export interface GeneralTurn { + id: GeneralTurnFields.id; + generalId: GeneralTurnFields.generalId; + turnIdx: GeneralTurnFields.turnIdx; + action: GeneralTurnFields.action; + arg: GeneralTurnFields.arg; + brief: GeneralTurnFields.brief; + +} + +export namespace HallFields { + export type id = number; + export type serverId = string; + export type season = number; + export type scenario = number; + export type generalNo = number; + export type type = string; + export type value = number; + export type owner = number | null; + export type aux = string; + +} + +export interface Hall { + id: HallFields.id; + serverId: HallFields.serverId; + season: HallFields.season; + scenario: HallFields.scenario; + generalNo: HallFields.generalNo; + type: HallFields.type; + value: HallFields.value; + owner: HallFields.owner; + aux: HallFields.aux; + +} + +export namespace MessageFields { + export type id = number; + export type mailbox = number; + export type type = EnumMsgType; + export type src = number; + export type dest = number; + export type time = Date; + export type validUntil = Date; + export type message = string; + +} + +export interface Message { + id: MessageFields.id; + mailbox: MessageFields.mailbox; + type: MessageFields.type; + src: MessageFields.src; + dest: MessageFields.dest; + time: MessageFields.time; + validUntil: MessageFields.validUntil; + message: MessageFields.message; + +} + +export namespace NationFields { + export type nation = number; + export type name = string; + export type color = string; + export type capital = number | null; + export type capset = number | null; + export type gennum = number | null; + export type gold = number | null; + export type rice = number | null; + export type bill = number | null; + export type rate = number | null; + export type rateTmp = number | null; + export type secretlimit = number | null; + export type chiefSet = number; + export type scout = number | null; + export type war = number | null; + export type strategicCmdLimit = number | null; + export type surlimit = number | null; + export type tech = number | null; + export type power = number | null; + export type spy = string; + export type level = number | null; + export type type = string; + export type aux = string; + +} + +export interface Nation { + nation: NationFields.nation; + name: NationFields.name; + color: NationFields.color; + capital: NationFields.capital; + capset: NationFields.capset; + gennum: NationFields.gennum; + gold: NationFields.gold; + rice: NationFields.rice; + bill: NationFields.bill; + rate: NationFields.rate; + rateTmp: NationFields.rateTmp; + secretlimit: NationFields.secretlimit; + chiefSet: NationFields.chiefSet; + scout: NationFields.scout; + war: NationFields.war; + strategicCmdLimit: NationFields.strategicCmdLimit; + surlimit: NationFields.surlimit; + tech: NationFields.tech; + power: NationFields.power; + spy: NationFields.spy; + level: NationFields.level; + type: NationFields.type; + aux: NationFields.aux; + +} + +export namespace NationEnvFields { + export type id = number; + export type namespace = number; + export type key = string; + export type value = string; + +} + +export interface NationEnv { + id: NationEnvFields.id; + namespace: NationEnvFields.namespace; + key: NationEnvFields.key; + value: NationEnvFields.value; + +} + +export namespace NationTurnFields { + export type id = number; + export type nationId = number; + export type officerLevel = number; + export type turnIdx = number; + export type action = string; + export type arg = string | null; + export type brief = string | null; + +} + +export interface NationTurn { + id: NationTurnFields.id; + nationId: NationTurnFields.nationId; + officerLevel: NationTurnFields.officerLevel; + turnIdx: NationTurnFields.turnIdx; + action: NationTurnFields.action; + arg: NationTurnFields.arg; + brief: NationTurnFields.brief; + +} + +export namespace NgAuctionFields { + export type id = number; + export type type = EnumAuctionType; + export type finished = Buffer; + export type target = string | null; + export type hostGeneralId = number; + export type reqResource = EnumReqResource; + export type openDate = Date; + export type closeDate = Date; + export type detail = string; + +} + +export interface NgAuction { + id: NgAuctionFields.id; + type: NgAuctionFields.type; + finished: NgAuctionFields.finished; + target: NgAuctionFields.target; + hostGeneralId: NgAuctionFields.hostGeneralId; + reqResource: NgAuctionFields.reqResource; + openDate: NgAuctionFields.openDate; + closeDate: NgAuctionFields.closeDate; + detail: NgAuctionFields.detail; + +} + +export namespace NgAuctionBidFields { + export type no = number; + export type auctionId = number; + export type owner = number | null; + export type generalId = number; + export type amount = number; + export type date = Date; + export type aux = string; + +} + +export interface NgAuctionBid { + no: NgAuctionBidFields.no; + auctionId: NgAuctionBidFields.auctionId; + owner: NgAuctionBidFields.owner; + generalId: NgAuctionBidFields.generalId; + amount: NgAuctionBidFields.amount; + date: NgAuctionBidFields.date; + aux: NgAuctionBidFields.aux; + +} + +export namespace NgBettingFields { + export type id = number; + export type bettingId = number; + export type generalId = number; + export type userId = number | null; + export type bettingType = string; + export type amount = number; + +} + +export interface NgBetting { + id: NgBettingFields.id; + bettingId: NgBettingFields.bettingId; + generalId: NgBettingFields.generalId; + userId: NgBettingFields.userId; + bettingType: NgBettingFields.bettingType; + amount: NgBettingFields.amount; + +} + +export namespace NgDiplomacyFields { + export type no = number; + export type srcNationId = number; + export type destNationId = number; + export type prevNo = number | null; + export type state = EnumState; + export type textBrief = string; + export type textDetail = string; + export type date = Date; + export type srcSigner = number; + export type destSigner = number | null; + export type aux = string | null; + +} + +export interface NgDiplomacy { + no: NgDiplomacyFields.no; + srcNationId: NgDiplomacyFields.srcNationId; + destNationId: NgDiplomacyFields.destNationId; + prevNo: NgDiplomacyFields.prevNo; + state: NgDiplomacyFields.state; + textBrief: NgDiplomacyFields.textBrief; + textDetail: NgDiplomacyFields.textDetail; + date: NgDiplomacyFields.date; + srcSigner: NgDiplomacyFields.srcSigner; + destSigner: NgDiplomacyFields.destSigner; + aux: NgDiplomacyFields.aux; + +} + +export namespace NgGamesFields { + export type id = number; + export type serverId = string; + export type date = Date; + export type winnerNation = number | null; + export type map = string | null; + export type season = number; + export type scenario = number; + export type scenarioName = string; + export type env = string; + +} + +export interface NgGames { + id: NgGamesFields.id; + serverId: NgGamesFields.serverId; + date: NgGamesFields.date; + winnerNation: NgGamesFields.winnerNation; + map: NgGamesFields.map; + season: NgGamesFields.season; + scenario: NgGamesFields.scenario; + scenarioName: NgGamesFields.scenarioName; + env: NgGamesFields.env; + +} + +export namespace NgHistoryFields { + export type no = number; + export type serverId = string; + export type year = number | null; + export type month = number | null; + export type map = string | null; + export type globalHistory = string | null; + export type globalAction = string | null; + export type nations = string | null; + +} + +export interface NgHistory { + no: NgHistoryFields.no; + serverId: NgHistoryFields.serverId; + year: NgHistoryFields.year; + month: NgHistoryFields.month; + map: NgHistoryFields.map; + globalHistory: NgHistoryFields.globalHistory; + globalAction: NgHistoryFields.globalAction; + nations: NgHistoryFields.nations; + +} + +export namespace NgOldGeneralsFields { + export type id = number; + export type serverId = string; + export type generalNo = number; + export type owner = number | null; + export type name = string; + export type lastYearmonth = number; + export type turntime = Date; + export type data = string; + +} + +export interface NgOldGenerals { + id: NgOldGeneralsFields.id; + serverId: NgOldGeneralsFields.serverId; + generalNo: NgOldGeneralsFields.generalNo; + owner: NgOldGeneralsFields.owner; + name: NgOldGeneralsFields.name; + lastYearmonth: NgOldGeneralsFields.lastYearmonth; + turntime: NgOldGeneralsFields.turntime; + data: NgOldGeneralsFields.data; + +} + +export namespace NgOldNationsFields { + export type id = number; + export type serverId = string; + export type nation = number; + export type data = string; + export type date = Date; + +} + +export interface NgOldNations { + id: NgOldNationsFields.id; + serverId: NgOldNationsFields.serverId; + nation: NgOldNationsFields.nation; + data: NgOldNationsFields.data; + date: NgOldNationsFields.date; + +} + +export namespace PlockFields { + export type no = number; + export type type = EnumType; + export type plock = number; + export type locktime = Date; + +} + +export interface Plock { + no: PlockFields.no; + type: PlockFields.type; + plock: PlockFields.plock; + locktime: PlockFields.locktime; + +} + +export namespace RankDataFields { + export type id = number; + export type nationId = number; + export type generalId = number; + export type type = string; + export type value = number; + +} + +export interface RankData { + id: RankDataFields.id; + nationId: RankDataFields.nationId; + generalId: RankDataFields.generalId; + type: RankDataFields.type; + value: RankDataFields.value; + +} + +export namespace ReservedOpenFields { + export type id = number; + export type options = string | null; + export type date = Date | null; + +} + +export interface ReservedOpen { + id: ReservedOpenFields.id; + options: ReservedOpenFields.options; + date: ReservedOpenFields.date; + +} + +export namespace SelectNpcTokenFields { + export type id = number; + export type owner = number; + export type validUntil = Date; + export type pickMoreFrom = Date; + export type pickResult = string; + export type nonce = number; + +} + +export interface SelectNpcToken { + id: SelectNpcTokenFields.id; + owner: SelectNpcTokenFields.owner; + validUntil: SelectNpcTokenFields.validUntil; + pickMoreFrom: SelectNpcTokenFields.pickMoreFrom; + pickResult: SelectNpcTokenFields.pickResult; + nonce: SelectNpcTokenFields.nonce; + +} + +export namespace SelectPoolFields { + export type id = number; + export type uniqueName = string; + export type owner = number | null; + export type generalId = number | null; + export type reservedUntil = Date | null; + export type info = string; + +} + +export interface SelectPool { + id: SelectPoolFields.id; + uniqueName: SelectPoolFields.uniqueName; + owner: SelectPoolFields.owner; + generalId: SelectPoolFields.generalId; + reservedUntil: SelectPoolFields.reservedUntil; + info: SelectPoolFields.info; + +} + +export namespace StatisticFields { + export type no = number; + export type year = number | null; + export type month = number | null; + export type nationCount = number | null; + export type nationName = string | null; + export type nationHist = string | null; + export type genCount = string | null; + export type personalHist = string | null; + export type specialHist = string | null; + export type powerHist = string | null; + export type crewtype = string | null; + export type etc = string | null; + export type aux = string | null; + +} + +export interface Statistic { + no: StatisticFields.no; + year: StatisticFields.year; + month: StatisticFields.month; + nationCount: StatisticFields.nationCount; + nationName: StatisticFields.nationName; + nationHist: StatisticFields.nationHist; + genCount: StatisticFields.genCount; + personalHist: StatisticFields.personalHist; + specialHist: StatisticFields.specialHist; + powerHist: StatisticFields.powerHist; + crewtype: StatisticFields.crewtype; + etc: StatisticFields.etc; + aux: StatisticFields.aux; + +} + +export namespace StorageFields { + export type id = number; + export type namespace = string; + export type key = string; + export type value = string; + +} + +export interface Storage { + id: StorageFields.id; + namespace: StorageFields.namespace; + key: StorageFields.key; + value: StorageFields.value; + +} + +export namespace TournamentFields { + export type seq = number; + export type no = number | null; + export type npc = number | null; + export type name = string | null; + export type w = string | null; + export type b = string | null; + export type h = string | null; + export type leadership = number | null; + export type strength = number | null; + export type intel = number | null; + export type lvl = number | null; + export type grp = number | null; + export type grpNo = number | null; + export type win = number | null; + export type draw = number | null; + export type lose = number | null; + export type gl = number | null; + export type prmt = number | null; + +} + +export interface Tournament { + seq: TournamentFields.seq; + no: TournamentFields.no; + npc: TournamentFields.npc; + name: TournamentFields.name; + w: TournamentFields.w; + b: TournamentFields.b; + h: TournamentFields.h; + leadership: TournamentFields.leadership; + strength: TournamentFields.strength; + intel: TournamentFields.intel; + lvl: TournamentFields.lvl; + grp: TournamentFields.grp; + grpNo: TournamentFields.grpNo; + win: TournamentFields.win; + draw: TournamentFields.draw; + lose: TournamentFields.lose; + gl: TournamentFields.gl; + prmt: TournamentFields.prmt; + +} + +export namespace TroopFields { + export type troopLeader = number; + export type nation = number; + export type name = string; + +} + +export interface Troop { + troopLeader: TroopFields.troopLeader; + nation: TroopFields.nation; + name: TroopFields.name; + +} + +export namespace UserRecordFields { + export type id = number; + export type userId = number; + export type serverId = string; + export type logType = string; + export type year = number; + export type month = number; + export type date = Date | null; + export type text = string; + +} + +export interface UserRecord { + id: UserRecordFields.id; + userId: UserRecordFields.userId; + serverId: UserRecordFields.serverId; + logType: UserRecordFields.logType; + year: UserRecordFields.year; + month: UserRecordFields.month; + date: UserRecordFields.date; + text: UserRecordFields.text; + +} + +export namespace VoteFields { + export type id = number; + export type voteId = number; + export type generalId = number; + export type nationId = number; + export type selection = string; + +} + +export interface Vote { + id: VoteFields.id; + voteId: VoteFields.voteId; + generalId: VoteFields.generalId; + nationId: VoteFields.nationId; + selection: VoteFields.selection; + +} + +export namespace VoteCommentFields { + export type id = number; + export type voteId = number; + export type generalId = number; + export type nationId = number; + export type generalName = string; + export type nationName = string; + export type text = string; + export type date = Date | null; + +} + +export interface VoteComment { + id: VoteCommentFields.id; + voteId: VoteCommentFields.voteId; + generalId: VoteCommentFields.generalId; + nationId: VoteCommentFields.nationId; + generalName: VoteCommentFields.generalName; + nationName: VoteCommentFields.nationName; + text: VoteCommentFields.text; + date: VoteCommentFields.date; + +} + +export namespace WorldHistoryFields { + export type id = number; + export type nationId = number; + export type year = number; + export type month = number; + export type text = string; + +} + +export interface WorldHistory { + id: WorldHistoryFields.id; + nationId: WorldHistoryFields.nationId; + year: WorldHistoryFields.year; + month: WorldHistoryFields.month; + text: WorldHistoryFields.text; + +} diff --git a/tsconfig.base.json b/tsconfig.base.json new file mode 100644 index 0000000..302dea6 --- /dev/null +++ b/tsconfig.base.json @@ -0,0 +1,30 @@ +{ + "compilerOptions": { + "target": "ESNext", + "module": "node16", + "moduleResolution": "node16", + "resolveJsonModule": true, + "declaration": true, + "declarationMap": true, + "importHelpers": true, + "isolatedModules": true, + "verbatimModuleSyntax": true, + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "removeComments": false, + "strict": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "noImplicitOverride": true, + "skipLibCheck": true, + "incremental": true, + "sourceMap": true, + "composite": true + }, + "ts-node": { + "esm": true, + "experimentalSpecifierResolution": "node" + }, + } + \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..5f408c3 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,17 @@ +{ + "extends": "./tsconfig.base.json", + "references": [ + { + "path": "./@sammo/gateway_client" + }, + { + "path": "./@sammo/gateway_server" + }, + { + "path": "./@sammo/server" + }, + { + "path": "./@sammo/client" + }, + ], +}